/* Charte « station de lavage agricole / environnement » :
   bandeaux vert forêt, boutons ton blé-ocre, fond papier naturel verdi,
   statuts en vert feuille / bleu eau / ambre / terre cuite.
   (Les noms de variables historiques --navy, --salmon sont conservés
   pour compatibilité ; leurs valeurs suivent désormais ce thème.) */
:root{
  --bg: #F1F4E9;
  --card: #FFFFFF;
  --card-border: #DFE3D1;
  --navy: #24462E;
  --navy-2: #2E5A3B;
  --navy-text: #EFF3E2;
  --salmon: #C68A38;
  --salmon-dark: #A5702A;
  --btn: #8A6A26;
  --btn-active: #6E531D;
  --ink: #2A2B20;
  --ink-soft: #5F6150;
  --green: #4E9A51;
  --blue: #2F80A6;
  --orange: #E0912F;
  --red: #C4482F;
  --off: #C6BEA6;
  --font-display: 'Space Grotesk', sans-serif;
  --font-body: 'IBM Plex Sans', sans-serif;
  --font-mono: 'IBM Plex Mono', monospace;
}
*{box-sizing:border-box;}
body{
  margin:0;
  background:var(--bg);
  color:var(--ink);
  font-family:var(--font-body);
  -webkit-font-smoothing:antialiased;
}
h1,h2,h3,.brand{font-family:var(--font-display);}
a{color:inherit; text-decoration:none;}
button{font-family:var(--font-body); cursor:pointer;}
:focus-visible{outline:3px solid var(--blue); outline-offset:2px;}

