/* La console d'administration, habillée comme les pages de jeu.
 *
 * Les trois pages du panneau (`/`, `/reglages`, `/systeme`) portaient chacune
 * leur propre palette en ligne : fond #10161a, accent ambre, angles vifs,
 * Archivo et IBM Plex Mono chargées chez Google. Le site des jeux, lui, suit
 * les jetons du superviseur — accent turquoise, cartes arrondies, clair ET
 * sombre, polices du système. Deux identités sur un même domaine, à un clic
 * l'une de l'autre.
 *
 * CETTE FEUILLE NE TOUCHE NI AU HTML NI AU JS DE LA CONSOLE. Elle reprend ses
 * classes une à une — `.bay`, `.lamp`, `.pod`, `.console`, `.gate`… — et les
 * redessine avec les jetons de `style.css`, qui doit être chargée avant elle.
 * C'est ce qui permet de l'habiller sans rien casser de ce qui marche : la
 * structure de l'information ne bouge pas, seule la matière change.
 *
 * CE QUI EST GARDÉ, parce que c'en est la signature : le voyant d'état, qui
 * respire quand un serveur tourne. Il passe simplement de l'ambre à l'accent.
 *
 * CE QUI DISPARAÎT : les deux polices Google. Une console d'administration qui
 * va chercher ses caractères sur un serveur tiers à chaque ouverture, c'est une
 * dépendance externe qu'on peut s'épargner — le site des jeux n'en a aucune.
 */

/* ==================================================================== base */
/* style.css est la feuille d'une APPLICATION qui remplit la fenetre : elle pose
   `html,body{height:100%}`, `body{overflow:hidden}`, et fait de `nav` et `main`
   des panneaux extensibles a defilement propre. Rien de tout cela ne vaut pour
   une page qui defile normalement — et `overflow:hidden` sur le body rend
   simplement inatteignable tout ce qui depasse la premiere fenetre. On defait
   ces quatre regles avant toute chose. */
html, body { height: auto; overflow: visible; }
nav { flex: none; overflow-y: visible; padding: 0; }
main:not(.reg-liste) { overflow-y: visible; }
/* `header { height: 58px }` est la barre de titre a hauteur fixe du
   superviseur. Ici l'en-tete porte l'identite ET les quatre vitaux, et il passe
   a la ligne en etroit : une hauteur fixe l'aurait tronque en silence. */
header { height: auto; }

* { box-sizing: border-box; margin: 0; padding: 0; }

body {
  background: var(--fond);
  color: var(--texte);
  font-family: var(--f);
  font-size: 14px;
  line-height: 1.55;
  min-height: 100vh;
  padding: 0 0 4rem;
  -webkit-font-smoothing: antialiased;
}
.mono { font-family: var(--fm); }
.hidden, .cache { display: none !important; }
.grow { flex: 1; }

button:focus-visible, select:focus-visible, input:focus-visible, a:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* ============================================================== bandeau */
.masthead {
  border-bottom: 1px solid var(--bord);
  background: var(--carte);
  padding: 18px 22px 16px;
  display: flex; flex-wrap: wrap; gap: 18px 36px;
  align-items: flex-end; justify-content: space-between;
}
.ident h1 {
  font-size: 19px; font-weight: 700; letter-spacing: -.01em;
  text-transform: none;                      /* les capitales espacées partaient
                                                d'une autre identité graphique */
}
.ident p {
  font-family: var(--fm); font-size: 11px;
  color: var(--texte-3); letter-spacing: .04em; margin-top: 2px;
}

.vitals { display: flex; gap: 26px; flex-wrap: wrap; }
.vital { min-width: 108px; }
/* Collision de nom de classe : `.vital` designe ici un releve minuscule du
   bandeau, alors que theme.css lui pose un halo de 150 px prevu pour les
   grandes tuiles du superviseur. Ce halo est en `position: absolute` et
   `right: -30px` ; comme aucun `.vital` n'est positionne, il se cale sur le
   <header> sticky et faisait deborder TOUTE la page de 30 px en largeur —
   une barre de defilement horizontale sur l'accueil, sans rien de visible. */
