/* Socle d'interface — servi par /ui.css.
   Aucun style en ligne : la CSP pose style-src 'self', qui couvre aussi les
   attributs style="…" via style-src-attr. */
/* ══════════════════════════════════════════════════════════════════════
   LES COULEURS SONT CELLES DU POC DE BERNARD, REPRISES A L IDENTIQUE.

   Source : WorkOrders_LIVE.css, bloc :root. Daniel, le 2026-08-29 :
   << on n a pas reproduit le UI UX exactement tel qu il avait ete
   construit >>. Son ecran a ete valide avec le client ; le notre a ete
   dessine sans qu aucun repartiteur l ait vu. Sur l APPARENCE, c est donc
   sa version qui fait autorite.

   Les NOMS restent francais, les VALEURS deviennent les siennes. On ne
   renomme pas : les jetons sont references a plus de cent endroits dans
   console.ts et ici, et un renommage massif pour un gain cosmetique est
   exactement le genre de changement qui casse un ecran sans que personne
   ne sache lequel. La correspondance est donnee en commentaire, ligne a
   ligne, pour qu on puisse rejouer la comparaison plus tard.

   ⚠️ Ce que ce bloc NE fait PAS : il ne change ni la navigation, ni les
   ecrans, ni les gestes. Un ecart de GESTE frustre bien plus qu un ecart
   de couleur, et il se corrige ailleurs.
   ══════════════════════════════════════════════════════════════════════ */
:root {
  --fond: #0f172a;          /* son --bg      — etait #10141c */
  --panneau: #111c33;       /* son --panel   — etait #161c28 */
  --barre: #16233f;         /* son --panel2  — etait #1a2030 */
  --texte: #e6edf7;         /* son --ink     — etait #e6e9ef */
  --texte-faible: #93a3bd;  /* son --mut     — etait #9aa3b2 */
  --trait: #22314f;         /* son --line    — etait #2a3448 */
  --accent: #3b82f6;        /* son --accent  — etait #4c8dff */
  --grave: #ef4444;         /* son --bad     — etait #ff4d4f */
  --moyenne: #f59e0b;       /* son --warn    — etait #ffa940 */
  --faible: #22c55e;        /* son --good    — etait #52c41a */

  /* Les quatre jetons qu il a et que nous n avions pas. Ils ne sont pas
     encore employes ici : ils sont poses pour que les ecrans a venir
     puissent s y referer plutot que de reinventer une valeur proche. */
  --accent2: #22d3ee;       /* son --accent2 */
  --pastille: #1e2b48;      /* son --chip    */
  --rose: #ec4899;          /* son --pink    */
  --mauve: #a78bfa;         /* son --purple  */

  /* Les deux qui n existent pas chez lui : la carte du parc est un ecran
     que le POC n a pas sous cette forme. Reaccordes a sa palette plutot
     que laisses tels quels, sinon ils jurent avec le reste. */
  --parc: #64748b;          /* etait #5a6b85 */
  --parc-travail: #f87171;  /* etait #ff7875 */
}
* { box-sizing: border-box; }
html, body { height: 100%; margin: 0; }
body {
  font: 14px/1.45 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  background: var(--fond); color: var(--texte);
}
a { color: var(--accent); }

/* ══════════════════════════════════════════════════════════════════════
   MISE EN PAGE — RELEVEE SUR WorkOrders_LIVE.css, PAS INVENTEE.

   Le POC pose une grille de 230 px + le reste, avec la navigation A GAUCHE.
   Nous avions une barre horizontale en haut. C est l ecart de forme le plus
   visible des deux, avant meme les couleurs : quelqu un qui a appris a
   chercher ses ecrans dans une colonne de gauche ne les trouve pas en haut.

   ⚠️ Les pages qui n ont PAS de .app (la carte plein ecran) gardent l ancien
   comportement : la grille ne s applique qu a l interieur de .app, et body
   n est plus un conteneur flex. Verifie avant de croire que c est inoffensif.
   ══════════════════════════════════════════════════════════════════════ */
.app { display: grid; grid-template-columns: 230px 1fr; height: 100vh; }

.side {
  background: #0b1428; border-right: 1px solid var(--trait);
  display: flex; flex-direction: column; overflow: auto;
}
.brand { padding: 16px 16px 12px; border-bottom: 1px solid var(--trait); }
.brand h1 { font-size: 15px; margin: 0; letter-spacing: .3px; }
.brand small { color: var(--texte-faible); font-size: 11px; display: block; margin-top: 3px; }

