/* =============================================================================
   L'ÉCRAN DE VENTE — lot L1-b, sous la contrainte `V3-y`.

   ThinkPad X230 tactile, 1366 × 768, plein écran, utilisé au doigt.

   LE BUDGET, ET IL EST TENU PAR CONSTRUCTION :
       728 px utiles (768 − 40 de bandeau)
     −  16 px de marge haute et basse
     = 712 px pour la page
     −  56 px d'en-tête
     = 656 px pour le cadre

   LA LARGEUR :
       1366 px  écran
     −  16 px   marges latérales
     −  14 px   gouttière
     − 370 px   panier   (la caisse v1 : 380 px, agenda.css l. 603)
     = 966 px   pour la grille → 4 colonnes de 234 px

   ⚠️  `overflow: hidden` partout où la caisse vit. Si un contenu ne tient pas,
       on réduit le contenu — on n'ajoute jamais une barre de défilement.
   ============================================================================= */

/* -----------------------------------------------------------------------------
   LA PAGE DE CAISSE — elle fait exactement la hauteur utile, jamais plus
   -------------------------------------------------------------------------- */
body.caisse { overflow: hidden; }

/* ⚠️  `position: fixed`, ET C'EST LE CLAVIER TACTILE QUI L'EXIGE (`V3-ac` ②).
       Le clavier est `fixed` en bas de l'écran : il RECOUVRE la page. Sur les
       768 px du X230 il prend 268 px, et le champ Remise passe dessous.
       TACT-1b sait dégager un champ de trois façons — faire défiler un
       conteneur, faire défiler le document, ou SOULEVER le panneau `fixed` qui
       porte le champ. Les deux premières sont interdites ici : `V3-y` ① dit
       qu'aucune barre de défilement n'apparaît dans la caisse. La troisième ne
       défile pas, elle translate — et elle est reprise à l'identique à la
       fermeture. Ce panneau existe pour qu'elle s'applique.
       Le clavier, lui, est SŒUR de ce bloc et non son enfant : il n'est pas
       emporté par la translation. */