.masthead .vital { overflow: visible; }
.masthead .vital::after { content: none; }
.vital .k {
  font-size: 10.5px; letter-spacing: .09em; text-transform: uppercase;
  color: var(--texte-3);
}
.vital .v {
  font-family: var(--fm); font-size: 15px; font-weight: 500; margin: 2px 0 5px;
}
.meter {
  height: 4px; background: var(--creux); border-radius: 2px; overflow: hidden;
}
.meter span {
  display: block; height: 100%; background: var(--accent);
  border-radius: 2px; transition: width .6s ease;
}
.meter.warn span { background: var(--crit); }

.account { display: flex; align-items: center; gap: 10px; }
.account .who {
  font-family: var(--fm); font-size: 12px; color: var(--accent);
}

/* Les boutons de la console prennent l'aspect de `.bouton` du site. */
.signout, .retour, .controls button, .console-head button, button.act {
  background: var(--carte);
  border: 1px solid var(--bord);
  color: var(--texte-2);
  font-family: var(--f);
  font-size: 12.5px;
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
  padding: 7px 12px;
  border-radius: var(--r-s);
  cursor: pointer;
  text-decoration: none;
  transition: border-color .15s, color .15s, background .15s;
}
.signout:hover, .retour:hover, .console-head button:hover,
.controls button:hover:not(:disabled), button.act:hover:not(:disabled) {
  border-color: var(--accent-bord);
  color: var(--accent);
  background: var(--accent-fond);
}
.controls button:disabled, button.act:disabled { opacity: .45; cursor: not-allowed; }

/* Le bouton qui détruit ou qui coupe : rouge au survol, jamais au repos —
   une rangée de boutons rouges ne hiérarchise plus rien. */