/* --- Bannière de démonstration --- */
.demo-bar{
  background:#2A2B20; color:#EFF3E2; font-family:var(--font-mono); font-size:12px;
  padding:8px 16px; display:flex; gap:16px; align-items:center; flex-wrap:wrap; justify-content:space-between;
}
.demo-bar b{color:#F2C9B0;}
.demo-bar select{
  background:#3A2F27; color:#EFF3E2; border:1px solid #5A4A3D; border-radius:4px; padding:3px 6px;
  font-family:var(--font-mono); font-size:12px;
}
.demo-left{display:flex; align-items:center; gap:16px; flex-wrap:wrap;}
.quick-access{display:flex; align-items:center; gap:6px; flex-wrap:wrap;}
.quick-access a{
  background:#3A2F27; color:#EFF3E2; border:1px solid #5A4A3D; border-radius:14px;
  padding:4px 11px; font-family:var(--font-mono); font-size:11.5px; display:inline-block;
}
.quick-access a:hover{background:var(--salmon-dark); border-color:var(--salmon-dark);}
.quick-access a.current{background:var(--salmon); border-color:var(--salmon); color:#fff;}

/* --- Bandeaux --- */
.bandeau{
  background:linear-gradient(180deg,var(--navy),var(--navy-2));
  color:var(--navy-text);
  padding:10px 20px;
  display:flex; align-items:center; justify-content:space-between; gap:12px; flex-wrap:wrap;
}
.bandeau-top{position:sticky; top:0; z-index:20;}
.brand{font-size:21px; font-weight:700; letter-spacing:.3px; display:flex; align-items:center; gap:10px;}
.brand .dot{width:9px;height:9px;border-radius:50%;background:var(--salmon);display:inline-block;}
.brand-logo{height:34px; width:auto; border-radius:6px; background:#fff; padding:3px; box-shadow:0 1px 3px rgba(0,0,0,.25); display:block;}
/* Logo du site : à droite du bandeau, juste avant le code site.
   Même hauteur que le logo Concepto, pour ne pas modifier la hauteur du bandeau. */
.site-logo{height:34px; width:auto; border-radius:6px; background:#fff; padding:3px;
  box-shadow:0 1px 3px rgba(0,0,0,.25); display:block; flex:0 0 auto;}
.session-meta{display:flex; gap:10px; align-items:center; font-size:14px; font-family:var(--font-mono);}
.pill{
  border:1px solid rgba(242,236,225,.35); border-radius:20px; padding:5px 13px;
}
.pill.admin{background:rgba(198,138,56,.18); border-color:var(--salmon);}
.pill.client{background:rgba(47,128,166,.18); border-color:var(--blue);}
/* L'ancien bandeau d'onglets horizontal (.nav) a été supprimé : la navigation
   se fait par la colonne latérale (.rail), engendrée par common.js. */

/* Déconnexion : tout à droite du bandeau supérieur.
   L'icône seule serait ambiguë (marche/arrêt de la machine ? de la station ?),
   d'où le libellé, masqué seulement sur écran étroit. */
.logout-top{
  display:inline-flex; align-items:center; gap:8px;
  background:transparent; border:1px solid rgba(242,236,225,.42); color:var(--navy-text);
  padding:7px 14px; border-radius:8px; font-size:14px; font-family:var(--font-body);
  font-weight:500; margin-left:6px; white-space:nowrap;
  transition:background .12s ease, border-color .12s ease;
}
.logout-top:hover{background:rgba(242,236,225,.14); border-color:rgba(242,236,225,.75);}
.icon-power{
  width:17px; height:17px; flex:0 0 auto;
  fill:none; stroke:currentColor; stroke-width:2.1; stroke-linecap:round;
}

.footer-bandeau{
  display:flex; justify-content:space-between; align-items:center; font-size:13.5px; padding:12px 20px;
}

/* .shell porte les gouttières et le rembourrage ; le PLAFOND de largeur, lui,
   appartient à main (max-width:1400px). .shell s'étend sur toute la largeur
   pour que le rail s'ancre à gauche, aligné sur le logo du bandeau.
   main reste une piste de la grille de .shell : lui laisser son propre
   rembourrage de 20 px l'aurait ajouté à celui du conteneur.
   Cf. la section « Ossature ». */

.card{
  background:var(--card); border:1px solid var(--card-border); border-radius:14px;
  padding:22px; margin-bottom:18px;
}
.page-title{display:flex; align-items:baseline; justify-content:space-between; flex-wrap:wrap; gap:10px; margin-bottom:14px;}
.page-title h2{margin:0; font-size:25px;}
.page-title .sub{color:var(--ink-soft); font-size:14px; font-family:var(--font-mono);}

.toolbar{display:flex; gap:10px; flex-wrap:wrap; margin-bottom:16px; align-items:center;}
select, input[type=text], input[type=password]{
  font-family:var(--font-mono); font-size:14.5px; padding:9px 12px; border-radius:7px;
  border:1px solid var(--card-border); background:#FCFDF7; color:var(--ink);
}
label{font-size:13px; color:var(--ink-soft); display:block; margin-bottom:5px; font-family:var(--font-body);}

/* --- LOGIN --- */
.login-wrap{
  min-height:calc(100vh - 60px); display:flex; align-items:center; justify-content:center; padding:40px 20px;
}
.login-card{
  background:var(--card); border:1px solid var(--card-border); border-radius:16px; padding:38px;
  width:100%; max-width:400px; box-shadow:0 18px 40px -20px rgba(23,33,59,.25);
}
.login-card h1{font-size:24px; margin:0 0 4px;}
.login-card p.lede{color:var(--ink-soft); font-size:14.5px; margin:0 0 22px;}
.field{margin-bottom:14px;}
.field input{width:100%;}
.btn-primary{
  width:100%; background:var(--btn); color:#fff; border:none; padding:12px; border-radius:8px;
  font-weight:600; font-size:15.5px; margin-top:6px; display:block; text-align:center;
}
.btn-primary:hover{background:var(--btn-active);}
.btn-ghost{background:transparent; border:1px solid var(--card-border); color:var(--ink); padding:10px 16px; border-radius:8px; font-size:14px;}
.otp-boxes{display:flex; gap:8px; margin-bottom:8px;}
.otp-boxes input{width:44px; height:52px; text-align:center; font-size:19px;}
.step-label{font-size:12.5px; font-family:var(--font-mono); color:var(--salmon-dark); text-transform:uppercase; letter-spacing:.08em; margin-bottom:6px;}
.role-picker{display:flex; gap:8px; margin-bottom:18px; flex-wrap:wrap;}
.role-picker button{
  flex:1; min-width:100px; background:#EEF1E2; border:1px solid var(--card-border); border-radius:8px;
  padding:8px 6px; font-size:11.5px; font-family:var(--font-mono); color:var(--ink-soft);
}
.role-picker button.selected{background:var(--navy); color:var(--navy-text); border-color:var(--navy);}

/* --- Tables --- */
.table-wrap{width:100%; overflow-x:auto; -webkit-overflow-scrolling:touch;}
.table-wrap table{min-width:660px;}
table{width:100%; border-collapse:collapse; font-size:14.5px;}
th{
  text-align:left; font-family:var(--font-mono); font-weight:600; font-size:12.5px; text-transform:uppercase;
  letter-spacing:.05em; color:var(--ink-soft); border-bottom:2px solid var(--card-border); padding:10px 9px;
}
td{padding:10px 9px; border-bottom:1px solid #E7EBDB; font-family:var(--font-mono); font-size:14px;}
.conso{font-weight:600;}

/* --- Historique : chaque enregistrement est une carte ---------------------
   border-collapse:collapse IGNORE border-radius. Le passage en `separate` est
   donc obligatoire, et c'est lui qui permet aussi d'espacer les rangées.
   La teinte de badge se pose sur les CELLULES : un fond de <tr> se peint en
   rectangle derrière les cellules et ressort dans les angles arrondis.

   Densité : les deux seules valeurs à toucher pour resserrer ou aérer la liste. */
.table-cards{
  --carte-ecart:5px;      /* espace vertical entre deux enregistrements */
  --carte-marge:8px;      /* respiration interne, en haut et en bas */
  border-collapse:separate; border-spacing:0 var(--carte-ecart);
}
.table-cards thead th{padding-bottom:4px;}
.table-cards tbody td{
  background:var(--card);
  padding:var(--carte-marge) 10px;
  border-top:1px solid var(--card-border);
  border-bottom:1px solid var(--card-border);
  transition:background .12s ease;
}
.table-cards tbody td:first-child{
  border-left:1px solid var(--card-border);
  border-top-left-radius:10px; border-bottom-left-radius:10px;
}
.table-cards tbody td:last-child{
  border-right:1px solid var(--card-border);
  border-top-right-radius:10px; border-bottom-right-radius:10px;
}
/* Rangée « aucun passage » : une cellule unique, donc à la fois première et
   dernière. Sans cette règle, seuls les angles droits seraient arrondis. */
.table-cards tbody td:first-child:last-child{
  border:1px solid var(--card-border); border-radius:10px;
}

/* Teintes par badge, portées par les cellules. */
.table-cards tr.badge-A td{background:#F5ECD8;}
.table-cards tr.badge-B td{background:#E0EDF2;}
.table-cards tr.badge-C td{background:#E7F1DE;}
.table-cards tr.badge-A:hover td{background:#EFE3C6;}
.table-cards tr.badge-B:hover td{background:#D2E5EE;}
.table-cards tr.badge-C:hover td{background:#DCEBCE;}
/* Le liseré de couleur épouse l'angle arrondi de la première cellule. */
.table-cards tr.badge-A td:first-child{border-left:4px solid var(--salmon);}
.table-cards tr.badge-B td:first-child{border-left:4px solid var(--blue);}
.table-cards tr.badge-C td:first-child{border-left:4px solid var(--green);}

/* --- Historique : un enregistrement tient sur deux lignes dans la même rangée ---
   Une rangée = un passage. Les deux lignes sont obtenues DANS la cellule, pas
   par un second <tr> : le filtre par badge, le tri et le comptage manipulent des
   rangées, et un rowspan les désynchroniserait. */
.cell-id, .cell-dh{ line-height:1.3; white-space:nowrap; }
.cell-id .l1, .cell-dh .l1{ font-weight:600; color:var(--ink); }
.cell-id .l2, .cell-dh .l2{ color:var(--ink-soft); font-size:13px; margin-top:1px; }
.cell-id .sep{ opacity:.55; margin:0 5px; }
/* Le nombre se lit au centre du bloc de deux lignes. */
td.conso{ vertical-align:middle; }
.swatch{width:12px; height:12px; border-radius:3px; display:inline-block; border:1px solid rgba(0,0,0,.12);}
.swatch-A{background:var(--salmon);}
.swatch-B{background:var(--blue);}
.swatch-C{background:var(--green);}

.badge-checks{display:flex; gap:14px; margin-bottom:14px; flex-wrap:wrap;}
.badge-checks label{display:flex; align-items:center; gap:6px; font-size:14px; color:var(--ink); font-family:var(--font-body);}

/* =========================================================================
   HISTORIQUE — bandeau latéral (Stations / Clients / Badges) + tableau
   ========================================================================= */
.hist-layout{
  --tree-w:250px;
  display:grid; grid-template-columns:var(--tree-w) minmax(0,1fr); gap:18px; align-items:start;
}
/* minmax(0,1fr) est indispensable : sans lui, une piste de grille refuse de
   descendre sous la largeur de son contenu et le tableau déborde de la carte. */

.tree-panel{
  border:1px solid var(--card-border); border-radius:12px; background:#FAFCF4;
  overflow:hidden; position:sticky; top:66px;
}
.tree-head{
  display:flex; align-items:center; justify-content:space-between; gap:8px;
  padding:10px 12px; border-bottom:1px solid var(--card-border); background:#F1F4E9;
}
.tree-title{
  font-family:var(--font-mono); font-size:12px; font-weight:600; letter-spacing:.06em;
  text-transform:uppercase; color:var(--ink-soft);
}
/* Le libellé bascule entre « Tout afficher » et « Tout masquer » : sans nowrap,
   le plus long se brise en deux lignes et déforme l'entête du bandeau. */
.tree-all{
  background:transparent; border:1px solid var(--card-border); border-radius:6px;
  font-size:12px; padding:3px 8px; color:var(--ink-soft); font-family:var(--font-body);
  white-space:nowrap; flex:0 0 auto;
}
.tree-all:hover{background:#E7EBDB; color:var(--ink);}
.tree-scroll{max-height:min(62vh,560px); overflow-y:auto; padding:6px 4px 8px;}

.tree, .tree ul{list-style:none; margin:0; padding:0;}
.tree-kids{margin-left:14px; border-left:1px solid #E2E7D4; padding-left:2px;}
.tree-kids[hidden]{display:none;}

.tree-row{display:flex; align-items:center; gap:2px; border-radius:7px;}
.tree-row:hover{background:#EDF1E1;}

/* Chevron : n'agit QUE sur le dépliage. Le clic est arrêté avant le libellé,
   sinon déplier une société la masquerait du même geste. */
.tree-chev{
  flex:0 0 auto; width:20px; height:24px; padding:0; border:none; background:transparent;
  color:var(--ink-soft); display:inline-flex; align-items:center; justify-content:center;
}
.tree-chev svg{width:10px; height:10px; fill:currentColor; transition:transform .13s ease;}
.tree-chev[aria-expanded="true"] svg{transform:rotate(90deg);}
.tree-spacer{flex:0 0 auto; width:20px;}

/* Libellé : bascule l'affichage des données. « pressed » = visible. */
.tree-lab{
  flex:1 1 auto; min-width:0; display:flex; align-items:center; gap:7px;
  background:transparent; border:none; text-align:left;
  padding:5px 6px 5px 2px; border-radius:6px;
  font-family:var(--font-body); font-size:14px; color:var(--ink);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.tree-lab.lvl-soc{font-weight:600;}
.tree-lab.lvl-badge{font-size:13.5px; color:var(--ink-soft);}
.tree-lab.lvl-site{font-weight:700; font-family:var(--font-mono); font-size:13px;}

/* État masqué : l'opacité seule ne suffit pas (elle se confond avec un texte
   secondaire), d'où la rature — et le repère non chromatique exigé par le RGAA. */
.tree-lab[aria-pressed="false"]{color:#9BA08A; text-decoration:line-through;}
.tree-lab[aria-pressed="false"] .tree-dot{background:transparent; border-style:dashed;}
/* Société dont une partie seulement des badges est masquée. */
.tree-lab[data-partiel="1"]{font-style:italic;}
.tree-lab[data-partiel="1"]::after{
  content:"partiel"; margin-left:auto; flex:0 0 auto;
  font-family:var(--font-mono); font-size:11px; font-style:normal; letter-spacing:.04em;
  color:var(--ink-soft); background:#E7EBDB; border-radius:5px; padding:1px 5px;
}
.tree-dot{
  flex:0 0 auto; width:9px; height:9px; border-radius:50%;
  border:1px solid rgba(0,0,0,.15); background:var(--off);
}
.tree-dot.badge-A{background:var(--salmon);}
.tree-dot.badge-B{background:var(--blue);}
.tree-dot.badge-C{background:var(--green);}

/* Corps du tableau seul défilant : la barre d'outils et l'entête restent fixes.
   L'entête est `sticky` À L'INTÉRIEUR de ce conteneur ; la barre d'outils est
   à l'extérieur, elle ne bouge donc jamais. */
.table-scroll{
  max-height:min(64vh,640px);
  overflow:auto; -webkit-overflow-scrolling:touch;
  border-radius:10px;
}
.table-scroll table{min-width:660px;}
.table-scroll thead th{
  position:sticky; top:0; z-index:3;
  background:var(--card);      /* opaque : les rangées défilent dessous */
  box-shadow:inset 0 -2px 0 var(--card-border);
  border-bottom:none;          /* remplacée par l'ombre : une bordure ne suit pas un th sticky */
}

@media (max-width:900px){
  .hist-layout{grid-template-columns:1fr;}
  .tree-panel{position:static;}
  .tree-scroll{max-height:230px;}
  .table-scroll{max-height:none;}   /* sur mobile, la page défile d'un bloc */
}

/* -------------------------------------------------------------------------
   Sous 700 px : l'historique abandonne le tableau pour des cartes empilées.
   Le tableau impose 660 px de large, soit 2,4 fois un écran de téléphone —
   un défilement latéral dans une page qui défile déjà verticalement.
   La structure <table> reste en place (tri, filtres et comptage continuent
   d'opérer dessus) ; seul l'affichage change. L'entête est masquée, chaque
   cellule de mode rappelle son intitulé via data-mode.
   ------------------------------------------------------------------------- */
@media (max-width:700px){
  .table-scroll{overflow:visible;}
  .table-scroll table{min-width:0; width:100%; border-spacing:0;}
  .table-scroll thead{position:absolute; width:1px; height:1px; overflow:hidden; clip:rect(0 0 0 0);}
  .table-scroll tbody, .table-scroll tr, .table-scroll td{display:block;}
  .table-scroll tr{
    border:1px solid var(--card-border); border-left-width:4px; border-radius:10px;
    padding:10px 12px; margin-bottom:8px;
  }
  /* La teinte était portée par les <td> (border-collapse:separate l'exigeait) ;
     en cartes, c'est la rangée qui la porte, et les cellules redeviennent nues.
     Les valeurs reprennent celles des règles .table-cards tr.badge-* td. */
  .table-scroll tr.badge-A{background:#F5ECD8; border-left-color:var(--salmon);}
  .table-scroll tr.badge-B{background:#E0EDF2; border-left-color:var(--blue);}
  .table-scroll tr.badge-C{background:#E7F1DE; border-left-color:var(--green);}
  .table-scroll td{
    background:transparent !important; border:none !important; border-radius:0 !important;
    padding:2px 0; white-space:normal;
  }
  .table-scroll .cell-id, .table-scroll .cell-dh{padding-bottom:6px;}
  .table-scroll .cell-dh{border-bottom:1px solid rgba(0,0,0,.09) !important; margin-bottom:6px;}
  /* Les modes en paires « intitulé : valeur », deux par ligne. */
  .table-scroll td.conso{
    display:flex; justify-content:space-between; align-items:baseline; gap:10px;
    padding:3px 0; font-size:14px;
  }
  .table-scroll td.conso::before{
    content:attr(data-mode); color:var(--ink-soft); font-size:12.5px;
    overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
  }
  /* Rangée « aucun résultat » : elle n'a ni teinte ni bordure de carte. */
  .table-scroll tr:only-child td[colspan]{border:none; background:transparent;}
  .table-scroll tr:only-child{border:none; background:transparent; padding:0;}
}
@media (max-width:560px){
  .logout-top-txt{display:none;}
  .logout-top{padding:7px 10px;}
}

/* =========================================================================
   SUPERVISION — onglet Fréquentation (passages par mois et par année)
   ========================================================================= */
.freq-section{
  margin-bottom:10px; border:1px solid var(--card-border); border-radius:10px;
  background:#FAFCF4; overflow:hidden;
}
/* Le marqueur natif est remplacé par notre chevron, cohérent avec l'arbre de
   l'historique. list-style:none seul ne suffit pas sous WebKit. */
.freq-summary{
  cursor:pointer; list-style:none; padding:11px 13px;
  display:flex; align-items:baseline; gap:10px; flex-wrap:wrap;
}
.freq-summary::-webkit-details-marker{display:none;}
.freq-summary:hover{background:#F1F4E9;}
.freq-chev{
  width:9px; height:9px; flex:0 0 auto; fill:var(--ink-soft);
  transition:transform .13s ease; align-self:center;
}
.freq-section[open] > .freq-summary .freq-chev{transform:rotate(90deg);}
.freq-section[open] > .freq-summary{border-bottom:1px solid var(--card-border);}
.freq-body{padding:12px 13px 4px;}
.freq-title{
  font-family:var(--font-display); font-size:18px; margin:0; color:var(--navy);
}
.freq-sub{font-family:var(--font-mono); font-size:13px; font-weight:400; color:var(--ink-soft);}
.freq-muets{
  font-family:var(--font-mono); font-size:12.5px; color:var(--ink-soft);
  margin:10px 2px 8px;
}
/* Une station sur cinq ou six ans dépasse la largeur utile : on fait défiler
   ce tableau-là seul, plutôt que toute la page. */
.freq-scroll{overflow-x:auto; -webkit-overflow-scrolling:touch;}
/* La table n'est plus étirée à 100 % : avec une seule année, la colonne
   occupait toute la largeur et la barre de proportion devenait absurde.
   Les colonnes se dimensionnent sur leur contenu ; freq-scroll prend le relais
   quand les années s'accumulent. */
.freq-table{border-collapse:collapse;}
.freq-table th[scope="col"]{
  text-align:right; font-family:var(--font-mono); font-weight:600; font-size:12.5px;
  text-transform:uppercase; letter-spacing:.05em; color:var(--ink-soft);
  border-bottom:2px solid var(--card-border); padding:8px 10px; min-width:92px;
}
.freq-table th[scope="col"]:first-child{text-align:left;}
.freq-table th[scope="row"]{
  text-align:left; font-family:var(--font-body); font-weight:500; font-size:14px;
  color:var(--ink); padding:7px 10px; border-bottom:1px solid #E7EBDB; white-space:nowrap;
  min-width:104px;
}
.freq-table tbody tr:hover th[scope="row"], .freq-table tbody tr:hover .freq-cell{background:#F4F7EC;}

/* La barre est un RENFORT : le nombre reste lisible seul (RGAA — l'information
   ne doit pas reposer sur la seule couleur ni sur la seule longueur).

   ⚠ La barre est posée dans une PISTE inscrite dans la cellule, et non
   directement dans la cellule. Auparavant elle valait « left:2px; width:X% » :
   à X=100, son bord droit tombait 2 px au-delà de la cellule. Un élément
   absolu compte dans le débordement de son conteneur, ce qui déclenchait une
   barre de défilement horizontale. Ici « width:100% » = la piste exactement. */
.freq-cell{
  position:relative; text-align:right; padding:7px 10px; border-bottom:1px solid #E7EBDB;
  font-family:var(--font-mono); font-size:14px; min-width:92px;
}
/* Cellule renseignée : le bouton porte le rembourrage, sinon la zone cliquable
   ne couvrirait pas toute la cellule. */
.freq-cell-btn{padding:0;}
.freq-open{
  display:block; width:100%; position:relative; border:none; background:transparent;
  text-align:right; padding:7px 10px;
  font-family:var(--font-mono); font-size:14px; color:var(--ink); cursor:pointer;
}
.freq-open:hover .freq-bar{background:rgba(198,138,56,.52);}
/* Cellule dépliée : repère non chromatique (soulignement), pas seulement la teinte. */
.freq-open[aria-expanded="true"]{background:#EDF1E1;}
.freq-open[aria-expanded="true"] .freq-val{text-decoration:underline; text-underline-offset:3px;}
.freq-open[aria-expanded="true"] .freq-bar{background:rgba(198,138,56,.55);}
.freq-track{position:absolute; left:2px; right:2px; top:4px; bottom:4px; pointer-events:none;}
.freq-bar{
  position:absolute; left:0; top:0; bottom:0; border-radius:4px;
  background:rgba(198,138,56,.30); transition:background .12s ease;
}
.freq-val{position:relative;}

/* Détail par jour, sous la table. */
.freq-detail{
  margin-top:12px; padding:11px 12px; background:#F4F7EC;
  border:1px solid var(--card-border); border-radius:9px;
}
.freq-detail[hidden]{display:none;}
.freq-jours-tete{
  font-family:var(--font-mono); font-size:12.5px; color:var(--ink-soft); margin-bottom:9px;
}
/* Calendrier du mois. La grille reste rectangulaire : les cases vides avant le
   1er et après le dernier jour sont bien présentes, simplement invisibles.

   ⚠ minmax(0, 1fr) et NON minmax(40px, 1fr) : le minimum d'un minmax l'emporte
   sur l'espace réellement disponible. À 40 px, la grille exigeait
   7×40 + 6×4 = 304 px alors qu'un téléphone n'en offre que 222 — et comme le
   calendrier n'est pas dans .freq-scroll, c'est la PAGE entière qui se mettait
   à défiler de travers. Le même piège que .piste-grid. */
.cal{
  display:grid; grid-template-columns:repeat(7, minmax(0, 1fr)); gap:4px;
  max-width:400px;
}
.cal-tete{
  font-family:var(--font-mono); font-size:11.5px; text-transform:uppercase;
  letter-spacing:.04em; color:var(--ink-soft); text-align:center; padding:0 0 3px;
}
.cal-jour{
  aspect-ratio:1 / 1; border-radius:7px;
  display:flex; flex-direction:column; align-items:center; justify-content:center; gap:1px;
}
.cal-vide{background:transparent;}
.cal-off{background:#F0F3E6; border:1px solid #E4E8D6;}
.cal-on{border:1px solid rgba(165,112,42,.35);}
.cal-num{font-family:var(--font-mono); font-size:11px; color:var(--ink-soft); line-height:1;}
.cal-on .cal-num{color:var(--salmon-dark);}
.cal-n{font-family:var(--font-mono); font-size:15px; font-weight:700; color:var(--ink); line-height:1.1;}
.cal-hors{
  font-family:var(--font-mono); font-size:12px; color:var(--ink-soft);
  margin:10px 0 0; padding:7px 9px; background:#EEF1E2; border:1px dashed #D6DCC2; border-radius:7px;
}

/* Sous 700 px, la case tombe à ~29 px : le texte actuel (11 + 15 px) en
   réclame 28,5 et la ferait grandir, cassant les carrés. On resserre le
   rembourrage de la chaîne pour gagner de la largeur, et les deux nombres. */
@media (max-width:700px){
  .freq-body{padding:10px 9px 4px;}
  .freq-detail{padding:9px 9px;}
  .cal{gap:3px;}
  .cal-jour{border-radius:5px;}
  .cal-tete{font-size:10.5px; padding-bottom:2px;}
  .cal-num{font-size:10px;}
  .cal-n{font-size:13px;}
}
.freq-zero{color:#A9AE96;}
.freq-tot{font-weight:700; background:#F7F9F0;}
.freq-table tfoot th[scope="row"], .freq-table tfoot td{
  border-top:2px solid var(--card-border); border-bottom:none;
  font-weight:700; padding:9px 10px; text-align:right;
  font-family:var(--font-mono); font-size:14px;
}
.freq-table tfoot th[scope="row"]{text-align:left; font-family:var(--font-body);}

/* =========================================================================
   Ossature : colonne de navigation à gauche, contenu à droite
   ========================================================================= */
/* .shell n'est plus centré : il occupe toute la largeur, comme .bandeau
   (padding:10px 20px, sans plafond). Le rail s'aligne ainsi sur le logo, à
   20 px du bord — auparavant `max-width:1400px; margin:0 auto` le repoussait
   vers le centre, seul élément de gauche à ne pas suivre le bandeau.

   Le plafond de 1400 px n'a PAS disparu : il est passé sur `main`, à qui il
   appartenait en réalité. Effet mesuré : main n'était plafonné qu'à
   1400−40−238−18 = 1104 px, jamais 1400 comme l'affirme le §7.8 du dossier.
   Il atteint désormais bien 1400. */
.shell{
  --rail-w:238px;
  display:grid; grid-template-columns:var(--rail-w) minmax(0,1fr); gap:18px;
  padding:20px 20px 48px; align-items:start;
}
/* minmax(0,1fr) : sans lui, une piste de grille refuse de descendre sous la
   largeur de son contenu et les tableaux larges débordent de la page. */
main{min-width:0; max-width:1400px;}

/* Affluence à 50 % et caméra dans l'espace libéré.
   minmax(0,1fr) et NON 1fr : cf. §7.5 — le minimum implicite (auto) d'une
   piste de grille l'emporte sur l'espace disponible, et le SVG de la courbe
   refuserait de descendre sous sa largeur intrinsèque.

   Seuil à 1500 px, MESURÉ : à 1501 px la zone de dessin vaut encore 547 px
   (viewBox 600, échelle 0,91, libellés à 10,5 px, une heure sur deux). En
   deçà elle tomberait sous 500 px et les 24 heures deviendraient illisibles ;
   la duo repasse alors en une seule colonne et la courbe reprend toute la
   largeur de main. */
.accueil-duo{
  display:grid; grid-template-columns:minmax(0,1fr) minmax(0,1fr);
  gap:18px; align-items:start;
}

/* Cumul en 2e colonne : les deux cartes s'étirent à la MÊME hauteur, et leurs
   graphiques reposent sur la même ligne de base.
   align-items:start laissait chaque carte à sa hauteur propre — or la carte
   Affluence porte, en plus, les onglets des jours (49 px) et la légende du
   dégradé (28 px), soit 77 px de plus. Égaliser les seuls SVG n'y suffisait
   donc pas : c'est la structure des cartes qui diffère, pas le dessin.
   La cale reprend la hauteur des onglets, que le cumul n'a pas : les deux
   graphiques démarrent alors à la même ordonnée. Les 28 px restants tombent
   sous le cumul, là où l'affluence porte sa légende — les cartes se terminent
   ensemble. */
.accueil-duo.duo-cumul{align-items:stretch;}
@media (min-width:1501px){
  .duo-cumul .cumul-cale{margin-top:49px;}
}
@media (max-width:1500px){
  .accueil-duo{grid-template-columns:minmax(0,1fr);}
}
/* Les cartes de la duo ne portent pas la marge basse des cartes empilées : la
   gouttière de la grille s'en charge, sinon les deux s'additionneraient. */
.accueil-duo > .card{margin-bottom:0;}

/* Session administrateur avec un cumul porté à l'accueil : la duo devient
   Affluence | Cumul, et la caméra passe sous les deux. Elle garde ainsi ses
   645 px à l'affluence, dont la courbe des 24 heures se réduirait sous ~600 px
   (plancher du viewBox) — un trio à colonnes égales l'aurait ramenée à 409 px.
   Le cadre 16/9 est plafonné et centré : sur 1400 px de large il mesurerait
   sinon 787 px de haut et mangerait tout l'écran. */
.accueil-duo > .cam-pleine{grid-column:1 / -1;}
.cam-pleine .cam-zone{max-width:746px; margin-inline:auto;}   /* 420 × 16/9 */

/* 16/9 : le cadre garde sa place avant même que la première image arrive, ce
   qui évite que la carte saute de hauteur au premier chargement du flux. */
.cam-zone{
  aspect-ratio:16 / 9; width:100%;
  display:flex; align-items:center; justify-content:center;
  background:#EDF0E2; border:1px solid var(--card-border); border-radius:10px;
  overflow:hidden;
}
/* contain et non cover : une vue de station recadrée perdrait ses bords, or
   c'est justement ce qu'on cherche à surveiller. */
.cam-zone img{width:100%; height:100%; object-fit:contain; display:block;}

/* grid-auto-rows:1fr — et non plus flex-direction:column : en flex, chaque
   tuile prenait la hauteur de son propre contenu, d'où trois hauteurs (58,4 /
   72,8 / 76,4 px) selon que le titre ou le sous-titre se plie. Les rangées 1fr
   s'alignent toutes sur la plus haute, ici « Consommation mensuelle », dont le
   titre tient sur deux lignes.

   Aucune hauteur en dur : elle se recalcule seule si un libellé change ou selon
   le rôle — le rail compte 3 tuiles pour un client, 5 pour un administrateur et
   6 pour un super-administrateur, « Super-administration » se pliant lui aussi.
   .rail-tuile garde align-items:center : le texte reste centré dans la hauteur
   ainsi gagnée. */
.rail{
  display:grid; grid-auto-rows:1fr; gap:8px;
  position:sticky; top:66px;      /* sous le bandeau : logo 34 + 2×10 de marge */
}
.rail-tuile{
  display:flex; align-items:center; gap:12px; min-width:0;
  padding:12px 14px; border-radius:12px;
  background:linear-gradient(180deg,var(--navy-2),var(--navy));
  color:var(--navy-text); border:1px solid rgba(0,0,0,.12);
  box-shadow:0 6px 16px -12px rgba(23,33,59,.55);
  transition:transform .12s ease, box-shadow .12s ease;
}
.rail-tuile:hover{transform:translateX(2px); box-shadow:0 10px 20px -12px rgba(23,33,59,.6);}
/* La page courante : teinte ambre ET liseré épais à gauche — un repère non
   chromatique, la couleur seule ne suffit pas (RGAA 1.4.1). */
.rail-tuile.active{
  background:linear-gradient(180deg,#3A6B47,#2A5235);
  border-color:var(--salmon); box-shadow:inset 4px 0 0 var(--salmon);
  padding-left:18px;
}
.rail-ico{
  width:24px; height:24px; flex:0 0 auto;
  fill:none; stroke:var(--salmon); stroke-width:1.9; stroke-linecap:round; stroke-linejoin:round;
}
.rail-txt{display:flex; flex-direction:column; min-width:0;}
.rail-titre{font-family:var(--font-display); font-weight:700; font-size:15px; line-height:1.2;}
.rail-sous{font-size:11.5px; opacity:.76; line-height:1.25;}

/* Sous 900 px, une colonne latérale n'a plus de place : les tuiles repassent en
   bandeau horizontal, sans leur sous-titre. Deux à quatre par ligne selon la
   largeur — un client n'en a que trois. */
@media (max-width:900px){
  .shell{grid-template-columns:1fr; gap:12px;}
  .rail{
    display:grid; grid-template-columns:repeat(auto-fit, minmax(min(150px,100%), 1fr));
    position:static; gap:8px;
  }
  .rail-tuile{padding:10px 12px;}
  .rail-tuile.active{padding-left:14px; box-shadow:inset 0 -4px 0 var(--salmon);}
  .rail-sous{display:none;}
  .rail-titre{font-size:14px;}
}
/* Toujours 5 colonnes : les emplacements inutilisés du dernier bandeau restent
   vides plutôt que de laisser les pistes s'étirer. Elles s'alignent ainsi d'un
   bandeau à l'autre. */
/* =========================================================================
   ACCUEIL — bandeaux de pistes + affluence moyenne
   ========================================================================= */
/* 4 colonnes. À tenir d'accord avec PAR_BANDEAU dans accueil.html : c'est ce
   couple qui garantit que les pistes s'alignent d'un bandeau à l'autre et que
   le dernier bandeau est complété par le bon nombre de .pb-vide. */
.pistes-bandeau{
  display:grid; grid-template-columns:repeat(4, 1fr); gap:8px; margin-bottom:8px;
}
/* Sans cela, la dernière rangée ajoute sa marge au rembourrage bas de la carte :
   le vide sous les pistes doublait. */
.pistes-bandeau:last-child{margin-bottom:0;}
.pb-vide{visibility:hidden;}
.pb-piste{
  display:flex; align-items:center; gap:10px;
  padding:8px 12px; border:1px solid var(--card-border); border-radius:10px;
  background:linear-gradient(180deg,#FDFEF8,#F1F4E9); min-width:0;
}
.pb-led{
  width:30px; height:30px; border-radius:50%; flex:0 0 auto;
  border:1px solid rgba(0,0,0,.22);
}
/* Vert = libre, orange = occupée, rouge = indisponible. Le libellé à droite
   porte la même information : rien ne repose sur la seule couleur — et le
   rouge est justement la teinte que distingue le moins un daltonien. */
.pb-libre{
  background:radial-gradient(circle at 35% 30%, #8FD68F, var(--green) 65%);
  box-shadow:0 0 8px rgba(78,154,81,.6);
}
.pb-occ{
  background:radial-gradient(circle at 35% 30%, #F5C070, var(--orange) 65%);
  box-shadow:0 0 8px rgba(224,145,47,.65);
}
.pb-indispo{
  background:radial-gradient(circle at 35% 30%, #E88A78, var(--red) 65%);
  box-shadow:0 0 8px rgba(196,72,47,.7);
}
/* Numéro à gauche, état poussé à droite : les états s'alignent ainsi en colonne
   d'une carte à l'autre, quelle que soit la longueur de « Piste 1 » ou
   « Piste 10 ».

   ⚠ La ligne unique réclame 262 px par colonne (24 rembourrage + 30 voyant +
   2×10 gouttière + 71 « Piste 10 » + 115 « Indisponible »). À 4 colonnes et
   main plafonné à 1400 px, chaque colonne dispose de 332,5 px — la marge est
   confortable. Il faut main ≥ 1118, soit, le rail occupant 238 + 18 px à sa
   gauche, un écran d'au moins 1414 px. En deçà, on repasse l'état sous le
   numéro, aligné avec lui.
   Le seuil est mesuré, pas choisi : cf. le calcul ci-dessus. */
.pb-num{
  font-family:var(--font-display); font-weight:700; font-size:18.5px; color:var(--navy);
  line-height:1.15; white-space:nowrap;
}
.pb-etat{
  font-family:var(--font-mono); font-size:16px; color:var(--ink-soft);
  margin-left:auto; white-space:nowrap; line-height:1.25;
}
/* Seuil RECALCULÉ pour 4 colonnes. À 5 colonnes il valait 1684 (arrondi 1690).
   À 4, la ligne unique réclame main ≥ 4×262 + 3×8 + 46 = 1118, soit, le rail
   occupant 238 + 18 px à sa gauche, un écran d'au moins 1414 px. Arrondi à
   1420, comme le dossier arrondit 1428 → 1430. Passer de 5 à 4 colonnes
   ABAISSE donc le seuil de 270 px : la ligne unique tient bien plus tôt. */
@media (max-width:1420px){
  .pb-piste{flex-wrap:wrap;}
  /* flex-basis:100% force le retour à la ligne ; la marge de 40 px
     (voyant 30 + gouttière 10) aligne l'état sous le numéro. */
  .pb-etat{flex-basis:100%; margin-left:40px;}
}

/* Accès rapide : tuiles vers les autres pages. auto-fit plutôt que 4 colonnes
   fixes — un client n'en voit que deux (Supervision et Paramétrage lui sont
   fermés), elles ne doivent pas s'étirer à la moitié de l'écran chacune.
   min(230px, 100%) : le minimum tient sur les écrans connus, mais un minmax à
   minimum figé finit toujours par déborder quelque part. */
/* Les tuiles d'accès (.acces / .acces-tuile) ont été supprimées : elles sont
   devenues la colonne latérale, présente sur TOUTES les pages. Cf. .rail-*. */

/* Affluence : courbe SVG. Le viewBox est fixe, le tracé s'adapte à la largeur ;
   la borne max évite que les textes du SVG ne grossissent démesurément sur un
   écran large. */
/* Plus de max-width : la largeur du viewBox est mesurée sur ce conteneur
   (cf. dessinerAffluence), le SVG est donc rendu à l'échelle 1 et occupe
   toute la carte. Le brider laissait ~400 px de vide sur une carte large. */
.aff-graph{width:100%;}
.aff-graph svg{width:100%; height:auto; display:block;}
/* Repère compact (viewBox 340) : les tailles sont en unités du repère, donc
   réduites par la mise à l'échelle. Sur une carte de 276 px, le facteur est
   0,81 — il faut 15 unités pour obtenir 12 px réels. Cf. dessinerAffluence(). */
.aff-compact .ac-ylab{font-size:14px;}
.aff-compact .ac-xlab{font-size:15px;}
.aff-compact .ac-val{font-size:16px;}
.aff-compact .aff-compact .ac-grille{stroke:#E2E7D4; stroke-width:1;}
.ac-ylab{font-family:var(--font-mono); font-size:11px; fill:var(--ink-soft); text-anchor:end;}
.ac-xlab{font-family:var(--font-mono); font-size:11.5px; fill:var(--ink-soft); text-anchor:middle;}
.ac-val{font-family:var(--font-mono); font-size:12px; font-weight:700; fill:var(--ink); text-anchor:middle;}
.aff-echelle{
  display:flex; align-items:center; gap:9px; margin-top:14px;
  font-family:var(--font-mono); font-size:12px; color:var(--ink-soft);
}
.aff-degrade{
  flex:0 1 210px; height:9px; border-radius:5px; border:1px solid rgba(0,0,0,.10);
  /* Mêmes arrêts que PALETTE dans accueil.html : une légende qui ne montre
     pas la palette du tracé est pire que pas de légende. */
  background:linear-gradient(90deg,
    rgb(78,154,81) 0%, rgb(150,176,58) 30%, rgb(224,145,47) 55%,
    rgb(196,72,47) 78%, rgb(145,32,24) 100%);
}

@media (max-width:820px){
  .pistes-bandeau{grid-template-columns:repeat(2, 1fr);}
  .pb-vide{display:none;}   /* à 2 colonnes, les cases vides feraient des trous */
}

/* --- Tabs (badges / pistes) --- */
.subtabs{display:flex; gap:6px; margin-bottom:16px; flex-wrap:wrap;}
.subtabs button{
  background:#ECEFDF; border:none; padding:8px 16px; border-radius:20px; font-size:14px; font-weight:500; color:var(--ink);
}
.subtabs button.active{background:var(--navy); color:var(--navy-text);}

/* --- Supervision synoptic (harmonisé avec la charte, voyants réalistes) --- */
/* min(300px, 100%) et non 300px : le minimum d'un minmax l'emporte sur
   l'espace disponible. À 300 px fixes, une piste débordait de 24 px dans une
   carte de 276 px et faisait défiler toute la page de travers sur téléphone.
   Même piège que .cal — cf. le commentaire de sa règle. */
.piste-grid{display:grid; grid-template-columns:repeat(auto-fit,minmax(min(300px,100%),1fr)); gap:16px; align-items:start;}

.synoptic{
  display:flex; flex-direction:column;
  border-radius:14px;
  padding:16px 16px 14px;
  color:var(--ink);
  background:linear-gradient(180deg,#FDFEF8,#EEF2E4);
  border:1px solid var(--card-border);
  box-shadow:0 10px 24px -18px rgba(23,33,59,.35);
  overflow:hidden;
}

.synoptic-top{display:flex; justify-content:space-between; align-items:flex-start; gap:12px; flex-wrap:nowrap; margin-bottom:16px;}
.synoptic-info{display:flex; flex-direction:column; gap:4px; min-width:0; flex:1;}
.piste-title{font-family:var(--font-display); font-weight:700; font-size:21px; color:var(--navy); line-height:1;}
.info-line{font-size:13px; color:var(--ink-soft); line-height:1.3;}
.info-line b{font-weight:600; color:var(--ink); overflow-wrap:anywhere;}
.info-line.presence{height:2.7em; overflow:hidden;}
/* Deux lignes autorisées : un mode long (« Stérilisation ») ne tient pas sur une seule.
   La hauteur reste fixe pour que tous les panneaux gardent la même taille. */
.info-line.mode{height:2.6em; overflow:hidden; overflow-wrap:anywhere;}

.alarm-group{display:flex; gap:12px; flex:none;}
.alarm{display:flex; flex-direction:column; align-items:center; gap:7px;}
.alarm-label{
  white-space:nowrap;
  background:var(--navy); color:var(--navy-text);
  font-family:var(--font-mono); font-size:12px; font-weight:500; letter-spacing:.02em;
  padding:4px 12px; border-radius:20px;
}

.voyant-grid{display:grid; grid-template-columns:repeat(5,minmax(0,1fr)); gap:12px 8px; margin-bottom:14px;}
/* Panneau de contrôle : mêmes voyants que les synoptiques de piste, 5 par
   rangée (20 voyants → 4 rangées). Interligne plus large : ici les rangées ne
   sont pas séparées par le cadre d'une piste. */
.panneau-grid{display:grid; grid-template-columns:repeat(5,minmax(0,1fr)); gap:22px 8px; max-width:760px;}
.voyant{display:flex; flex-direction:column; align-items:center; gap:6px; min-width:0;}
.voyant-label{
  width:100%; box-sizing:border-box; text-align:center;
  background:#ECEFDF; color:var(--ink-soft);
  font-family:var(--font-mono); font-size:12px; font-weight:500; line-height:1.15;
  padding:4px; border-radius:6px; border:1px solid var(--card-border);
  min-height:32px; display:flex; align-items:center; justify-content:center;
  overflow-wrap:anywhere; hyphens:auto;
}

/* Pastille présence : distinction nette piste occupée / libre */
.presence-pill{
  align-self:flex-start; display:inline-flex; align-items:center; gap:6px; white-space:nowrap;
  font-family:var(--font-mono); font-size:12.5px; font-weight:600;
  padding:4px 12px; border-radius:20px; margin:2px 0 2px;
}
.presence-pill .pdot{width:8px; height:8px; border-radius:50%; display:inline-block;}
.synoptic.occupied .presence-pill{background:#E7F1E0; color:#2F6B33; border:1px solid #C2D8AE;}
.synoptic.occupied .presence-pill .pdot{background:var(--green);}
.synoptic.empty .presence-pill{background:#E9ECDD; color:var(--ink-soft); border:1px solid var(--card-border);}
.synoptic.empty .presence-pill .pdot{background:var(--off);}

/* Voyant moderne : pastille pleine, anneau clair, halo doux (assorti à la charte) */
.led{
  position:relative; flex:none; box-sizing:border-box;
  width:40px; height:40px; border-radius:50%;
  border:4px solid #FDFEF8;
  background:var(--off);
  box-shadow:0 1px 2px rgba(23,33,59,.15), inset 0 0 0 1px rgba(0,0,0,.06);
}
.led::after{
  content:""; position:absolute; top:14%; left:20%; width:42%; height:30%; border-radius:50%;
  background:radial-gradient(ellipse at center, rgba(255,255,255,.6), rgba(255,255,255,0) 70%);
}
.led.on-green{background:var(--green); box-shadow:0 1px 2px rgba(23,33,59,.15), inset 0 0 0 1px rgba(0,0,0,.06), 0 0 10px 1px rgba(78,154,81,.45);}
.led.on-blue{background:var(--blue); box-shadow:0 1px 2px rgba(23,33,59,.15), inset 0 0 0 1px rgba(0,0,0,.06), 0 0 10px 1px rgba(47,128,166,.45);}
.led.on-orange{background:var(--orange); box-shadow:0 1px 2px rgba(23,33,59,.15), inset 0 0 0 1px rgba(0,0,0,.06), 0 0 10px 1px rgba(224,145,47,.45);}
.led.on-red{background:var(--red); box-shadow:0 1px 2px rgba(23,33,59,.15), inset 0 0 0 1px rgba(0,0,0,.06), 0 0 10px 1px rgba(196,72,47,.5);}

.led-lg{width:48px; height:48px; border-width:5px;}

.defaut-bar{
  margin-top:2px;
  background:#EEF1E2; border:1px dashed #D6DCC2; color:var(--ink-soft);
  font-family:var(--font-mono); font-size:12px;
  padding:8px 12px; border-radius:8px;
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}
.defaut-bar.active{
  background:#AE3B26; border:1px solid #AE3B26; border-style:solid; color:#fff; font-weight:600;
  animation:pulse 1.6s infinite;
}
@keyframes pulse{0%,100%{opacity:1;}50%{opacity:.6;}}
@media (prefers-reduced-motion: reduce){ .defaut-bar.active{animation:none;} }

.compteur-list{display:flex; flex-direction:column; gap:8px;}
/* ⚠ La 4e colonne est à largeur FIXE, et non en `auto`.
   .compteur-list est un flex vertical : chaque rangée est donc une grille
   INDÉPENDANTE. Avec `auto`, cette colonne se dimensionnait sur son propre
   contenu — « en marche » étant ~8 px plus large que « à l'arrêt » — et les
   colonnes en fr se partageaient un reste différent d'une rangée à l'autre.
   Résultat : pastilles et valeurs décalées selon l'état du compteur.
   110 px couvrent le plus long des deux libellés (~78 px) avec du jeu.
   Une alternative serait `subgrid` sur .compteur-list, mais son absence de
   repli propre ferait s'empiler les colonnes sur un navigateur ancien. */
.compteur-row{display:grid; grid-template-columns:1.4fr 1fr 1fr 110px; gap:10px; align-items:center; padding:11px 13px; background:#F1F4E9; border:1px solid var(--card-border); border-radius:9px; font-size:14px;}
.compteur-row > span:last-child{white-space:nowrap;}

/* Sous 700 px, quatre colonnes dans 276 px sont illisibles : le nom prend la
   première ligne, valeur / unité / état se rangent sur la seconde.
   Le placement se fait par FLUX : le 1er span occupant toute la ligne 1, les
   trois suivants tombent d'eux-mêmes en ligne 2. Les forcer explicitement les
   ferait entrer en collision. */
@media (max-width:700px){
  .compteur-row{grid-template-columns:auto 1fr auto; row-gap:4px; column-gap:8px;}
  .compteur-row > span:first-child{grid-column:1 / -1; font-weight:600;}
  .compteur-row > span:last-child{justify-self:end;}
}
.dot-state{width:9px; height:9px; border-radius:50%; display:inline-block;}
.dot-state.run{background:var(--green); box-shadow:0 0 6px 1px rgba(78,154,81,.6);}
.dot-state.stop{background:var(--off);}

/* --- Paramétrage --- */
.badge-list{display:flex; flex-direction:column; gap:8px; margin-bottom:20px;}
.badge-row{
  display:grid; grid-template-columns:1.2fr 1fr auto; gap:10px; align-items:center;
  padding:11px 15px; border-radius:9px; border:1px solid var(--card-border); background:#FCFDF7; font-size:14.5px;
}
.badge-row.assigned{background:#E7F1E0; border-color:#C2D8AE;}
.tag{font-size:12px; font-family:var(--font-mono); padding:3px 8px; border-radius:6px; background:var(--card-border);}
.badge-row.assigned .tag{background:#CFE3BC; color:#2F6B33;}
.form-grid{display:grid; grid-template-columns:1fr 1fr; gap:14px; margin-bottom:16px;}
@media(max-width:640px){.form-grid{grid-template-columns:1fr;}}

/* --- Gestion des sessions (créer / modifier / supprimer) --- */
.session-list{display:flex; flex-direction:column; gap:8px; margin-bottom:18px;}
.srow{
  display:grid; grid-template-columns:minmax(0,1fr) auto; gap:12px; align-items:center;
  padding:12px 14px; border-radius:9px; border:1px solid var(--card-border); background:#FCFDF7;
}
.srow.assigned{background:#E7F1E0; border-color:#C2D8AE;}

/* Identifiant composé : préfixe figé + partie saisissable.
   Le préfixe est HORS de l'input — dans l'input, il aurait pu être effacé au
   clavier, et le serveur l'aurait alors remis sans que l'écran le dise. */
.ident-compose{display:flex; align-items:stretch;}
.ident-prefixe{
  display:flex; align-items:center; padding:0 10px;
  font-family:var(--font-mono); font-size:14px; font-weight:600; color:var(--ink-soft);
  background:#EDF1E1; border:1px solid var(--card-border); border-right:none;
  border-radius:8px 0 0 8px; white-space:nowrap; user-select:none;
}
.ident-compose input.avec-prefixe{border-radius:0 8px 8px 0; min-width:0;}
.ident-compose input{flex:1;}

/* Sessions clientes : le NIVEAU porte la couleur.
   Vert = responsable, bleu = adhérent. L'indentation seule ne suffisait pas —
   sur une liste longue le décalage se perd, et l'ancienne étiquette grise
   (.tag sur --card-border) ne se détachait pas du fond vert de la ligne.
   Le bleu est --blue (#2F80A6), déjà celui de l'histogramme des cumuls : aucune
   teinte nouvelle n'entre dans le thème. */
.srow.adherent{background:#E9F1F6; border-color:#B4CEDD;}
.tag-respo{background:#CFE3BC; color:#2F6B33;}
.tag-adh{background:#C6DEEC; color:#1E5A78;}

/* Compteur « adhérents / badges » du bandeau responsable.
   Il dit, sans qu'on ait à déplier, combien de badges attendent encore un
   adhérent. La couleur ne fait que doubler le chiffre — elle n'apporte aucune
   information que le rapport ne donne déjà, elle le rend juste repérable dans
   une longue liste. */
.cpt-adh{
  font-family:var(--font-mono); font-size:12.5px; font-weight:600;
  padding:2px 8px; border-radius:10px; margin-left:6px; white-space:nowrap;
  background:var(--card-border); color:var(--ink-soft);
}
.cpt-adh.vide{background:#E4E7DA; color:#6A6C58;}      /* aucun badge délégué */
.cpt-adh.partiel{background:#F4E2C4; color:#8A5A16;}   /* il reste des badges à confier */
.cpt-adh.complet{background:#CFE3BC; color:#2F6B33;}   /* tous les badges ont un adhérent */

/* Bloc pliable des adhérents d'un responsable. Le filet vertical prolonge la
   ligne du responsable jusqu'à ses adhérents : c'est lui qui dit le
   rattachement, mieux que l'indentation. */
.adh-bloc{margin:6px 0 0 26px; padding-left:14px; border-left:2px solid #B4CEDD;}
.adh-groupe{display:grid; gap:8px; margin-top:8px;}
/* INDISPENSABLE : l'attribut `hidden` passe par la règle [hidden]{display:none}
   de la feuille par défaut du navigateur — même spécificité (0,1,0) que
   `.adh-groupe`, mais déclarée AVANT. Sans ce sélecteur (0,2,0), `display:grid`
   l'emporte et le bloc reste affiché : le pliage n'a aucun effet. */
.adh-groupe[hidden]{display:none;}
.btn-fold{
  font-family:var(--font-body); font-size:13.5px; font-weight:600; color:var(--ink);
  display:inline-flex; align-items:center; gap:7px;
  padding:5px 12px; border-radius:7px; border:1px solid #B4CEDD; background:#EDF3F7;
}
.btn-fold:hover{background:#DCE9F1; border-color:#8FB6CB;}
/* Le chevron était en 11px : il se réduisait à un point. Il porte à lui seul
   l'information « ceci s'ouvre », il doit se voir. */
.btn-fold .chev{
  display:inline-block; font-size:15px; line-height:1; color:#2F80A6;
  transition:transform .15s ease;
}
.btn-fold.ouvert .chev{transform:rotate(90deg);}
/* Rappelle qu'un adhérent existe sans avoir à déplier. */
.srow-note{font-size:13px; color:var(--ink-soft); margin:10px 0 6px;}
.srow.editing{outline:2px solid var(--salmon); outline-offset:1px;}
.srow-main{min-width:0; display:flex; flex-direction:column; gap:3px;}
.srow-id{font-family:var(--font-mono); font-weight:600; font-size:15px; color:var(--ink); overflow:hidden; text-overflow:ellipsis;}
.srow-sub{font-size:13.5px; color:var(--ink-soft); overflow:hidden; text-overflow:ellipsis;}
.srow-actions{display:flex; gap:8px; flex-wrap:wrap; justify-content:flex-end;}
.btn-mini{
  font-family:var(--font-body); font-size:13.5px; padding:7px 14px; border-radius:7px;
  border:1px solid var(--card-border); background:#FFF; color:var(--ink); white-space:nowrap;
}
.btn-mini:hover{background:#ECEFDF;}
.btn-mini.danger{color:#A5432B; border-color:#E0B6A3; background:#F6E7DF;}
.btn-mini.danger:hover{background:#F0D8CB;}
.form-card{background:#FCFDF7; border:1px solid var(--card-border); border-radius:11px; padding:16px;}
.form-actions{display:flex; gap:10px; align-items:center; flex-wrap:wrap; margin-top:6px;}
.form-card .badge-checks{flex-direction:column; gap:8px; margin-top:6px;}
.form-card .badge-checks label{width:100%;}
.empty{font-size:14px; color:var(--ink-soft); font-family:var(--font-mono); padding:6px 2px;}

.note{
  font-size:13.5px; color:var(--ink-soft); background:#EEF1E2; border:1px dashed #D6DCC2; border-radius:8px; padding:10px 12px; margin-top:12px;
}
/* min(320px, 60vh) et non 45vh : à 45vh le seuil tombait à 711 px de viseur,
   c'est-à-dire qu'un portable 13 pouces voyait son graphique rétrécir sans
   raison. À 60vh, le seuil descend à 533 px : seules les fenêtres réellement
   basses sont touchées, ce qui est le but. */
.chart-wrap{height:min(320px, 60vh);}
.legend-row{display:flex; gap:16px; margin-top:10px; flex-wrap:wrap; font-size:13.5px; font-family:var(--font-mono);}
.legend-dot{width:10px; height:10px; border-radius:50%; display:inline-block; margin-right:6px;}

.locked-msg{
  background:#EEF1E2; border:1px dashed #D6DCC2; border-radius:10px; padding:30px; text-align:center;
  color:var(--ink-soft); font-family:var(--font-mono); font-size:14px;
}

/* --- Bascule segmentée (type de graphique) & cases valeurs (mensuelle) --- */
.seg{display:inline-flex;gap:6px;flex-wrap:wrap;}
.seg button{border:1px solid var(--card-border);background:#fff;color:var(--ink);border-radius:8px;padding:6px 12px;font:inherit;cursor:pointer;}
.seg button:hover{border-color:var(--btn);}
.seg button.active{background:var(--btn);color:#fff;border-color:var(--btn);}
.mode-checks{border:1px solid var(--card-border);border-radius:10px;padding:10px 14px;margin:0 0 14px;display:flex;flex-wrap:wrap;gap:8px 20px;}
.mode-checks legend{padding:0 6px;color:var(--ink-soft);font-weight:600;font-size:14px;}
.mode-checks label{display:inline-flex;align-items:center;gap:6px;font-size:15px;cursor:pointer;}

/* --- Onglets internes (paramétrage) --- */
.tabbar{display:flex;gap:6px;flex-wrap:wrap;border-bottom:2px solid var(--card-border);margin:0 0 18px;}
.tabbar button{border:none;background:transparent;color:var(--ink-soft);font:inherit;font-weight:600;padding:9px 14px;border-radius:8px 8px 0 0;cursor:pointer;border-bottom:3px solid transparent;margin-bottom:-2px;}
.tabbar button:hover{color:var(--ink);}
.tabbar button.active{color:var(--navy);border-bottom-color:var(--salmon);background:#fff;}
.tabpane{display:none;}
.tabpane.active{display:block;}

/* --- Table des sites (super-administration) --- */
.site-row{display:grid;grid-template-columns:1.1fr 1.6fr auto auto;gap:14px;align-items:center;padding:12px 14px;border:1px solid var(--card-border);border-radius:10px;margin-bottom:10px;background:#fff;}
.site-code{font-family:var(--font-mono);font-weight:700;color:var(--navy);}
.switch{display:inline-flex;align-items:center;gap:8px;font-size:14px;color:var(--ink-soft);}
.switch input{width:16px;height:16px;}
.badge-state{display:inline-block;padding:3px 11px;border-radius:999px;font-size:13px;font-weight:600;}
.state-on{background:#E4F0DD;color:#2F6B36;}
.state-off{background:#F0E1DD;color:#9E4527;}

/* Le O final de DataPrO est en italique (identité de marque).
   Le nom est regroupé dans .brand-name : sans cela, le <span> deviendrait un
   élément flex distinct de .brand et hériterait de son gap. */
.brand-name{white-space:nowrap;}
.logo-o{font-style:italic; letter-spacing:0;}

/* Logo de l'application, centré au-dessus du titre de la page de connexion */
.login-logo{
  display:block;
  margin:0 auto 16px;
  max-width:200px;
  max-height:90px;
  width:auto; height:auto;
  border-radius:8px;
}

/* Mention « Hébergé en France » — typographie inspirée du label Made in France :
   deux barres (bleu, rouge) au-dessus d'un texte capitalisé et espacé. */
.hosted-fr{
  margin:22px auto 0;
  width:max-content;
  text-align:center;
}
.hosted-fr .hosted-bar{
  display:inline-block;
  width:46px; height:4px;
  vertical-align:middle;
  margin:0 6px 8px;
}
.hosted-fr .bar-blue{background:#0B3B75;}
.hosted-fr .bar-red{background:#C8102E;}
.hosted-fr .hosted-text{
  display:block;
  font-size:11px;
  letter-spacing:.22em;
  text-transform:uppercase;
  color:var(--ink-soft);
}

/* Image de fond de la page de connexion.
   Un voile vert forêt assombrit la photo : sans lui, le contraste de la carte
   et du texte varierait selon la zone de l'image, au détriment de la lisibilité. */
body.login-page{ min-height:100vh; margin:0; }

/* Diaporama de fond : deux calques alternent, seul celui du dessus varie en opacité.
   Le voile vert assure un contraste stable quelle que soit la photo affichée. */
.bg-slideshow{position:fixed; inset:0; z-index:-1; overflow:hidden;}
.bg-layer{
  position:absolute; inset:0;
  background-size:cover;
  background-position:center;
  background-repeat:no-repeat;
  opacity:0;
  transition:opacity 1.6s ease-in-out;
  will-change:opacity;
}
.bg-layer.visible{opacity:1;}
.bg-overlay{position:absolute; inset:0; background:rgba(36,70,46,.62);}

/* Mouvement réduit : pas d'enchaînement, une seule image fixe. */
@media (prefers-reduced-motion: reduce){
  .bg-layer{transition:none;}
}
body.login-page .login-card{
  box-shadow:0 18px 50px rgba(0,0,0,.35);
}

/* Écran de changement de mot de passe imposé */
.step2-title{font-size:20px; margin:0 0 6px; color:var(--navy);}

/* Éditeur de logo de site (paramétrage) */
.logo-actuel{display:flex; align-items:center; gap:12px; margin-bottom:16px; flex-wrap:wrap;}
.logo-actuel img{height:44px; width:auto; background:#fff; border:1px solid var(--card-border); border-radius:6px; padding:3px;}
.logo-scene{border:1px solid var(--card-border); border-radius:10px; overflow:hidden; background:#EEF1E2; display:inline-block; margin:8px 0;}
#logoCanvas{display:block; cursor:move; max-width:100%;}
.logo-controls{display:flex; align-items:center; gap:12px; flex-wrap:wrap; margin-bottom:10px;}
.logo-controls input[type=range]{width:220px;}
