/*
 * © 2026 DATASHIELD RISK CONSULTING (SAS) · Zerval
 * Tous droits réservés. Code propriétaire.
 */
/* ===========================================================================
   LE SOCLE. Échelle, sol, vocabulaire.

   POURQUOI CE FICHIER EXISTE. `styles.css` fait 390 Ko et porte 68 TAILLES DE
   POLICE DISTINCTES, 553 couleurs écrites en dur et 185 rgba() bruts, alors que
   52 jetons existent. L'identité « L'Affût » a donc été appliquée comme
   décoration (une image, un logo, une teinte) et jamais comme système. Le détail
   qui résume tout : `.875rem` employé 592 fois, `14px` 100 fois, `14.5px` 35
   fois. Trois écritures pour la même chose, dont une que personne ne choisit.

   CE FICHIER SE CHARGE EN DERNIER et n'écrase que ce dont il prend la
   responsabilité : le sol, l'échelle, les surfaces, les boutons, les chiffres.
   Il ne touche pas aux écrans un par un ; c'est justement le but, les trois
   applications partagent cette coque et bougent ensemble.

   CE QU'ON REFUSE, ET C'EST UNE CONSIGNE EXPLICITE. Pas de style générique :
   pas de dégradé violet-bleu, pas de grands rayons mous, pas de pastilles
   colorées à chaque information. La différence vient du métier : un outil qui
   traite des incidents et produit des preuves est un INSTRUMENT DE MESURE. D'où
   les chiffres tabulaires en largeur fixe, les angles serrés, les filets d'un
   cheveu, et la sévérité rendue par la structure plutôt que par la couleur.

   LES VALEURS VIENNENT DU SITE, PAS DE NULLE PART. `--fauve`, `--pro`,
   `--smart`, Fraunces, Inter, JetBrains Mono, et le sol `#050d1c` déjà résolu
   par les sections sombres de zerval.io. La seule chose qui manquait des deux
   côtés, c'est l'échelle : elle est créée ici.
   =========================================================================== */

:root {
  /* ---- Familles. Celles de la charte, sans substitution. ---- */
  --z-display: 'Fraunces', Georgia, 'Times New Roman', serif;
  --z-texte:   'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Arial, sans-serif;
  --z-mono:    'JetBrains Mono', ui-monospace, 'SFMono-Regular', Menlo, Consolas, monospace;

  /* ---- L'ÉCHELLE. Sept crans, et pas un de plus.
         Elle remplace 68 tailles. Un cran manquant se résout en choisissant le
         voisin, jamais en inventant un 14,5 px. ---- */
  --z-t0: 11px;   /* surtitre capitales, étiquette d'unité */
  --z-t1: 12px;   /* légende, mention secondaire */
  --z-t2: 13px;   /* texte dense : tableaux, listes longues */
  --z-t3: 14px;   /* texte courant */
  --z-t4: 16px;   /* titre de carte */
  --z-t5: 20px;   /* titre de section */
  --z-t6: clamp(28px, 2.6vw, 40px);   /* titre d'écran, en display */

  /* ---- Graisses. Celles réellement employées sur le site. ---- */
  --z-w-normal: 400;
  --z-w-moyen:  500;
  --z-w-appuye: 600;
  --z-w-fort:   700;
  --z-w-titre:  800;

  /* ---- Interlettrage. Négatif sur les grands corps, ouvert sur les capitales :
         c'est ce que fait déjà le site, ce n'est écrit nulle part. ---- */
  --z-ls-titre: -.022em;
  --z-ls-caps:  .1em;

  /* ---- Espacement. Une seule suite, multiple de 4. ---- */
  --z-e1: 4px;  --z-e2: 8px;  --z-e3: 12px; --z-e4: 16px;
  --z-e5: 24px; --z-e6: 32px; --z-e7: 48px; --z-e8: 64px;

  /* ---- Rayons SERRÉS. 4 px, pas 12. Un instrument n'a pas des coins mous ;
         c'est aussi ce qui éloigne le plus du gabarit générique. ---- */
  --z-r-xs: 2px;
  --z-r:    4px;
  --z-r-lg: 6px;
  --z-r-pill: 999px;

  /* ---- Le sol, repris des sections sombres de zerval.io. Un APLAT.
         Aucune photographie sous du contenu de travail : elle mange le
         contraste, oblige chaque carte à devenir un panneau translucide, et
         entre en concurrence avec les chiffres. L'image reste un héros, à
         l'entrée, où elle est spectaculaire. ---- */
  --z-sol:      #050d1c;
  --z-sol-2:    #08131f;
  --z-surface:  rgba(255, 255, 255, .035);
  --z-surface-h:rgba(255, 255, 255, .055);
  --z-filet:    rgba(140, 170, 210, .16);
  --z-filet-fort: rgba(140, 170, 210, .28);
  --z-encre:    #eaf1fb;
  --z-encre-2:  #9fb4cf;

  /* ---- UN accent, et un seul. Le fauve de la charte, réservé à l'action
         principale. Tout le reste du produit s'en passe. ---- */
  --z-accent:   #e0872a;
  --z-accent-h: #f09a3d;

  /* ---- Couleurs SÉMANTIQUES, distinctes de l'accent. Elles ne servent qu'à
         dire un état, jamais à décorer. ---- */
  --z-crit: #c93c4b;
  --z-haut: #d98324;
  --z-sain: #0c8c67;
  --z-info: #3da6e8;

  /* ---- Élévation. Deux niveaux, discrets. Le relief vient du filet. ---- */
  --z-ombre:    0 1px 2px rgba(0, 0, 0, .35);
  --z-ombre-lg: 0 12px 32px rgba(0, 0, 0, .45);
}

/* ===========================================================================
   1. LE SOL
   La photographie quitte les écrans de travail. Le calque de décor existe
   toujours et la personnalisation reste possible : elle devient un choix, elle
   n'est plus le défaut.
   =========================================================================== */
:root[data-theme="dark"] { background: var(--z-sol); }