.controls button.danger:hover:not(:disabled),
button.act.danger:hover:not(:disabled) {
  border-color: var(--crit); color: var(--crit); background: var(--crit-fond);
}
button.act.fort {
  background: var(--accent); color: var(--sur-plein, #fff); border-color: transparent; font-weight: 650;
}
button.act.fort:hover:not(:disabled) { filter: brightness(1.08); color: var(--sur-plein, #fff); }

/* ======================================================= titres de section */
.section-label {
  font-size: 11px; letter-spacing: .12em; text-transform: uppercase;
  color: var(--texte-3);
  padding: 26px 22px 10px; display: flex; align-items: center; gap: 12px;
}
.section-label::after {
  content: ''; flex: 1; height: 1px; background: var(--bord);
}

/* =============================================================== baies */
/* La grille de 1 px sur fond de bordure devient un vrai jeu de cartes, comme
   sur les pages de jeu : espacées, arrondies, posées sur le fond. */
.bays {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(278px, 1fr));
  gap: 12px; padding: 0 22px;
  background: none; border: none;
}
.bay {
  background: var(--carte);
  border: 1px solid var(--bord);
  border-radius: var(--r);
  box-shadow: var(--ombre);
  padding: 16px 18px 15px;
  display: flex; flex-direction: column; gap: 14px;
  transition: border-color .25s ease;
}
.bay.running { border-color: var(--accent-bord); }
.bay-head { display: flex; align-items: flex-start; gap: 11px; }

/* Le voyant : la signature de la console, gardée telle quelle dans son
   principe — éteint il est creux, allumé il respire. Seule la couleur suit
   désormais l'accent du site. */
.lamp {
  width: 14px; height: 14px; border-radius: 50%;
  background: var(--creux);
  border: 1px solid var(--bord-fort);
  flex: 0 0 auto; margin-top: 4px;
}
.bay.running .lamp {
  background: var(--accent);
  border-color: transparent;
  box-shadow: 0 0 0 3px var(--accent-fond), 0 0 12px var(--accent-bord);
  animation: respire 3.4s ease-in-out infinite;
}
@keyframes respire {
  0%, 100% { box-shadow: 0 0 0 3px var(--accent-fond), 0 0 8px var(--accent-bord); }
  50%      { box-shadow: 0 0 0 4px var(--accent-fond), 0 0 18px var(--accent-bord); }
}
@media (prefers-reduced-motion: reduce) { .bay.running .lamp { animation: none; } }

.bay-title { flex: 1; min-width: 0; }
.bay-title h2 {
  font-size: 15px; font-weight: 650; letter-spacing: -.005em; text-transform: none;
}
.bay-title .unit { font-family: var(--fm); font-size: 11px; color: var(--texte-3); }

.readout {
  display: grid; grid-template-columns: 1fr 1fr; gap: 10px 12px;
  border-top: 1px solid var(--bord); padding-top: 13px;
}
.readout .k {
  font-size: 10.5px; letter-spacing: .08em; text-transform: uppercase;
  color: var(--texte-3);
}
.readout .v {
  font-family: var(--fm); font-size: 13px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.readout .v.off { color: var(--texte-3); }

.controls { display: flex; gap: 7px; flex-wrap: wrap; margin-top: auto; }
.controls button { flex: 1 1 auto; padding: 7px 9px; font-size: 12px; }

/* ========================================================== conteneurs */
.pods {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(244px, 1fr));
  gap: 10px; padding: 0 22px;
  background: none; border: none;
}
.pod {
  background: var(--carte); border: 1px solid var(--bord);
  border-radius: var(--r-s); box-shadow: var(--ombre);
  padding: 12px 14px; display: flex; flex-direction: column; gap: 9px;
}
.pod.up { border-color: var(--accent-bord); }
.pod-head { display: flex; align-items: center; gap: 9px; }
.dot {
  width: 9px; height: 9px; border-radius: 50%; flex: 0 0 auto;
  background: var(--creux); border: 1px solid var(--bord-fort);
}
.pod.up .dot {
  background: var(--accent); border-color: transparent;
  box-shadow: 0 0 0 3px var(--accent-fond);
}
.pod-head h3 {
  font-size: 13px; font-weight: 600; letter-spacing: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.pod .meta {
  font-family: var(--fm); font-size: 11px; color: var(--texte-3);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.pod .warn-tag {
  font-size: 10.5px; color: var(--warn);
  letter-spacing: .06em; text-transform: uppercase;
}
.pod .controls button { font-size: 11.5px; padding: 6px 8px; }

/* =============================================== console d'avancement */
.console {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 60;
  background: var(--carte);
  border-top: 2px solid var(--accent);
  max-height: 62vh; display: flex; flex-direction: column;
  box-shadow: var(--ombre-forte);
}
.console.done { border-top-color: var(--bord-fort); }
.console.failed { border-top-color: var(--crit); }

.console-head {
  display: flex; align-items: center; gap: 14px;
  padding: 11px 20px; border-bottom: 1px solid var(--bord);
}
.spinner {
  width: 10px; height: 10px; border-radius: 50%; flex: 0 0 auto;
  background: var(--accent); animation: bat 1.1s ease-in-out infinite;
}
.console.done .spinner { background: var(--texte-3); animation: none; }
.console.failed .spinner { background: var(--crit); animation: none; }
@keyframes bat { 0%, 100% { opacity: .35; } 50% { opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .spinner { animation: none; } }

.console-head .title {
  font-size: 13px; font-weight: 600; flex: 1;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.console-head .clock { font-family: var(--fm); font-size: 12px; color: var(--texte-3); }

.console-body {
  overflow-y: auto; padding: 12px 20px 16px;
  font-family: var(--fm); font-size: 11.5px; line-height: 1.75;
  white-space: pre-wrap; word-break: break-word; color: var(--texte-2);
}
.console-body .err { color: var(--crit); }
.console-body .ok { color: var(--accent); }

/* ============================================================== journal */
.log-bar { display: flex; align-items: center; gap: 12px; padding: 0 22px 12px; }
select {
  background: var(--carte); color: var(--texte);
  border: 1px solid var(--bord); border-radius: var(--r-s);
  font-family: var(--f); font-size: 13px; padding: 7px 10px;
}
select:focus { outline: none; border-color: var(--accent-bord); }

.log, #journal {
  margin: 0 22px; background: var(--creux);
  border: 1px solid var(--bord); border-radius: var(--r-s);
  padding: 12px 14px; font-family: var(--fm);
  font-size: 11.5px; line-height: 1.7; height: 300px; overflow-y: auto;
  white-space: pre-wrap; word-break: break-word; color: var(--texte-2);
}
.log .err, #journal .err { color: var(--crit); }
.log .warn { color: var(--warn); }

/* =========================================================== sauvegardes */
.backups {
  margin: 0 22px; border: 1px solid var(--bord);
  border-radius: var(--r-s); overflow: hidden; background: var(--carte);
}
.backup-row {
  display: flex; gap: 16px; align-items: baseline;
  padding: 9px 14px; border-bottom: 1px solid var(--bord);
  font-family: var(--fm); font-size: 12px;
}
.backup-row:last-child { border-bottom: none; }
.backup-row .g { color: var(--accent); min-width: 92px; }
.backup-row .f {
  flex: 1; color: var(--texte-2);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.backup-row .s { color: var(--texte-3); }
.empty { padding: 22px 14px; color: var(--texte-3); font-size: 13px; text-align: center; }

/* ============================================================= connexion */
.gate {
  min-height: 100vh; display: flex; align-items: center; justify-content: center;
  padding: 2rem;
}
.gate form {
  width: 100%; max-width: 340px;
  background: var(--carte); border: 1px solid var(--bord);
  border-radius: var(--r); box-shadow: var(--ombre-forte);
  padding: 26px 24px;
}
.gate h1 {
  font-size: 20px; font-weight: 700; letter-spacing: -.01em;
  text-transform: none; margin-bottom: 4px;
}
.gate p {
  font-family: var(--fm); font-size: 11.5px; color: var(--texte-3);
  letter-spacing: .03em; margin-bottom: 22px;
}
.gate label {
  display: block; font-size: 11px; letter-spacing: .08em;
  text-transform: uppercase; color: var(--texte-3); margin-bottom: 5px;
}
.gate input {
  width: 100%; background: var(--creux);
  border: 1px solid var(--bord); border-radius: var(--r-s);
  color: var(--texte); font-family: var(--fm); font-size: 14px;
  padding: 9px 11px; margin-bottom: 14px;
}
.gate input:focus { outline: none; border-color: var(--accent-bord); }
.gate button {
  width: 100%; background: var(--accent); border: none; color: var(--sur-plein, #fff);
  font-family: var(--f); font-weight: 650; font-size: 13.5px;
  letter-spacing: .02em; padding: 11px; border-radius: var(--r-s); cursor: pointer;
}
.gate button:hover { filter: brightness(1.08); }
/* `.gate .voir-mdp` et non `.voir-mdp` : cette etiquette-ci est DANS .gate,
   donc `.gate label` (0,2,0) l'emportait sur elle (0,1,0) et lui imposait les
   capitales et le `display: block` des etiquettes de champ. */
.gate .voir-mdp {
  display: flex; align-items: center; gap: .5em;
  font-size: 12px; color: var(--texte-3); font-weight: normal;
  margin: -6px 0 14px; cursor: pointer; text-transform: none; letter-spacing: 0;
}
.gate .voir-mdp input {
  width: auto; margin: 0; cursor: pointer;
  accent-color: var(--accent);   /* sinon la case reste blanche sur fond noir */
}

/* ============================================================== messages */
.flash {
  position: fixed; top: 18px; left: 50%; transform: translateX(-50%);
  background: var(--carte); border: 1px solid var(--bord-fort);
  border-radius: var(--r-s); box-shadow: var(--ombre-forte);
  padding: 10px 18px; font-size: 13px;
  max-width: min(90vw, 560px); z-index: 70;
}
.flash.bad { border-color: var(--crit); color: var(--crit); }

/* ====================================== page Système et page Réglages */
header {
  background: var(--carte); border-bottom: 1px solid var(--bord);
  padding: 12px 18px; display: flex; align-items: center; gap: 14px;
  flex-wrap: wrap; position: sticky; top: 0; z-index: 20;
}
header h1 {
  font-size: 15px; font-weight: 700; letter-spacing: 0; text-transform: none;
}
header h1 .jeu { color: var(--accent); }

/* `:not(.reg-liste)` : sur /reglages, la liste des réglages EST un <main>, et
   c'est reglages.css qui la gouverne. Sans cette exclusion, elle héritait ici
   d'une largeur bornée et d'un empilement en colonne. */
main:not(.reg-liste) {
  flex: 1; width: 100%; max-width: 1000px; margin: 0 auto;
  padding: 18px 18px 48px;
  display: flex; flex-direction: column; gap: 14px;
}
section {
  background: var(--carte); border: 1px solid var(--bord);
  border-radius: var(--r); box-shadow: var(--ombre);
}
section > h2 {
  font-size: 12px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
  color: var(--texte-3); padding: 11px 16px; border-bottom: 1px solid var(--bord);
}
.corps { padding: 16px; }
.actions { display: flex; gap: 8px; flex-wrap: wrap; }

.lignes {
  display: grid; grid-template-columns: auto 1fr; gap: 7px 18px; font-size: 13.5px;
}
.lignes dt { color: var(--texte-3); white-space: nowrap; }
.lignes dd { color: var(--texte); }
.muet { color: var(--texte-3); }

.pastille {
  display: inline-block; padding: 2px 8px; border-radius: 999px;
  font-size: 11px; font-weight: 600; letter-spacing: .03em; text-transform: uppercase;
}
.p-ok    { background: var(--ok-fond);     color: var(--ok); }
.p-lamp  { background: var(--accent-fond); color: var(--accent); }
.p-alert { background: var(--crit-fond);   color: var(--crit); }

table { width: 100%; border-collapse: collapse; font-size: 13px; }
th {
  text-align: left; font-size: 11px; letter-spacing: .07em; text-transform: uppercase;
  color: var(--texte-3); font-weight: 600;
  padding: 7px 10px; border-bottom: 1px solid var(--bord);
}
td { padding: 7px 10px; border-bottom: 1px solid var(--bord); }
tr:last-child td { border-bottom: none; }
td.n { font-family: var(--fm); }
td.v { font-family: var(--fm); color: var(--texte-2); }

.avis {
  padding: 11px 14px; border-radius: var(--r-s); font-size: 13px;
  border: 1px solid var(--bord); background: var(--creux);
  color: var(--texte-2); line-height: 1.5;
}
.avis.chaud   { border-color: var(--warn);        color: var(--warn); }
.avis.mauvais,
.avis.rouge   { border-color: var(--crit);        color: var(--crit); }
.avis.bon     { border-color: var(--accent-bord); color: var(--accent); }
.avis strong  { color: var(--texte); }

/* ========================================================== étroitesse */
@media (max-width: 640px) {
  .masthead { padding: 14px 14px; }
  .vitals { gap: 16px; }
  .section-label, .log-bar { padding-left: 14px; padding-right: 14px; }
  .log, #journal, .backups, .bays, .pods { margin-left: 0; padding-left: 14px; padding-right: 14px; }
  .log, #journal, .backups { margin-left: 14px; margin-right: 14px; padding-left: 12px; padding-right: 12px; }
  .console-head, .console-body { padding-left: 14px; padding-right: 14px; }
  main { padding: 14px 14px 40px; }
}

/* Une baie dont le jeu a sa page : toute la carte mène à elle. Les boutons
   d'action ont quitté l'accueil le 2026-08-24 — ils vivent dans l'onglet
   Serveur de la page du jeu, et les avoir aux deux endroits, c'était deux
   endroits à tenir pour le même geste. */
.bay.lien { cursor: pointer; }
.bay.lien:hover, .bay.lien:focus-visible {
  border-color: var(--accent-bord);
  box-shadow: var(--ombre-forte);
}
.bay .ouvrir {
  font-size: 12.5px; color: var(--texte-3);
  transition: color .15s;
}
.bay.lien:hover .ouvrir { color: var(--accent); }

/* ═══════════════════════════════════════════════════ IDENTITÉ DE LA CONSOLE
 *
 * Les sept jeux ont chacun leur accent, leur géométrie et leur trame. La
 * console n'avait rien : pas de `data-vue`, donc l'accent turquoise par défaut
 * de style.css, et le même rendu partout.
 *
 * On ne touche PAS à son HTML. Cette feuille n'est chargée que par les quatre
 * pages du panneau et charge en dernier : elle redéfinit les jetons pour elle
 * seule, depuis /opt/jeux/site.
 *
 * LA DIRECTION : la salle des machines. La console n'est pas un huitième jeu,
 * c'est l'instrument qui les regarde — cadran de laiton, voyants sous verre,
 * panneau perforé. D'où un laiton chaud, une géométrie plus serrée que celle
 * des jeux (un panneau de commande est plus carré qu'une fiche de jeu), et des
 * chiffres à chasse fixe partout où une valeur se compare à elle-même.
 * ═══════════════════════════════════════════════════════════════════════════ */

/* ------------------------------------------------------------------ jetons */
:root {
  /* L'accent de la console : celui de la vue d'ensemble du superviseur, qui
     est aussi le turquoise par defaut de style.css. Le laiton essaye ici a
     ete juge trop present — sept cartes de la meme couleur chaude, ca finit
     par tout aplatir. Le turquoise laisse aux tuiles de jeu la couleur, et
     ne garde pour la console que ce qui est a elle.
     `--accent-2` DOIT etre defini : la trame le referrence, et un `var()`
     indefini dans un `color-mix()` rend toute la declaration invalide. */
  --accent: #0B8C7A;
  --accent-2: #3B5BDB;
  --accent-fond: color-mix(in srgb, var(--accent) 11%, transparent);
  --accent-bord: color-mix(in srgb, var(--accent) 40%, transparent);
  --halo:   color-mix(in srgb, var(--accent) 13%, transparent);
  --halo-2: color-mix(in srgb, var(--accent-2) 11%, transparent);

  /* Plus serré que les jeux : Palworld est à 18 px, la console à 10. */
  --r-panneau: 10px;
  --r-organe: 7px;

  /* Panneau perforé : une perforation tous les 26 px, et un rail horizontal
     tous les quatre rangs, comme les trous de fixation d'une baie 19 pouces. */
  --motif:
    radial-gradient(circle at 50% 50%,
      color-mix(in srgb, var(--accent) 34%, transparent) 0 1.2px, transparent 1.8px),
    repeating-linear-gradient(0deg,
      color-mix(in srgb, var(--accent-2) 13%, transparent) 0 1px, transparent 1px 104px);
  --motif-taille: 26px 26px, auto;
  --motif-opacite: .5;

  /* L'encre des etiquettes : les petites capitales des cadrans et des titres
     de section. `--texte-3` seul rend 3,43:1 en clair, sous AA — et le mêler
     d'accent ne suffit PAS : le turquoise clair plafonne a 4,16:1, meme pur.
     C'est vers `--texte-2` qu'il faut mêler, qui bascule avec le theme. Pire
     cas mesure sur les huit accents — la console et les sept jeux, puisque
     les tuiles portent le leur : 5,11:1 en clair, 7,12:1 en sombre.
     Accessoirement la bonne couleur : sur une face d'instrument, les legendes
     sont gravees dans la teinte de l'appareil. */
  --encre-etiquette: color-mix(in srgb, var(--texte-2) 50%, var(--accent));
}
:root[data-theme="sombre"],
html:not([data-theme="clair"]) body.auto-sombre {
  --accent: #2FD4BC;
  --accent-2: #7C9BFF;
  --motif-opacite: .42;
}

/* --------------------------------------------------------------- la trame */
/* `.principal` du superviseur ne convient pas : style.css en fait une colonne
   flex, et theme.css ne remonte au-dessus de ses pseudo-éléments que `header`
   et `main` — or l'accueil et la porte de connexion vivent dans des `<div>` de
   premier niveau. On peint donc sur le body, en couche FIXE : une console se
   lit en défilant, et un fond qui glisse avec le texte fatigue. */
body::before {
  content: ""; position: fixed; inset: 0; pointer-events: none; z-index: 0;
  background: var(--motif); background-size: var(--motif-taille);
  opacity: var(--motif-opacite);
  -webkit-mask-image: linear-gradient(180deg, #000 0%, #000 62%, transparent 100%);
          mask-image: linear-gradient(180deg, #000 0%, #000 62%, transparent 100%);
}
/* Le halo : deux foyers de lumière, l'un d'accent en haut à gauche, l'autre de
   la teinte secondaire en haut à droite. Même dispositif que `.principal::after`
   des pages de jeu, posé ici sur le body. */
body::after {
  content: ""; position: fixed; inset: 0; pointer-events: none; z-index: 0;
  background:
    radial-gradient(72% 54% at 6% -12%,  var(--halo),   transparent 66%),
    radial-gradient(54% 44% at 97% -4%,  var(--halo-2), transparent 68%);
}
/* Sans cette ligne, tout ce qui n'est ni `header` ni `main` passe SOUS les deux
   couches. `.console`, en `position:fixed` et `z-index:60`, garde les siens :
   sa spécificité de classe l'emporte sur ce sélecteur. */
body > div { position: relative; z-index: 1 }

/* ------------------------------------------------------------- géométrie */
.bay, .pod, section, .gate form, .backups, .log, #journal, .flash, .console {
  border-radius: var(--r-panneau);
}
.signout, .retour, .controls button, .console-head button, button.act,
.gate button, select, .gate input, input, textarea {
  border-radius: var(--r-organe);
}

/* --------------------------------------------------------------- bandeau */
/* Il était un aplat de `--carte` avec un filet gris. Il devient la face de
   l'instrument : un filet d'accent en tête, une lumière rasante, et le fond
   qui se dégrade vers le corps de la page. */
.masthead, header {
  position: relative;
  background:
    linear-gradient(180deg,
      color-mix(in srgb, var(--accent) 7%, var(--carte)) 0%,
      var(--carte) 78%);
  border-bottom-color: color-mix(in srgb, var(--bord) 62%, var(--accent));
}
.masthead::before, header::before {
  content: ""; position: absolute; left: 0; right: 0; top: 0; height: 2px;
  background: linear-gradient(90deg,
    var(--accent) 0%,
    color-mix(in srgb, var(--accent) 45%, transparent) 38%,
    transparent 72%);
}
.ident h1, header h1 { letter-spacing: -.015em }
/* La pastille qui précède le titre : le repère de la console, comme le trait
   d'accent qui ouvre le titre d'une page de jeu. */
.ident h1::before, header h1::before {
  content: ""; display: inline-block; vertical-align: -1px;
  width: 3px; height: 15px; margin-right: 9px; border-radius: 2px;
  background: var(--accent);
}

/* Les relevés du bandeau : des cadrans. Chasse fixe et chiffres tabulaires —
   une valeur qui varie ne doit pas faire danser celles d'à côté. */
.vital .v, .readout .v, .backup-row .s, .console-head .clock {
  font-variant-numeric: tabular-nums;
}
.vital .k { color: var(--encre-etiquette) }
.meter {
  height: 5px; border-radius: 3px;
  background: color-mix(in srgb, var(--creux) 70%, var(--bord));
  box-shadow: inset 0 1px 2px rgb(0 0 0 / .28);
}
.meter span {
  background: linear-gradient(90deg,
    color-mix(in srgb, var(--accent) 62%, transparent), var(--accent));
  border-radius: 3px;
  box-shadow: 0 0 7px var(--accent-bord);
}

/* ------------------------------------------------------ titres de section */
/* Le filet fuyant devient une graduation : un tiret d'accent, puis le trait. */
.section-label { color: var(--encre-etiquette) }
.section-label::before {
  content: ""; width: 14px; height: 2px; border-radius: 1px;
  background: var(--accent); flex: 0 0 auto;
}
.section-label::after {
  background: linear-gradient(90deg,
    color-mix(in srgb, var(--bord) 40%, var(--accent)), var(--bord) 30%);
}

/* --------------------------------------------------------------- les baies */
/* Une baie en marche porte un rail d'accent sur sa tranche gauche — on repère
   d'un coup d'œil ce qui tourne, sans lire une seule ligne. */
.bay, .pod { position: relative; overflow: hidden; }
.bay::before, .pod::before {
  content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 3px;
  background: var(--accent);
  transform: scaleX(0); transform-origin: left;
  opacity: 1;
  transition: transform .25s ease, opacity .25s ease;
}
.bay.running::before, .pod.up::before { transform: scaleX(1) }

/* Une tuile de jeu garde son rail même à l'arrêt, en veilleuse : la COULEUR
   dit quel jeu c'est, l'INTENSITÉ dit s'il tourne. Sans cela, un serveur
   éteint perdait toute identité et les trois tuiles arrêtées se ressemblaient
   — ce qu'on reprochait justement à la version d'avant. */
.bay[data-jeu]::before { transform: scaleX(1); opacity: .3 }
.bay[data-jeu].running::before { opacity: 1 }
.bay.running, .pod.up {
  background:
    linear-gradient(105deg,
      color-mix(in srgb, var(--accent) 5%, var(--carte)) 0%,
      var(--carte) 52%);
}

/* Le voyant sous verre : le creux gagne une ombre interne, l'allumé un
   reflet en haut à gauche. C'est la signature de la console — elle mérite
   d'être regardée de près. */
.lamp {
  width: 15px; height: 15px;
  box-shadow: inset 0 1px 2px rgb(0 0 0 / .45);
  position: relative;
}
.bay.running .lamp::after, .pod.up .dot::after {
  content: ""; position: absolute; left: 22%; top: 18%;
  width: 32%; height: 26%; border-radius: 50%;
  background: rgb(255 255 255 / .5);
}
.pod.up .dot { position: relative }

/* La trame du jeu sur sa tuile. `--motif` descend par les jumeaux
   `[data-jeu]` de theme.css ; on la peint sur `::after` — `::before` porte
   deja le rail — et on la retient : les opacites sont reglees pour une page
   entiere, sur une carte de 278 px elles couvriraient le texte. Le masque la
   fait mourir avant les commandes, en bas. */
.bay[data-jeu]::after {
  content: ""; position: absolute; inset: 0; pointer-events: none; z-index: 0;
  background: var(--motif, none);
  background-size: var(--motif-taille, auto);
  opacity: calc(var(--motif-opacite, 1) * .5);
  -webkit-mask-image: linear-gradient(180deg, #000 0%, transparent 74%);
          mask-image: linear-gradient(180deg, #000 0%, transparent 74%);
}
/* Le contenu repasse au-dessus : sans cela la trame recouvre les releves. */
.bay[data-jeu] > * { position: relative; z-index: 1 }

/* Une pastille de la couleur du jeu devant son nom : la tuile s'identifie
   même quand le voyant est éteint. */
.bay[data-jeu] .bay-title h2::after {
  content: ""; display: inline-block; vertical-align: middle;
  width: 6px; height: 6px; border-radius: 50%; margin-left: 8px;
  background: var(--accent);
}

.readout { border-top-color: color-mix(in srgb, var(--bord) 74%, var(--accent)) }
.readout .k { color: var(--encre-etiquette) }

/* ------------------------------------------------------------- le journal */
/* Un journal, c'est un rouleau : fond creusé, filet d'accent à gauche. */
.log, #journal, .console-body {
  background: color-mix(in srgb, var(--creux) 82%, var(--fond));
  border-left: 2px solid color-mix(in srgb, var(--accent) 34%, transparent);
}

/* ------------------------------------------------------------ la connexion */
/* La porte : la carte se pose dans le halo, filet d'accent en tête. */
.gate form { position: relative; overflow: hidden; }
.gate form::before {
  content: ""; position: absolute; left: 0; right: 0; top: 0; height: 2px;
  background: linear-gradient(90deg, var(--accent), var(--accent-2));
}
.gate h1::before {
  content: ""; display: block; width: 26px; height: 2px; border-radius: 1px;
  background: var(--accent); margin-bottom: 12px;
}

/* --------------------------------------------------------------- pastilles */
.p-lamp { box-shadow: inset 0 0 0 1px var(--accent-bord) }

@media (prefers-reduced-motion: reduce) {
  .bay::before, .pod::before { transition: none }
}
