/* Configurateur RF — JNJ automation SA
   Couleurs reprises du logo : indigo JNJ et rouge de l'accent suisse. */

:root {
  --jnj: #453b8a;
  --jnj-clair: #6a5fb5;
  --jnj-pale: #f2f1fb;
  --rouge: #d0021b;
  --fond: #f4f5f9;
  --carte: #fff;
  --texte: #1c1c22;
  --gris: #6b6b78;
  --bord: #dcdce6;
  --jaune: #fff6d6;      /* champ repris mais non reconnu (réponse C4) */
  --jaune-bord: #e5b800;
  --vert: #2e7d4f;
  --ombre: 0 1px 3px rgba(20, 20, 45, .07), 0 6px 18px rgba(20, 20, 45, .05);
}

* { box-sizing: border-box; }

/* Un élément portant l'attribut « hidden » doit disparaître, point.
   Sans cette règle, n'importe quelle règle de mise en page qui fixe un
   « display » plus loin dans la feuille reprend le dessus et l'élément
   reste affiché — c'est exactement ce qui arrivait à l'écran de connexion,
   qui restait empilé au-dessus de l'application une fois connecté. */
[hidden] { display: none !important; }

html, body { margin: 0; padding: 0; }
body {
  background: var(--fond);
  color: var(--texte);
  font: 15px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif;
  -webkit-text-size-adjust: 100%;
}
a { color: var(--jnj); }