:root[data-theme="dark"] .app-bgfond {
  /* Un aplat, plus une seule respiration très basse en haut à droite, qui donne
     la profondeur sans redevenir une image. */
  background:
    radial-gradient(140% 90% at 88% -10%, rgba(61, 166, 232, .07), transparent 62%),
    var(--z-sol) !important;
  opacity: 1 !important;
}
:root[data-theme="dark"] .app-bgfond::after { display: none !important; }

/* ===========================================================================
   2. LA TYPOGRAPHIE
   =========================================================================== */
.app-body, .app-main { font-family: var(--z-texte); font-size: var(--z-t3); }

/* Le titre d'écran retrouve sa vraie taille. Il ne faisait, jusqu'ici, guère
   plus qu'un titre de carte : le contraste qui fait toute l'identité du site
   était perdu, et il ne restait qu'une police inhabituelle. */
.app-main .view-title {
  font-family: var(--z-display);
  font-size: var(--z-t6);
  font-weight: var(--z-w-fort);
  letter-spacing: var(--z-ls-titre);
  line-height: 1.06;
  margin: 0 0 var(--z-e3);
  color: var(--z-encre);
}

/* LE SURTITRE À FILET, dispositif déjà présent sur le site et absent des
   écrans. Il donne un chemin à l'œil sans ajouter une seule couleur. */
.z-sur {
  display: flex; align-items: center; gap: var(--z-e2);
  font-size: var(--z-t0); font-weight: var(--z-w-appuye);
  letter-spacing: var(--z-ls-caps); text-transform: uppercase;
  color: var(--z-encre-2); margin-bottom: var(--z-e2);
}
.z-sur::before {
  content: ""; width: 22px; height: 1px; background: var(--z-filet-fort); flex: none;
}

/* ===========================================================================
   3. LE CHIFFRE EST UN INSTRUMENT
   Largeur fixe et chiffres tabulaires : les colonnes s'alignent, les scores se
   comparent d'un coup d'oeil, et l'ensemble cesse de ressembler a une page.
   =========================================================================== */
.z-num, .kpi-value, .stat-value, .app-main .num {
  font-family: var(--z-mono);
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1, "zero" 1;
  letter-spacing: -.01em;
}

/* ===========================================================================
   4. LES SURFACES
   UN SEUL NIVEAU. Les cartes dans les cartes dans les cartes sont le bruit le
   plus couteux de l'application : trois bordures visibles pour une seule
   information. Une carte imbriquee perd son cadre et ne garde que son air.
   =========================================================================== */
:root[data-theme="dark"] .app-main .card,
:root[data-theme="dark"] .app-main .panel,
:root[data-theme="dark"] .app-main .home-card,
:root[data-theme="dark"] .app-main .esp-card {
  background: var(--z-surface);
  border: 1px solid var(--z-filet);
  border-radius: var(--z-r);
  box-shadow: none;
}
:root[data-theme="dark"] .app-main .card .card,
:root[data-theme="dark"] .app-main .card .panel,
:root[data-theme="dark"] .app-main .panel .card,
:root[data-theme="dark"] .app-main .card .esp-card {
  background: transparent;
  border: 0;
  border-radius: 0;
  padding-left: 0; padding-right: 0;
}
/* Deux enfants successifs se separent par un filet, pas par deux cadres. */
:root[data-theme="dark"] .app-main .card .card + .card,
:root[data-theme="dark"] .app-main .card .panel + .panel {
  border-top: 1px solid var(--z-filet);
}

/* ===========================================================================
   5. LA SÉVÉRITÉ EST UNE STRUCTURE
   Un filet vertical dont l'epaisseur dit le niveau, et un code lisible. Pas une
   pastille de plus : l'ecran en portait deja cinq familles de couleurs.
   =========================================================================== */
.z-sev { border-left: 2px solid var(--z-filet-fort); padding-left: var(--z-e3); }
.z-sev--p1 { border-left-width: 3px; border-left-color: var(--z-crit); }
.z-sev--p2 { border-left-width: 2px; border-left-color: var(--z-haut); }
.z-sev--p3 { border-left-width: 2px; border-left-color: var(--z-filet-fort); }
.z-sev-code {
  font-family: var(--z-mono); font-size: var(--z-t0);
  letter-spacing: var(--z-ls-caps); color: var(--z-encre-2);
}

/* ===========================================================================
   6. LES BOUTONS : DEUX STYLES, PLUS UN LIEN
   L'application en portait quatre (orange plein, sombre contoure, gris petit,
   lien fleche), sans regle. Ici : une action principale par ecran, le reste en
   fantome, et le lien pour naviguer.
   =========================================================================== */
:root[data-theme="dark"] .app-main .btn,
:root[data-theme="dark"] .app-main button.btn {
  font-family: var(--z-texte);
  font-size: var(--z-t2);
  font-weight: var(--z-w-appuye);
  border-radius: var(--z-r);
  padding: var(--z-e2) var(--z-e4);
  border: 1px solid var(--z-filet-fort);
  background: transparent;
  color: var(--z-encre);
  transition: background .14s cubic-bezier(.2,.8,.2,1), border-color .14s;
}
:root[data-theme="dark"] .app-main .btn:hover { background: var(--z-surface-h); }

:root[data-theme="dark"] .app-main .btn.primary,
:root[data-theme="dark"] .app-main .btn-primary {
  background: var(--z-accent);
  border-color: var(--z-accent);
  color: #17110a;
  font-weight: var(--z-w-fort);
}
:root[data-theme="dark"] .app-main .btn.primary:hover,
:root[data-theme="dark"] .app-main .btn-primary:hover {
  background: var(--z-accent-h); border-color: var(--z-accent-h);
}

/* Le foyer clavier n'est jamais supprime : il devient visible et net. */
:root[data-theme="dark"] .app-main :is(a, button, input, select, textarea):focus-visible {
  outline: 2px solid var(--z-info);
  outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
  :root[data-theme="dark"] .app-main .btn { transition: none; }
}