.page.caisse {
  position: fixed;
  top: var(--bandeau); left: 0; right: 0;
  max-width: none;
  height: var(--utile);
  padding: 8px 8px 8px;
  margin: 0;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

.page.caisse > section { flex: 1; min-height: 0; overflow: hidden; display: flex; flex-direction: column; }
/* ⚠️  SANS CETTE LIGNE, `display: flex` ci-dessus écrase le `display: none` que
       l'attribut `hidden` porte par défaut : les DEUX étapes s'affichent, et
       chacune n'a plus que la moitié du budget de hauteur. Trouvé par la
       mesure de `V3-y`, pas par relecture. */
.page.caisse > section[hidden] { display: none; }
.page.caisse h1 { font-size: 1.25rem; }
.page.caisse h2 { font-size: 0.92rem; margin: 0 0 7px; }

.entete-vente {
  display: flex; align-items: center; justify-content: space-between;
  gap: 14px; height: 56px; flex: 0 0 56px; overflow: hidden;
}
.entete-vente h1 { margin: 0; line-height: 1.15; }
.entete-vente .sous-titre { margin: 0; font-size: 0.84rem; }

/* ⚠️  60 px, PAS 44 : `V3-y` ② — « les cibles se touchent au doigt, 60 px de
       haut minimum pour une case de service, un bouton, une ligne de panier ».
       Le poste est un ThinkPad tactile, pas une souris. */
.retour-hub { min-height: var(--cible, 60px); padding-inline: 18px; }

/* Le premier écran répond d'abord au geste qui l'a ouvert : rechercher un
   client. Les alertes restent visibles, mais ne prennent plus deux étages. */
/* ⛔ LES BANDEAUX NE MANGENT PLUS L'ÉCRAN — 28/08, `B000-D386`.

      David, capture à l'appui : *« ça par contre, pas très pratique. »* Cinq
      paiements en attente, et `.alertes-comptoir` prenait **215 px en haut de
      l'écran de confirmation** : « C'est payé » repoussé, le ticket écrasé.

      La cause était `flex: 0 0 auto` — **la zone ne pouvait pas rétrécir**, donc
      elle servait sa hauteur avant tout le monde et les sections en dessous se
      faisaient rogner par l'`overflow: hidden` de la page.

      ⚠️  ON NE RÉDUIT PAS LE CONTENU, ET C'EST LE POINT. `V3-y` ① dit *« si un
          contenu ne tient pas, on réduit le contenu »* — **pas ici** : ce sont
          des paiements réels peut-être débités et des ventes non réglées. Les
          cacher serait exactement ce que `B000-D220` interdit. C'est le motif
          des trois exceptions déjà admises — le panier, le panneau de gestion,
          la liste des rendez-vous : *le contenu n'est pas à nous.*

      ⟶ La zone est bornée et défile **dans son propre cadre**. Vide, elle ne
        prend toujours **aucune hauteur** : `max-height` n'agit que sur ce qui
        existe, et les deux blocs restent `hidden` tant qu'il n'y a rien.

      ⚠️  D'OÙ VIENT LE 118. Ce n'est pas un chiffre rond posé au hasard : c'est
          **la ligne de titre plus trois lignes de détail**, aux mesures de ce
          bandeau — 16 px de remplissage, un titre de ~20 px, des lignes de
          ~26 px. Au-delà de trois paiements en attente, on défile. En deçà,
          **rien ne change pour le comptoir**, et c'était le cas jusqu'au 27/08. */
.alertes-comptoir {
  display: flex;
  gap: 10px;
  flex: 0 1 auto;
  min-height: 0;
  align-items: flex-start;
}

/* ⚠️  LA BORNE EST SUR CHAQUE BANDEAU, PAS SUR LEUR CONTENEUR. Posée sur le
       conteneur, une seule barre servait les deux : faire défiler les cartes
       faisait défiler les créances avec elles, et le bandeau court se
       retrouvait à hauteur du long pour rien. Chacun défile chez lui. */
.alertes-comptoir .bloc-suspens {
  flex: 1 1 0;
  min-width: 0;
  margin-bottom: 10px;
  padding: 8px 12px;
  font-size: 0.9rem;
  max-height: 118px;
  overflow-y: auto;
}
.alertes-comptoir .bloc-suspens ul { margin-top: 3px; }

/* Le cadre : la grille à gauche, le panier à droite. `V3-y` ③ */
.cadre {
  display: grid;
  grid-template-columns: minmax(0, 1fr) var(--panier);
  gap: 14px;
  flex: 1;
  min-height: 0;
  overflow: hidden;
}
.colonne-gauche, .colonne-droite {
  min-height: 0; overflow: hidden;
  display: flex; flex-direction: column;
}

/* -----------------------------------------------------------------------------
   LES CASES — 4 colonnes, et chacune se touche au doigt
   -------------------------------------------------------------------------- */
.grille {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 9px;
  overflow: hidden;
}
.grille.trois { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.grille.deux  { grid-template-columns: repeat(2, minmax(0, 1fr)); }

.case {
  position: relative;
  display: flex; flex-direction: column; justify-content: center; gap: 2px;
  background: var(--bleu); color: var(--texte);
  border: 1px solid var(--bleu-clair); border-radius: 10px;
  padding: 8px 11px; text-align: left; cursor: pointer;
  font-family: inherit; font-size: 0.95rem;
  min-height: 74px;              /* `V3-y` ② — au-dessus des 60 px exigés */
  overflow: hidden;
}
.case:hover { border-color: var(--or); }
.case .nom {
  font-weight: 700; line-height: 1.2;
  overflow: hidden; text-overflow: ellipsis;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
}
.case .prix    { color: var(--or); font-weight: 700; font-variant-numeric: tabular-nums; }
.case .service,
.case .heure   { color: var(--gris); font-size: 0.8rem; white-space: nowrap;
                 overflow: hidden; text-overflow: ellipsis; }
.case .heure   { font-variant-numeric: tabular-nums; font-weight: 700; color: var(--texte); }
.case.info     { cursor: default; }
.case.info:hover { border-color: var(--bleu-clair); }

/* Le service du rendez-vous — §2a. Et la remise appliquée — `V3-z` ②. */
.case.du-rdv { border-color: var(--or); background: #22314a; }

/* `V3-ac` ① — UNE REMISE ÉTEINTE DIT POURQUOI, ET ÇA SE LIT.
   Avant : `opacity: 0.42` sur toute la case, et le motif dans une ligne à
   `nowrap` qui le coupait. David voyait une case grise sans explication —
   « une caisse qui a l'air cassée ». Maintenant : c'est le TITRE et le MONTANT
   qui pâlissent, jamais le motif. Lui reste au contraste plein, sur sa propre
   ligne, et il passe à la ligne. */
.case.eteinte { background: #182437; border-color: #2b3c56; }
.case.eteinte .nom,
.case.eteinte .prix { opacity: 0.5; }
.case.remise .motif {
  color: var(--jaune);
  font-size: 0.8rem; line-height: 1.15;
  white-space: normal;
  overflow: hidden; text-overflow: ellipsis;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
}
.case.remise { min-height: 88px; padding-right: 8px; }

/* `V3-ab` ② — une remise de comptoir est un BOUTON, pas une règle. */
.case.bouton-remise { cursor: pointer; }
.case.bouton-remise:hover { border-color: var(--or); }
.repere.gris { background: var(--bleu-clair); color: var(--gris); }

/* `V3-ac` ④ — la case « Vente de produit ». Elle ferme la grille et n'est pas
   un service : elle ouvre une fenêtre. */
.case.produit { border-color: var(--orange); border-style: dashed; }
.case.produit:hover { border-color: var(--or); }

/* Le moyen de paiement — un choix, deux cases. */
/* ⚠️  DÉFAUT TROUVÉ PAR L'ÉPREUVE, 24/08 — le bouton Bit s'affichait alors que
   son réglage l'éteint. L'attribut `hidden` était bien posé (mesuré :
   `hasAttribute('hidden') === true`), mais `.case { display: flex }` écrase la
   règle du navigateur `[hidden] { display: none }`. Une règle d'auteur bat
   toujours la feuille de style de l'agent.

   La logique était juste et l'écran mentait. C'est le genre de défaut qu'aucune
   relecture ne trouve, et qu'un seul regard à l'écran trouve tout de suite. */
.case[hidden] { display: none; }

.case.moyen { min-height: 92px; }
.case.moyen:disabled { opacity: 0.45; cursor: default; }
.case.moyen:disabled:hover { border-color: var(--bleu-clair); }

.repere {
  display: inline-block;
  background: var(--or); color: #1a1400;
  font-size: 0.66rem; font-weight: 800; letter-spacing: 0.5px;
  padding: 1px 6px; border-radius: 999px;
  position: absolute; top: 6px; right: 6px;
}
.repere.petit { position: static; font-size: 0.62rem; }
.repere.petit.produit { background: var(--orange); color: #fff; }
/* `CAISSE-4` — pour qui est la ligne. Il n'apparaît qu'à plusieurs personnes. */
.repere.petit.personne { background: var(--or); color: #11203a; }

/* =============================================================================
   `CAISSE-4`, 02/09/2026 — LES PERSONNES DE LA VENTE.
   Cibles 60 px (`V3-y`) : on choisit une personne au doigt, pas à la souris.
   ============================================================================= */
.personnes { margin: 0 0 8px; }
#liste-personnes { display: flex; gap: 6px; flex-wrap: wrap; }
.personne {
  position: relative; min-height: 60px; padding: 6px 34px 6px 12px;
  border-radius: 10px; border: 1.5px solid var(--bleu-clair);
  background: var(--bleu-clair); color: var(--texte); font: inherit; cursor: pointer;
  display: flex; flex-direction: column; justify-content: center; gap: 2px; text-align: left;
}
.personne .nom { font-size: 0.95rem; font-weight: 700; line-height: 1.15; }
.personne .combien { font-size: 0.72rem; color: var(--gris); }
.personne.actif { border-color: var(--jaune); background: #2c3d5c; }
.personne.actif .combien { color: var(--jaune); }
.personne .oter {
  position: absolute; top: 4px; right: 4px; width: 26px; height: 26px;
  border-radius: 7px; display: grid; place-items: center;
  background: rgba(196,69,58,.16); color: var(--rouge); font-weight: 800;
}
.recherche-personne { margin: 6px 0 10px; }
.recherche-personne input { width: 100%; }
#resultats-personne { margin-top: 6px; max-height: 190px; overflow: auto; }

/* `CAISSE-5`, 02/09 — le panneau propose le foyer avant qu'on ait tapé. Le
   titre sépare ce que la caisse propose de ce qu'on est allé chercher. */
#resultats-personne .titre-groupe {
  margin: 2px 0 4px; font-size: 0.78rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.04em; color: var(--gris);
}

/* Les blocs de la colonne gauche : le premier prend la place, les autres non.
   `V3-ac` ④ a retiré `.bloc-produit` — la case a rejoint la grille et rendu sa
   hauteur aux motifs de `V3-ac` ①. */
.bloc-services { flex: 0 0 auto; }
.bloc-promos   { flex: 1; min-height: 0; overflow: hidden; margin-top: 10px; }

/* -----------------------------------------------------------------------------
   LE PANIER — §2d. Il tient dans sa colonne, sans défiler.
   -------------------------------------------------------------------------- */
.panier {
  background: var(--bleu); border: 1px solid var(--bleu-clair);
  border-radius: 12px; padding: 12px 14px;
  height: 100%; overflow: hidden;
  display: flex; flex-direction: column;
}

#lignes-panier { flex: 1; min-height: 0; overflow: hidden; }

.panier .ligne {
  display: grid; grid-template-columns: minmax(0, 1fr) 84px 56px;
  align-items: center; gap: 6px;
  min-height: var(--cible);       /* `V3-y` ② */
  border-bottom: 1px solid var(--bleu-clair);
}
/* `V3-ae` ① et ③ : un libellé, un prix. Rien sous le libellé. */
.panier .ligne .libelle {
  font-size: 0.9rem; line-height: 1.2;
  min-width: 0;
  overflow: hidden; text-overflow: ellipsis;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
}
.panier .ligne input.prix-ligne {
  text-align: right; padding: 0 8px; font-size: 0.95rem;
  min-height: 56px;
}
/* `V3-y` ② — « pas de croix minuscule ». La cible fait 56 px de côté, dans une
   ligne de 60. Elle ne peut pas faire 60 elle-même : il faut la place de la
   bordure qui sépare deux lignes. */
.panier .retirer {
  background: var(--bleu-clair); border: none; color: var(--gris);
  font-size: 1.6rem; line-height: 1; cursor: pointer;
  width: 56px; height: 56px; border-radius: 8px;
}
.panier .retirer:hover { color: #fff; background: var(--rouge); }

/* -----------------------------------------------------------------------------
   `V3-ac` ② — LA REMISE LIBRE SE TAPE, ELLE NE SE POUSSE PLUS.
   « C'est n'importe quoi de mettre ça pour des remises » : les remises du
   catalogue sont fixes, ce sont des boutons. Seule la remise libre reste — le
   point ④ de `V3-z` — et elle se saisit au clavier tactile (TACT-1).
   -------------------------------------------------------------------------- */
.bloc-remise {
  flex: 0 0 auto;
  margin-top: 8px; padding-top: 8px;
  border-top: 1px solid var(--bleu-clair);
}

/* -----------------------------------------------------------------------------
   LES PAVÉS DE SAISIE — pourboire et montant reçu, sur l'ÉCRAN D'ENCAISSEMENT.
   `V3-ac` ③ : c'est là leur bon usage, et ils n'apparaissent plus ailleurs.
   Repris de la v1 : trois colonnes ▲ / pas / ▼, jamais de clavier.
   -------------------------------------------------------------------------- */
.paves {
  display: grid; grid-template-columns: 1fr 1fr; gap: 14px;
  margin-top: 14px; padding-top: 12px;
  border-top: 1px solid var(--bleu-clair);
  flex: 0 0 auto;
  /* Un pavé se vise au doigt, il ne se traverse pas : étalé sur 966 px, la
     colonne des centaines et celle des unités seraient à deux mains d'écart. */
  max-width: 620px;
}
/* `V3-ad` ③ — il n'en reste qu'un : le pourboire. */
.paves.un-seul { grid-template-columns: 1fr; max-width: 310px; }
.bloc-saisie { min-width: 0; }
.entete-saisie {
  display: flex; justify-content: space-between; align-items: baseline;
  margin-bottom: 5px;
}
.entete-saisie label { font-size: 0.88rem; font-weight: 700; color: var(--or); }
.entete-saisie strong { font-variant-numeric: tabular-nums; font-size: 1.05rem; }

.fleches { display: grid; grid-template-columns: repeat(3, 1fr); gap: 7px; }
.colonne-pas { display: flex; flex-direction: column; align-items: stretch; gap: 3px; }

/* `V3-y` ② : on tape dessus au doigt. Deux flèches de 44 encadrent le pas —
   la colonne entière fait 100 px, bien au-delà des 60 exigés pour une cible. */
.fleche {
  background: var(--bleu-clair); border: none; color: var(--texte);
  border-radius: 8px; height: 44px; font-size: 1.15rem; line-height: 1;
  cursor: pointer; font-family: inherit;
}
.fleche:hover { background: var(--or); color: #1a1400; }
.fleche:disabled { opacity: 0.4; cursor: default; }
.colonne-pas .pas {
  text-align: center; font-size: 0.76rem; font-weight: 700;
  color: var(--gris); font-variant-numeric: tabular-nums;
}

.total {
  display: flex; justify-content: space-between; align-items: baseline;
  margin: 10px 0 10px; padding-top: 10px;
  border-top: 2px solid var(--bleu-clair);
  font-size: 1rem; flex: 0 0 auto;
}
.total strong { font-size: 1.7rem; color: var(--or); font-variant-numeric: tabular-nums; }

/* `V3-ac` ③ — LE RENDU. Il n'a de sens qu'en espèces, et seulement quand
   quelque chose a été reçu. `manque` dit qu'on n'a pas encore de quoi rendre :
   ce n'est pas une erreur, c'est l'état de la saisie. */
/* Le récapitulatif de l'encaissement : ce qu'on additionne, ligne à ligne. */
#recapitulatif { flex: 1; min-height: 0; overflow: hidden; }
.ligne-recap {
  display: flex; justify-content: space-between; align-items: baseline;
  min-height: 44px; font-size: 0.95rem;
  border-bottom: 1px solid var(--bleu-clair);
}
.ligne-recap strong { font-variant-numeric: tabular-nums; }
.ligne-recap.remise strong { color: var(--or); }

/* §5 bis — `À PAYER` EST UNE INFORMATION, JAMAIS UN BOUTON.
   « On ne clique pas sur un montant » (David, 24/08). Aucun `cursor: pointer`,
   aucun `:hover`, aucune bordure de bouton : rien qui invite au doigt. */
.a-payer {
  display: flex; align-items: baseline; justify-content: space-between; gap: 16px;
  background: var(--bleu); border: 1px solid var(--bleu-clair); border-radius: 12px;
  padding: 14px 20px; margin-bottom: 14px;
}
.a-payer-libelle { color: var(--gris); font-size: 1rem; }
.a-payer-montant {
  font-size: 2.6rem; font-weight: 800; color: var(--or);
  font-variant-numeric: tabular-nums; line-height: 1.1;
}

/* La confirmation — §6. Le montant payé, gros, et rien à interpréter. */
.carte-confirmation {
  background: var(--bleu); border: 1px solid var(--vert); border-radius: 12px;
  padding: 24px 26px;
}
.montant-paye {
  display: block; font-size: 3.4rem; font-weight: 800; color: var(--vert);
  font-variant-numeric: tabular-nums; line-height: 1.1; margin-bottom: 12px;
}
/* `A-2` — UNE CRÉANCE N'EST PAS VERTE. Le vert veut dire « c'est encaissé »
   partout ailleurs dans cette caisse ; l'afficher sur ce qui reste dû, c'est
   dire le contraire de ce que dit le titre. Défaut trouvé à l'écran, pas au
   code (`B000-D190`). */
.carte-confirmation.creance { border-color: #c98a2e; }
.carte-confirmation.creance .montant-paye { color: #f2c777; }
/* `D-1` tâche 3 — le justificatif n'est pas parti, et ça se voit.
   Orange, pas rouge : la vente est bonne, c'est la pièce qui manque. */
.alerte-document {
  margin: 14px 0 0; padding: 10px 12px; border-radius: 8px;
  background: #4a3410; border: 1px solid #c98a2e; color: #f2c777;
  font-size: 1rem; line-height: 1.35;
}

/* `E-1` tâche 4 — CE QUI RESTE EN SUSPENS SE VOIT, ET NE SE CHERCHE PAS.
   Même famille que `.alerte-document` : orange pour ce qui attend, vert pour
   ce que la reprise a retrouvé et écrit. Rouge est réservé aux refus. */
.bloc-suspens {
  margin: 0 0 14px; padding: 12px 14px; border-radius: 10px;
  background: #4a3410; border: 1px solid #c98a2e; color: #f2c777;
  font-size: 1rem; line-height: 1.4;
}
.bloc-suspens strong { display: block; margin-bottom: 4px; }
.bloc-suspens ul { margin: 6px 0 0; padding-left: 20px; }
.bloc-suspens li { font-variant-numeric: tabular-nums; }
.bloc-suspens .retrouve { color: var(--vert); }

/* La sortie du bloc « ouverture ratée » — 28/08. Elle doit se voir : quand ce
   bloc s'affiche, les trois sections du parcours sont cachées et ce lien est le
   SEUL geste possible sur l'écran. */
#ouverture-ratee a { color: var(--or); font-weight: 700; }

/* `A-2` — LES CRÉANCES. Même forme que le bandeau des cartes en suspens : ce
   n'est pas une alerte, c'est un compte qui se voit. Une teinte de moins pour
   qu'il ne crie pas plus fort qu'un paiement carte perdu. */
.bloc-suspens.creances { background: #33290f; border-color: #8a6a2e; color: #e0c98d; }
.bloc-suspens.creances strong { display: inline; margin: 0; color: var(--or); }

/* `A-2` — LE TROISIÈME CHEMIN, « plus tard ». Il vit sous les moyens, à la
   largeur d'un seul pavé : c'est un geste rare, il ne prend pas la place des
   deux qui servent cent fois par semaine. `V3-y` ② : 60 px minimum au doigt,
   et le champ d'acompte en fait autant. */
.bloc-saisie.creance {
  max-width: 310px; margin-top: 14px; padding-top: 12px;
  border-top: 1px solid var(--bleu-clair);
}
.bloc-saisie.creance input {
  width: 100%; min-height: 60px; box-sizing: border-box;
  font-size: 1.2rem; font-variant-numeric: tabular-nums; text-align: center;
  margin-bottom: 8px;
}
.case.moyen.plus-tard { min-height: 60px; width: 100%; }

#confirme-detail { flex: 1; min-height: 0; overflow: hidden; }
#etape-confirmation .panier .bouton { margin-top: 10px; flex: 0 0 auto; }

/* À l'impression, on ne sort que le ticket. Le reste de la caisse n'a rien à
   faire sur le papier. */
@media print {
  #bandeau-etat, #clavier-tactile, #message,
  #etape-confirmation .entete-vente, #etape-confirmation .colonne-gauche,
  #etape-confirmation .panier .bouton { display: none !important; }
  body.caisse, .page.caisse { position: static; height: auto; overflow: visible; }
  .cadre { display: block; }
  .panier { border: none; background: none; color: #000; }
  .ligne-recap { border-color: #999; }
}

.bouton.payer { width: 100%; min-height: 64px; font-size: 1.1rem; flex: 0 0 auto; }
.panier .note { font-size: 0.76rem; margin: 8px 0 0; flex: 0 0 auto; }

/* -----------------------------------------------------------------------------
   CRÉATION DE FICHE — §0
   -------------------------------------------------------------------------- */
.ligne-creation {
  display: flex; gap: 8px; flex-wrap: wrap; align-items: center;
}
/* ⚠️  `min-width: 0`, ET IL EST LOAD-BEARING (mesuré à l'écran le 24/08).
       Sans lui, `min-width: auto` d'un élément flexible vaut la largeur
       intrinsèque d'un `<input>` — environ 177 px pour la taille par défaut de
       20 caractères. Deux champs plus la gouttière font alors 362 px là où le
       panier en offre 342 : la ligne passait en DEUX rangées, et ces 68 px de
       plus chassaient la fiche trouvée hors de la colonne. */
.ligne-creation input[type="text"] { flex: 1 1 130px; width: auto; min-width: 0; }
.ligne-creation .bouton { flex: 0 0 auto; }

/* -----------------------------------------------------------------------------
   LOT `B2`, 24/08 — LE CLIENT PAR SON TÉLÉPHONE.

   LE BUDGET DE LA COLONNE, ET IL EST TENU PAR CONSTRUCTION :
       656 px de cadre − 24 de remplissage du panier = 632 px
     −  22 px  le titre
     −  60 px  le champ du numéro          (`V3-y` ② : la cible fait 60)
     −  8  px  la gouttière
     = 542 px  pour les fiches, le bouton d'ajout et la fiche vierge
       4 fiches × 69 = 276 · le compte des autres 20 · le bouton 68
       la fiche vierge 171                            → 535 px. Ça tient.
   -------------------------------------------------------------------------- */

/* Une fiche par ligne. Dans les 370 px du panier, trois colonnes donneraient
   108 px chacune — un nom de client n'y tient pas, il serait coupé. */
.grille.une { grid-template-columns: 1fr; }
/* 60 px : la plus petite cible tactile de `V3-y` ②, et de quoi porter le nom
   au-dessus du numéro. Quatre en tiennent là où trois de 74 tenaient. */
.grille.une .case { min-height: var(--cible); }

#etape-client #liste-clients { flex: 1; min-height: 0; overflow: hidden; margin-top: 8px; }

/* Recherche à gauche, donc large et immédiate. Les rendez-vous restent un
   raccourci secondaire à droite pour ouvrir une vente depuis le passage du
   jour, sans reprendre la place du geste « Chercher un client ». */
#etape-client .cadre-client {
  grid-template-columns: minmax(0, 1fr) 420px;
}
#etape-client .recherche-client { border-color: var(--or); }
#etape-client .recherche-client > h2 { font-size: 1.08rem; }
/* ⚠️  PAS DE LIGNE D'AIDE SOUS CE TITRE — `V3-ae` ③, David captures à l'appui :
       « pas de texte sur ce qui fonctionne, c'est clair sans les explications ».
       Le motif ne reste que sur ce qui est ÉTEINT. Un champ « Numéro de
       téléphone » qui marche n'a rien à expliquer. */
#etape-client #tel-client {
  min-height: 68px;
  border-color: var(--or);
  font-size: 1.2rem;
}
#etape-client #liste-clients .grille.une {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}
#etape-client .rendez-vous-client {
  height: 100%;
  min-height: 0;
  padding: 12px;
  overflow: hidden;
  background: rgba(27, 42, 65, 0.62);
  border: 1px solid var(--bleu-clair);
  border-radius: 12px;
}
#etape-client .rendez-vous-client > h2 { margin-bottom: 8px; }
#etape-client .rendez-vous-client #liste-rdv { margin-top: 0; }
#etape-client #liste-rdv .grille.trois {
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 7px;
}
#etape-client #liste-rdv .case {
  min-height: var(--cible);
  padding: 6px 8px;
}

/* ⚠️  MÊME PIÈGE QUE LE BOUTON BIT, l. 150 : `.bouton { display: inline-flex }`
       est une règle d'auteur, et elle bat le `[hidden] { display: none }` du
       navigateur. Sans cette ligne, « Ajouter une personne » resterait à
       l'écran sur un numéro inconnu. */
.bouton[hidden] { display: none; }

#ajouter-sur-ce-numero { flex: 0 0 auto; width: 100%; margin-top: 8px; }

#fiche-neuve {
  flex: 0 0 auto; margin-top: 10px; padding-top: 10px;
  border-top: 1px solid var(--bleu-clair);
}
#fiche-neuve .bouton { width: 100%; margin-top: 8px; }

/* -----------------------------------------------------------------------------
   `V3-ac` ④ — LA FENÊTRE « VENTE DE PRODUIT »
   Elle recouvre l'écran ; elle ne le pousse pas et elle ne le fait pas défiler.
   Elle passe SOUS le clavier tactile (z-index 9999 chez lui) : on doit pouvoir
   taper dedans.
   -------------------------------------------------------------------------- */
.fenetre {
  position: fixed; inset: 0; z-index: 9990;
  background: rgba(8, 13, 22, 0.72);
  display: flex; align-items: center; justify-content: center;
  padding: 20px;
}
.fenetre[hidden] { display: none; }
.fenetre-boite {
  background: var(--bleu);
  border: 1px solid var(--bleu-clair); border-radius: 14px;
  padding: 20px 22px; width: 460px; max-width: 100%;
  box-shadow: 0 18px 48px rgba(0,0,0,0.55);
}
.fenetre-boite h2 { margin: 0 0 6px; }
.fenetre-boite label {
  display: block; margin: 12px 0 6px;
  font-size: 0.88rem; font-weight: 700; color: var(--or);
}
.fenetre-actions {
  display: flex; gap: 10px; justify-content: flex-end; margin-top: 18px;
}

/* -----------------------------------------------------------------------------
   LA FENÊTRE DES PRODUITS — `STOCK-1`, David, 25/08.
   *« Le client prend le produit, je le trouve facilement. »*
   Une grille, une recherche, un clic. Le même dessin que la grille des
   services : c'est la demande — *« même geste, même écran »*.

   ⚠️  `V3-y` — LA FENÊTRE NE DÉFILE PAS, ET ELLE TIENT. Mesure : 19 produits
       sur 4 colonnes font 5 rangées, soit ~450 px de grille ; avec le titre,
       la recherche et le pied, ~610 px pour les 768 de l'écran. **Aucune barre
       n'est posée** — si le catalogue devait dépasser ~24 articles, ce serait
       une décision de David (cacher des produits réels est pire que défiler,
       comme pour la liste des rendez-vous, `B000-D250`), pas un choix du code.
   -------------------------------------------------------------------------- */
.fenetre-boite.large { width: 980px; }

/* Le champ de recherche — large, haut, sous le doigt. `V3-y` ②.
   Il ne porte PAS d'`inputmode` : il doit ouvrir les lettres du clavier
   tactile, et c'est lui qui recevra le lecteur de code-barres, qui tape
   comme un clavier. */
#produit-recherche {
  width: 100%; margin: 10px 0 14px;
  min-height: 60px; padding: 0 16px;
  background: #16233a; color: var(--texte);
  border: 1px solid var(--bleu-clair); border-radius: 10px;
  font-family: inherit; font-size: 1.05rem;
}
#produit-recherche:focus { outline: none; border-color: var(--or); }

.grille.produits { gap: 9px; }

/* La case d'un produit — exactement la case d'un service, avec sa contenance
   en plus. Rien d'autre : ni photo, ni catégorie, ni favori (David, 25/08). */
.case.produit-case { min-height: 92px; }
.case.produit-case .contenance {
  color: var(--gris); font-size: 0.82rem; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
}

/* ⚠️  LE STOCK INFORME, IL NE REFUSE PAS (`B000-D260`). La case reste
       cliquable à zéro : c'est David qui décide s'il vend son dernier flacon,
       pas l'écran. Rien n'est grisé, rien n'est désactivé.
   ⚠️  ET « JAMAIS RELEVÉ » N'EST PAS « ÉPUISÉ » : la classe `epuise` n'est
       posée que sur un produit qui a des mouvements ET tombe à zéro. Colorer
       en orange un produit jamais relevé crierait au manque sur une étagère
       peut-être pleine (`B000-D220`). */
.case.produit-case .stock {
  color: var(--gris); font-size: 0.8rem; white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.case.produit-case .stock.epuise { color: var(--orange); font-weight: 700; }

/* Le catalogue vide, et ce qu'il faut faire — `B000-D220` : on dit qu'il est
   vide, on ne montre pas d'exemples. */
.grille.produits .vide { grid-column: 1 / -1; margin: 0; padding: 18px 2px; }
.grille.produits .vide a { color: var(--or); }

.page.caisse .carte { padding: 11px 13px; margin-bottom: 0; }
.page.caisse .note  { font-size: 0.78rem; margin: 0 0 7px; }
.page.caisse .sous-titre { margin: 0 0 8px; font-size: 0.86rem; }

/* -----------------------------------------------------------------------------
   LE BOUTON DU HUB — toujours présent, en bas à droite

   ⛔ IL S'APPELAIT `.bouton-caisse` ET IL MENAIT À LA CAISSE. David, 28/08 :
      *« le bouton caisse en jaune en bas à droite, c'est pas utile, il faut un
      bouton hub à la place. »* Depuis `HUB-6`, la caisse ne s'ouvre plus jamais
      sans client : on désigne qui est là sur le hub, et ENCAISSER part de sa
      fiche. Un bouton vers `/vente.html` nu tombait donc sur un écran de
      recherche que le hub fait déjà — du bruit, et rien d'autre.

   ⚠️  LE NOM DE LA CLASSE A SUIVI LE LIBELLÉ. Un `.bouton-caisse` qui ramène au
       hub est un mensonge qui se lit dans six mois. Les neuf pages qui chargent
       cette feuille ont été reprises dans le même geste.
   -------------------------------------------------------------------------- */
.bouton-hub {
  position: fixed; right: 20px; bottom: 20px; z-index: 9997;
  background: var(--or); color: #1a1400;
  border: none; border-radius: 999px;
  min-height: 64px; padding: 0 30px;
  font-size: 1.05rem; font-weight: 800;
  font-family: inherit; text-decoration: none;
  box-shadow: 0 6px 20px rgba(0,0,0,0.45);
  display: inline-flex; align-items: center; gap: 9px; cursor: pointer;
}
.bouton-hub:hover { filter: brightness(1.07); }

/* -----------------------------------------------------------------------------
   LE MESSAGE NE COUVRE JAMAIS LE BOUTON DU BAS — `CAISSE-1`, 25/08

   Mesuré : `#message` (hub.css) est fixe à right:16 bottom:16 z-index:9998, le
   bouton de caisse à right:20 bottom:20 z-index:9997. Le message se posait
   dessus, une couche au-dessus, 4 s à chaque écriture — et sur l'écran Options,
   qui écrit à chaque champ quitté, en continu. Le clic tombait sur le message.
   David, 25/08 : « le bouton caisse, il n'amène pas à la caisse. »

   ⚠️  LA RÈGLE VIT ICI, PAS DANS `hub.css`. `vente.css` est chargée APRÈS
       `hub.css` sur les huit pages qui portent le bouton, et c'est la feuille
       qui possède ce bouton. Même spécificité, feuille plus tardive : elle
       gagne. La poser dans `hub.css` aurait obligé à un numéro de version sur
       treize pages au lieu de neuf.

   ⚠️  UN MESSAGE SE LIT, IL NE SE CLIQUE PAS. `pointer-events: none` est la
       vraie correction : même recouvert, le clic passe. Le `bottom` n'est là
       que pour qu'on voie les deux.
   -------------------------------------------------------------------------- */
#message {
  bottom: 96px;          /* 20 (bouton) + 64 (sa hauteur) + 12 (l'air) */
  pointer-events: none;
}

/* =============================================================================
   LA FENÊTRE DU PAIEMENT PAR CARTE — `CAISSE-2`, 26/08.

   *« Un clic sur Carte ouvre une fenêtre qui ne se quitte pas avant la fin. »*

   ⚠️  ELLE COUVRE TOUT L'ÉCRAN ET N'A AUCUNE CROIX. On n'en sort que par un
       bouton d'issue — c'est le sens de la phrase de David. Pendant qu'une
       carte est en train de passer, rien d'autre ne doit être atteignable.

   ⚠️  ELLE NE DÉFILE PAS (`V3-y` ①). Quatre étapes, un chrono, une issue,
       trois boutons au maximum : le contenu est borné par construction.
   -------------------------------------------------------------------------- */
.carte-voile {
  position: fixed;
  inset: 0;
  z-index: 10000;                 /* au-dessus du bandeau : il ne se touche pas */
  background: rgba(8, 13, 21, .82);
  display: grid;
  place-items: center;
  padding: 16px;
}
.carte-voile[hidden] { display: none; }

.carte-boite {
  width: 560px; max-width: 100%;
  background: var(--bleu);
  border: 1px solid var(--or);
  border-radius: 10px;
  padding: 24px 26px;
  box-shadow: 0 18px 48px rgba(0, 0, 0, .6);
}

.carte-boite h2 {
  margin: 0 0 2px; font-size: 1.15rem; color: var(--texte);
}
.carte-montant {
  font-size: 2rem; font-weight: 800; color: var(--or);
  font-variant-numeric: tabular-nums;
  margin-bottom: 16px;
}

/* Les quatre étapes. `--gris` = pas encore, `--texte` = en cours, vert = fait. */
.carte-etapes { list-style: none; margin: 0; padding: 0; display: grid; gap: 9px; }
.carte-etapes li {
  display: flex; align-items: center; gap: 11px;
  color: var(--gris); font-size: .95rem;
}
.carte-etapes .puce {
  width: 11px; height: 11px; border-radius: 50%;
  background: var(--bleu-clair); flex: 0 0 auto;
}
.carte-etapes li.en-cours { color: var(--texte); font-weight: 600; }
.carte-etapes li.en-cours .puce { background: var(--or); }
.carte-etapes li.fait { color: var(--texte); }
.carte-etapes li.fait .puce { background: var(--vert); }
.carte-etapes li.rate  { color: var(--texte); }
.carte-etapes li.rate .puce { background: var(--rouge); }

/* ⚠️  LE CHRONO EST LE VRAI — 90 s, le délai de l'appel. Il est gros parce
       qu'on le lit de loin, la main sur l'appareil. */
.carte-chrono {
  margin-top: 16px;
  font-size: 1.5rem; font-weight: 700; color: var(--texte);
  font-variant-numeric: tabular-nums;
}
.carte-chrono[hidden] { display: none; }

.carte-issue { margin-top: 18px; }
.carte-issue[hidden] { display: none; }
.carte-issue h3 { margin: 0 0 6px; font-size: 1.05rem; color: var(--texte); }
.carte-issue p  { margin: 0; color: var(--gris); font-size: .95rem; line-height: 1.5; }
.carte-issue strong { color: var(--texte); }
.carte-detail { display: inline-block; margin-top: 6px; font-size: .84rem; opacity: .8; }

/* `V3-y` ② : 60 px, on tape dedans au doigt. */
.carte-boutons {
  margin-top: 20px; display: flex; flex-wrap: wrap; gap: 10px;
}
.carte-boutons[hidden] { display: none; }
.carte-boutons .bouton { flex: 1 1 auto; min-height: var(--cible); }