nav.nav { padding: 8px; display: flex; flex-direction: column; gap: 2px; }
nav.nav a {
  display: flex; gap: 9px; align-items: center; width: 100%;
  text-align: left; background: none; border: 0; color: var(--texte-faible);
  padding: 9px 11px; border-radius: 8px; cursor: pointer; font-size: 13px;
  text-decoration: none;
}
nav.nav a .ic { width: 18px; text-align: center; flex: 0 0 auto; }
nav.nav a:hover { background: var(--panneau); color: var(--texte); }
nav.nav a.actif { background: var(--accent); color: #fff; }

/* Nos quatre ecrans que le POC n a pas sont groupes sous une etiquette
   plutot que fondus dans sa liste. Les melanger donnerait a croire qu il
   manque huit entrees a sa console ; les separer dit la verite : ce sont
   des ecrans NEUFS, nes du multi-locataire et de l audit. */
.nav-sep {
  margin: 12px 11px 4px; font-size: 10px; letter-spacing: .8px;
  text-transform: uppercase; color: var(--texte-faible); opacity: .65;
}

.main { overflow: auto; display: flex; flex-direction: column; }
#barre.topbar {
  position: sticky; top: 0; z-index: 600;
  background: rgba(15, 23, 42, .92);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
  border-bottom: 1px solid var(--trait);
  padding: 10px 18px; display: flex; gap: 10px; align-items: center;
  flex-wrap: wrap; flex: 0 0 auto;
}
#barre.topbar h2 { margin: 0; font-size: 16px; flex: 0 0 auto; }
.topbar .spacer { flex: 1; }
#vue.content { padding: 18px; flex: 1 1 auto; }
.etiquette {
  padding: 2px 8px; border-radius: 10px; background: #232c40;
  color: var(--texte-faible); font-size: 12px; white-space: nowrap;
}
.pousse { margin-left: auto; }
/* LE BADGE DE LANGUE ET SON PANNEAU, dans le bloc .brand — meme place et meme
   forme que dans les six applications servies. La difference est QUI le peint :
   la-bas c est mes-preferences.js, ici c est la Console, faute de
   window.PASSERELLE et de window.PKCE. Voir #badge-langue dans console.ts. */
#langue-enveloppe { position: relative; }
#badge-langue {
  margin-top: 6px; width: 100%; text-align: left;
  padding: 5px 8px; font-size: 12px; font-weight: 600;
}
#panneau-langue {
  position: absolute; top: calc(100% + 6px); left: 0; z-index: 100001;
  width: 280px; max-width: calc(100vw - 24px);
  background: var(--panneau); color: var(--texte);
  border: 1px solid var(--trait); border-radius: 10px; padding: 12px;
  box-shadow: 0 12px 32px -12px rgba(0, 0, 0, .55);
}
#panneau-langue[hidden] { display: none; }
/* Son .btn (WorkOrders_LIVE.css:31-38). Trois ecarts corriges :
   - notre fond #2b3550 n existait dans AUCUNE des deux palettes ;
   - notre survol changeait le FOND, le sien change la BORDURE ;
   - ⚠️ button.primaire posait un texte #08111f, choisi pour l ancien accent
     #4c8dff. Sur son #3b82f6, il devient illisible — regression introduite
     ce soir en changeant les jetons, et attrapee par l analyse d ecart. */