/* ===========================================================================
   7. LES CHIFFRES, DEUXIÈME TOUR
   Le premier visait `.kpi-value` et `.z-num` : ces classes n'existent pas dans
   cette application. Mesure faite dans le navigateur, les vraies sont
   `.eb-stat-v`, `.dash-hero-v`, `.dash-k`, `.dg-kpi-v`, une par module.

   ON VISE DONC PAR MOTIF, PAS PAR ÉNUMÉRATION. Il y a 149 espaces de noms dans
   cette feuille de style, chacun avec sa propre classe de valeur. Les nommer un
   par un serait faux dès le prochain module écrit ; le motif, lui, les attrape
   d'avance.

   Au passage, ceci corrige un défaut visible : `.dg-kpi-v` tombait sur ARIAL,
   pendant que tout le reste de l'application est en Inter.
   =========================================================================== */
:root[data-theme="dark"] .app-main [class*="-num"],
:root[data-theme="dark"] .app-main [class*="-kpi-v"],
:root[data-theme="dark"] .app-main [class*="-stat-v"],
:root[data-theme="dark"] .app-main .dash-hero-v,
:root[data-theme="dark"] .app-main .dash-k {
  font-family: var(--z-mono);
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1, "zero" 1;
  letter-spacing: -.015em;
  font-weight: var(--z-w-appuye);
}

/* La valeur héros du tableau de bord : c'est le chiffre qui doit se voir de
   loin, il mérite le cran du dessus et l'encre pleine. */
:root[data-theme="dark"] .app-main .dash-hero-v {
  font-size: var(--z-t6);
  font-weight: var(--z-w-fort);
  color: var(--z-encre);
  line-height: 1.05;
  /* Une mono a une chasse large : a 40 px, un montant part en accordeon. Le
     resserrement doit croitre avec le corps, il n est pas le meme a 22 px. */
  letter-spacing: -.045em;
}

/* ===========================================================================
   8. LES COMPOSANTS MAISON REJOIGNENT LE RAYON DU SYSTÈME
   `su-b`, `su-pick-item` et leurs semblables n'utilisent pas le vocabulaire des
   boutons : ils portent leur propre bleu et leur propre rayon de 6 px. Le
   balayage des 149 espaces de noms les traitera un par un ; en attendant, on
   aligne au moins le rayon, qui est ce qui se voit le plus.
   =========================================================================== */
:root[data-theme="dark"] .app-main .su-b,
:root[data-theme="dark"] .app-main .su-pick-item,
:root[data-theme="dark"] .app-main [class*="-chip"],
:root[data-theme="dark"] .app-main [class*="-tab"] {
  border-radius: var(--z-r);
}

/* ===========================================================================
   9. LA POLICE DES CHIFFRES EST ENFIN LIVRÉE
   La charte nomme JetBrains Mono depuis le début, et l'application ne l'a
   JAMAIS embarquée : elle est présente sur la vitrine, sur MSP et sur Smart,
   mais pas dans `/app/assets/fonts`. Tout ce qui était censé être en mono
   retombait donc sur Consolas ou Menlo, c'est-à-dire sur la police par défaut
   du poste du client. Une identité ne peut pas dépendre de ça.

   63 Ko pour trois graisses. L'application livre déjà 376 Ko d'Inter Italique.
   =========================================================================== */
@font-face {
  font-family: 'JetBrains Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/JetBrainsMono-400.woff2') format('woff2');
}
@font-face {
  font-family: 'JetBrains Mono';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('../fonts/JetBrainsMono-500.woff2') format('woff2');
}
@font-face {
  font-family: 'JetBrains Mono';
  font-style: normal;
  font-weight: 600 700;
  font-display: swap;
  src: url('../fonts/JetBrainsMono-700.woff2') format('woff2');
}

/* ===========================================================================
   10. LES ÉCRANS DE GROUPE CESSENT D'ÊTRE UN GABARIT

   CE QU'ILS ÉTAIENT. Quatre boîtes grises identiques, une petite icône bleue
   dans un carré teinté en haut à gauche, un titre gras, deux lignes de gris.
   C'est le gabarit qu'on peut coller sur n'importe quel produit du monde. Deux
   des quatre icônes étaient d'ailleurs LA MÊME.

   L'ICÔNE DANS SON CARRÉ TEINTÉ EST LE SIGNE LE PLUS RECONNAISSABLE de ce
   gabarit. Elle disparaît. Ce qui la remplace n'est pas une autre décoration :
   c'est un filet vertical, le même dispositif que la sévérité, qui s'épaissit
   et prend l'accent au survol. Le mouvement sans l'ornement.

   DEUX COLONNES, PAS TROIS. Avec trois, quatre outils donnent une ligne de
   trois et une carte orpheline qui casse le rythme. Avec deux, ils donnent un
   carré. Et les cartes respirent au lieu de flotter dans deux tiers de vide.
   =========================================================================== */
:root[data-theme="dark"] .app-main .home-grid,
:root[data-theme="dark"] .app-main .esp-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(340px, 1fr));
  gap: var(--z-e3);
  max-width: 1080px;
}

:root[data-theme="dark"] .app-main .esp-card,
:root[data-theme="dark"] .app-main .home-card {
  position: relative;
  display: grid;
  grid-template-columns: 1fr auto;
  grid-template-areas: "titre valeur" "desc valeur";
  align-items: start;
  gap: var(--z-e1) var(--z-e4);
  text-align: left;
  background: var(--z-surface);
  border: 1px solid var(--z-filet);
  border-left: 2px solid var(--z-filet-fort);
  border-radius: var(--z-r);
  padding: var(--z-e4) var(--z-e5) var(--z-e4) var(--z-e4);
  transition: border-left-color .16s cubic-bezier(.2,.8,.2,1),
              border-left-width .16s cubic-bezier(.2,.8,.2,1),
              background .16s;
}
:root[data-theme="dark"] .app-main .esp-card:hover,
:root[data-theme="dark"] .app-main .esp-card:focus-visible {
  background: var(--z-surface-h);
  border-left-color: var(--z-accent);
  border-left-width: 3px;
}