/* ---------------------------------------------------------------- boutons */
.bouton {
  font: inherit; font-weight: 600; cursor: pointer;
  border: 1.5px solid var(--bord); background: #fff; color: var(--texte);
  border-radius: 9px; padding: 8px 14px; white-space: nowrap;
}
.bouton:hover { border-color: var(--jnj-clair); }
.bouton.primaire { background: var(--jnj); border-color: var(--jnj); color: #fff; }
.bouton.primaire:hover { background: var(--jnj-clair); }
.bouton.discret { border: 0; background: none; color: var(--gris); }
.bouton.discret:hover { color: var(--jnj); }
.bouton.large { width: 100%; padding: 11px; font-size: 16px; }
.bouton:disabled { opacity: .5; cursor: default; }

/* ------------------------------------------------------------- connexion */
.ecran-connexion {
  min-height: 100vh; display: grid; place-items: center; padding: 24px;
  background: linear-gradient(150deg, var(--jnj) 0%, #2a2456 100%);
}
.carte-connexion {
  background: #fff; border-radius: 16px; padding: 34px 30px;
  width: 100%; max-width: 380px; box-shadow: 0 20px 60px rgba(0, 0, 0, .3);
  text-align: center;
}
.logo-connexion { width: 62px; border-radius: 10px; }
.carte-connexion h1 { margin: 14px 0 2px; font-size: 21px; }
.sous-titre { margin: 0 0 22px; color: var(--gris); font-size: 14px; }
.carte-connexion label {
  display: block; text-align: left; font-size: 13px; color: var(--gris);
  font-weight: 600; margin-bottom: 14px;
}
.carte-connexion input {
  display: block; width: 100%; margin-top: 5px; padding: 10px 12px;
  border: 1.5px solid var(--bord); border-radius: 9px; font: inherit; color: var(--texte);
}
.carte-connexion input:focus { outline: 0; border-color: var(--jnj); }
.erreur { color: var(--rouge); font-size: 14px; margin: 0 0 12px; }
.trace { font-size: 12px; color: var(--gris); margin: 10px 0 0; min-height: 15px; }
#bloc-journal { margin-top: 14px; text-align: left; }
#bloc-journal summary { font-size: 12px; color: var(--gris); cursor: pointer; }
#journal {
  max-height: 220px; overflow: auto; background: #f7f7fb; border: 1px solid var(--bord);
  border-radius: 8px; padding: 9px; margin: 8px 0; white-space: pre-wrap; word-break: break-word;
  font: 11px/1.45 ui-monospace, Consolas, monospace; color: var(--texte);
}
#copier-journal { font-size: 12px; padding: 5px 10px; }

/* --------------------------------------------------------------- bandeau */
.bandeau {
  position: sticky; top: 0; z-index: 30; background: #fff;
  border-bottom: 1px solid var(--bord);
  display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
  padding: 10px 20px;
}
.marque { display: flex; align-items: center; gap: 10px; text-decoration: none; color: var(--jnj); }
.marque img { height: 32px; border-radius: 6px; }
.marque span { font-weight: 700; font-size: 16px; }
.bandeau-actions { margin-left: auto; display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
.utilisateur { font-size: 13px; color: var(--gris); text-decoration: none; border-bottom: 1px dotted var(--bord); }
.utilisateur:hover { color: var(--jnj); border-bottom-color: var(--jnj); }
.bascule { display: flex; align-items: center; gap: 7px; font-size: 13px; color: var(--gris); cursor: pointer; }
.bascule input { accent-color: var(--jnj); width: 16px; height: 16px; }
/* indicateur « hors ligne » du bandeau */
.pastille {
  font-size: 12px; font-weight: 700; padding: 3px 9px; border-radius: 20px;
  background: #fdecec; color: var(--rouge);
}
.pied { text-align: center; color: var(--gris); font-size: 12px; padding: 26px 16px 40px; }

main { padding: 20px; max-width: 1500px; margin: 0 auto; }

/* ------------------------------------------------------------------ menu */
.menu { display: flex; align-items: center; gap: 4px; margin-left: 22px; }
.menu a {
  font-size: 14px; font-weight: 600; color: var(--gris); text-decoration: none;
  padding: 7px 12px; border-radius: 9px; white-space: nowrap;
}
.menu a:hover { background: var(--jnj-pale); color: var(--jnj); }
.menu a.actif { background: var(--jnj-pale); color: var(--jnj); }
.menu a#lien-export { cursor: pointer; }
.menu a.inactif { opacity: .45; pointer-events: none; }

/* Ce qui dépend de la page ouverte, à la suite du menu et séparé de lui par
   un trait : les deux sous-entrées de Configuration, et les actions du parc.
   Tout tient sur la même ligne que le menu — c'était la demande : une barre
   de boutons, pas deux. */
.menu-contextuel {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding-left: 14px; margin-left: 4px; border-left: 1.5px solid var(--bord);
}
.menu-contextuel:not(:has(> *:not([hidden]))) { border-left: 0; padding-left: 0; }
.menu-contextuel .nouveau-rf { padding: 7px 13px; font-size: 14px; }
.sous-menu {
  font-size: 13.5px; font-weight: 600; color: var(--gris); text-decoration: none;
  padding: 6px 11px; border-radius: 8px; white-space: nowrap;
  border: 1.5px solid var(--bord); background: #fff;
}
.sous-menu:hover { border-color: var(--jnj-clair); color: var(--jnj); }
.sous-menu.actif { background: var(--jnj-pale); border-color: var(--jnj-pale); color: var(--jnj); }

/* ------------------------------------------------ le parc en pleine page */
/* Le tableau occupe toute la largeur et toute la hauteur de la fenêtre.
   C'est ce qui garde la barre de défilement horizontale collée en bas de
   l'écran : avant, elle suivait le bas de la liste et il fallait descendre
   toute la page pour l'atteindre — invisible sur un écran large. */
body.pleine-page { overflow: hidden; }
body.pleine-page #application { display: flex; flex-direction: column; height: 100vh; }
body.pleine-page .bandeau { flex: none; }
body.pleine-page main {
  flex: 1; min-height: 0; display: flex; flex-direction: column;
  max-width: none; padding: 14px 16px 0;
  /* « margin: 0 auto » centrait la page ; sur un élément de flexbox, une
     marge automatique empêche l'étirement sur toute la largeur. */
  margin: 0;
}
/* « min-width: 0 » n'est pas décoratif : sans lui, un élément de flexbox
   refuse de descendre sous la largeur de son contenu. Le cadre du tableau
   prenait alors les 28 000 px du tableau, et sa barre de défilement se
   retrouvait très loin hors de l'écran — le défaut qu'on corrige ici. */
body.pleine-page main,
body.pleine-page main > * { min-width: 0; }
body.pleine-page .barre-titre,
body.pleine-page .filtres,
body.pleine-page .barre-groupes,
body.pleine-page .barre-familles { flex: none; }
body.pleine-page .tableau-cadre {
  flex: 1; min-height: 0; max-height: none; width: 100%;
  border-radius: 12px 12px 0 0; border-bottom: 0;
}
body.pleine-page .pied { display: none; }

/* ----------------------------------------------------------------- barre */
.barre-titre {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap; margin-bottom: 16px;
}
.barre-titre h1 { margin: 0; font-size: 20px; }
.barre-titre .compte { color: var(--gris); font-size: 14px; }
.barre-titre .a-droite { margin-left: auto; display: flex; gap: 8px; flex-wrap: wrap; }

.filtres {
  display: flex; gap: 10px; flex-wrap: wrap; margin-bottom: 14px;
  background: #fff; border: 1px solid var(--bord); border-radius: 12px; padding: 12px;
}
.filtres input, .filtres select {
  font: inherit; padding: 8px 11px; border: 1.5px solid var(--bord);
  border-radius: 9px; color: var(--texte); background: #fff;
}
.filtres input:focus, .filtres select:focus { outline: 0; border-color: var(--jnj); }
/* La recherche prenait toute la largeur restante. Elle est large sans être
   démesurée, et la place gagnée sert au compteur et au reste des filtres. */
.filtres input[type=search] { flex: 0 1 340px; min-width: 180px; }
.filtres label.case { display: flex; align-items: center; gap: 7px; font-size: 14px; color: var(--gris); }
/* le nombre de machines ou de clients, poussé au bout de la ligne de filtres */
.filtres .compte { margin-left: auto; color: var(--gris); font-size: 14px; align-self: center; }
.filtres .aide-chip { align-self: center; }

/* --------------------------------------------------------------- tableau */
.tableau-cadre {
  background: #fff; border: 1px solid var(--bord); border-radius: 12px;
  overflow: auto; box-shadow: var(--ombre); max-height: calc(100vh - 230px);
}
table { border-collapse: collapse; width: 100%; font-size: 14px; }

/* Largeurs fixes, données par les <col> et calculées en JavaScript sur
   l'ensemble des machines. Sans ça, le navigateur les recalcule d'après les
   seules lignes présentes dans le DOM — et comme on ne dessine que les lignes
   visibles, les colonnes se décalaient latéralement pendant qu'on défilait. */
/* min-width : quand peu de groupes sont affichés, le tableau s'étire quand
   même sur toute la largeur de l'écran, quelle que soit sa taille. */
#tableau-parc { table-layout: fixed; min-width: 100%; }
thead th {
  position: sticky; top: 0; background: #fff; z-index: 2;
  text-align: left; font-size: 12px; text-transform: uppercase; letter-spacing: .4px;
  color: var(--gris); padding: 10px 12px; border-bottom: 2px solid var(--bord); white-space: nowrap;
}
tbody td { padding: 9px 12px; border-bottom: 1px solid #eeeef4; vertical-align: top; }
tbody tr.selectionnee { background: #eae7fb; }

/* ------------------------------------------------------ saisie directe */
/* Le tableau se remplit comme un tableur : on clique dans une cellule et on
   écrit, sans quitter la vue d'ensemble. Seul le n° ouvre la fiche. */
tbody tr:hover td[class*="cat-"] { filter: brightness(.965); }
/* Hauteur de ligne fixe : elle sert au calcul des lignes visibles. */
tbody td {
  height: 39px; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap;
}
thead th { overflow: hidden; }
tr.cale td { padding: 0; border: 0; background: none; }

td.saisissable { cursor: text; }
td.saisissable:hover { box-shadow: inset 0 0 0 1.5px var(--jnj-clair); }
td.saisissable:focus-visible { outline: 2px solid var(--jnj); outline-offset: -2px; }
td.fige { color: #55555f; }
td .creux { color: #bfbfcc; }

td.en-saisie { padding: 0 !important; box-shadow: inset 0 0 0 2px var(--jnj); overflow: visible; }
.saisie {
  width: 100%; min-width: 110px; font: inherit; font-size: 14px;
  border: 0; padding: 8px 10px; background: #fff; color: var(--texte);
  border-radius: 0; resize: vertical;
}
.saisie:focus { outline: 0; }
textarea.saisie { min-height: 38px; white-space: pre-wrap; }

/* Case modifiée mais pas encore envoyée : le liseré rappelle qu'il reste
   quelque chose à enregistrer, et il survit au défilement. */
tbody td.non-enregistre {
  box-shadow: inset 0 -3px 0 var(--jnj-clair);
}
.tableau-clients input.non-enregistre, .tableau-clients select.non-enregistre {
  border-color: var(--jnj-clair); box-shadow: inset 0 -3px 0 var(--jnj-clair);
}
/* le bouton du bandeau, quand il y a quelque chose à envoyer */
#bouton-enregistrer-tout.en-attente { animation: respiration 2.4s ease-in-out infinite; }
@keyframes respiration { 50% { box-shadow: 0 0 0 4px rgba(69, 59, 138, .18); } }

/* la question posée avant de quitter une saisie */
.fenetre-question {
  background: #fff; border-radius: 16px; padding: 24px 26px; max-width: 460px;
  box-shadow: 0 24px 70px rgba(0, 0, 0, .35);
}
.fenetre-question h2 { margin: 0 0 10px; font-size: 18px; color: var(--jnj); }
.fenetre-question p { margin: 0 0 18px; font-size: 14.5px; line-height: 1.5; }
.boutons-question { display: flex; gap: 9px; justify-content: flex-end; flex-wrap: wrap; }

@keyframes pulsation { 50% { background: #fff8dc; } }
td.enregistrement { animation: pulsation .8s ease-in-out infinite; }
td.enregistre { background: #e3f6e9 !important; transition: background 1s; }
td.echec { background: #fdecec !important; box-shadow: inset 0 0 0 2px var(--rouge); }

td.numero a {
  font-weight: 700; text-decoration: none; display: inline-flex; align-items: center; gap: 3px;
  background: var(--jnj-pale); border-radius: 7px; padding: 3px 7px 3px 9px;
  border: 1px solid transparent; transition: .12s;
}
td.numero a:hover { background: var(--jnj); color: #fff; border-color: var(--jnj); }
td.numero a { background: #fff; border-color: var(--bord); }
td.numero .chevron { font-size: 17px; line-height: 1; opacity: .55; margin-top: -2px; }
td.numero a:hover .chevron { opacity: 1; }

/* Le n° et la case à cocher restent visibles quand on fait défiler
   horizontalement les 122 colonnes. */
th.colonne-coche, td.colonne-coche { position: sticky; left: 0; z-index: 3; background: #fff; }
thead th.colonne-coche { z-index: 5; }
/* Trois colonnes figées : le statut du RF, la reprise, puis le n°. Leurs
   décalages sont calculés en JavaScript (voir « appliquerLargeurs ») : chacun
   dépend de la largeur des colonnes qui précèdent. */
th.colle-statut, td.colle-statut {
  position: sticky; left: var(--l-statut, 34px); z-index: 3; background: #fff;
}
thead th.colle-statut { z-index: 5; }
th.colle-reprise, td.colle-reprise {
  position: sticky; left: var(--l-reprise, 34px); z-index: 3; background: #fff;
}
thead th.colle-reprise { z-index: 5; }
th.colle, td.colle { position: sticky; left: var(--l-numero, 34px); z-index: 3; background: #fff; }
thead th.colle { z-index: 5; }
/* Colonnes collées à la demande (bouton épingle). Leur « left » est écrit par
   appliquerLargeurs dans la feuille « css-colonnes-collees » : il dépend de la
   largeur de tout ce qui les précède. Elles gardent la couleur de leur
   catégorie, sinon elles trancheraient au milieu du bloc Identité. */
th.collee, td.collee { position: sticky; z-index: 3; background: var(--teinte, #fff); }
thead th.collee { z-index: 5; background: var(--teinte-forte, #fff); }
.ligne-filtres th.collee { background: var(--teinte, #fafaff); }
.ligne-filtres th.colle, .ligne-filtres th.colle-statut, .ligne-filtres th.colle-reprise,
.ligne-filtres th.colonne-coche { background: #fafaff; }
tr.selectionnee td.colle, tr.selectionnee td.colle-statut, tr.selectionnee td.colle-reprise,
tr.selectionnee td.colonne-coche { background: #eae7fb; }
td.colle { box-shadow: 2px 0 4px -2px rgba(20, 20, 45, .15); }
td.gris, .gris { color: var(--gris); }
.etiquette {
  display: inline-block; font-size: 11px; font-weight: 700; padding: 2px 7px;
  border-radius: 5px; background: var(--jnj-pale); color: var(--jnj);
}
.etiquette.ancienne { background: #f1f1f4; color: var(--gris); }
/* compte créé mais encore fermé : il lui manque un mot de passe */
.etiquette.a-definir { background: #fff3d6; color: #8a6100; }
/* les trois états de la migration : rouge -> jaune -> vert (NJ, 24.08) */
.etiquette.a-migrer { background: #fdecec; color: #b3261e; }
.etiquette.a-verifier { background: var(--jaune); color: #8a6d00; }
.etiquette.verifiee { background: #e6f5ec; color: var(--vert); }

/* Les mêmes couleurs dans les menus déroulants de la reprise — la case fermée
   comme chacun de ses choix. Les <option> acceptent background et color sous
   Chrome et Edge, les navigateurs de JNJ ; ailleurs on retombe simplement sur
   le blanc, sans rien casser. */
option.etat-a_migrer, .saisie-etat.etat-a_migrer { background: #fdecec; color: #b3261e; }
option.etat-migree_auto, .saisie-etat.etat-migree_auto { background: var(--jaune); color: #8a6d00; }
option.etat-verifiee, .saisie-etat.etat-verifiee { background: #e6f5ec; color: var(--vert); }
.saisie-etat { font-weight: 700; }
/* le « — » du menu n'est pas un état : il reste neutre au lieu d'hériter de
   la couleur de l'état courant */
.saisie-etat option:not([class]) { background: #fff; color: var(--texte); font-weight: 400; }
.vide { text-align: center; color: var(--gris); padding: 40px; }

/* ----------------------------------------------------------------- fiche */
.fiche { display: grid; grid-template-columns: 1fr 320px; gap: 18px; align-items: start; }
@media (max-width: 1000px) { .fiche { grid-template-columns: 1fr; } }

.carte {
  background: #fff; border: 1px solid var(--bord); border-radius: 12px;
  padding: 16px 18px; box-shadow: var(--ombre); margin-bottom: 16px;
}
.carte h2 {
  margin: 0 0 14px; font-size: 15px; color: var(--jnj);
  border-bottom: 2px solid var(--jnj-pale); padding-bottom: 8px;
}
.grille { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 14px; }

/* onglets = les catégories de la ligne 2 de l'Excel (réponse A1) */
.onglets { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 16px; }
.onglet {
  font: inherit; font-weight: 600; font-size: 14px; cursor: pointer;
  border: 1.5px solid var(--bord); background: #fff; color: var(--gris);
  border-radius: 9px; padding: 8px 14px;
}
.onglet.actif { background: var(--jnj); border-color: var(--jnj); color: #fff; }
.onglet:disabled { opacity: .45; cursor: not-allowed; }

/* ------------------------------------ fiche : explications derrière le « i » */
/* Tous les champs restent visibles et alignés. Le texte d'explication, dont la
   longueur change d'un champ à l'autre, ne tient plus de place dans la page :
   c'est lui qui décalait les blocs verticalement les uns par rapport aux
   autres. Il s'ouvre en surimpression, sous le « i ». */
.grille-champs { align-items: start; }
.grille-champs .champ { position: relative; }
.grille-champs .champ > label {
  display: flex; align-items: center; gap: 6px;
  white-space: nowrap; overflow: hidden;          /* un nom long ne passe pas à la ligne */
}
.grille-champs .nom-champ { overflow: hidden; text-overflow: ellipsis; }
.unite-champ { font-weight: 400; color: var(--gris); flex: none; }

.i-bulle {
  display: inline-flex; align-items: center; justify-content: center;
  width: 18px; height: 18px; flex: none; border-radius: 50%; cursor: help;
  background: #fff; border: 1.5px solid var(--bord); color: var(--jnj);
  font: italic 700 11px/1 Georgia, serif; padding: 0;
}
.i-bulle:hover { background: var(--jnj); border-color: var(--jnj); color: #fff; }
.i-bulle.demo { vertical-align: middle; cursor: default; }
.champ.epinglee .i-bulle { background: var(--jnj); border-color: var(--jnj); color: #fff; }

.detail-bulle {
  position: absolute; top: 24px; left: 0; z-index: 40; width: 300px; max-width: 90vw;
  background: #fff; border: 1.5px solid var(--jnj-clair); border-radius: 12px;
  padding: 12px 14px; box-shadow: 0 14px 38px rgba(20, 20, 45, .22);
}
.detail-bulle .titre-detail { display: block; font-size: 13.5px; margin-bottom: 6px; }
.detail-bulle .aide { margin: 0 0 6px; }
.detail-bulle .cellule-xls { margin: 0; }

/* --------------------------------------------------------------- champs */
.champ { margin-bottom: 4px; }
.champ > label { display: block; font-size: 13px; font-weight: 700; margin-bottom: 4px; }
.champ .aide { font-size: 12px; color: var(--gris); margin: 0 0 5px; }
.champ input, .champ select, .champ textarea {
  width: 100%; font: inherit; padding: 9px 11px;
  border: 1.5px solid var(--bord); border-radius: 9px; background: #fff; color: var(--texte);
}
.champ input:focus, .champ select:focus, .champ textarea:focus { outline: 0; border-color: var(--jnj); }
.champ textarea { min-height: 90px; resize: vertical; }
.champ.a-verifier input, .champ.a-verifier select {
  background: var(--jaune); border-color: var(--jaune-bord);
}
.champ .case-oui-non { display: flex; align-items: center; gap: 9px; padding: 9px 0; }
.champ .case-oui-non input { width: 18px; height: 18px; accent-color: var(--jnj); }

/* copie de la cellule Excel, affichée juste au-dessus du champ (réponse C2a) */
.cellule-xls {
  font-size: 12px; color: var(--gris); background: #f7f7fb;
  border: 1px dashed var(--bord); border-radius: 7px;
  padding: 4px 8px; margin-bottom: 5px; white-space: pre-wrap;
}
.cellule-xls .code {
  font-weight: 700; color: var(--jnj); margin-right: 6px;
  font-family: ui-monospace, Consolas, monospace;
}
.cellule-xls.absente { font-style: italic; opacity: .6; }
/* La même cellule, en pied de champ, pendant la comparaison avec l'Excel.
   Quatre lignes, toujours : une hauteur qui suivrait le texte décalerait les
   champs voisins et l'on ne pourrait plus lire une ligne de la grille d'un
   bout à l'autre. Au-delà, le texte défile dans son cadre. */
.cellule-xls.en-zone {
  margin: 8px 0 0; line-height: 1.35;
  height: calc(4 * 1.35em + 10px); overflow-y: auto;
}
.cellule-xls.en-zone::-webkit-scrollbar { width: 8px; }
.cellule-xls.en-zone::-webkit-scrollbar-thumb {
  background: var(--bord); border-radius: 4px;
}
/* Quand les cellules Excel sont posées sous les champs, les blocs d'une même
   rangée prennent la même hauteur et la cellule se cale en bas : les quatre
   zones d'une rangée se lisent alors sur une seule ligne, comme les lignes du
   fichier qu'on est en train de comparer. Hors de ce mode, rien ne change —
   les blocs restent calés en haut, au plus court. */
body.xls-zone .grille-champs { align-items: stretch; }
body.xls-zone .grille-champs .champ { display: flex; flex-direction: column; }
body.xls-zone .grille-champs .champ .cellule-xls.en-zone { margin-top: auto; }

.note-champ { margin-top: 5px; }
.note-champ input { font-size: 13px; border-style: dashed; }

/* ----------------------------------------------------------- historique */
.historique { list-style: none; margin: 0; padding: 0; font-size: 13px; }
.historique li { padding: 9px 0; border-bottom: 1px solid #eeeef4; }
.historique .quand { color: var(--gris); font-size: 12px; }
.historique .avant { color: var(--gris); text-decoration: line-through; }
.historique .apres { font-weight: 600; }

/* ------------------------------------------------- filtres par colonne */
/* Une ligne de filtres sous les en-têtes, comme les filtres d'Excel. */
.ligne-filtres th {
  position: sticky; top: 34px; z-index: 2; background: #fafaff;
  padding: 5px 7px; border-bottom: 1px solid var(--bord);
}
.ligne-filtres input, .ligne-filtres select {
  width: 100%; min-width: 90px; font: inherit; font-size: 12.5px; font-weight: 400;
  padding: 4px 7px; border: 1px solid var(--bord); border-radius: 6px;
  background: #fff; color: var(--texte); text-transform: none; letter-spacing: 0;
}
.ligne-filtres input:focus, .ligne-filtres select:focus { outline: 0; border-color: var(--jnj); }
thead th[data-tri] { cursor: pointer; user-select: none; }
thead th[data-tri]:hover { color: var(--jnj); }
thead th.trie { color: var(--jnj); }
/* largeur figée à 34 px, la même que le « left » des colonnes collées */
.colonne-coche { width: 34px; padding-left: 8px; padding-right: 8px; }
td.remarque {
  max-width: 320px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.petit { font-size: 12.5px; }

/* ------------------------------------------- groupes affichés ou masqués */
/* Une pastille par catégorie : on masque d'un clic tout un groupe de
   colonnes, pour ne garder à l'écran que ce qu'on regarde. */
.barre-groupes {
  display: flex; align-items: center; gap: 7px; flex-wrap: wrap;
  background: #fff; border: 1px solid var(--bord); border-radius: 12px;
  padding: 10px 13px; margin-bottom: 14px;
}
.titre-barre {
  font-size: 11.5px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .5px; color: var(--gris); margin-right: 4px;
}

/* Les deux flèches encadrent le mot « Groupes » : on avance ou on recule
   d'un groupe, le tableau s'aligne sur le suivant ou le précédent. */
.nav-groupes {
  display: inline-flex; align-items: center; gap: 7px; margin-right: 8px;
  padding-right: 10px; border-right: 1px solid var(--bord);
}
.nav-groupes .titre-barre { margin: 0; }
.fleche-groupe {
  display: inline-flex; align-items: center; justify-content: center;
  width: 32px; height: 32px; flex: none; cursor: pointer;
  border: 0; border-radius: 50%; background: var(--jnj); color: #fff;
  box-shadow: 0 1px 3px rgba(20, 20, 45, .18); transition: .12s;
}
.fleche-groupe:hover { background: var(--jnj-clair); transform: scale(1.06); }
.fleche-groupe:active { transform: scale(.96); }
.fleche-groupe svg {
  width: 17px; height: 17px; fill: none; stroke: currentColor;
  stroke-width: 2.6; stroke-linecap: round; stroke-linejoin: round;
}
/* texte réservé aux lecteurs d'écran */
.sr {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap;
}
/* Deux gestes distincts sur une pastille : le nom amène le tableau sur le
   groupe, le petit œil le masque ou le réaffiche. */
.puce-groupe {
  display: inline-flex; align-items: center; gap: 2px;
  font-size: 13px; font-weight: 600;
  border: 1.5px solid transparent; border-radius: 20px; padding: 3px 6px 3px 8px;
  background: var(--teinte); color: #3a3a48; transition: .12s;
}
.puce-groupe:hover { border-color: var(--jnj-clair); }
.puce-groupe .nom-groupe {
  display: inline-flex; align-items: center; gap: 6px;
  font: inherit; color: inherit; cursor: pointer;
  border: 0; background: none; padding: 2px 4px; border-radius: 14px;
}
.puce-groupe .nom-groupe:hover { color: var(--jnj); }
.puce-groupe .nb {
  font-size: 11px; font-weight: 700; opacity: .55;
  background: rgba(255, 255, 255, .65); border-radius: 10px; padding: 0 6px;
}
.puce-groupe .oeil {
  display: inline-flex; align-items: center; justify-content: center;
  width: 24px; height: 22px; padding: 0; cursor: pointer;
  border: 0; background: none; color: #5b5b6b; border-radius: 12px; opacity: .55;
}
.puce-groupe .oeil svg {
  width: 15px; height: 15px; fill: none; stroke: currentColor;
  stroke-width: 1.8; stroke-linecap: round;
}
.puce-groupe .oeil:hover { opacity: 1; background: rgba(255, 255, 255, .75); color: var(--jnj); }
/* Le groupe où l'on se trouve : sa teinte passe en soutenu et il prend le
   contour indigo, pour qu'on sache d'un coup d'œil où on est quand on se
   déplace avec les flèches. */
.puce-groupe.courant {
  background: var(--teinte-forte); border-color: var(--jnj); color: var(--jnj);
  box-shadow: 0 0 0 3px rgba(69, 59, 138, .14);
}
.puce-groupe.courant .nom-groupe { font-weight: 800; }
.puce-groupe.courant .nb { background: #fff; opacity: .8; }
.puce-groupe.courant .oeil { color: var(--jnj); opacity: .8; }

.puce-groupe.masquee {
  background: #fff; color: #a8a8b8; border-color: var(--bord);
}
.puce-groupe.masquee .nom-groupe { text-decoration: line-through; text-decoration-thickness: 1.5px; }
.puce-groupe.masquee .nb { background: #f1f1f6; }
.puce-groupe.masquee .oeil { color: #a8a8b8; opacity: .9; }

/* le groupe qu'on vient de rejoindre clignote une fois */
@keyframes vise { 0%, 100% { background: var(--teinte-forte); } 35% { background: #fff3b0; } }
#entetes-groupes th.vise { animation: vise 1.4s ease-in-out; }
@keyframes ligne-neuve { 0%, 100% { background: var(--teinte); } 35% { background: #fff3b0; } }
tbody tr.nouvelle td { animation: ligne-neuve 1.2s ease-in-out 2; }

/* ------------------------------------------------------- familles de RF */
/* Un bouton par modèle, plus les couples de générations (RF1-RF11,
   RF3-RF13). On peut en retenir plusieurs à la fois. */
.barre-familles {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  background: #fff; border: 1px solid var(--bord); border-radius: 12px;
  padding: 8px 13px; margin-bottom: 14px;
}
.puce-famille {
  font: inherit; font-size: 13px; font-weight: 700; cursor: pointer;
  border: 1.5px solid var(--bord); background: #fff; color: var(--gris);
  border-radius: 8px; padding: 5px 12px; transition: .12s; white-space: nowrap;
}
.puce-famille:hover { border-color: var(--jnj-clair); color: var(--jnj); }
.puce-famille.active {
  background: var(--jnj); border-color: var(--jnj); color: #fff;
}
.puce-famille.couple { border-style: dashed; }
.puce-famille.couple.active { border-style: solid; }
.puce-famille.tout { font-weight: 600; }
.puce-famille.tout.active { background: var(--jnj-pale); border-color: var(--jnj-pale); color: var(--jnj); }

/* le texte cherché, mis en évidence dans les cellules */
mark {
  background: #ffe680; color: inherit; border-radius: 3px; padding: 0 1px;
  font-weight: 600;
}

/* colonnes masquées une par une : elles restent visibles ici, on ne les perd pas */
.colonnes-cachees {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  padding-left: 12px; margin-left: 4px; border-left: 2px solid var(--bord);
}
.puce-colonne {
  display: inline-flex; align-items: center; gap: 5px; cursor: pointer;
  font: inherit; font-size: 12px; font-weight: 600; color: var(--gris);
  background: #fff; border: 1.5px dashed var(--bord); border-radius: 16px; padding: 3px 9px;
}
.puce-colonne:hover { border-color: var(--jnj); color: var(--jnj); border-style: solid; }
.puce-colonne .plus { font-size: 14px; font-weight: 700; color: var(--jnj); }

/* en-tête : code de colonne, bouton masquer, poignée de largeur
   Surtout ne pas mettre « position: relative » ici : ça écraserait le
   « position: sticky » des en-têtes et les trois lignes se superposeraient.
   Un élément sticky sert déjà de repère aux enfants positionnés. */
/* Un nom de colonne trop long pour la largeur choisie s'empile sur trois
   lignes au maximum, puis se coupe. Sans ça, rétrécir une colonne effaçait la
   fin du titre et on ne savait plus ce qu'on lisait. Trois lignes : au-delà,
   l'en-tête mangerait l'écran. */
.titre-colonne {
  cursor: pointer; padding-right: 14px;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3;
  overflow: hidden; white-space: normal; overflow-wrap: anywhere;
  line-height: 1.22;
}
#entetes th, .tableau-clients thead th { white-space: normal; vertical-align: top; }
.code-colonne {
  font: 10.5px ui-monospace, Consolas, monospace; font-weight: 700;
  color: var(--jnj); background: rgba(255, 255, 255, .7);
  border-radius: 4px; padding: 1px 4px; margin-right: 4px; text-transform: none;
}
/* le même code devant le nom du champ dans la fiche : là, le fond blanc ne
   ressortirait pas, il lui faut la teinte pâle de l'application */
.champ label .code-colonne {
  background: var(--jnj-pale); font-size: 10.5px; vertical-align: 1px;
}
.masquer-colonne {
  position: absolute; top: 4px; right: 9px; opacity: 0; transition: .12s;
  border: 0; background: none; cursor: pointer; color: var(--gris);
  font-size: 15px; line-height: 1; padding: 2px 4px; border-radius: 4px;
}
thead th:hover .masquer-colonne { opacity: 1; }
.masquer-colonne:hover { background: var(--rouge); color: #fff; }
/* Épingler une colonne : elle rejoint le statut et le n° collés à gauche.
   L'épingle reste visible en permanence, comme l'œil des pastilles de groupe :
   on ne peut pas deviner une commande qui n'apparaît qu'au survol. Décrochée,
   elle est grise et creuse ; posée, elle est indigo pleine sur pastille claire
   — la différence se voit sans avoir à comparer deux colonnes. */
.epingler-colonne {
  position: absolute; top: 3px; right: 26px; opacity: .5; transition: .12s;
  border: 0; background: none; cursor: pointer; color: #5b5b6b;
  line-height: 0; padding: 3px; border-radius: 5px;
}
thead th:hover .epingler-colonne { opacity: .8; }
.epingler-colonne:hover { background: var(--jnj-pale); color: var(--jnj); opacity: 1; }
.epingler-colonne.posee,
thead th:hover .epingler-colonne.posee {
  opacity: 1; color: var(--jnj); background: #fff;
  box-shadow: 0 0 0 1.5px var(--jnj);
}
.epingler-colonne.posee svg { fill: currentColor; fill-opacity: .55; }
.epingler-colonne.posee:hover { background: var(--jnj); color: #fff; }
/* de la place pour l'épingle et la croix : sinon elles se posent sur la fin
   du nom de la colonne, qui s'empile déjà sur trois lignes */
#entetes th.epinglable .titre-colonne { padding-right: 42px; }

.poignee-largeur {
  position: absolute; top: 0; right: 0; width: 6px; height: 100%;
  cursor: col-resize; user-select: none;
}
.poignee-largeur:hover { background: var(--jnj); }
body.redimensionne { cursor: col-resize; user-select: none; }

/* valeur hors liste : saisie et affichage */
.saisie-liste { display: flex; gap: 4px; align-items: stretch; }
.saisie-liste .saisie { min-width: 90px; }
.saisie-libre, .valeur-libre {
  font: inherit; font-size: 14px; border: 0; padding: 8px 10px;
  background: #fffbe9; color: var(--texte); min-width: 80px; width: 100%;
  border-radius: 0;
}
.valeur-libre {
  border: 1.5px solid var(--jaune-bord); border-radius: 9px; margin-top: 6px;
}
.saisie-libre:focus, .valeur-libre:focus { outline: 0; box-shadow: inset 0 0 0 2px var(--jaune-bord); }

.bouton.danger { border-color: #f0c8ce; color: var(--rouge); }
.bouton.danger:hover { background: var(--rouge); color: #fff; border-color: var(--rouge); }
.actions-champ { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 6px; }
.ligne-champ.retire .nom { text-decoration: line-through; opacity: .6; }

/* glisser-déposer pour changer l'ordre des colonnes */
.puce-groupe { cursor: grab; user-select: none; }
.puce-groupe:active { cursor: grabbing; }
.puce-groupe .poignee { opacity: .35; font-size: 12px; letter-spacing: -1px; }
.puce-groupe:hover .poignee { opacity: .7; }
.puce-groupe.en-deplacement { opacity: .45; border-color: var(--jnj); border-style: dashed; }

/* ------------------------------------------- couleurs par catégorie */
/* Une teinte pastel par groupe de colonnes, reprise sur la ligne des
   catégories, les en-têtes, les filtres et les cellules — pour se repérer
   dans les 122 colonnes sans lire les titres. */
.cat-IDENTITE          { --teinte: #eef0f6; --teinte-forte: #dfe3ee; }
.cat-MODELE            { --teinte: #eceafa; --teinte-forte: #d8d3f3; }
.cat-FROMAGE           { --teinte: #fdf4e4; --teinte-forte: #f6e5c2; }
.cat-CAVE              { --teinte: #e9f4ec; --teinte-forte: #cfe8d7; }
.cat-MACHINE           { --teinte: #eaf1fa; --teinte-forte: #cfe0f3; }
.cat-MODULES           { --teinte: #f6eef8; --teinte-forte: #ead7ef; }
.cat-ACCESSOIRES       { --teinte: #fdeef1; --teinte-forte: #f7d6de; }
.cat-COURROIE          { --teinte: #f4f1e6; --teinte-forte: #e6dfc6; }
.cat-OPTIONS           { --teinte: #e9f5f5; --teinte-forte: #cfe8e8; }
.cat-ALIMENTATION      { --teinte: #fdf0e6; --teinte-forte: #f7dcc4; }
.cat-DETECTEURS        { --teinte: #eff4e7; --teinte-forte: #dde8c9; }
.cat-FONCTION_CODAGES  { --teinte: #f0eef9; --teinte-forte: #dbd6ef; }

td[class*="cat-"] { background: var(--teinte); }
thead th[class*="cat-"] { background: var(--teinte-forte); }
.ligne-filtres th[class*="cat-"] { background: var(--teinte); }

/* ligne des catégories, l'équivalent de la ligne 2 de l'Excel */
#entetes-groupes th.groupe {
  position: sticky; top: 0; z-index: 4;
  text-align: center; font-size: 11.5px; font-weight: 800;
  text-transform: uppercase; letter-spacing: .6px; color: #4a4a58;
  padding: 6px 10px; border-bottom: 1px solid rgba(0, 0, 0, .07);
  border-right: 2px solid #fff;
}
/* Les trois lignes d'en-tête se collent les unes sous les autres. Leurs
   hauteurs sont mesurées après l'affichage (voir « caler_entetes » dans
   app.js) : elles changent avec le zoom, la police et la longueur des noms.
   Des valeurs écrites en dur ici finissaient par se chevaucher. */
#entetes th { top: var(--h-groupes, 28px); }
.ligne-filtres th { top: var(--h-noms, 62px); }

/* ---------------------------------------------------------- comparaison */
/* Une machine par ligne, un champ par colonne — comme dans l'Excel. */
.comparaison td.numero { font-weight: 700; }
.comparaison th.differe, .comparaison td.differe { background: var(--jaune); }

/* ---------------------------------------------------------- historique */
.tableau-historique { width: 100%; font-size: 13px; }
.tableau-historique th {
  text-align: left; font-size: 11.5px; text-transform: uppercase; color: var(--gris);
  border-bottom: 2px solid var(--bord); padding: 7px 9px;
}
.tableau-historique td { padding: 7px 9px; border-bottom: 1px solid #eeeef4; vertical-align: top; }
.tableau-historique .avant { color: var(--gris); text-decoration: line-through; }
.tableau-historique .apres { font-weight: 600; }

/* ------------------------------------------------------- configuration */
.config { display: grid; grid-template-columns: 340px 1fr; gap: 18px; align-items: start; }
@media (max-width: 900px) { .config { grid-template-columns: 1fr; } }
.config-liste { max-height: 74vh; overflow: auto; }
.config-liste input[type=search] {
  width: 100%; padding: 8px 11px; border: 1.5px solid var(--bord);
  border-radius: 9px; font: inherit; margin-bottom: 10px;
}
/* Liste des champs repliée par groupe : 131 colonnes d'affilée sont
   illisibles. Seul le groupe ouvert montre ses champs. */
.groupe-config { margin-bottom: 6px; }
.groupe-config .titre-groupe {
  display: flex; align-items: center; gap: 9px; width: 100%; cursor: pointer;
  font: inherit; font-size: 13.5px; font-weight: 700; color: var(--texte);
  background: #f7f7fb; border: 1px solid var(--bord); border-radius: 9px;
  padding: 9px 11px; text-align: left;
}
.groupe-config .titre-groupe:hover { border-color: var(--jnj-clair); background: var(--jnj-pale); }
.groupe-config .nom-groupe-config { flex: 1; }
.groupe-config .nb-groupe {
  font-size: 11px; font-weight: 700; color: var(--gris);
  background: #fff; border: 1px solid var(--bord); border-radius: 10px; padding: 1px 7px;
}
.chevron-groupe {
  flex: none; font-size: 17px; line-height: 1; color: var(--jnj);
  transition: transform .15s; display: inline-block;
}
.groupe-config.ouvert .chevron-groupe { transform: rotate(90deg); }
.groupe-config.ouvert .titre-groupe { background: var(--jnj-pale); border-color: var(--jnj-clair); }
.champs-groupe { display: none; padding: 5px 0 8px 6px; }
.groupe-config.ouvert .champs-groupe { display: block; }
.ligne-champ {
  display: flex; align-items: center; gap: 8px; padding: 6px 8px; border-radius: 7px;
  text-decoration: none; color: var(--texte); font-size: 13.5px;
}
.ligne-champ:hover { background: var(--jnj-pale); }
.ligne-champ.actif { background: var(--jnj); color: #fff; }
.ligne-champ .code {
  font: 11px ui-monospace, Consolas, monospace; color: var(--gris);
  background: #f1f1f6; border-radius: 4px; padding: 1px 5px; flex: none; min-width: 34px; text-align: center;
}
.ligne-champ.actif .code { background: rgba(255, 255, 255, .25); color: #fff; }
.ligne-champ .nom { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ligne-champ .badge {
  font-size: 10.5px; font-weight: 700; padding: 2px 6px; border-radius: 4px;
  background: #f1f1f6; color: var(--gris); flex: none;
}
.ligne-champ .badge.liste { background: #e6f5ec; color: var(--vert); }
.ligne-champ.actif .badge { background: rgba(255, 255, 255, .25); color: #fff; }

.alerte {
  background: var(--jaune); border: 1px solid var(--jaune-bord); border-radius: 9px;
  padding: 10px 13px; font-size: 13.5px; margin: 12px 0;
}
.ajout-valeur { display: flex; gap: 8px; margin: 12px 0; }
.ajout-valeur input {
  flex: 1; padding: 8px 11px; border: 1.5px solid var(--bord); border-radius: 9px; font: inherit;
}
.tableau-valeurs { width: 100%; font-size: 13.5px; }
.tableau-valeurs th {
  text-align: left; font-size: 11.5px; text-transform: uppercase; color: var(--gris);
  border-bottom: 2px solid var(--bord); padding: 7px 6px;
}
.tableau-valeurs td { padding: 5px 6px; border-bottom: 1px solid #eeeef4; vertical-align: middle; }
/* le sélecteur vise le texte : sans ça, les cases à cocher des familles
   héritaient de « width: 100% » et occupaient toute la colonne */
.tableau-valeurs input[type="text"], .tableau-valeurs select {
  width: 100%; padding: 6px 9px; border: 1px solid var(--bord); border-radius: 7px; font: inherit;
}
/* une ligne modifiée mais pas encore envoyée : même repère que partout */
.tableau-valeurs tr.non-enregistre td { background: rgba(69, 59, 138, .05); }
.tableau-valeurs tr.non-enregistre td:first-child {
  box-shadow: inset 3px 0 0 var(--jnj-clair);
}
/* la corbeille : discrète au repos, franchement rouge quand on la vise */
.tableau-valeurs .col-poubelle { width: 40px; text-align: right; }
.poubelle-valeur {
  border: 0; background: none; cursor: pointer; color: var(--gris);
  line-height: 0; padding: 6px; border-radius: 7px; opacity: .55; transition: .12s;
}
.tableau-valeurs tr:hover .poubelle-valeur { opacity: .85; }
.poubelle-valeur:hover { opacity: 1; background: var(--rouge); color: #fff; }
.invisible {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap;
}
.bandeau-info { border-left: 4px solid var(--jnj); }

/* ------------------------------------------ choix d'une variante en photo */
.voile {
  position: fixed; inset: 0; background: rgba(20, 20, 45, .55); z-index: 200;
  display: grid; place-items: center; padding: 20px;
}
.fenetre-photos {
  background: #fff; border-radius: 16px; padding: 22px 24px;
  max-width: 980px; width: 100%; max-height: 88vh; overflow: auto;
  box-shadow: 0 24px 70px rgba(0, 0, 0, .35);
}
.entete-fenetre { display: flex; align-items: center; gap: 14px; }
.entete-fenetre h2 { margin: 0; font-size: 18px; color: var(--jnj); flex: 1; }
.grille-photos {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: 14px; margin: 16px 0;
}
.carte-photo {
  display: flex; flex-direction: column; gap: 10px; text-align: left;
  background: #fff; border: 2px solid var(--bord); border-radius: 12px;
  padding: 12px; cursor: pointer; font: inherit; transition: .14s;
}
.carte-photo:hover { border-color: var(--jnj); box-shadow: 0 6px 18px rgba(69, 59, 138, .18); }
.carte-photo.choisie { border-color: var(--jnj); background: var(--jnj-pale); }
/* Les photos d'articles sont en portrait : on leur laisse de la hauteur. */
.carte-photo img {
  width: 100%; height: 190px; object-fit: contain; background: #fafafd;
  border-radius: 8px; padding: 8px;
}
.carte-photo .sans-photo {
  height: 190px; display: grid; place-items: center; color: var(--gris);
  background: #fafafd; border-radius: 8px; font-size: 13px;
}
.carte-photo .legende { font-size: 13.5px; line-height: 1.45; }
.carte-photo .reference {
  font: 12px ui-monospace, Consolas, monospace; color: var(--jnj);
  background: var(--jnj-pale); border-radius: 5px; padding: 1px 6px;
}
.carte-photo .aide { display: block; color: var(--gris); font-size: 12.5px; margin-top: 5px; }
.pied-fenetre { border-top: 1px solid var(--bord); padding-top: 14px; text-align: right; }

/* le bouton dans la fiche, qui montre la variante retenue */
.choix-photo {
  display: flex; align-items: center; gap: 11px; width: 100%; text-align: left;
  background: #fff; border: 1.5px solid var(--bord); border-radius: 9px;
  padding: 8px 11px; cursor: pointer; font: inherit; min-height: 56px;
}
.choix-photo:hover { border-color: var(--jnj); }
.choix-photo img { width: 34px; height: 46px; object-fit: contain; background: #fafafd; border-radius: 6px; padding: 2px; }
.choix-photo .vide-photo { color: var(--gris); font-size: 13.5px; }
/* valeur choisie dont l'article n'a pas encore de plan */
.choix-photo .sans-plan {
  width: 34px; height: 46px; flex: none; display: grid; place-items: center;
  background: #fafafd; border: 1px dashed var(--bord); border-radius: 6px;
  color: var(--gris); font-size: 9px; text-align: center; line-height: 1.1;
}
.choix-photo .reference {
  font: 11.5px ui-monospace, Consolas, monospace; color: var(--jnj);
}

/* ------------------------------------------------- bulle d'aide du parc */
/* Le mode d'emploi tient dans une bulle : la place qu'il prenait sous le
   tableau revient à la barre de défilement, collée en bas de l'écran. */
.aide-chip {
  display: inline-flex; align-items: center; justify-content: center;
  width: 20px; height: 20px; border-radius: 50%; cursor: help;
  background: var(--jnj-pale); color: var(--jnj); font-size: 12px; font-weight: 700;
}
.aide-chip:hover { background: var(--jnj); color: #fff; }

/* -------------------------------------------------- fenêtres de saisie */
.fenetre {
  background: #fff; border-radius: 16px; padding: 20px 24px 18px;
  max-width: 520px; width: 100%; max-height: 88vh; overflow: auto;
  box-shadow: 0 24px 70px rgba(0, 0, 0, .35);
}
.fenetre .corps-fenetre { margin: 14px 0 4px; }
.fenetre .grille { gap: 12px; }
.fenetre .pied-fenetre { display: flex; justify-content: flex-end; gap: 8px; margin-top: 14px; }
.fenetre .erreur { margin: 8px 0 0; }
.info-rf {
  font-size: 13px; color: var(--gris); background: #f7f7fb;
  border: 1px dashed var(--bord); border-radius: 9px; padding: 8px 11px; margin: 4px 0 0;
}
.info-rf.attention { background: var(--jaune); border-color: var(--jaune-bord); color: #7a6100; }
.info-rf.erreur {
  background: #fdecec; border-color: #f0c8ce; color: var(--rouge); border-style: solid;
}

/* ------------------------------------------------------ liste des clients */
/* Largeurs fixées par le <colgroup> : sans « table-layout: fixed », le
   navigateur les recalculerait d'après le contenu et la poignée n'aurait
   aucun effet. La dernière colonne, sans largeur, prend ce qui reste. */
.tableau-clients { width: 100%; table-layout: fixed; font-size: 14px; }
.tableau-clients th {
  position: sticky; top: 0; z-index: 2; background: #fff; text-align: left;
  font-size: 11.5px; text-transform: uppercase; letter-spacing: .4px; color: var(--gris);
  border-bottom: 2px solid var(--bord); padding: 9px 10px; white-space: nowrap;
}
.tableau-clients td {
  padding: 4px 8px; border-bottom: 1px solid #eeeef4; vertical-align: middle;
  height: auto; white-space: normal; overflow: hidden;
}
/* Une bande sur deux, pour suivre une ligne des yeux jusqu'au bout : le
   tableau fait sept colonnes de large et un client peut tenir sur quatre
   lignes. La teinte est celle de la maison, très pâle. */
.tableau-clients tbody tr.bande td { background: var(--jnj-pale); }
/* Pas de teinte au survol de la ligne. Les cases Nom et Lieu traversent
   toutes les lignes de leur client (rowspan) : survoler une case en colorait
   donc le bloc entier, sauf justement celle qu'on visait — dont la zone de
   saisie repasse en blanc. Le repère se pose maintenant sur la case seule,
   par un liseré, le même que celui des consignes du tableau principal. */
.tableau-clients tbody td:hover { box-shadow: inset 2px 0 0 var(--jnj-clair); }
/* une case de filtre par colonne, comme dans le parc */
.tableau-clients .ligne-filtres th {
  top: var(--h-clients, 36px); background: #fafaff; padding: 5px 7px;
  border-bottom: 1px solid var(--bord);
}
.tableau-clients .ligne-filtres input {
  width: 100%; font: inherit; font-size: 12.5px; font-weight: 400; text-transform: none;
  letter-spacing: 0; padding: 4px 7px; border: 1px solid var(--bord); border-radius: 6px;
  background: #fff;
}
.tableau-clients input, .tableau-clients select {
  width: 100%; font: inherit; font-size: 13.5px; padding: 6px 9px;
  border: 1px solid transparent; border-radius: 7px; background: none; color: var(--texte);
}
.tableau-clients input:hover, .tableau-clients select:hover { border-color: var(--bord); background: #fff; }
.tableau-clients input:focus, .tableau-clients select:focus {
  outline: 0; border-color: var(--jnj); background: #fff;
}
/* le texte cherché : la case entière se teinte, comme le surlignage jaune
   de la Liste RF — on ne peut pas surligner un morceau dans un champ de saisie */
.tableau-clients .trouve, .tableau-clients .trouve:hover {
  background: #ffe680; font-weight: 600;
}
.tableau-clients .trouve:focus { background: #fff; font-weight: 400; }
.tableau-clients .droite, th.droite { text-align: right; }
/* nom du site + sa croix de suppression : la croix ne se montre qu'au survol
   de la case, comme celle des en-têtes de colonne — supprimer un lieu n'est
   pas un geste qu'on doit pouvoir faire par mégarde en visant à côté */
.cellule-site { display: flex; align-items: center; gap: 2px; }
.cellule-site input { min-width: 0; }
.supprimer-site {
  flex: none; opacity: 0; transition: .12s; border: 0; background: none;
  cursor: pointer; color: var(--gris); font-size: 16px; line-height: 1;
  padding: 3px 6px; border-radius: 5px;
}
.tableau-clients td:hover .supprimer-site { opacity: .75; }
.supprimer-site:hover { opacity: 1; background: var(--rouge); color: #fff; }
.lien {
  font: inherit; font-size: 12.5px; font-weight: 600; cursor: pointer;
  border: 0; background: none; color: var(--jnj); text-decoration: underline;
  padding: 4px 6px; white-space: nowrap;
}

/* ------------------------------------------------- cases de filtre à liste */
/* On tape pour chercher, ou on ouvre la liste de toutes les valeurs de la
   colonne : sans elle, il faut connaître l'orthographe exacte pour filtrer. */
.combo-filtre { display: flex; align-items: stretch; gap: 0; }
.combo-filtre input { border-radius: 6px 0 0 6px; border-right: 0; min-width: 0; }
.fleche-filtre {
  flex: none; width: 20px; cursor: pointer; font-size: 11px; line-height: 1;
  border: 1px solid var(--bord); border-left: 0; border-radius: 0 6px 6px 0;
  background: #fff; color: var(--gris); padding: 0;
}
.fleche-filtre:hover { background: var(--jnj-pale); color: var(--jnj); }

/* Effacer un filtre. La croix ne se montre que si la case contient quelque
   chose : « :placeholder-shown » est vrai tant qu'elle est vide, l'inverse
   dit donc « il y a du texte ». Pas de JavaScript à tenir à jour à chaque
   frappe. La croix que Chrome ajoute lui-même aux champs de recherche est
   masquée, sinon on en aurait deux côte à côte. */
.combo-filtre input[type=search]::-webkit-search-cancel-button { display: none; }
.vider-filtre {
  display: none; flex: none; width: 20px; align-items: center; justify-content: center;
  cursor: pointer; font-size: 15px; font-weight: 700; line-height: 1; padding: 0;
  border: 1px solid var(--bord); border-left: 0; border-right: 0;
  background: #fff; color: var(--rouge);
}
.combo-filtre input:not(:placeholder-shown) ~ .vider-filtre { display: inline-flex; }
.vider-filtre:hover { background: var(--rouge); color: #fff; }
.ligne-filtres input[data-exact] { font-weight: 700; color: var(--jnj); }

.menu-filtre {
  position: fixed; z-index: 320; width: 290px;
  background: #fff; border: 1px solid var(--bord); border-radius: 11px;
  box-shadow: 0 12px 34px rgba(20, 20, 45, .22); overflow: hidden;
}
.menu-filtre .entete-filtre { padding: 9px 10px 8px; border-bottom: 1px solid var(--bord); }
.menu-filtre .titre-menu {
  display: block; font-size: 11.5px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .4px; color: var(--gris); margin-bottom: 7px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.menu-filtre .recherche-menu {
  width: 100%; font: inherit; font-size: 13px; padding: 6px 9px;
  border: 1.5px solid var(--bord); border-radius: 8px; color: var(--texte);
}
.menu-filtre .recherche-menu:focus { outline: 0; border-color: var(--jnj); }
/* la liste défile : une colonne peut compter 215 clients */
.valeurs-filtre { max-height: 300px; overflow-y: auto; padding: 5px; }
.valeurs-filtre button {
  display: flex; align-items: center; gap: 8px; width: 100%; text-align: left;
  font: inherit; font-size: 13.5px; cursor: pointer; border: 0; background: none;
  color: var(--texte); padding: 6px 9px; border-radius: 7px;
}
.valeurs-filtre button:hover { background: var(--jnj-pale); }
.valeurs-filtre button.actif { font-weight: 700; color: var(--jnj); background: var(--jnj-pale); }
.valeurs-filtre .texte-choix { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.valeurs-filtre .nb-choix {
  flex: none; font-size: 11px; font-weight: 700; color: var(--gris);
  background: #f1f1f6; border-radius: 10px; padding: 1px 7px;
}
.separateur-filtre { height: 1px; background: var(--bord); margin: 5px 4px; }
.vide-filtre { text-align: center; padding: 14px 8px; margin: 0; }

/* ------------------------------------------- consignes posées au clic droit */
/* Une couleur sur une case dit à un collègue ce qu'il reste à y faire. Elle
   doit se lire par-dessus la teinte pastel du groupe : d'où le fond franc et
   le liseré à gauche, qui la distingue aussi du surlignage de recherche. */
/* Le choix des consignes, dans la barre de filtres, porte les mêmes teintes
   que les cellules du tableau : la couleur se reconnaît avant que le texte
   se lise. Les classes marque-* sont celles du tableau — rien n'est répété
   ici, seules leurs variables sont relues. */
#f-marque option[class*="marque-"] {
  background: var(--fond-marque); color: var(--texte); font-weight: 600;
}
#f-marque[class*="marque-"] {
  background: var(--fond-marque); border-color: var(--trait-marque); font-weight: 600;
}

.marque-jaune  { --fond-marque: #ffeaa0; --trait-marque: #e5a400; }
.marque-bleu   { --fond-marque: #cfe0fb; --trait-marque: #2f6fd0; }
.marque-rouge  { --fond-marque: #fbd0d6; --trait-marque: #cf1f36; }
.marque-vert   { --fond-marque: #cdebd8; --trait-marque: #2e7d4f; }
.marque-orange { --fond-marque: #ffdcc0; --trait-marque: #d2691e; }
.marque-violet { --fond-marque: #e2d7f6; --trait-marque: #6b4bb5; }
.marque-gris   { --fond-marque: #e2e2ea; --trait-marque: #6b6b78; }

/* Pas de « !important » : la couleur de consigne doit céder le pas au vert de
   l'enregistrement et au rouge de l'échec, le temps de la sauvegarde. */
tbody td[class*="marque-"] {
  background: var(--fond-marque);
  box-shadow: inset 3px 0 0 var(--trait-marque);
}
tbody tr:hover td[class*="marque-"] { filter: brightness(.97); }

/* sur la fiche machine, le même repère autour du champ */
.champ[class*="marque-"] {
  background: var(--fond-marque); border-radius: 10px; padding: 8px 10px;
  box-shadow: inset 3px 0 0 var(--trait-marque);
}
.puce-consigne {
  display: inline-block; margin-left: 8px; font-size: 11px; font-weight: 700;
  padding: 1px 7px; border-radius: 10px;
  background: var(--trait-marque); color: #fff; vertical-align: middle;
}
/* champ restreint à d'autres familles de robots, gardé parce qu'il porte
   déjà une valeur : il se voit, mais on comprend tout de suite pourquoi */
.puce-hors-famille {
  display: inline-block; margin-left: 8px; font-size: 10.5px; font-weight: 700;
  padding: 1px 7px; border-radius: 10px; text-transform: uppercase; letter-spacing: .3px;
  background: #f1f1f6; color: var(--gris); border: 1px solid var(--bord);
  vertical-align: middle;
}
.champ.hors-famille .nom-champ { color: var(--gris); }
/* la même idée dans le parc : la case garde sa place mais ne se saisit pas */
td.hors-famille {
  color: #c6c6d2; background: repeating-linear-gradient(135deg,
    transparent 0 6px, rgba(0, 0, 0, .028) 6px 12px);
  text-align: center; cursor: default;
}
/* Familles et mode d'affichage côte à côte : la place à droite des familles
   était perdue, le réglage d'affichage la remplit. */
.reglages-champ {
  display: flex; gap: 26px; flex-wrap: wrap; align-items: flex-start;
}
.reglages-champ .champ { margin: 0; }
.affichage-champ .bascule-affichage { display: flex; gap: 8px; margin-top: 4px; }
.affichage-champ .case-famille input { accent-color: var(--jnj); }
#aide-affichage { margin: 6px 0 0; max-width: 380px; }

/* cases à cocher des familles, dans Configurer les champs */
.familles-champ .cases-familles {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-top: 4px;
}
.case-famille {
  display: inline-flex; align-items: center; gap: 6px; cursor: pointer;
  font-size: 13.5px; font-weight: 600; padding: 5px 11px 5px 8px;
  border: 1.5px solid var(--bord); border-radius: 16px; background: #fff;
}
.case-famille:hover { border-color: var(--jnj); color: var(--jnj); }
.case-famille:has(input:checked) {
  border-color: var(--jnj); background: var(--jnj-pale); color: var(--jnj);
}
.case-famille input { margin: 0; }
/* la même pastille, en plus petit, dans le tableau des valeurs possibles */
.case-famille.petite {
  font-size: 12px; padding: 3px 8px 3px 6px; gap: 4px; border-width: 1px;
}
.tableau-valeurs .cases-familles { gap: 5px; margin: 0; }

.pastille-marque {
  display: inline-block; width: 14px; height: 14px; border-radius: 4px;
  background: var(--fond-marque); border: 1.5px solid var(--trait-marque);
  vertical-align: middle; margin-right: 7px; flex: none;
}
/* ⛔ Le « padding: 0 » n'est pas décoratif : la règle générale « .vide » des
   pages sans contenu (40 px de marge) s'appliquait aussi à cette pastille et
   en faisait un carré blanc six fois trop grand dans le menu du clic droit. */
.pastille-marque.vide {
  background: #fff; border: 1.5px dashed var(--bord); padding: 0;
}

/* le menu du clic droit */
.menu-marque {
  position: fixed; z-index: 300; min-width: 210px;
  background: #fff; border: 1px solid var(--bord); border-radius: 11px;
  box-shadow: 0 12px 34px rgba(20, 20, 45, .22); padding: 6px; overflow: hidden;
}
.menu-marque .titre-menu {
  font-size: 11.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .4px;
  color: var(--gris); padding: 6px 9px 8px; border-bottom: 1px solid var(--bord);
  margin-bottom: 5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* « nowrap » plutôt qu'une largeur minimale plus grande : le menu s'élargit
   de lui-même pour tenir « Créer la fiche montage XLS » sur une ligne, et
   restera juste si un libellé change encore. */
.menu-marque button {
  display: flex; align-items: center; width: 100%; text-align: left;
  font: inherit; font-size: 13.5px; cursor: pointer; white-space: nowrap;
  border: 0; background: none; color: var(--texte);
  padding: 7px 9px; border-radius: 8px;
}
.menu-marque button:hover { background: var(--jnj-pale); }
.menu-marque button.actif { font-weight: 700; }
.menu-marque button.actif::after { content: '✓'; margin-left: auto; color: var(--jnj); }
.menu-marque .retirer { color: var(--gris); }
/* Trois parties : les consignes de couleur, ce qu'on sort de la machine,
   ce qu'on va régler ailleurs. Un filet sépare chacune de la suivante. */
.menu-marque .bloc-menu + .bloc-menu {
  border-top: 1px solid var(--bord); margin-top: 5px; padding-top: 5px;
}
/* le lien vers Configurer les champs, et le bouton de la fiche de montage */
.menu-marque .configurer-champ,
.menu-marque .action-menu {
  display: flex; align-items: center; gap: 8px; width: 100%; text-align: left;
  padding: 8px 12px; border: 0; background: none; border-radius: 8px;
  font: inherit; font-size: 13px; font-weight: 600; white-space: nowrap;
  color: var(--jnj); text-decoration: none; cursor: pointer;
}
.menu-marque .configurer-champ:hover,
.menu-marque .action-menu:hover { background: var(--jnj-pale); }
.menu-marque .configurer-champ .rouage,
.menu-marque .action-menu .rouage { display: inline-flex; line-height: 0; }

/* --------------------------------------------------------------- divers */
.toast {
  position: fixed; left: 50%; transform: translateX(-50%); bottom: 20px;
  background: #23233a; color: #fff; padding: 11px 20px; border-radius: 10px;
  font-size: 14px; opacity: 0; pointer-events: none; transition: .25s; z-index: 100;
}
.toast.visible { opacity: 1; bottom: 32px; }
.toast.erreur { background: var(--rouge); }
.barre-enregistrement {
  position: sticky; bottom: 0; background: #fff; border-top: 1px solid var(--bord);
  padding: 12px 18px; display: flex; gap: 10px; align-items: center; flex-wrap: wrap;
  margin: 0 -18px -16px; border-radius: 0 0 12px 12px;
}
.barre-enregistrement .info { color: var(--gris); font-size: 13px; margin-right: auto; }

/* ------------------------------------------------------------ impression */
/* Sert d'export PDF de la fiche machine (réponse E4) : Ctrl+P puis
   « Enregistrer au format PDF ». */
@media print {
  .bandeau, .pied, .onglets, .barre-enregistrement, .toast,
  .filtres, .barre-titre .a-droite, .cellule-xls { display: none !important; }
  body { background: #fff; }
  main { padding: 0; max-width: none; }
  .carte { border: 1px solid #ccc; box-shadow: none; break-inside: avoid; margin-bottom: 10px; }
  .fiche { grid-template-columns: 1fr; }
  .champ input, .champ select, .champ textarea {
    border: 0; border-bottom: 1px solid #ccc; border-radius: 0; padding-left: 0;
    background: none !important; font-weight: 600;
  }
  .tableau-cadre { max-height: none; overflow: visible; }
}


/* --------------------------------------------------------- utilisateurs */
/* Une ligne par compte, réglable sur place : le groupe et les droits se
   choisissent dans une liste, le reste se tape. Tout s'enregistre en sortant
   de la case, comme dans la liste des clients. */
.tableau-utilisateurs { table-layout: auto; }
.tableau-utilisateurs td { vertical-align: middle; }
.tableau-utilisateurs input[type=checkbox] { width: 17px; height: 17px; accent-color: var(--jnj); }
.tableau-utilisateurs .lien { font-size: 12.5px; margin-left: 6px; }
.lien.danger { color: var(--rouge); }
/* un champ et son intitulé, empilés — dans les fenêtres de saisie */
.bloc { display: block; margin-bottom: 12px; font-size: 13.5px; font-weight: 600; }
.bloc input, .bloc select {
  display: block; width: 100%; margin-top: 5px; font: inherit; font-weight: 400;
  padding: 9px 11px; border: 1.5px solid var(--bord); border-radius: 9px; background: #fff;
}
.bloc input:focus, .bloc select:focus { outline: 0; border-color: var(--jnj); }

/* ------------------------------------------------------ consultation seule */
/* Les comptes en lecture voient tout et ne touchent à rien. Les cases restent
   lisibles — grisées, elles seraient pénibles à lire toute la journée — mais
   n'acceptent plus ni le clic ni la frappe. */
body.lecture-seule .champ input,
body.lecture-seule .champ select,
body.lecture-seule .champ textarea,
body.lecture-seule .tableau-clients input,
body.lecture-seule .tableau-clients select,
body.lecture-seule .choix-photo,
body.lecture-seule td.saisissable {
  pointer-events: none;
}
body.lecture-seule .champ input,
body.lecture-seule .champ select,
body.lecture-seule .champ textarea { background: #fbfbfd; }
body.lecture-seule .note-champ,
body.lecture-seule .barre-enregistrement,
body.lecture-seule #bouton-enregistrer-tout,
body.lecture-seule #bouton-annuler-tout { display: none !important; }