button {
  padding: 8px 12px; border: 1px solid var(--trait); border-radius: 8px;
  background: var(--panneau); color: var(--texte); cursor: pointer;
  font: inherit; font-size: 13px;
}
button:hover { border-color: var(--accent); }
button:disabled { opacity: .5; cursor: not-allowed; }
button.primaire { background: var(--accent); border-color: var(--accent); color: #fff; font-weight: 600; }
button.petit { padding: 5px 9px; font-size: 12px; }
button.bon { background: var(--faible); border-color: var(--faible); color: #04240f; }
button.avertit { background: var(--moyenne); border-color: var(--moyenne); color: #3a2600; }
button.danger { background: var(--grave); border-color: var(--grave); color: #fff; }
input, select, textarea {
  padding: 6px 9px; border: 1px solid var(--trait); border-radius: 6px;
  background: #0f1420; color: var(--texte); font: inherit;
}
textarea { min-height: 64px; resize: vertical; width: 100%; }
label { color: var(--texte-faible); font-size: 13px; }
.cache { display: none !important; }
#message { color: var(--moyenne); font-size: 13px; }
#message.erreur { color: var(--grave); }
#vue { flex: 1 1 auto; min-height: 0; overflow: auto; padding: 14px; }
#vue.plein { padding: 0; overflow: hidden; }

/* ----------------------------------------------------------- composants */
/* ⚠️ APRES #vue.content, ET C EST L ORDRE QUI COMPTE.
   << #vue.plein >> et << #vue.content >> ont la MEME specificite (un id +
   une classe) : a egalite, c est la derniere declaree qui gagne. Declarer
   << .content >> apres aurait donc pose 18 px de marge sur la carte
   PLEIN ECRAN, qui existe justement pour n en avoir aucune. */
#vue.plein { padding: 0; overflow: hidden; }

/* Les tuiles chiffrees, relevees sur son .cards / .card :
     .cards{display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));gap:12px}
     .card{border-radius:12px;padding:14px}
     .card .k{color:var(--mut);font-size:12px}     <- LE LIBELLE EN PREMIER
     .card .v{font-size:26px;font-weight:700;margin-top:4px}
     .card .s{font-size:11px;color:var(--mut);margin-top:2px}

   Deux ecarts de forme, tous deux visibles :
   - il pose une GRILLE a colonnes egales, nous avions un flex en drapeau —
     ses tuiles s alignent, les notres finissaient en escalier ;
   - il met le LIBELLE AU-DESSUS du chiffre. Nous faisions l inverse. A
     l oeil, une colonne de gros chiffres sans etiquette au-dessus se lit
     beaucoup moins bien qu une colonne d etiquettes suivies de leur chiffre.

   La classe .s (sous-libelle : << 0 total >>, << of 24 >>, << 26 fleet
   units >>) n existait pas chez nous. Elle est posee ici pour que les
   tuiles puissent porter leur denominateur, comme les siennes. */
.cartes {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: 12px; margin-bottom: 16px;
}
.carte-chiffre {
  background: var(--panneau); border: 1px solid var(--trait); border-radius: 12px;
  padding: 14px;
}
a.carte-lien { display: block; color: inherit; text-decoration: none; cursor: pointer; }
a.carte-lien:hover { border-color: var(--texte-faible); }
.carte-chiffre .l { color: var(--texte-faible); font-size: 12px; }
.carte-chiffre .n { font-size: 26px; font-weight: 700; margin-top: 4px; }
.carte-chiffre .s { font-size: 11px; color: var(--texte-faible); margin-top: 2px; }
.carte-chiffre.alerte .n { color: var(--moyenne); }
.carte-chiffre.grave .n { color: var(--grave); }
.carte-chiffre.ras { border-color: #1f4a37; }
.carte-chiffre.ras .ras-ligne { font-size: 13px; margin-top: 5px; color: #22c55e; }

table { border-collapse: collapse; width: 100%; background: var(--panneau); }
th, td { padding: 7px 10px; text-align: left; border-bottom: 1px solid var(--trait); }
/* ⚠️ Le fond OPAQUE et le z-index ne sont pas decoratifs : sans eux, les
   cellules defilent VISIBLEMENT par-dessus l en-tete colle, et l ecran a
   l air casse. A cent lignes par page, sans en-tete colle on ne sait plus
   quelle colonne on lit des la vingtieme. */
th {
  color: var(--texte-faible); font-weight: 600; font-size: 11px;
  text-transform: uppercase; letter-spacing: .4px;
  position: sticky; top: 0; background: var(--panneau); z-index: 1;
}
/* ⚠️ << cursor: pointer >> etait pose sur TOUS les tableaux — y compris les
   trois du tableau de bord, construits sans surClic. L utilisateur voyait
   la main, cliquait, et rien ne se passait. La main ne s affiche plus que
   sur une ligne REELLEMENT cliquable, classe posee par tableau(). */
/* ── LE TRI : L EN-TETE EST CLIQUABLE, ET IL DOIT LE MONTRER ─────────────
   Meme lecon que << cursor: pointer >> juste au-dessus, dans l autre sens :
   la main ne se posait que sur les lignes REELLEMENT cliquables ; les en-tetes
   le sont TOUTES depuis que rendreTriable() vit dans les deux fabriques.

   << user-select: none >> : sans lui, cliquer deux fois pour inverser le tri
   selectionne le titre de la colonne en surbrillance bleue, et l ecran a l air
   casse. Deux clics sur un en-tete de tri sont le geste NORMAL. */
th.triable { cursor: pointer; user-select: none; -webkit-user-select: none; }
th.triable:hover { color: var(--texte); }
/* Le focus doit etre VISIBLE : ces en-tetes sont focalisables au clavier
   (tabindex=0), donc quelqu un qui navigue au clavier doit voir ou il est. */
th.triable:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
/* La fleche ne reserve pas de place quand elle est vide : les colonnes ne
   doivent pas sauter en largeur au premier tri. */
.tri-marque { color: var(--accent); font-size: 10px; }

tbody tr:hover { background: var(--barre); }
tbody tr.cliquable { cursor: pointer; }
tbody tr.selectionne { background: #23304a; }
.enveloppe-table { max-height: 62vh; overflow: auto; border: 1px solid var(--trait); border-radius: 10px; }

/* Valeurs de son .flt (WorkOrders_LIVE.css:132). ⚠️ UNE SEULE declaration :
   il y en avait DEUX a specificite egale, et la seconde ecrasait la moitie
   de la premiere sans que ni l une ni l autre ne le laisse voir. */
.filtres { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin-bottom: 10px; }
.champ { display: flex; flex-direction: column; gap: 3px; }

/* Le groupe de cases d'une selection multiple (champCases).
   La hauteur est BORNEE et le contenu defile : une liste de trois cents
   valeurs pousserait sinon le bouton d'enregistrement hors de l'ecran. */
.cases { display: flex; flex-direction: column; gap: 2px; max-height: 190px;
         overflow-y: auto; border: 1px solid #2a3142; border-radius: 6px;
         padding: 6px 8px; min-width: 210px; }
.cases .case { display: flex; flex-direction: row; align-items: center;
               gap: 6px; font-weight: normal; cursor: pointer; }
.cases input { margin: 0; }

/* La fenetre d acces d un compte (migration 0128), a droite de la ligne de
   modification du profil. ENCADREE, et ce n est pas de la decoration : elle
   porte son propre bouton d enregistrement, et sans cadre << Restrict hours >>
   se lisait comme un troisieme bouton de la ligne du profil — donc comme
   quelque chose que << Enregistrer >> aurait deja pris en charge.
   La largeur est bornee : sept cases a jour libre repoussaient les boutons
   hors du panneau sur un ecran de portable. */
.fenetre-acces { border: 1px solid var(--trait); border-radius: 8px;
                 padding: 8px 10px; min-width: 260px; max-width: 360px; }
.fenetre-acces .jours-acces { display: flex; flex-wrap: wrap; gap: 2px 10px; }
.fenetre-acces .jours-acces label { display: flex; flex-direction: row;
                                    align-items: center; gap: 4px;
                                    font-weight: normal; cursor: pointer; }
.fenetre-acces .plage-acces { display: flex; flex-direction: row;
                              align-items: center; gap: 6px; }
.fenetre-acces button { align-self: flex-start; }

/* Un bloc de liste depliable dans l ecran d administration. Le cadre et
   l espacement separent visuellement des listes qui se ressemblent : sans
   eux, dix blocs se lisent comme un seul tableau. */
.liste-bloc { border: 1px solid #2a3142; border-radius: 6px;
              padding: 8px 12px; margin-bottom: 10px; }
.liste-bloc > summary { cursor: pointer; font-weight: 600; }

/* -- LA CARTE DES TOURNEES : NUMEROS, FLECHES, LEGENDE ------------------

   La couleur de fond est posee par JavaScript (CSSOM), pas par un attribut
   style : la CSP servie est style-src 'self' sans unsafe-inline, et un
   attribut style serait rejete. */
.arret-num { width: 24px; height: 24px; border-radius: 50%;
             border: 2px solid #0b0e14; box-sizing: border-box;
             color: #0b0e14; font-weight: 700; font-size: 12px;
             line-height: 20px; text-align: center;
             box-shadow: 0 1px 3px rgba(0,0,0,.5); }

.legende-carte { display: flex; flex-wrap: wrap; gap: 14px; align-items: center;
                 padding: 8px 10px; margin-top: 6px;
                 border: 1px solid #2a3142; border-radius: 6px; font-size: 13px; }
.legende-item { display: inline-flex; align-items: center; gap: 6px; }
.legende-couleur { width: 14px; height: 14px; border-radius: 50%;
                   border: 2px solid #0b0e14; display: inline-block; }
.legende-depot { background: #8ea2c4; }

/* Ses sept valeurs d etat, a l identique.

   ⚠️ UN CONTRESENS CORRIGE, ET CE N EST PAS UNE QUESTION DE GOUT : notre
   .st-Onsite etait VERT (#1f4a37). Le sien est AMBRE. Pour un repartiteur,
   vert veut dire << termine >> — un bon en cours affiche en vert se lit comme
   un bon fini, et il disparait de l attention au moment ou il en demande le
   plus. Le sien reserve le vert au seul .st-Fixed.

   ⚠️ ET LA PRIORITE CESSE D ETRE UNE PASTILLE. Sa ligne porte UNE pastille
   (l etat) et UN MOT COLORE (la priorite) ; la notre en portait deux cote a
   cote, ce qui met sur le meme plan visuel un etat du cycle de vie et un
   degre d urgence. On neutralise background et padding DANS LA REGLE plutot
   que de changer la fabrique pastille(valeur, prefixe) : tout appel de la
   forme pastille(x, 'pr') ailleurs dans le fichier reste correct, et on evite
   le defaut deja documente ici — une classe absente rend la cellule sans mise
   en forme ET SANS AUCUNE ERREUR. */
.pastille { padding: 2px 9px; border-radius: 20px; font-size: 11px; font-weight: 700; white-space: nowrap; }
.st-New { background: #334155; color: #cbd5e1; }
.st-Scheduled { background: #1e3a8a; color: #bfdbfe; }
.st-Onsite { background: #78350f; color: #fde68a; }
.st-Problem { background: #7c2d12; color: #fed7aa; }
.st-Fixed { background: #14532d; color: #bbf7d0; }
.st-NotFixed { background: #7f1d1d; color: #fecaca; }
.st-Cancelled { background: #3f3f46; color: #a1a1aa; }
.pr-Critical { color: var(--grave); font-weight: 700; background: none; padding: 0; }
.pr-High { color: var(--moyenne); font-weight: 700; background: none; padding: 0; }
.pr-Normal { color: var(--texte-faible); background: none; padding: 0; }
.pr-Low { color: var(--texte-faible); opacity: .8; background: none; padding: 0; }
/* Les barres du tableau de bord : memes couleurs que les mots .pr-*, et
   Normal passe a l accent — en texte faible il se confondrait avec Low. */
.histo-barre { display: flex; height: 14px; border-radius: 3px; overflow: hidden; min-width: 2px; }
.panneau > .histo-barre { height: 22px; }
.histo-Critical { background: var(--grave); }
.histo-High { background: var(--moyenne); }
.histo-Normal { background: var(--accent); }
.histo-Low { background: var(--texte-faible); opacity: .6; }
.histo-pleine { background: var(--accent); }
.histo-legende { display: flex; flex-wrap: wrap; gap: 6px 18px; margin-top: 10px; font-size: 13px; }
.histo-puce { display: inline-block; width: 9px; height: 9px; border-radius: 2px; margin-right: 6px; }
.histo-zones { display: flex; flex-direction: column; gap: 8px; }
.histo-ligne { display: grid; grid-template-columns: minmax(120px, 240px) 1fr 48px; align-items: center; gap: 10px; }
.histo-piste { min-width: 0; }
.histo-nom { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.histo-total { text-align: right; }
.cal-retard-defile { overflow-x: auto; }
.cal-retard { display: grid; grid-auto-flow: column; grid-template-rows: 16px repeat(7, 18px);
  grid-template-columns: 32px; grid-auto-columns: 18px; gap: 4px; width: max-content;
  font-size: 11px; color: var(--texte-faible); }
.cal-retard-mois { white-space: nowrap; line-height: 16px; }
.cal-retard-jsem { line-height: 18px; }
.cal-retard-case { width: 18px; height: 18px; border-radius: 3px; background: var(--pastille); }
.cal-retard-auj { outline: 2px solid var(--accent); outline-offset: 1px; }
.cal-retard-rampe { margin-right: 2px; }
.cal-retard-sous-titre { margin-left: 8px; font-size: 12px; font-weight: 400; color: var(--texte-faible); }
.histo-flux { display: flex; align-items: flex-end; gap: 4px; height: 140px; }
.histo-jour { flex: 1; display: flex; flex-direction: column; align-items: center; height: 100%; min-width: 0; }
.histo-paire { flex: 1; width: 100%; display: flex; align-items: flex-end; justify-content: center; gap: 2px; }
.histo-paire > div { width: 42%; max-width: 14px; min-height: 1px; border-radius: 2px 2px 0 0; }
.histo-cree { background: var(--accent); }
.histo-repare { background: #22c55e; }
.histo-date { font-size: 11px; color: var(--texte-faible); margin-top: 4px; }
.graphique-zones { position: relative; height: 240px; width: 100%; }
.cf-low, .cf-medium { color: var(--moyenne); font-weight: 600; }
/* a.lien-bon et non .lien-bon : « .leaflet-container a » de Leaflet le repeignait en bleu. */
a.lien-bon { color: var(--moyenne); font-weight: 600; margin-left: 8px; white-space: nowrap; }
/* DEFAUT LATENT CORRIGE le 2026-08-28 : la cellule de confiance fabrique sa
   classe par 'cf-' + texte(confiance, 'inconnue'). Un actif sans adresse
   geocodee produisait donc .cf-inconnue, une classe qui n'existait pas — la
   cellule etait rendue SANS mise en forme, sans aucune erreur. En espagnol la
   meme ligne produirait .cf-desconocida, d'ou la regle sur les deux. */
.cf-inconnue, .cf-unknown, .cf-desconocida { color: var(--texte-faible); font-style: italic; }

/* --- les trois controles de l'en-tete (ADR-0018, ADR-0019) --------------- */
#barre select {
  background: var(--panneau); color: var(--texte);
  border: 1px solid var(--trait); border-radius: 4px;
  padding: 2px 6px; font-size: 0.85rem; max-width: 16rem;
}
#choix-langue { min-width: 4rem; }
/* Le locataire courant doit se voir SANS effort : sur un compte transverse,
   planifier chez la mauvaise ville est une faute que le modele precedent
   rendait impossible (ADR-0018). D'ou le contraste, pas la discretion. */
#locataire { font-weight: 600; }
#bouton-deconnexion { background: transparent; border: 1px solid var(--trait); }
.pagination { display: flex; gap: 0.5rem; align-items: center; margin: 0.6rem 0; }
.cf-high { color: var(--texte-faible); }

/* Releve sur son .panel : rayon 12 (nous avions 10), titre a 14 px (nous
   avions 15). Deux ecarts d un ou deux pixels — pris un par un ils ne se
   voient pas, mais un ecran en aligne une dizaine, et c est cette somme qui
   fait dire << ce n est pas mon interface >>. */
.panneau {
  background: var(--panneau); border: 1px solid var(--trait);
  border-radius: 12px; padding: 14px; margin-bottom: 14px;
}
.panneau h3 { margin: 0 0 10px; font-size: 14px; }

/* ── SOUS-ONGLETS ──────────────────────────────────────────────────────
 * Un ruban de sections A L INTERIEUR d un panneau (ecran Utilisateurs).
 * Ce ne sont PAS les liens .nav : ceux-la changent d ecran, ceux-ci
 * changent de section sans quitter l ecran. La classe .onglet est deja
 * declaree interface (donc traduite par creer) dans ui-commun ; elle
 * recoit ici son premier style. Le bouton perd sa bordure de boite pour
 * un seul trait sous l onglet actif, comme un jeu d onglets classique. */
.sous-onglets {
  display: flex; flex-wrap: wrap; gap: 4px;
  border-bottom: 1px solid var(--trait); margin-bottom: 12px;
}
.sous-onglets .onglet {
  background: none; border: 0; border-bottom: 2px solid transparent;
  border-radius: 0; margin-bottom: -1px;
  padding: 8px 12px; color: var(--texte-faible);
}
.sous-onglets .onglet:hover { color: var(--texte); border-color: var(--trait); }
.sous-onglets .onglet.actif {
  color: var(--texte); border-color: var(--accent); font-weight: 600;
}
.sous-onglets .onglet:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* Sa grille a deux colonnes de panneaux (tableau de bord). Elle retombe a
   une seule colonne sous 900 px : son .row fait de meme. */
.grille-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
@media (max-width: 900px) { .grille-2 { grid-template-columns: 1fr; } }
dl.paires { display: grid; grid-template-columns: auto 1fr; gap: 3px 12px; margin: 0; }
dl.paires dt { color: var(--texte-faible); }
dl.paires dd { margin: 0; }
.actions { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 12px; }
.vide { color: var(--texte-faible); padding: 24px; text-align: center; }
.avert { color: var(--grave); font-weight: 600; }

/* ── TROIS CLASSES POSEES DEPUIS LONGTEMPS ET JAMAIS DEFINIES ──────────
 *
 * Trouvees le 2026-08-29 par le cas 8 de tests/security/js-navigateur.test.ts,
 * ecrit ce jour-la. <<aide>> etait posee SEIZE fois dans le console, <<sous>>
 * deux fois, et <<alerte>> n existait qu en selecteur compose
 * (.carte-chiffre.alerte .n) — donc un message d erreur pose seul, comme
 * ceux de vueLicences, s affichait en texte ordinaire.
 *
 * Rien ne levait, rien ne rougissait : la page se rendait, simplement sans
 * style. C est la variante silencieuse du defaut dominant de ce depot. */
.aide { color: var(--texte-faible); font-size: 13px; line-height: 1.5; margin: 6px 0; }
.sous { color: var(--texte-faible); font-size: 12px; }
.alerte { color: var(--grave); font-weight: 600; border: 1px solid var(--grave);
          border-radius: 6px; padding: 8px 12px; margin: 6px 0; }
.deux-colonnes { display: grid; grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr); gap: 14px; }

/* L ECRAN DES PROBLEMES : LA LISTE PREND TOUTE LA LARGEUR TANT QUE RIEN N EST
   OUVERT. Les trois autres ecrans qui se partagent << deux-colonnes >>
   arrivent avec leur colonne de droite deja garnie ; celui-la non, et la
   moitie vide etait son etat par defaut. La colonne de droite est RETIREE du
   flux (display: none) plutot que laissee vide : une piste de grille vide
   garde sa gouttiere, donc 14 px de decalage sans rien dedans. */
.ep-scindee { grid-template-columns: minmax(0, 1fr); }
.ep-scindee > :last-child { display: none; }
/* LA LISTE PREND DEUX PARTS SUR TROIS, ET LE CHIFFRE EST MESURE. Elle en
   prenait 1,4 contre 1 — les proportions des trois autres ecrans, qui n ont
   pas huit colonnes a loger. Mesure a 1440 px, panneau ouvert : la liste passe
   de 677 a 773 px, et le panneau de 483 a 387. Ce que le panneau perd ne lui
   coute rien — a 387 comme a 483, une seule de ses douze valeurs se replie
   (le diagnostic en toutes lettres), et elle se repliait deja.

   Le plancher de 300 px est la pour les largeurs intermediaires : en dessous,
   la colonne des valeurs tombe sous 150 px et le descripteur verbatim se
   dechire mot par mot. Il coute 25 px a la liste vers 1100 px de fenetre, et
   les lui rend des 1250. */
.ep-scindee.ouverte { grid-template-columns: minmax(0, 2fr) minmax(300px, 1fr); }
.ep-scindee.ouverte > :last-child { display: block; }

/* Le cadre de 62 vh est calibre pour une demi-largeur ; en pleine largeur la
   liste peut descendre jusqu au bas de la fenetre. La reserve couvre la barre
   du haut, les filtres, le depliant replie et la marge de << #vue >>. */
.ep-scindee .enveloppe-table { max-height: calc(100vh - 230px); }

/* PANNEAU OUVERT : DEUX COLONNES DE LA LISTE S EFFACENT.

   ⚠️ LA RAISON A CHANGE, ET LA REGLE RESTE. Elle est nee d un encombrement :
   a 676 px de liste (l ancien partage 1,4 contre 1) les huit colonnes se
   repliaient sur deux lignes par cellule — hauteur de ligne mesuree a 56 px
   contre 35. Depuis que la liste prend deux parts sur trois elle tient 773 px,
   et les huit colonnes y tiennent SANS se replier (35 px, mesure, sans
   debordement horizontal). L encombrement n est donc plus l argument.

   Ce qui reste, et qui suffit : ce sont l ETAT (2e) et l APPAREIL (6e) qui
   partent, et le panneau ouvert porte DEJA les deux, en toutes lettres
   (<< toujours actif >> et << device_sn >>). Les garder afficherait deux fois
   la meme chose a 30 cm d ecart. On ne cache aucune information — on retire un
   doublon le temps que le panneau l affiche, et on rend 90 px a ce qui n est
   PAS duplique.

   ⚠️ CES DEUX RANGS SUIVENT L ORDRE DES COLONNES DE vueEpisodes(). Ajouter
   une colonne AVANT la sixieme deplace la cible sans qu aucun test ne le
   voie : l en-tete et la cellule se cacheraient simplement ailleurs. Le
   commentaire de l appel a tableau() renvoie ici. */
.ep-scindee.ouverte th:nth-child(2), .ep-scindee.ouverte td:nth-child(2),
.ep-scindee.ouverte th:nth-child(6), .ep-scindee.ouverte td:nth-child(6) {
  display: none;
}

/* Un titre de panneau et son bouton de fermeture sur la meme ligne. La marge
   basse du h3 (10 px) est reprise par le conteneur, sinon le bouton la porte
   aussi et les deux ne s alignent plus. */
.tete-panneau { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
.tete-panneau h3 { margin: 0; flex: 1 1 auto; }
.carte-plein { height: 100%; width: 100%; }
.carte-tournee { height: 460px; width: 100%; border-radius: 8px; overflow: hidden; }

/* Marqueurs : classes appliquees aux cercles VECTORIELS de Leaflet. On
   n'utilise pas les marqueurs par defaut, qui chargent des images absentes du
   serveur (trois 404 mesures), ni les divIcon des applications du POC, dont le
   HTML porte style="..." — bloque par style-src. */
.marqueur-grave { stroke: #fff; fill: var(--grave); }
.marqueur-moyenne { stroke: #fff; fill: var(--moyenne); }
.marqueur-faible { stroke: #fff; fill: var(--faible); }

/* La ligne d'etat de la couche « parc » de la carte, en bas a gauche. Elle dit
   le REGIME (agrege ou un a un), le compte, et la troncature : une carte
   amputee au plafond du serveur se lit comme un inventaire tant que personne
   n'ecrit que c'en est un sous-ensemble. */
.parc-legende { background: #1c2333; color: var(--texte); border-radius: 6px;
                padding: 6px 10px; font-size: 12px; line-height: 1.4;
                max-width: 340px; box-shadow: 0 1px 5px rgba(0, 0, 0, 0.4); }

/* Fenetres surgissantes : Leaflet les cree, on ne fait que les habiller. */
.leaflet-popup-content-wrapper { background: #1c2333; color: var(--texte); }
.leaflet-popup-tip { background: #1c2333; }
.leaflet-popup-content { margin: 10px 12px; font-size: 13px; }
.leaflet-popup-content h4 { margin: 0 0 6px; font-size: 14px; }
.leaflet-control button { padding: 5px 10px; }
/* ⚠️ << .ep-scindee.ouverte >> pese deux classes contre une : sans la nommer
   ici, elle gagnait sur << .deux-colonnes >> et l ecran des problemes serait
   reste a deux colonnes sur un ecran etroit, seul de son espece. */
@media (max-width: 900px) {
  .deux-colonnes, .ep-scindee.ouverte { grid-template-columns: 1fr; }
}

/* ══════════════════════════════════════════════════════════════════════
   LA PAGE D ACCUEIL — la premiere chose qu un client voit.

   Elle etait du HTML nu, avec la mise en forme par defaut du navigateur :
   du Times New Roman noir sur blanc et des puces. Daniel, le 2026-08-30 :
   << this is the landing page, it absolutely needs to look professional,
   this is a multi-million dollars business >>.

   ⚠️ LA VOIE ETAIT DEJA ECRITE DANS accueil.ts, ET ON LA SUIT :
   << si un jour cette page merite d etre habillee, la voie est une FEUILLE
   DE STYLE SERVIE DEPUIS 'self' — pas un assouplissement de la politique >>.
   Aucune balise style, aucun attribut de mise en forme, aucun script. La
   page reste conforme aux neuf controles de accueil.test.ts.
   ══════════════════════════════════════════════════════════════════════ */
.accueil { max-width: 1120px; margin: 0 auto; padding: 0 24px 32px; }

/* ⚠️ ANCIENNEMENT << .bandeau-essai >>, EN AMBRE, ET IL DISAIT LE CONTRAIRE
   CE QU IL FALLAIT COMPRENDRE. Il annoncait << donnees d essai, effacables
   sans preavis >> sur un serveur qui porte 38 890 actifs, 85 bons issus de
   6 lots reellement ingeres et 6 679 evenements d audit appartenant a deux
   vrais clients. L ambre invitait a experimenter ; le bleu dit que c est en
   service. */
.bandeau-reel {
  background: linear-gradient(90deg, rgba(59,130,246,.16), rgba(59,130,246,.04));
  border-bottom: 1px solid rgba(59,130,246,.35);
  padding: 8px 24px; font-size: 12.5px; color: #bfdbfe; text-align: center;
}
.bandeau-reel b { color: #fff; }

/* Le selecteur de langue. Trois liens, aucun script -- la CSP de cette page
   interdit le JavaScript en ligne, et un selecteur n en a jamais eu besoin.
   Discret et en haut a droite : il doit se trouver quand on le cherche, sans
   disputer la place au titre. */
.langues {
  display: flex; justify-content: flex-end; gap: 4px;
  padding-top: 2px; font-size: 13px;
}
.langues a, .langues .langue-active {
  padding: 5px 11px; border-radius: 6px; text-decoration: none;
  border: 1px solid transparent;
}
.langues a { color: var(--txt-2); }
.langues a:hover { color: var(--txt); background: var(--fond-2); }
/* La langue courante n est PAS un lien : cliquer dessus ne ferait rien, et un
   lien qui ne mene nulle part est ce qui apprend a ne plus cliquer. */
.langues .langue-active {
  color: var(--txt); background: var(--fond-2); border-color: var(--trait);
  font-weight: 600;
}
/* ── THE HERO IS TWO COLUMNS, NOT A STACK ─────────────────────────────
   Bernard, 2026-09-10: << Move the SCMS-FS block to the right of the
   Big-font section >> -- and, in the same breath, << optimize the real
   estate of this screen so we don't have to scroll all the time >>.

   Measured before, at 1280x720: the hero alone was 589px, the page 1978px,
   and the seven application cards started at y=765. So the index page did
   not show a SINGLE card without scrolling -- the one thing a visitor comes
   here to click.

   Four moves, and only the first one was asked for:
     a. the promise paragraph sits beside the headline instead of under it;
     b. the language picker is a grid item of the hero (it used to own a
        40px row of its own). It stays FIRST in the DOM -- a visitor who
        cannot read the current language needs it early -- and lands
        top-right by grid placement, which is what grid is for;
     c. the icon shares the title line inside the cards (see .card-head);
     d. the two closing note lists sat side by side. One of them has since
        moved to the footer, so that grid is gone -- see .notes.

   ── AND THEN FOUR CUTS, decided by Bernard the same day ──────────────
   The layout stopped being the binding constraint; the CONTENT was. So:
   the four hardcoded figures left the hero (38 890 assets was true on
   2026-08-30 and would rot in silence on a page that claims real data),
   the << Applications >> label left (it named seven obvious cards), the
   card descriptions became one line each, and << Operations >> moved into
   the footer.

   ⚠️ The ingest endpoint was part of that last cut and Bernard had it put
   BACK the same hour, so the footer carries five items: they need 1164px of
   text in a 1072px row and therefore wrap at EVERY desktop width -- no gap
   value avoids it. Hence << gap: 10px 28px >> below: a 28px row gap left the
   repository link floating alone, 10px reads as one block.

   Measured after, at 1280x720, on the page rendered from source:

       en 832px   fr 851px   es 851px      (from 1978px)
       hero 226px (from 589px) - cards at y=261 (from y=765)

   The page now ENDS at y=771 in English: footer included, nothing needs
   scrolling on a laptop. That is the target, and it is why the figures
   were dropped rather than served live -- see the note below.

   ⚠️ THE FIGURES WERE NOT MOVED TO THE DATABASE, AND THE REASON IS NOT
   LAZINESS. A cross-tenant count cannot be read from sansLocataire():
   RLS applies to us too, so SELECT count(*) FROM app.asset would return
   ZERO rather than fail -- routes/locataires.ts already says so in as many
   words. Serving live figures needs a SECURITY DEFINER aggregate (a new
   migration) reachable from a PUBLIC unauthenticated page. That is a
   decision, not a refactor, so the numbers were cut instead.

   ⚠️ .heros, .marque and .promesse KEEP their French names. Renaming them
   is tier 3 of the language migration and buys nothing here; what the rule
   forbids is MIXING two languages inside one identifier, and the new
   classes below are plain English words on their own.                    */
.heros {
  display: grid;
  grid-template-columns: minmax(0, 1.08fr) minmax(0, 1fr);
  column-gap: 56px;
  padding: 26px 0 30px;
  border-bottom: 1px solid var(--trait);
}
.heros > .top-right { grid-column: 2; grid-row: 1; justify-self: end; }
.top-right { display: flex; flex-direction: column; align-items: flex-end; gap: 6px; }

/* The home page behind sign-in (accueil.ts, /accueil.js): until a token is
   obtained, only the waiting block shows. */
body.awaiting-sign-in > :not(.sign-in-wait):not(script) { display: none !important; }
body:not(.awaiting-sign-in) > .sign-in-wait { display: none; }
.sign-in-wait {
  min-height: 60vh; display: flex; flex-direction: column; align-items: center;
  justify-content: center; gap: 12px; color: var(--texte-faible); font-size: 14px;
}
.session { font-size: 12.5px; color: var(--texte-faible); }
.session b { color: var(--texte); font-weight: 600; }
.session button {
  margin-left: 8px; padding: 3px 10px; font-size: 12.5px; cursor: pointer;
  border-radius: 6px; border: 1px solid var(--trait); background: transparent; color: var(--texte-faible);
}
.session button:hover { color: var(--texte); border-color: var(--texte-faible); }
/* The headline spans both rows so it stays optically centred against the
   picker + paragraph + figures column. */
.hero-main { grid-column: 1; grid-row: 1 / 3; align-self: center; }
.hero-side { grid-column: 2; grid-row: 2; }
.heros .marque {
  display: inline-flex; align-items: center; gap: 10px;
  font-size: 12px; letter-spacing: 2.4px; text-transform: uppercase;
  color: var(--accent2); margin-bottom: 14px;
}
.heros .marque::before {
  content: ""; width: 26px; height: 2px; background: var(--accent2); display: block;
}
.heros h1 {
  margin: 0; font-size: 40px; line-height: 1.1; font-weight: 700;
  letter-spacing: -1px; max-width: 20ch;
}
.heros h1 span { color: var(--accent); }
/* No max-width here any more: the column IS the measure. */
.heros .promesse {
  margin: 0; font-size: 15.5px; line-height: 1.6; color: var(--texte-faible);
}
/* The dated figures (question 173, option b): a measurement with its date,
   never a live count -- see accueil.ts. Quiet on purpose: one line under
   the paragraph, not a hero of its own. */
.heros .chiffres {
  margin: 10px 0 0; font-size: 13px; letter-spacing: .2px; color: var(--texte-faible);
}
.heros .chiffres b { color: var(--texte); font-weight: 600; }
.section-titre {
  font-size: 12px; letter-spacing: 2px; text-transform: uppercase;
  color: var(--texte-faible); margin: 30px 0 14px;
}

.grille-apps {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 14px;
}
.app-carte {
  display: flex; flex-direction: column; text-decoration: none; color: inherit;
  background: var(--panneau); border: 1px solid var(--trait);
  border-radius: 12px; padding: 16px 18px 14px;
  transition: border-color .15s, transform .15s;
}
.app-carte:hover { border-color: var(--accent); transform: translateY(-2px); }
.card-head { display: flex; align-items: center; gap: 10px; margin-bottom: 7px; }
.app-carte .ic { font-size: 17px; display: block; margin: 0; }
.app-carte h3 { margin: 0; font-size: 15px; font-weight: 650; }
.app-carte p { margin: 0; font-size: 12.8px; line-height: 1.5; color: var(--texte-faible); }
/* margin-top auto, not a fixed gap: cards in a row are stretched to the
   tallest one, and the link used to float wherever the text ended. */
.app-carte .aller {
  display: inline-block; margin-top: auto; padding-top: 10px; font-size: 12.5px;
  font-weight: 600; color: var(--accent);
}

.notes { margin-top: 14px; max-width: 88ch; }
.notes li { color: var(--texte-faible); font-size: 13px; line-height: 1.6; }
.notes b { color: var(--texte); }

.pied {
  margin-top: 34px; padding-top: 16px; border-top: 1px solid var(--trait);
  display: flex; gap: 10px 28px; flex-wrap: wrap;
  font-size: 12.5px; color: var(--texte-faible);
}
.pied a { color: var(--texte-faible); }
.pied a:hover { color: var(--accent); }
.pied a { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }

@media (max-width: 880px) {
  .heros { grid-template-columns: 1fr; row-gap: 18px; padding: 18px 0 26px; }
  .heros > .top-right { grid-column: 1; grid-row: 1; }
  .hero-main { grid-column: 1; grid-row: 2; }
  .hero-side { grid-column: 1; grid-row: 3; }
  .heros h1 { font-size: 32px; max-width: none; }
  .heros .promesse { font-size: 15px; }
}