/* L'icone dans son carre teinte : c'est elle, le gabarit. Elle s'en va. */
:root[data-theme="dark"] .app-main .esp-card .hc-ic,
:root[data-theme="dark"] .app-main .home-card .hc-ic { display: none; }

:root[data-theme="dark"] .app-main .esp-card .hc-t {
  grid-area: titre;
  font-family: var(--z-display);
  font-size: var(--z-t4);
  font-weight: var(--z-w-fort);
  letter-spacing: -.012em;
  color: var(--z-encre);
  line-height: 1.2;
}
:root[data-theme="dark"] .app-main .esp-card .hc-d {
  grid-area: desc;
  font-size: var(--z-t2);
  line-height: 1.45;
  color: var(--z-encre-2);
  max-width: 46ch;
}

/* La place de l'etat, a droite. Vide tant qu'aucune mesure n'existe : on
   n'invente pas un chiffre pour remplir une case. */
:root[data-theme="dark"] .app-main .esp-card .hc-v {
  grid-area: valeur;
  align-self: center;
  font-family: var(--z-mono);
  font-variant-numeric: tabular-nums;
  font-size: var(--z-t5);
  font-weight: var(--z-w-appuye);
  letter-spacing: -.03em;
  color: var(--z-encre);
  white-space: nowrap;
}
:root[data-theme="dark"] .app-main .esp-card .hc-u {
  display: block;
  font-family: var(--z-texte);
  font-size: var(--z-t0);
  font-weight: var(--z-w-appuye);
  letter-spacing: var(--z-ls-caps);
  text-transform: uppercase;
  color: var(--z-encre-2);
  text-align: right;
  margin-top: 2px;
}

/* ===========================================================================
   11. LA BARRE D'EN-TÊTE RETROUVE UNE GRAMMAIRE
   Mesure faite dans le navigateur : SEPT contrôles, SEPT hauteurs (42, 26, 26,
   36, 31, 34, 34 px), trois fonds, deux rayons. Une hauteur unique et un seul
   traitement suffisent à transformer un empilement en barre.
   =========================================================================== */
:root[data-theme="dark"] .app-header .cmdk-trigger,
:root[data-theme="dark"] .app-header .header-cta,
:root[data-theme="dark"] .app-header .header-install,
:root[data-theme="dark"] .app-header .header-help,
:root[data-theme="dark"] .app-header .bell-trigger,
/* JAMAIS `> *` SUR UN PORTEUR DE MENU. Cette regle visait tous les enfants des
   deux selecteurs, donc AUSSI leurs `<ul>` deroulants : ils recevaient
   `display: inline-flex` et `height: 34px`, ce qui transformait les menus
   verticaux en rangees horizontales debordant l ecran, et rendait visibles les
   libelles caches (« Language · Langue · Sprache... »). On vise les BOUTONS,
   qui sont les seuls objets de la barre. */
:root[data-theme="dark"] .app-header .ctry-btn,
:root[data-theme="dark"] .app-header .lang-btn {
  height: 34px;
  min-height: 34px;
  border-radius: var(--z-r);
  font-size: var(--z-t2);
  display: inline-flex;
  align-items: center;
}
:root[data-theme="dark"] .app-header .header-cta,
:root[data-theme="dark"] .app-header .header-install,
:root[data-theme="dark"] .app-header .header-help,
:root[data-theme="dark"] .app-header .bell-trigger {
  background: transparent;
  border: 1px solid var(--z-filet);
  color: var(--z-encre-2);
  padding: 0 var(--z-e3);
}
:root[data-theme="dark"] .app-header .header-cta:hover,
:root[data-theme="dark"] .app-header .header-install:hover,
:root[data-theme="dark"] .app-header .header-help:hover,
:root[data-theme="dark"] .app-header .bell-trigger:hover {
  background: var(--z-surface-h);
  color: var(--z-encre);
}
/* La recherche est la seule chose que l'on cherche vraiment dans une barre :
   elle garde un fond, les autres deviennent des fantomes. */
:root[data-theme="dark"] .app-header .cmdk-trigger {
  background: var(--z-surface);
  border: 1px solid var(--z-filet-fort);
}

/* ===========================================================================
   12. LA POSTURE DEVIENT UN INSTRUMENT

   CE QUI ÉTAIT LÀ. Un anneau en camembert avec le score au centre, et quatre
   barres de progression arrondies. C'est LE poncif du tableau de bord : on le
   trouve à l'identique dans des centaines de produits, et il ne dit rien de
   plus qu'un nombre.

   CE QUI LE REMPLACE, ET POURQUOI CE N'EST PAS UN AUTRE ORNEMENT.
   Un chiffre massif en chasse fixe, une jauge d'un cheveu dessous dont la
   longueur EST le score, et les quatre volets en relevé tabulaire aligné. C'est
   la grammaire d'un appareil de mesure, pas d'une page. Elle vient du métier :
   un outil qui produit des preuves affiche des relevés, pas des camemberts.

   ET ELLE EST ASYMÉTRIQUE. Une colonne étroite pour la mesure, une large pour
   le détail. La grille de blocs égaux est ce qui fait « gabarit » ; le
   déséquilibre délibéré est ce qui fait composition.
   =========================================================================== */
:root[data-theme="dark"] .app-main .pg-hero {
  display: grid;
  grid-template-columns: minmax(210px, 260px) 1fr;
  gap: var(--z-e7);
  align-items: start;
  padding: var(--z-e5) var(--z-e5) var(--z-e5) 0;
}

/* L'anneau perd son cercle : il ne reste que la mesure. */
:root[data-theme="dark"] .app-main .pg-ring {
  background: none !important;
  border: 0 !important;
  border-radius: 0 !important;
  width: auto !important;
  height: auto !important;
  padding: 0 !important;
  display: block;
  position: relative;
}
:root[data-theme="dark"] .app-main .pg-ring::before,
:root[data-theme="dark"] .app-main .pg-ring::after { content: none !important; }
:root[data-theme="dark"] .app-main .pg-ring-c {
  position: static !important;
  transform: none !important;
  display: block;
  width: auto; height: auto;
}
:root[data-theme="dark"] .app-main .pg-ring-v {
  font-family: var(--z-mono);
  font-variant-numeric: tabular-nums;
  font-size: clamp(64px, 7vw, 104px);
  font-weight: var(--z-w-fort);
  letter-spacing: -.06em;
  line-height: .92;
  color: var(--z-encre);
  display: block;
}
:root[data-theme="dark"] .app-main .pg-ring-v small {
  font-size: var(--z-t4);
  font-weight: var(--z-w-moyen);
  letter-spacing: -.02em;
  color: var(--z-encre-2);
  margin-left: 2px;
}

/* LA JAUGE. Sa longueur EST le score : `--p` est déjà posé en style en ligne
   par le module, on ne réinvente donc aucune donnée. */
:root[data-theme="dark"] .app-main .pg-ring-l {
  display: block;
  margin-top: var(--z-e3);
  font-size: var(--z-t0);
  font-weight: var(--z-w-appuye);
  letter-spacing: var(--z-ls-caps);
  text-transform: uppercase;
  color: var(--z-encre-2);
  position: relative;
  padding-top: var(--z-e3);
}
:root[data-theme="dark"] .app-main .pg-ring-l::before {
  content: "";
  position: absolute; top: 0; left: 0; right: 0;
  height: 2px; background: var(--z-filet);
}
:root[data-theme="dark"] .app-main .pg-ring-l::after {
  content: "";
  position: absolute; top: 0; left: 0;
  height: 2px; width: calc(var(--p, 0) * 1%);
  background: var(--z-accent);
}

/* Le niveau (« Correcte ») devient le surtitre à filet, pas une pastille. */
:root[data-theme="dark"] .app-main .pg-head { align-items: center; gap: var(--z-e3); }
:root[data-theme="dark"] .app-main .pg-level {
  background: none !important;
  border: 0 !important;
  padding: 0 !important;
  font-family: var(--z-texte);
  font-size: var(--z-t0);
  font-weight: var(--z-w-appuye);
  letter-spacing: var(--z-ls-caps);
  text-transform: uppercase;
  color: var(--z-encre-2);
}

/* LES QUATRE VOLETS EN RELEVÉ. Une ligne par volet, le libellé à gauche, la
   valeur à droite en chasse fixe, un filet de séparation, et la barre réduite à
   un soulignement de 2 px au lieu d'une pilule arrondie. */
:root[data-theme="dark"] .app-main .pg-parts {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0;
  margin-top: var(--z-e4);
}
:root[data-theme="dark"] .app-main .pg-part {
  display: block;
  width: 100%;
  background: none;
  border: 0;
  border-top: 1px solid var(--z-filet);
  border-radius: 0;
  padding: var(--z-e3) 0 0;
  margin: 0 0 var(--z-e3);
  text-align: left;
}
:root[data-theme="dark"] .app-main .pg-part:hover { background: none; }
:root[data-theme="dark"] .app-main .pg-part-h {
  display: flex; justify-content: space-between; align-items: baseline;
  font-size: var(--z-t2);
  color: var(--z-encre-2);
  margin-bottom: var(--z-e2);
}
:root[data-theme="dark"] .app-main .pg-part-h b {
  font-family: var(--z-mono);
  font-variant-numeric: tabular-nums;
  font-size: var(--z-t3);
  font-weight: var(--z-w-appuye);
  letter-spacing: -.02em;
  color: var(--z-encre);
}
:root[data-theme="dark"] .app-main .pg-part-track {
  height: 2px;
  border-radius: 0;
  background: var(--z-filet);
}
:root[data-theme="dark"] .app-main .pg-part-fill {
  height: 2px;
  border-radius: 0;
  background: var(--z-encre-2);
}
/* La couleur ne sert qu'à dire un état, et seulement quand il est mauvais. */
:root[data-theme="dark"] .app-main .pg-part-fill.r-crit { background: var(--z-crit); }
:root[data-theme="dark"] .app-main .pg-part-fill.r-high { background: var(--z-haut); }

/* ===========================================================================
   13. NARA RESTE UNE BANDE, MAIS SES LETTRES SE TIENNENT DEBOUT

   CE QUI N ALLAIT PAS N ETAIT PAS LA BANDE, C ETAIT LE TEXTE COUCHE. Le nom
   etait ecrit en `writing-mode: vertical-rl` PUIS retourne a 180 degres : les
   lettres partaient sur le flanc et se lisaient de bas en haut. C est le
   traitement des onglets de retour d'experience, pas d'une signature produit.

   `text-orientation: upright` empile les lettres SANS les coucher :

       N
       A
       R
       A

   La bande garde sa place, centree sur le cote droit. Elle prend en revanche la
   grammaire du systeme : le rayon, le filet d'un cheveu, la surface. Ce qui la
   distinguait etait sa fonction, pas ses coins arrondis a 10 px.
   =========================================================================== */
:root[data-theme="dark"] #ai-fab {
  right: 0 !important;
  top: 50% !important;
  bottom: auto !important;
  transform: translateY(-50%) !important;
  width: 46px !important;
  border-radius: var(--z-r) 0 0 var(--z-r) !important;
  background: var(--z-surface) !important;
  border: 1px solid var(--z-filet-fort) !important;
  border-right: 0 !important;
  box-shadow: var(--z-ombre-lg);
  display: flex !important;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--z-e2);
  padding: var(--z-e3) 0 !important;
  transition: background .16s cubic-bezier(.2,.8,.2,1), border-color .16s;
}
:root[data-theme="dark"] #ai-fab:hover,
:root[data-theme="dark"] #ai-fab:focus-visible {
  background: var(--z-surface-h) !important;
  border-color: var(--z-accent) !important;
}
:root[data-theme="dark"] #ai-fab .ai-fab-ic { width: 24px; height: 24px; flex: none; }

/* LES LETTRES DEBOUT, EMPILEES. `upright` les redresse une a une ; sans lui,
   `vertical-rl` seul les couche sur le flanc. La rotation de 180 degres qui
   etait la disparait : elle ne servait qu a rattraper ce couchage. */
:root[data-theme="dark"] #ai-fab .ai-fab-t {
  writing-mode: vertical-rl !important;
  text-orientation: upright !important;
  transform: none !important;
  font-size: var(--z-t0);
  font-weight: var(--z-w-appuye);
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--z-encre-2);
  line-height: 1;
}
:root[data-theme="dark"] #ai-fab:hover .ai-fab-t { color: var(--z-encre); }

/* ===========================================================================
   14. LE BANDEAU LECTURE SEULE CESSE DE COUVRIR L'ÉCRAN

   MESURE D'ORIGINE : une barre PLEINE LARGEUR de 50 px, epinglee en bas, en
   z-index 1250, en permanence. Elle masquait le pied de page et la derniere
   ligne de chaque tableau.

   LA REDUCTION EN PASTILLE N'A PAS SUFFI, et il faut le dire ici parce que
   cette section annoncait le contraire. Une pastille reste une surcouche : le
   01/09/2026, mesuree sur la demonstration, elle occupait 560 x 57 px a 24 px
   du coin bas gauche et recouvrait les liens du pied de page, la carte du
   compte, son bouton de deconnexion et jusqu'a deux onglets de navigation. La
   regle du plan directeur ne dit pas « une surcouche discrete », elle dit
   « zero element fixe masquant un contenu ou une action ».

   CE QUI CHANGE : le bandeau sort de la pile fixe et revient dans le flux, en
   tete de `#main` (voir `.ro-banner` dans styles.css et `applyAccess` dans
   access.js). Il pousse le contenu au lieu de le couvrir. La pile
   `.sys-stack` reste telle quelle pour les bandeaux TRANSITOIRES, dont celui
   de crise. Le refus, lui, reste bruyant AU MOMENT du geste, ce qui est le
   seul instant où il compte.
   =========================================================================== */
:root[data-theme="dark"] .sys-stack {
  left: var(--z-e5) !important;
  right: auto !important;
  bottom: var(--z-e5) !important;
  width: auto !important;
  max-width: min(560px, calc(100vw - 2 * var(--z-e5)));
  /* La pile ne capte plus le clic ; ses enfants, si. Sans ceci, une bande
     invisible de pleine largeur avalait les clics du bas de page. */
  pointer-events: none !important;
}
:root[data-theme="dark"] .sys-stack > * { pointer-events: auto; }

/* Une boite de flux, pas une pastille posee sur l'ecran. Le filet d'attention
   sur le bord de depart porte la severite ; l'ombre portee disparait, elle ne
   servait qu'a decoller la pastille du fond. */
:root[data-theme="dark"] .ro-banner {
  background: var(--z-surface);
  border: 1px solid var(--z-filet-fort);
  border-inline-start: 3px solid var(--z-haut);
  border-radius: var(--z-r);
  margin: 0 0 var(--z-e4);
  padding: var(--z-e3) var(--z-e4);
  font-size: var(--z-t2);
  line-height: 1.5;
  color: var(--z-encre-2);
}

/* LA COMPENSATION SUIT CE QU'ELLE COMPENSE, SINON ELLE DEVIENT UN TROU.

   Ce degagement de 88 px existait pour la pastille de lecture seule. Il etait
   pose SANS CONDITION : tous les comptes le payaient, y compris ceux qui n'ont
   jamais vu de pastille. Et il ne protegeait ni la barre laterale ni le pied
   de page, c'est-a-dire exactement ce que la pastille recouvrait : il coutait
   une bande a tout le monde sans regler le defaut pour personne.

   Le bandeau de lecture seule etant revenu dans le flux, la pile ne porte plus
   que des bandeaux transitoires. Le degagement n'est donc pose que lorsque la
   pile porte quelque chose. Le retirer purement et simplement aurait rouvert
   le recouvrement pour le bandeau de crise. */
:root[data-theme="dark"] body:has(#sys-stack > *) .app-main {
  padding-bottom: calc(var(--z-e8) + var(--z-e5));
}

@media (prefers-reduced-motion: reduce) {
  :root[data-theme="dark"] #ai-fab,
  :root[data-theme="dark"] #ai-fab .ai-fab-t { transition: none; }
}

/* ===========================================================================
   15. L'EN-TÊTE : DE SEPT OBJETS À QUATRE

   MESURE : sept contrôles pour 935 px de barre. Et deux d'entre eux étaient
   LITTÉRALEMENT jumeaux : même fond `rgb(23,27,33)`, même bordure, même rayon,
   même remplissage, et LE MÊME DRAPEAU affiché deux fois. Personne ne peut
   deviner que l'un choisit les normes applicables et l'autre la langue.

   PAYS ET LANGUE DEVIENNENT UN SEUL OBJET À DEUX FACETTES. Ils sont accolés,
   séparés par un filet interne, dans un seul cadre. On lit « France · FR »
   comme une seule information de contexte, ce qu'elle est. Le drapeau ne
   s'affiche plus qu'une fois : le répéter était ce qui les rendait
   indiscernables.

   LES UTILITAIRES PASSENT EN ICÔNES. « Installer l'app » (157 px) et « Mode
   d'emploi » (138 px) sont des gestes qu'on fait une fois. Ils gardent leur
   infobulle et leur libellé accessible ; ils ne gardent pas 295 px de barre.
   « Nous contacter » reste écrit : c'est le seul appel à l'action.
   =========================================================================== */

/* --- Pays et langue, accolés en un seul objet --- */
:root[data-theme="dark"] .app-header .lang-picker { margin-left: -12px; }

:root[data-theme="dark"] .app-header .ctry-btn,
:root[data-theme="dark"] .app-header .lang-btn {
  background: transparent !important;
  border: 1px solid var(--z-filet) !important;
  color: var(--z-encre-2) !important;
  height: 34px;
  padding: 0 var(--z-e3) !important;
  font-size: var(--z-t2);
}
:root[data-theme="dark"] .app-header .ctry-btn {
  border-radius: var(--z-r) 0 0 var(--z-r) !important;
  border-right: 0 !important;
}
:root[data-theme="dark"] .app-header .lang-btn {
  border-radius: 0 var(--z-r) var(--z-r) 0 !important;
  /* Le filet interne : c'est lui qui dit « deux facettes, un seul objet ». */
  border-left: 1px solid var(--z-filet-fort) !important;
}
:root[data-theme="dark"] .app-header .ctry-btn:hover,
:root[data-theme="dark"] .app-header .lang-btn:hover {
  background: var(--z-surface-h) !important;
  color: var(--z-encre) !important;
}
/* LE DRAPEAU EN DOUBLE ÉTAIT LA CAUSE DE LA CONFUSION. Il reste sur le pays,
   qu'il désigne vraiment ; la langue se dit par son code, qui suffit. */
/* Le drapeau n'est pas une image mais un `<span>` porteur d'un SVG en ligne :
   viser `img` ne pouvait rien attraper. Il reste sur le PAYS, qu'il designe
   vraiment ; la langue se dit par son code, qui suffit et ne se confond avec
   rien. On ne pose pas d'etiquette en CSS pour l'expliquer : `content` ne se
   traduit pas, et cette application vit en huit langues. */
:root[data-theme="dark"] .app-header .lang-btn .lang-flag { display: none !important; }
:root[data-theme="dark"] .app-header .lang-btn .lang-code {
  font-family: var(--z-mono);
  font-size: var(--z-t2);
  letter-spacing: .04em;
}

/* --- Les utilitaires passent en icônes --- */
:root[data-theme="dark"] .app-header .header-install .hi-label,
:root[data-theme="dark"] .app-header .header-help > span { display: none; }
:root[data-theme="dark"] .app-header .header-install,
:root[data-theme="dark"] .app-header .header-help {
  width: 34px;
  padding: 0 !important;
  justify-content: center;
}

/* ON NE TOUCHE PAS AUX MENUS. J'y avais ajoute deux regles « au cas ou », sans
   avoir lu comment ils s'ouvrent. Les deux etaient fausses, et de facon
   opposee : `display: block` annulait le `display: none` natif de l'attribut
   `hidden` (les menus restaient ouverts et debordaient l'ecran), puis
   `:not(.open)` les a rendus definitivement invisibles, la classe `open`
   n'existant nulle part. Le module fait `menu.hidden = false`, et le navigateur
   sait deja quoi en faire. La seule correction necessaire etait de viser les
   BOUTONS au lieu de `> *`. Une regle ecrite « par prudence » sur un mecanisme
   qu'on n'a pas lu n'est pas une prudence, c'est un pari. */

/* ===========================================================================
   16. LA BULLE EXPLICATIVE

   Elle existait mais gardait l'allure d'une infobulle de navigateur : un pavé
   gris sans hiérarchie, posé n'importe où. Comme elle va désormais s'afficher
   sur les 59 entrées du menu et plus seulement sur quelques-unes, elle passe à
   la grammaire du système : surface, filet d'un cheveu, rayon serré, et un
   filet d'accent sur la tranche gauche qui dit d'où elle vient.
   =========================================================================== */
:root[data-theme="dark"] .tip-bubble {
  background: var(--z-sol-2);
  border: 1px solid var(--z-filet-fort);
  border-left: 2px solid var(--z-accent);
  border-radius: var(--z-r);
  box-shadow: var(--z-ombre-lg);
  padding: var(--z-e3) var(--z-e4);
  max-width: 34ch;
  font-size: var(--z-t2);
  line-height: 1.5;
  color: var(--z-encre);
  /* Une bulle ne doit jamais capter le geste qui l'a fait apparaitre. */
  pointer-events: none;
}

/* ===========================================================================
   17. L'ETAT D'UNE CARTE SE LIT SANS LIRE LE CHIFFRE

   Un nombre seul se lit pareil qu'il soit bon ou mauvais : « 5 » ne dit pas si
   ces cinq actions sont en retard ou toutes traitees. Le ton pose par
   `data-ton` colore la valeur ET pose un filet vertical sur le bord de la
   carte, pour que l'etat passe par la FORME autant que par la couleur : un
   ecran lu de loin, ou par quelqu'un qui distingue mal le rouge de l'orange,
   garde l'information.

   Les couleurs viennent des jetons SEMANTIQUES, jamais de l'accent : l'accent
   fauve est reserve a l'action principale, il ne dit pas un etat.

   « neutre » n'a AUCUNE regle ici, volontairement : il reste dans la forme par
   defaut. Un etat ordinaire ne merite pas d'etre signale ; ne rien poser est
   la facon la plus sure de ne pas crier pour rien.
   =========================================================================== */
:root[data-theme="dark"] .app-main .esp-card[data-ton="alerte"] {
  box-shadow: inset 3px 0 0 var(--z-crit);
}
:root[data-theme="dark"] .app-main .esp-card[data-ton="alerte"] .hc-v,
:root[data-theme="dark"] .app-main .esp-card[data-ton="alerte"] .hc-u {
  color: var(--z-crit);
}
:root[data-theme="dark"] .app-main .esp-card[data-ton="attention"] {
  box-shadow: inset 3px 0 0 var(--z-haut);
}
:root[data-theme="dark"] .app-main .esp-card[data-ton="attention"] .hc-v,
:root[data-theme="dark"] .app-main .esp-card[data-ton="attention"] .hc-u {
  color: var(--z-haut);
}
/* « A jour » n'est pas une alerte : pas de filet, une couleur sobre, et la
   valeur revient a la taille du texte parce que ce n'est plus un nombre. */
:root[data-theme="dark"] .app-main .esp-card[data-ton="calme"] .hc-v {
  font-family: var(--z-texte);
  font-size: var(--z-t1);
  letter-spacing: 0;
  color: var(--z-sain);
}
:root[data-theme="dark"] .app-main .esp-card[data-ton="calme"] .hc-u {
  color: var(--z-encre-2);
}

/* ===========================================================================
   18. UNE PHRASE N'EST PAS UNE RANGEE D'ELEMENTS

   `.ro-banner` etait `display: flex; gap: 10px`. Son contenu est une icone
   suivie d'UNE phrase, dont deux mots sont en gras. En disposition flex, chaque
   fragment de texte autour du `<strong>` devient un element separe : « Mode »,
   « lecture seule », « : votre compte consulte... ». Le `gap` les ecartait de
   10 px, et chacun se renvoyait a la ligne pour son propre compte. Mesure dans
   le navigateur : le `<strong>` faisait 51 px de large et 40 px de haut,
   c'est-a-dire « lecture » au-dessus de « seule », au milieu d'une phrase.

   Le flux du texte est fait pour cela. L'icone redevient un signe pose devant
   la phrase, et la phrase reste une phrase.
   =========================================================================== */
:root[data-theme="dark"] .ro-banner {
  display: block;
  max-width: 78ch;
  line-height: 1.5;
}
:root[data-theme="dark"] .ro-banner > [class^="gi-"] {
  display: inline-block;
  vertical-align: -3px;
  margin: 0 var(--z-e2) 0 0;
}


/* ===========================================================================
   19. LA VISITE DU FIL

   UN PANNEAU, PAS UNE FENETRE MODALE. Il ne recouvre aucune action, ne capture
   ni le focus ni les clics, et l'application reste utilisable pendant la
   visite. C'est un guide, pas une porte fermee : on doit pouvoir s'en aller
   sans le chercher.

   IL SE POSE EN BAS A GAUCHE. A droite vivent deja la bande NARA et les
   indicateurs des cartes ; en haut, l'en-tete. Le coin bas-gauche est le seul
   qui ne recouvre rien, et c'est aussi le sens de lecture : on lit la consigne,
   puis on regarde l'ecran.

   LE LIEN EST L'ELEMENT LE PLUS VISIBLE de chaque etape, avant le titre : c'est
   lui que la visite demontre, l'objet n'en est que le support.
   =========================================================================== */
:root[data-theme="dark"] .visite {
  position: fixed;
  left: var(--z-e4, 20px);
  bottom: var(--z-e4, 20px);
  z-index: 1200;
  width: min(430px, calc(100vw - 40px));
  background: var(--z-sol-2);
  border: 1px solid var(--z-filet-fort);
  border-radius: var(--z-r, 6px);
  box-shadow: var(--z-ombre-lg);
  padding: var(--z-e3, 16px) var(--z-e4, 20px) var(--z-e4, 20px);
  color: var(--z-encre);
}
:root[data-theme="dark"] .visite-tete {
  display: flex;
  align-items: center;
  gap: var(--z-e2, 10px);
  margin: 0 0 var(--z-e3, 16px);
}
:root[data-theme="dark"] .visite-cote {
  flex: 1;
  font-family: var(--z-mono);
  font-size: 12px;
  letter-spacing: var(--z-ls-caps, .12em);
  text-transform: uppercase;
  color: var(--z-encre-2);
}
:root[data-theme="dark"] .visite-pas {
  font-family: var(--z-mono);
  font-variant-numeric: tabular-nums;
  font-size: 12px;
  color: var(--z-encre-2);
}
:root[data-theme="dark"] .visite-x {
  background: none;
  border: 0;
  color: var(--z-encre-2);
  font-size: 20px;
  line-height: 1;
  cursor: pointer;
  padding: 0 2px;
}
:root[data-theme="dark"] .visite-x:hover { color: var(--z-encre); }

/* LE LIEN, mis en avant avant le titre : c'est ce que l'etape demontre. */
:root[data-theme="dark"] .visite-lien {
  margin: 0 0 var(--z-e2, 10px);
}
:root[data-theme="dark"] .visite-lien span {
  display: inline-block;
  padding: 3px 10px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--z-info) 14%, transparent);
  border: 1px solid color-mix(in srgb, var(--z-info) 34%, transparent);
  font-family: var(--z-mono);
  font-size: 12px;
  color: var(--z-info);
}
:root[data-theme="dark"] .visite h3 {
  margin: 0 0 var(--z-e2, 10px);
  font-family: var(--z-display, var(--z-texte));
  font-size: var(--z-t3);
  line-height: 1.3;
  color: var(--z-encre);
}
:root[data-theme="dark"] .visite p {
  margin: 0 0 var(--z-e2, 10px);
  font-size: var(--z-t2);
  line-height: 1.55;
  color: var(--z-encre-2);
}
:root[data-theme="dark"] .visite-mesure {
  font-family: var(--z-mono);
  font-variant-numeric: tabular-nums;
  font-size: 12px;
  color: var(--z-info);
}
/* Une vue absente est DITE, pas masquee. */
:root[data-theme="dark"] .visite-absent {
  font-size: 12px;
  color: var(--z-haut);
}
:root[data-theme="dark"] .visite-pied {
  display: flex;
  gap: var(--z-e2, 10px);
  margin: var(--z-e3, 16px) 0 0;
}
:root[data-theme="dark"] .visite-pied .btn { flex: 1; }

/* La recapitulation : cinq objets, quatre fleches. */
:root[data-theme="dark"] .visite-fil {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  margin: 0 0 var(--z-e3, 16px);
  padding: 0;
  list-style: none;
  font-family: var(--z-mono);
  font-size: 12px;
  color: var(--z-encre-2);
}
:root[data-theme="dark"] .visite-fil li {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
:root[data-theme="dark"] .visite-fil-n {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: color-mix(in srgb, var(--z-info) 18%, transparent);
  color: var(--z-info);
}
:root[data-theme="dark"] .visite-fil-l { color: var(--z-info); }
:root[data-theme="dark"] .visite-limite {
  font-size: 12px;
  line-height: 1.5;
  color: var(--z-encre-2);
  border-top: 1px solid var(--z-filet);
  padding-top: var(--z-e2, 10px);
}

/* Sur un ecran etroit, le panneau prend toute la largeur du bas. */
@media (max-width: 640px) {
  :root[data-theme="dark"] .visite {
    left: 10px;
    right: 10px;
    bottom: 10px;
    width: auto;
  }
}
@media (prefers-reduced-motion: no-preference) {
  :root[data-theme="dark"] .visite { transition: none; }
}
