/* ============================================================================
 * GamePanel — Vanguard II
 *
 * Socle visuel unique du panel. Évolution de la direction Vanguard : mêmes
 * codes couleur (noir profond, or, bleu acier), hiérarchie, densité et
 * typographie revues.
 *
 * Chargé en dernier : ce fichier redéfinit les tokens de style.css et de
 * v3/base.css, puis reprend les composants qui changent de forme. Les six
 * thèmes saisonniers et le mode legacy ont été retirés — plus de sélecteur
 * « umbrella » à maintenir, plus de règle à décliner deux fois.
 *
 * Trois principes, tenus partout :
 *   - la couleur porte du sens (or = action, acier = information, vert =
 *     en ligne, ambre = vigilance, rouge = incident) ; aucun dégradé décoratif ;
 *   - les chiffres sont en mono, pour qu'ils ne dansent pas quand ils changent
 *     en direct ;
 *   - aucune animation sur un élément que le temps réel réécrit, sinon elle
 *     redémarre à chaque tick et se voit comme un clignotement.
 * ========================================================================== */

@import url('https://fonts.googleapis.com/css2?family=Saira:wght@400;500;600;700&family=IBM+Plex+Sans:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;700&display=swap');

/* ============================================================================
   1. TOKENS
   ========================================================================== */

:root,
body.ui-v3,
body.ui-v3.theme-direction-vanguard {
  /* Surfaces */
  --bg-0: #0A0C12;          /* fond global */
  --bg-1: #10141D;          /* panneaux et cartes */
  --bg-2: #151A25;          /* tuiles et surfaces élevées */
  --bg-3: #1F2636;          /* survols */

  --border: #1F2636;
  --border-strong: #2A3348;
  --border-subtle: #171D2A;

  /* Texte — contraste vérifié sur --bg-1 : 4.5:1 minimum jusqu'à --text-2 */
  --text-0: #F2EFE8;        /* crème, texte principal */
  --text-1: #C6CDDB;        /* texte secondaire */
  --text-2: #8A93A6;        /* libellés et légendes */
  --text-3: #616B80;        /* désactivé */

  /* Accents */
  --primary: #4A9EFF;                       /* acier — information */
  --primary-dim: rgba(74, 158, 255, 0.35);
  --primary-bg: rgba(74, 158, 255, 0.10);
  --primary-glow: rgba(74, 158, 255, 0.40);

  --secondary: #C89A3A;                     /* or — action */
  --secondary-dim: rgba(200, 154, 58, 0.35);
  --secondary-bg: rgba(200, 154, 58, 0.10);
  --secondary-glow: rgba(200, 154, 58, 0.40);

  --accent: #4A9EFF;
  --accent-dim: rgba(74, 158, 255, 0.30);
  --accent-bg: rgba(74, 158, 255, 0.10);

  /* États */
  --green: #10C97C;
  --green-bg: rgba(16, 201, 124, 0.10);
  --green-dim: rgba(16, 201, 124, 0.32);
  --green-glow: rgba(16, 201, 124, 0.40);

  --amber: #F0A22E;
  --amber-bg: rgba(240, 162, 46, 0.10);
  --amber-dim: rgba(240, 162, 46, 0.32);

  --red: #D23A3A;
  --red-bg: rgba(210, 58, 58, 0.10);
  --red-dim: rgba(210, 58, 58, 0.32);

  --blue: #4A9EFF;
  --blue-bg: rgba(74, 158, 255, 0.10);
  --blue-dim: rgba(74, 158, 255, 0.32);

  --status-online: #10C97C;
  --status-online-bg: rgba(16, 201, 124, 0.10);
  --status-online-glow: rgba(16, 201, 124, 0.40);
  --status-offline: #616B80;
  --status-offline-bg: rgba(97, 107, 128, 0.10);
  --status-warn: #F0A22E;
  --status-warn-bg: rgba(240, 162, 46, 0.10);

  /* Typographie */
  --font-hud: 'Saira', 'Segoe UI', sans-serif;
  --font-body: 'IBM Plex Sans', system-ui, sans-serif;
  --font-mono: 'JetBrains Mono', 'Fira Code', Menlo, monospace;

  /* Géométrie */
  --radius-sm: 7px;
  --radius: 9px;
  --radius-lg: 11px;

  --sidebar-bg: #0C0F17;
  --sidebar-w: 248px;
  --hero-bg: #10141D;
  --login-glow-a: rgba(74, 158, 255, 0.10);
  --login-glow-b: rgba(200, 154, 58, 0.08);
}

body.ui-v3 {
  font-family: var(--font-body);
  font-size: 14px;
  background: var(--bg-0);
  color: var(--text-0);
}

/* ============================================================================
   2. TYPOGRAPHIE
   ========================================================================== */

body.ui-v3 .page-title,
body.ui-v3 .card-title,
body.ui-v3 .section-title,
body.ui-v3 .modal-title,
body.ui-v3 h1, body.ui-v3 h2, body.ui-v3 h3 {
  font-family: var(--font-hud);
  font-weight: 600;
  letter-spacing: 0.01em;
  text-transform: none;
}

body.ui-v3 .page-title { font-size: 21px; }
body.ui-v3 .page-title span { color: var(--secondary); }

/* Emplacement d icone dans un titre de page.

   En inline-flex, et non en passant .page-title en flex : ce conteneur porte
   un <span> de mise en couleur (`DASH<span>BOARD</span>`) que le mode flex
   transformerait en element separe, avec une gouttiere au milieu du mot.

   :empty le masque tant que l icone n est pas chargee, sinon un creux de 22px
   precede le titre pendant le chargement. */
body.ui-v3 .page-title-icon {
  display: inline-flex;
  align-items: center;
  width: 22px;
  height: 22px;
  margin-right: 9px;
  vertical-align: -3px;
}

body.ui-v3 .page-title-icon:empty { display: none; }

body.ui-v3 .sidebar-logo-text {
  font-family: var(--font-hud);
  font-weight: 700;
  letter-spacing: 0.10em;
  font-size: 15px;
}

/* Les valeurs qui bougent en direct restent en mono : elles gardent la même
   largeur d'un tick à l'autre au lieu de faire respirer la mise en page. */
body.ui-v3 .stat-value,
body.ui-v3 .text-mono,
body.ui-v3 code {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
}

body.ui-v3 .stat-label {
  font-family: var(--font-mono);
  font-size: 9.5px;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--text-2);
}

/* ============================================================================
   3. SIDEBAR
   ========================================================================== */

body.ui-v3 #sidebar {
  background: var(--sidebar-bg);
  border-right: 1px solid var(--border);
}

body.ui-v3 .sidebar-section { border-bottom: 1px solid var(--border-subtle); }
body.ui-v3 .sidebar-section:last-of-type { border-bottom: none; }

body.ui-v3 .sidebar-section-label {
  font-family: var(--font-hud);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.16em;
  color: var(--secondary);
  opacity: 0.75;
}

body.ui-v3 .nav-item {
  border-radius: var(--radius-sm);
  margin: 1px 6px;
  font-size: 13.5px;
  transition: background 150ms ease, color 150ms ease;
}

body.ui-v3 .nav-item:hover { background: var(--bg-2); color: var(--text-0); }

body.ui-v3 .nav-item.active {
  background: var(--primary-bg);
  color: var(--primary);
  font-weight: 600;
}

/* ============================================================================
   4. TOPBAR
   ========================================================================== */

body.ui-v3 #topbar {
  background: var(--sidebar-bg);
  border-bottom: 1px solid var(--border);
}

body.ui-v3 #topbar-system .sys-chip,
body.ui-v3 #topbar-system > div {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
}

/* ============================================================================
   5. HERO — état de la flotte
   ========================================================================== */

body.ui-v3 .vg2-hero {
  position: relative;
  padding: 20px 22px;
  margin-bottom: 20px;
  background: var(--bg-1);
  border: 1px solid var(--border);
  border-radius: 12px;
  overflow: hidden;
}

/* Filet or en haut : la seule ligne décorative de la page. Statique, donc
   insensible aux réécritures DOM du temps réel. */
body.ui-v3 .vg2-hero::before {
  content: '';
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 1px;
  background: var(--secondary);
  opacity: 0.55;
}

body.ui-v3 .vg2-hero-head {
  display: flex;
  align-items: flex-end;
  gap: 14px;
  flex-wrap: wrap;
  margin-bottom: 18px;
}

body.ui-v3 .vg2-hero-title {
  font-family: var(--font-hud);
  font-size: 20px;
  font-weight: 600;
  color: var(--text-0);
}

body.ui-v3 .vg2-hero-sub {
  font-size: 12.5px;
  color: var(--text-2);
  margin-top: 3px;
}

body.ui-v3 .vg2-hero-spacer { flex: 1 1 auto; }

body.ui-v3 .vg2-hero-cta {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 44px;
  padding: 0 18px;
  background: var(--secondary);
  border: 1px solid var(--secondary);
  border-radius: 8px;
  color: var(--bg-0);
  font-family: var(--font-body);
  font-size: 13.5px;
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
  transition: filter 150ms ease;
}

body.ui-v3 .vg2-hero-cta:hover { filter: brightness(1.08); }

body.ui-v3 .vg2-hero-tiles {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(170px, 100%), 1fr));
  gap: 12px;
}

body.ui-v3 .vg2-tile {
  min-width: 0;
  padding: 13px 14px;
  background: var(--bg-2);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
}

body.ui-v3 .vg2-tile-label {
  font-family: var(--font-mono);
  font-size: 9.5px;
  letter-spacing: 0.14em;
  color: var(--text-2);
}

body.ui-v3 .vg2-tile-value {
  display: flex;
  align-items: baseline;
  gap: 4px;
  margin-top: 6px;
  font-family: var(--font-hud);
  font-size: 29px;
  font-weight: 600;
  line-height: 1;
  color: var(--text-0);
  font-variant-numeric: tabular-nums;
}

body.ui-v3 .vg2-tile-value.green { color: var(--green); }
body.ui-v3 .vg2-tile-value.amber { color: var(--amber); }
body.ui-v3 .vg2-tile-value.red   { color: var(--red); }

body.ui-v3 .vg2-tile-unit {
  font-family: var(--font-hud);
  font-size: 15px;
  font-weight: 400;
  color: var(--text-2);
}

body.ui-v3 .vg2-tile-bar {
  height: 4px;
  border-radius: 2px;
  background: var(--bg-3);
  margin-top: 11px;
  overflow: hidden;
}

body.ui-v3 .vg2-tile-bar > span {
  display: block;
  height: 100%;
  background: var(--primary);
  transition: width 400ms ease;
}

body.ui-v3 .vg2-tile-bar > span.green { background: var(--green); }
body.ui-v3 .vg2-tile-bar > span.amber { background: var(--amber); }
body.ui-v3 .vg2-tile-bar > span.red   { background: var(--red); }

body.ui-v3 .vg2-tile-spark { margin-top: 7px; height: 20px; }
body.ui-v3 .vg2-tile-spark svg { display: block; width: 100%; margin: 0; }

/* ============================================================================
   6. DASHBOARD — colonne principale + rail
   ========================================================================== */

/* Le dashboard etait un flex a deux colonnes : la grille des serveurs a
   gauche, un rail de 330px a droite. Les trois panneaux du rail sont partis
   sur la page Systeme, le dashboard reprend donc toute la largeur et les
   regles .vg2-dash-layout / -main / -rail n'ont plus d'emploi. */

/* Systeme sur deux colonnes.

   La page empilait treize panneaux sur une seule colonne, tous du meme poids :
   pour savoir si quelque chose n allait pas, il fallait derouler jusqu en bas.
   Les jauges restent en tete, pleine largeur, puis on separe ce qui vit — CPU
   par coeur, temps reel, historique, processus — de ce qui demande une
   decision — alertes, sauvegardes, partitions, securite.

   La colonne de gauche est la plus large : elle porte des courbes, qui ont
   besoin d abscisse. `minmax(0, …)` sur les deux pistes evite qu un canvas ou
   un contenu long impose sa largeur minimale et fasse deborder la grille. */
body.ui-v3 #page-system .sys-cols {
  display: grid;
  grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr);
  align-items: start;
  gap: 16px;
}

/* Sous 1200px, deux colonnes de courbes deviennent illisibles : on empile. */
@media (max-width: 1200px) {
  body.ui-v3 #page-system .sys-cols { grid-template-columns: minmax(0, 1fr); }
}

/* Fail2ban et Sessions SSH : deux panneaux courts, cote a cote. */
body.ui-v3 #page-system .sys-duo {
  display: grid;
  grid-template-columns: 1fr 1fr;
  align-items: start;
  gap: 12px;
}

@media (max-width: 900px) {
  body.ui-v3 #page-system .sys-duo { grid-template-columns: 1fr; }
}

body.ui-v3 .vg2-panel {
  background: var(--bg-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  overflow: hidden;
}

body.ui-v3 .vg2-panel-head {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 12px 15px;
  border-bottom: 1px solid var(--border);
}

body.ui-v3 .vg2-panel-title {
  font-family: var(--font-hud);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.12em;
  color: var(--text-1);
}

body.ui-v3 .vg2-panel-count {
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 700;
  color: var(--text-2);
}

body.ui-v3 .vg2-panel-count.alert { color: var(--red); }
body.ui-v3 .vg2-panel-spacer { flex: 1 1 auto; }

body.ui-v3 .vg2-row {
  display: flex;
  gap: 10px;
  padding: 11px 15px;
  border-bottom: 1px solid var(--border-subtle);
}

body.ui-v3 .vg2-row:last-child { border-bottom: none; }

body.ui-v3 .vg2-row-mark {
  flex-shrink: 0;
  width: 3px;
  border-radius: 2px;
  background: var(--text-3);
}

body.ui-v3 .vg2-row-mark.info  { background: var(--primary); }
body.ui-v3 .vg2-row-mark.ok    { background: var(--green); }
body.ui-v3 .vg2-row-mark.warn  { background: var(--amber); }
body.ui-v3 .vg2-row-mark.error { background: var(--red); }

body.ui-v3 .vg2-row-body { min-width: 0; flex: 1 1 auto; }

body.ui-v3 .vg2-row-text {
  font-size: 12.5px;
  color: var(--text-0);
  line-height: 1.45;
  overflow-wrap: anywhere;
}

body.ui-v3 .vg2-row-meta {
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--text-2);
  margin-top: 3px;
}

body.ui-v3 .vg2-row-time {
  flex-shrink: 0;
  width: 48px;
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 700;
  color: var(--secondary);
  font-variant-numeric: tabular-nums;
}

body.ui-v3 .vg2-empty {
  padding: 22px 15px;
  text-align: center;
  font-size: 12.5px;
  color: var(--text-2);
}

/* ============================================================================
   7. CARTES SERVEUR
   ========================================================================== */

body.ui-v3 .server-card {
  position: relative;
  min-width: 0;
  padding: 0;                 /* la marge intérieure vit sur .server-card-inner */
  gap: 0;
  background: var(--bg-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  overflow: hidden;
  box-shadow: none;
  transition: transform 250ms cubic-bezier(0.25, 0.46, 0.45, 0.94),
              border-color 250ms ease,
              box-shadow 250ms ease;
}

/* Le cadre reste neutre : c'est le bandeau de gauche qui porte la couleur du
   jeu, et la pastille d'état qui dit si le serveur tourne. Une bordure entière
   colorée en plus, c'est le même signal répété trois fois. */
body.ui-v3 .server-card.online { border-color: var(--border-strong); }
body.ui-v3 #dash-online-grid .server-card.online { box-shadow: none; }

/* Bandeau d'accent à gauche, dans la couleur du jeu. En pseudo-élément
   statique et jamais animé : un ::after porteur d'animation redémarre à
   chaque réécriture de className et se voit comme un clignotement (bug
   signalé trois fois avant d'être attribué à sa vraie cause). */
body.ui-v3 .server-card::before {
  content: '';
  position: absolute;
  top: 0; left: 0; bottom: 0;
  width: 5px;
  z-index: 1;
  background: var(--game-color, var(--text-3));
}

body.ui-v3 .server-card:not(.online)::before { opacity: 0.4; }

body.ui-v3 .server-card:hover {
  transform: translateY(-3px);
  border-color: var(--secondary-dim);
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.40);
}

body.ui-v3 .server-card-inner {
  min-width: 0;
  padding: 14px 16px 14px 21px;
}

/* Art officielle du jeu, en bandeau derriere l en-tete de la carte.
   Elle etait masquee en V3 (`display:none`) faute de source : les cartes
   n avaient qu un emoji. Les bannieres Steam sont illustratives et tres
   saturees — posees en aplat derriere du texte, elles le rendraient illisible
   et casseraient la direction sombre. On les degrade donc fortement et on les
   efface vers le bas, pour qu il reste une identite reconnaissable sans fond
   d ecran.

   Pas d `overflow:hidden` sur la carte : elle contient des menus en position
   absolue. Le bandeau arrondit lui-meme ses deux coins hauts. */
body.ui-v3 .server-card { position: relative; }

body.ui-v3 .server-card-bg {
  display: block;
  position: absolute;
  top: 0; left: 0; right: 0;
  /* 96px ne montraient que 44 % de l art : mise a l echelle sur la largeur de
     la carte, la banniere Steam fait 219px de haut. Le cadrage etait en outre
     centre a 32 %, ce qui coupait le logotype en deux — les bannieres Steam le
     placent en haut. 120px cadres en haut le montrent en entier. */
  height: 120px;
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  background-image: var(--card-art);
  background-size: cover;
  background-position: center top;
  opacity: 0.34;
  filter: saturate(0.5) contrast(0.9);
  -webkit-mask-image: linear-gradient(to bottom, #000, transparent);
  mask-image: linear-gradient(to bottom, #000, transparent);
  pointer-events: none;
}

/* Le contenu repasse au-dessus du bandeau. */
body.ui-v3 .server-card-inner { position: relative; z-index: 1; }

body.ui-v3 .server-card-name {
  font-family: var(--font-hud);
  font-size: 16px;
  font-weight: 600;
  color: var(--text-0);
}

body.ui-v3 .server-card-game {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-2);
  margin-top: 1px;
}

body.ui-v3 .server-card-icon-wrap {
  width: 42px;
  height: 42px;
  flex-shrink: 0;
  border-radius: var(--radius);
  background: var(--bg-2);
  border: 1px solid var(--border-strong);
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Tuiles de mesure de la carte */
body.ui-v3 .server-card .stats-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(0, 1fr));
  gap: 9px;
  margin-top: 13px;
}

body.ui-v3 .server-card .stat-box {
  min-width: 0;
  padding: 8px 10px;
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}

body.ui-v3 .server-card .stat-value {
  font-family: var(--font-hud);
  font-size: 17px;
  font-weight: 600;
  color: var(--text-0);
  margin-top: 2px;
  font-variant-numeric: tabular-nums;
}

body.ui-v3 .server-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  margin-top: 13px;
}

/* ============================================================================
   8. SERVEURS ARRÊTÉS
   ========================================================================== */

body.ui-v3 .dash-section-header {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 12px;
}

body.ui-v3 .dash-section-title {
  font-family: var(--font-hud);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.14em;
  color: var(--text-1);
}

body.ui-v3 .dash-section-count {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-2);
}

/* Grilles du dashboard, posées au niveau de l'ID.
 *
 * `.servers-grid` de style.css impose `minmax(480px, 1fr)` avec 48 px de
 * gouttière, et une requête média intermédiaire la rétrécit encore. Le
 * résultat : des cartes qui n'occupent pas la largeur disponible. On fixe la
 * grille ici, à la même spécificité que ces règles, pour que le dashboard ait
 * une mise en page déterministe.
 *
 * `min-width: 0` sur les cartes n'est pas cosmétique : sans lui, une adresse
 * de serveur un peu longue pousse la carte hors de sa colonne. */
body.ui-v3 #page-dashboard .dash-section-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(540px, 100%), 1fr));
  gap: 14px;
}

body.ui-v3 #page-dashboard .dash-section-grid .server-card { min-width: 0; }

body.ui-v3 #page-dashboard .dash-offline-grid,
body.ui-v3 .dash-offline-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(320px, 100%), 1fr));
  gap: 10px;
}

/* ============================================================================
   9. BOUTONS ET PASTILLES
   ========================================================================== */

/* Les libellés ne sont plus en capitales : « Redémarrer » se lit plus vite que
   « REDÉMARRER », et la casse naturelle laisse la typographie faire la
   hiérarchie plutôt que le crénage. */
body.ui-v3 .btn {
  height: 40px;
  padding: 0 14px;
  border-radius: 8px;
  border: 1px solid var(--border-strong);
  background: transparent;
  color: var(--text-1);
  font-family: var(--font-body);
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: 0;
  text-transform: none;
  transition: background 150ms ease, border-color 150ms ease, color 150ms ease;
}

body.ui-v3 .btn:hover {
  background: var(--bg-2);
  color: var(--text-0);
  transform: none;
  box-shadow: none;
}

body.ui-v3 .btn-sm { height: 32px; padding: 0 11px; font-size: 12px; }

body.ui-v3 .btn-primary {
  background: var(--primary-bg);
  border-color: var(--primary-dim);
  color: #86C0FF;
}

body.ui-v3 .btn-primary:hover {
  background: rgba(74, 158, 255, 0.18);
  border-color: var(--primary);
  color: #A8D3FF;
  opacity: 1;
}

body.ui-v3 .btn-start {
  background: var(--green-bg);
  border-color: var(--green-dim);
  color: var(--green);
  filter: none;
}

body.ui-v3 .btn-start:hover { background: rgba(16, 201, 124, 0.18); border-color: var(--green); }

body.ui-v3 .btn-stop {
  background: transparent;
  border-color: var(--red-dim);
  color: #E05A5A;
  filter: none;
  box-shadow: none;
}

body.ui-v3 .btn-stop:hover { background: var(--red-bg); border-color: var(--red); }

body.ui-v3 .btn-restart {
  background: transparent;
  border-color: var(--border-strong);
  color: var(--text-1);
  filter: none;
  box-shadow: none;
}

body.ui-v3 .btn-restart:hover { background: var(--bg-2); border-color: var(--secondary-dim); color: var(--text-0); }

body.ui-v3 .btn-update { border-color: var(--secondary-dim); color: var(--secondary); }
body.ui-v3 .btn-update:hover { background: var(--secondary-bg); border-color: var(--secondary); }

body.ui-v3 .status-badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 24px;
  padding: 0 10px;
  border-radius: 12px;
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  background: var(--bg-2);
  border: 1px solid var(--border-strong);
  color: var(--text-2);
}

body.ui-v3 .status-badge.online {
  background: var(--green-bg);
  border-color: var(--green-dim);
  color: var(--green);
}

body.ui-v3 .status-badge.loading {
  background: var(--primary-bg);
  border-color: var(--primary-dim);
  color: var(--primary);
}

body.ui-v3 .status-dot.online {
  background: var(--green);
  box-shadow: 0 0 7px var(--green-glow);
}

body.ui-v3 .status-dot.offline { background: var(--text-3); box-shadow: none; }

/* ============================================================================
   10. CARTES ET FORMULAIRES GÉNÉRIQUES
   ========================================================================== */

body.ui-v3 .card {
  background: var(--bg-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
}

body.ui-v3 .form-input,
body.ui-v3 .form-select {
  height: 40px;
  background: var(--bg-0);
  border: 1px solid var(--border-strong);
  border-radius: 8px;
  color: var(--text-0);
  font-family: var(--font-body);
}

body.ui-v3 .form-input:focus,
body.ui-v3 .form-select:focus { border-color: var(--primary); outline: none; }

body.ui-v3 .console-body {
  background: #070910;
  border-radius: var(--radius);
  font-family: var(--font-mono);
  font-size: 11.5px;
  line-height: 1.7;
}

/* ============================================================================
   11. SURFACES REPRISES DE L'ANCIEN FICHIER DE DIRECTION
   ----------------------------------------------------------------------------
   `v3/direction-vanguard.css` a été supprimé : il faisait le même travail que
   ce fichier, une couche plus tôt dans la cascade, et les deux se disputaient
   les mêmes sélecteurs. Ce qu'il portait d'utile est repris ici.
   ========================================================================== */

/* ---- Login ---- */

body.ui-v3 #login-page {
  background:
    radial-gradient(ellipse 60% 40% at 20% 30%, var(--login-glow-a) 0%, transparent 60%),
    radial-gradient(ellipse 50% 50% at 80% 70%, var(--login-glow-b) 0%, transparent 60%),
    var(--bg-0);
}

body.ui-v3 .login-card {
  background: var(--bg-1);
  border: 1px solid var(--border-strong);
  border-radius: 14px;
}

body.ui-v3 .login-card::before {
  background: linear-gradient(90deg, var(--primary), var(--secondary));
}

body.ui-v3 .login-logo-title { font-family: var(--font-hud); letter-spacing: 0.08em; }
body.ui-v3 .login-logo-title span { color: var(--secondary); }
/* La marque en or.

   Elle heritait de --primary, le bleu du theme, comme la manette avant elle.
   Or l accent de la maison est l or : tous les titres de page l utilisent
   (DASH<span>BOARD</span>, SYS<span>TEME</span>), ainsi que le bouton primaire.
   Seul le logo restait bleu — le mot-symbole « PANEL » compris.

   On ne peut pas se contenter de teinter le conteneur : `.sidebar-logo-mark svg`
   et `.login-logo-mark svg` fixent leur propre couleur dans base.css, donc
   currentColor a l interieur du trace ne suivait pas le parent. Les deux sont
   vises.

   La lueur portee suit la meme teinte : un halo bleu autour d un trace dore
   reproduirait exactement le defaut corrige en #326 sur les badges d etat. */
body.ui-v3 .sidebar-logo-mark,
body.ui-v3 .sidebar-logo-mark svg,
body.ui-v3 .login-logo-mark,
body.ui-v3 .login-logo-mark svg {
  color: var(--secondary);
}

/* La lueur est ANIMEE, pas simplement declaree : style.css fait pulser
   `.sidebar-logo-mark` avec un keyframe `logo-pulse` en violet (rgba(99,102,241)
   vers rgba(139,92,246)), herite d avant la V3 et sans rapport avec la palette.
   Une animation l emporte sur toute declaration normale — poser un `filter` ici
   ne servait donc a rien, la valeur calculee restait violette.

   On remplace l animation, et sa lueur reprend currentColor : elle suivra la
   marque si sa couleur change un jour, au lieu d avoir a etre rejouee.
   Meme principe qu en #326 sur les badges d etat. */
@keyframes vg2LogoPulse {
  0%, 100% { filter: drop-shadow(0 0 6px color-mix(in srgb, currentColor 45%, transparent)); }
  50%      { filter: drop-shadow(0 0 13px color-mix(in srgb, currentColor 72%, transparent)); }
}

body.ui-v3 .sidebar-logo-mark {
  animation: vg2LogoPulse 3s ease-in-out infinite;
}

body.ui-v3 .login-logo-mark {
  filter: drop-shadow(0 0 12px color-mix(in srgb, currentColor 55%, transparent));
}

@media (prefers-reduced-motion: reduce) {
  body.ui-v3 .sidebar-logo-mark { animation: none; filter: drop-shadow(0 0 6px color-mix(in srgb, currentColor 45%, transparent)); }
}

/* Le mot-symbole suit la marque, sinon le verrou porterait deux accents. */
body.ui-v3 .sidebar-logo-text span,
body.ui-v3 .login-logo-title span {
  color: var(--secondary);
}

body.ui-v3 .btn-login {
  height: 46px;
  background: var(--secondary);
  color: var(--bg-0);
  border: none;
  border-radius: 8px;
  font-family: var(--font-body);
  font-size: 14px;
  font-weight: 700;
  letter-spacing: 0;
  text-transform: none;
}

body.ui-v3 .btn-login:hover { filter: brightness(1.08); opacity: 1; transform: none; box-shadow: none; }

/* ---- Modales ---- */

body.ui-v3 .modal {
  background: var(--bg-1);
  border: 1px solid var(--border-strong);
  border-radius: 14px;
}

body.ui-v3 .modal-title {
  font-family: var(--font-hud);
  font-size: 18px;
  font-weight: 600;
  color: var(--text-0);
}

/* ---- Tableaux ---- */

body.ui-v3 .data-table th {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-2);
  border-bottom: 1px solid var(--border-strong);
}

body.ui-v3 .data-table td {
  border-bottom: 1px solid var(--border-subtle);
  font-size: 13px;
}

body.ui-v3 .data-table tr:hover td { background: var(--bg-2); }

/* ---- Barres de défilement ---- */

body.ui-v3 { scrollbar-width: thin; scrollbar-color: var(--border-strong) transparent; }
body.ui-v3 ::-webkit-scrollbar { width: 9px; height: 9px; }
body.ui-v3 ::-webkit-scrollbar-track { background: transparent; }
body.ui-v3 ::-webkit-scrollbar-thumb {
  background: var(--border-strong);
  border-radius: 5px;
}
body.ui-v3 ::-webkit-scrollbar-thumb:hover { background: var(--secondary-dim); }

/* ---- Carte arrêtée : survol discret ---- */

body.ui-v3 .server-card.offline:hover {
  transform: translateY(-1px);
  border-color: var(--border-strong);
  box-shadow: none;
}

/* ============================================================================
   12. CHROME — barre latérale et barre du haut
   ========================================================================== */

/* ---- Bouton de recherche / palette de commandes ---- */

body.ui-v3 .vg2-cmdk-btn {
  display: flex;
  align-items: center;
  gap: 9px;
  width: calc(100% - 20px);
  height: 40px;
  /* La barre latérale est un conteneur flex en colonne : sans ce
     `flex-shrink: 0`, la hauteur n'est qu'une taille de base et le bouton se
     fait écraser à la hauteur de son texte dès que la nav déborde. */
  flex-shrink: 0;
  margin: 14px 10px 4px;
  padding: 0 11px;
  box-sizing: border-box;
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: 8px;
  color: var(--text-2);
  font-family: var(--font-body);
  font-size: 13px;
  text-align: left;
  cursor: pointer;
  transition: border-color 150ms ease, color 150ms ease;
}

body.ui-v3 .vg2-cmdk-btn:hover { border-color: var(--border-strong); color: var(--text-1); }
body.ui-v3 .vg2-cmdk-btn span { flex: 1 1 auto; min-width: 0; }

body.ui-v3 .vg2-kbd {
  flex-shrink: 0;
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--text-3);
  border: 1px solid var(--border-strong);
  border-radius: 4px;
  padding: 2px 5px;
  line-height: 1;
}

/* ---- Pied de barre latérale : identité ---- */

body.ui-v3 #sidebar-user {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-shrink: 0;
  padding: 12px 16px;
  border-top: 1px solid var(--border);
}

body.ui-v3 .vg2-avatar {
  flex-shrink: 0;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--bg-3);
  border: 1px solid var(--border-strong);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-hud);
  font-size: 12px;
  font-weight: 600;
  color: var(--secondary);
}

body.ui-v3 .vg2-user-name { font-size: 12.5px; font-weight: 600; color: var(--text-0); }
body.ui-v3 .vg2-user-role {
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--text-2);
  margin-top: 1px;
}

/* ---- Pastilles de la barre du haut ---- */

body.ui-v3 #topbar-system { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; }

body.ui-v3 .vg2-chip {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  height: 30px;
  padding: 0 10px;
  background: var(--bg-1);
  border: 1px solid var(--border);
  border-radius: 15px;
  white-space: nowrap;
}

body.ui-v3 .vg2-chip-label {
  font-family: var(--font-mono);
  font-size: 9.5px;
  letter-spacing: 0.08em;
  color: var(--text-2);
}

body.ui-v3 .vg2-chip-value {
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 700;
  color: var(--text-0);
  font-variant-numeric: tabular-nums;
}

body.ui-v3 .vg2-chip-value.warn { color: var(--amber); }
body.ui-v3 .vg2-chip-value.alert { color: var(--red); }
body.ui-v3 .vg2-chip-spark { display: flex; align-items: center; }
body.ui-v3 .vg2-chip-spark svg { display: block; margin: 0; }

/* ---- Tuile de serveur arrêté ---- */

body.ui-v3 .mini-tile {
  display: flex;
  align-items: center;
  gap: 11px;
  min-width: 0;
  padding: 11px 13px;
  background: var(--bg-1);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  cursor: pointer;
  transition: border-color 150ms ease, background 150ms ease;
}

body.ui-v3 .mini-tile:hover { border-color: var(--border-strong); background: var(--bg-2); }

body.ui-v3 .mini-tile-icon {
  width: 32px;
  height: 32px;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-sm);
  background: color-mix(in srgb, var(--game-color, #616B80) 12%, transparent);
  border: 1px solid color-mix(in srgb, var(--game-color, #616B80) 28%, transparent);
  color: var(--game-color, var(--text-2));
  font-size: 16px;
}

body.ui-v3 .mini-tile-info { flex: 1 1 auto; min-width: 0; }
body.ui-v3 .mini-tile-name { font-size: 13.5px; font-weight: 600; color: var(--text-1); }
body.ui-v3 .mini-tile-sub {
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--text-2);
  margin-top: 2px;
  overflow-wrap: anywhere;
}

/* Bouton libellé plutôt qu'un chevron nu : « Démarrer » se comprend sans
   survol, et la cible de clic passe de 24 à 34 px de haut.
 *
 * `width: auto` est indispensable : `dashboard-v2.css` définit encore
 * `.mini-tile-play { width: 28px; border-radius: 50% }` — l'ancien bouton rond
 * — sans aucun scope de thème, donc la règle est vivante. Ne pas redéclarer la
 * largeur laissait le libellé écrasé dans 28 px et coupé en plein milieu.
 * Même chose pour le rayon et l'alignement du texte. */
body.ui-v3 .mini-tile-play {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  width: auto;
  height: 34px;
  white-space: nowrap;
  padding: 0 12px;
  background: var(--green-bg);
  border: 1px solid var(--green-dim);
  border-radius: var(--radius-sm);
  color: var(--green);
  font-family: var(--font-body);
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
  transition: background 150ms ease, border-color 150ms ease;
}

body.ui-v3 .mini-tile-play:hover { background: rgba(16, 201, 124, 0.18); border-color: var(--green); }

/* ============================================================================
   13. PALETTE DE COMMANDES
   ========================================================================== */

.gp-cmdk-backdrop {
  position: fixed;
  inset: 0;
  z-index: 10000;
  background: rgba(4, 6, 11, 0.62);
  backdrop-filter: blur(3px);
  display: flex;
  justify-content: center;
  align-items: flex-start;
  padding: 14vh 16px 16px;
}

.gp-cmdk {
  width: min(640px, 100%);
  max-height: 70vh;
  display: flex;
  flex-direction: column;
  background: var(--bg-1);
  border: 1px solid var(--border-strong);
  border-radius: 14px;
  box-shadow: 0 24px 70px rgba(0, 0, 0, 0.6);
  overflow: hidden;
}

.gp-cmdk-search {
  display: flex;
  align-items: center;
  gap: 11px;
  flex-shrink: 0;
  padding: 0 16px;
  height: 56px;
  border-bottom: 1px solid var(--border);
  color: var(--text-2);
}

.gp-cmdk-search input {
  flex: 1 1 auto;
  min-width: 0;
  height: 100%;
  background: none;
  border: none;
  outline: none;
  color: var(--text-0);
  font-family: var(--font-body);
  font-size: 15px;
}

.gp-cmdk-search input::placeholder { color: var(--text-3); }

.gp-cmdk-kbd {
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--text-2);
  background: var(--bg-2);
  border: 1px solid var(--border-strong);
  border-radius: 4px;
  padding: 2px 6px;
  line-height: 1.3;
}

.gp-cmdk-list {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  padding: 7px;
}

.gp-cmdk-item {
  display: flex;
  align-items: center;
  gap: 11px;
  width: 100%;
  height: 44px;
  padding: 0 10px;
  box-sizing: border-box;
  background: none;
  border: none;
  border-radius: 8px;
  color: var(--text-1);
  font-family: var(--font-body);
  font-size: 13.5px;
  text-align: left;
  cursor: pointer;
}

.gp-cmdk-item.active { background: var(--primary-bg); color: var(--text-0); }

.gp-cmdk-icon {
  flex-shrink: 0;
  width: 26px;
  height: 26px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 6px;
  background: var(--bg-2);
  border: 1px solid var(--border);
  color: var(--text-2);
}

.gp-cmdk-icon svg { width: 14px; height: 14px; }
.gp-cmdk-item.active .gp-cmdk-icon { border-color: var(--primary-dim); color: var(--primary); }
.gp-cmdk-icon.ok { color: var(--green); }
.gp-cmdk-icon.danger { color: #E05A5A; }
.gp-cmdk-icon.gold { color: var(--secondary); border-color: var(--secondary-dim); }

.gp-cmdk-label {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.gp-cmdk-badge {
  flex-shrink: 0;
  font-family: var(--font-mono);
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-3);
  border: 1px solid var(--border-strong);
  border-radius: 9px;
  padding: 2px 7px;
}

.gp-cmdk-badge.on {
  color: var(--green);
  border-color: var(--green-dim);
  background: var(--green-bg);
}

.gp-cmdk-hint {
  flex-shrink: 0;
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--text-3);
}

.gp-cmdk-empty {
  padding: 28px 16px;
  text-align: center;
  font-size: 13px;
  color: var(--text-2);
}

.gp-cmdk-foot {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-shrink: 0;
  height: 38px;
  padding: 0 16px;
  border-top: 1px solid var(--border);
  font-size: 11px;
  color: var(--text-2);
}

.gp-cmdk-foot span { display: inline-flex; align-items: center; gap: 5px; }
.gp-cmdk-foot-spacer { flex: 1 1 auto; }

@media (max-width: 560px) {
  .gp-cmdk-backdrop { padding-top: 8vh; }
  .gp-cmdk-hint { display: none; }
}

/* ============================================================================
   14. MOUVEMENT
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  body.ui-v3 *,
  body.ui-v3 *::before,
  body.ui-v3 *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
  body.ui-v3 .server-card:hover { transform: none; }
}


/* === Page Système : alignement sur le vocabulaire Vanguard II ===============
   La page redéfinissait ses cartes à la main (fond + bordure + rayon figé à
   12px) au lieu d'utiliser un composant : quand les tokens ont changé, elle
   n'a pas suivi. Ses cartes portent désormais .vg2-panel comme le dashboard.

   .sys-panel ne fait qu'ajouter l'espacement vertical, .vg2-panel n'en portant
   pas — sur le dashboard, l'écart vient du gap de la grille.
   .sys-label unifie les titres de section, qui cohabitaient en deux tailles
   (10px/.1em dans le squelette, 9px/.12em dans les renderers).
   ========================================================================== */
body.ui-v3 #page-system .sys-panel { margin-bottom: 14px; }

body.ui-v3 #page-system .sys-label {
  font-family: var(--font-mono);
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: .1em;
  color: var(--text-3);
}

/* Bandeau de titre facon vg2-panel-head, SANS restructurer le HTML.
   Le premier enfant de la carte est deja son en-tete (un titre, ou une ligne
   titre + compteurs). On le fait deborder de 15px de chaque cote pour qu il
   touche les bords, et on lui pose le trait de separation. La carte perd son
   padding haut, que le bandeau fournit.

   Reserve aux cartes marquees .has-head : les jauges (CPU, RAM, Reseau) ont un
   degrade en position:absolute comme premier enfant, pas un titre. */
body.ui-v3 #page-system .sys-panel.has-head { padding: 0 15px 14px; }
body.ui-v3 #page-system .sys-panel.has-head > :first-child {
  margin: 0 -15px 14px;
  padding: 12px 15px;
  border-bottom: 1px solid var(--border);
}

/* Titre de bandeau : meme voix que .card-title =========================
   Les deux familles de cartes partageaient enfin la meme anatomie (debord,
   filet, padding) mais pas la meme voix : les 13 en-tetes .card-header
   parlaient en Saira 12px/600 sentence-case, les 8 bandeaux Systeme en mono
   10px majuscules grisees. Cote a cote, Systeme restait une autre page.
   On aligne sur .card-title, majoritaire et deja le composant du systeme.

   .sys-label garde sa forme mono/majuscules PARTOUT ailleurs : dans le corps
   des cartes c est une etiquette de donnee, pas un titre. Seule l occurrence
   qui sert de titre de bandeau est requalifiee. */
body.ui-v3 #page-system .sys-panel.has-head > .sys-label:first-child,
body.ui-v3 #page-system .sys-panel.has-head > :first-child > .sys-label {
  font-family: var(--font-hud);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: none;
  color: var(--text-1);
}

/* === .card adopte l anatomie Vanguard II ====================================
   Constat : 15 modules (instance-page, mc-instances, minecraft, profile,
   docker, modpacks, admins, schedules...) utilisent `.card`, ~170 appels, alors
   que le dashboard et la bibliotheque sont passes a `.vg2-panel` / `.lib-card`.
   D ou deux familles visuelles dans le meme panel.

   On aligne `.card` sur `.vg2-panel` par le CSS plutot qu en convertissant les
   170 appels : meme resultat, aucun risque de casser du balisage, et un seul
   endroit a corriger si la direction doit bouger.

   Le bandeau se fait par debord negatif du `.card-header` quand il est premier
   enfant — pas de `:has()`, pas de restructuration : les cartes SANS en-tete
   gardent simplement leur padding normal.

   Pas d `overflow:hidden` ici, contrairement a `.vg2-panel` : certaines cartes
   contiennent des menus et des infobulles en position absolue, les rogner
   serait un degat invisible a l ecriture. */
body.ui-v3 .card {
  border-radius: var(--radius-lg);
  padding: 14px 15px;
}

body.ui-v3 .card > .card-header:first-child {
  margin: -14px -15px 14px;
  padding: 12px 15px;
  border-bottom: 1px solid var(--border);
}

body.ui-v3 .card-title {
  font-family: var(--font-hud);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.12em;
  color: var(--text-1);
}


/* ============================================================================
   DASHBOARD — les serveurs en lignes compactes
   ============================================================================

   Une carte occupait 291px de haut pour quatre chiffres. Six serveurs, et le
   dashboard demandait de derouler pour voir la flotte — alors que c est la page
   ou l on vient justement pour l embrasser d un coup d oeil.

   La carte devient une ligne : identite a gauche, mesures au centre, actions a
   droite. Rien ne change dans le balisage ni dans diffUpdateCard, qui met a
   jour les cartes en place via .status-badge, .server-card-game,
   .stat-box .stat-value, .player-bar-fill et .server-actions — toutes ces
   accroches sont conservees.

   PIEGE RENCONTRE : .server-card-inner est deja un flex EN COLONNE. Poser
   `display:flex` ne suffit pas, il faut `flex-direction: row` — sinon
   `flex: 0 0 268px` fixe une HAUTEUR de 268px au lieu d une largeur, et la
   carte passe a 780px de haut. Mesure a l appui avant correction.
   ========================================================================== */

/* Le selecteur porte #page-dashboard : sans lui,
   `body.ui-v3 #page-dashboard .dash-section-grid` plus haut dans ce meme
   fichier est plus specifique (un id et trois classes) et impose ses colonnes
   de 540px — la grille repassait a deux colonnes sur un ecran large. */
body.ui-v3 #page-dashboard #dash-online-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 10px;
}

body.ui-v3 #dashboard-cards .server-card-inner {
  display: flex;
  flex-direction: row;
  align-items: center;
  flex-wrap: wrap;
  gap: 18px;
  padding: 11px 15px;
}

body.ui-v3 #dashboard-cards .server-card-header {
  flex: 0 0 262px;
  align-items: center;
  gap: 11px;
  margin: 0;
}

body.ui-v3 #dashboard-cards .server-card-icon-wrap { width: 36px; height: 36px; }

/* Les mesures perdent leurs cadres : quatre boites encadrees dans une ligne de
   58px, c est du bruit. Le libelle au-dessus de la valeur suffit a les separer. */
body.ui-v3 #dashboard-cards .server-card .stats-grid {
  flex: 1 1 300px;
  display: flex;
  flex-direction: row;
  gap: 26px;
  margin-top: 0;
}

body.ui-v3 #dashboard-cards .server-card .stat-box {
  min-width: 72px;
  padding: 0;
  background: none;
  border: 0;
}

body.ui-v3 #dashboard-cards .server-card .stat-value { font-size: 15px; }

/* Les boutons partaient au milieu de la deuxieme ligne des que la largeur
   forcait un retour : l adresse, placee APRES eux dans le balisage, les
   poussait. On les remet en dernier avec `order`, et `margin-left: auto`
   absorbe l espace libre — ils collent donc au bord droit, sur une ligne comme
   sur deux. */
body.ui-v3 #dashboard-cards .server-actions {
  flex: 0 0 auto;
  order: 2;
  margin-top: 0;
  margin-left: auto;
}

body.ui-v3 #dashboard-cards .server-card-addr { order: 1; }

/* L adresse de connexion tenait sur une deuxieme ligne, ce qui coutait 58px —
   plus du tiers de la hauteur de la ligne, pour une quinzaine de caracteres. */
body.ui-v3 #dashboard-cards .server-card-addr {
  flex: 0 1 auto;
  min-width: 0;
  padding: 6px 11px;
  font-size: 11px;
}

/* L art passe en texture de fond sur toute la hauteur, effacee vers la droite
   pour laisser les mesures lisibles. Le bandeau de 120px du haut n avait plus
   de sens sur une ligne de 58px. */
body.ui-v3 #dashboard-cards .server-card-bg {
  height: 100%;
  border-radius: var(--radius-lg);

  /* `cover` etirait l art sur toute la ligne : 1400x81 a partir d une banniere
     460x215, soit un zoom de 8,6x dans une bande horizontale. On ne voyait plus
     un jeu, on voyait un aplat flou.

     L image est donc mise a la hauteur de la ligne, ancree a gauche, sans
     repetition : elle garde son rapport et reste entiere. Elle occupe environ
     173px — 81 de haut par 2.14 — quelle que soit la largeur de la ligne, donc
     rien ne peut plus s etirer.

     Le masque est en PIXELS et non en pourcentage : un pourcentage se calcule
     sur la largeur de la ligne, qui varie de 700 a 1500px selon l ecran, et
     l effacement se serait promene par rapport a une image de largeur fixe. */
  background-size: auto 100%;
  background-position: left center;
  background-repeat: no-repeat;
  opacity: 0.42;
  -webkit-mask-image: linear-gradient(90deg, #000 0px, #000 112px, transparent 208px);
  mask-image: linear-gradient(90deg, #000 0px, #000 112px, transparent 208px);
}

/* ---- Serveurs arretes : meme langage, meme art, toujours compacts ----------

   Ils etaient de petites tuiles sans art, visiblement de seconde classe — alors
   que ce sont justement celles sur lesquelles on clique pour demarrer quelque
   chose. Elles prennent l art de leur jeu, desaturee.

   Elles restent en plusieurs colonnes : les passer en pleine largeur les rendait
   plus visibles mais COUTAIT de la hauteur — quatre lignes empilees au lieu de
   deux rangees de trois. Mesure : 1284px avant, 1193px avec elles en colonnes,
   et davantage en pleine largeur. La densite et l equite se contredisaient ici,
   l art tranche sans rien coûter. */
body.ui-v3 #page-dashboard #dash-offline-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(310px, 1fr));
  gap: 10px;
}

body.ui-v3 #dash-offline-grid .mini-tile {
  position: relative;
  overflow: hidden;
  display: flex;
  align-items: center;
  gap: 13px;
  padding: 10px 14px;
  border-radius: var(--radius-lg);
}

body.ui-v3 #dash-offline-grid .mini-tile::before {
  content: '';
  position: absolute;
  inset: 0;
  background-image: var(--card-art);
  background-size: auto 100%;
  background-position: left center;
  background-repeat: no-repeat;
  opacity: 0.34;
  filter: saturate(0.30);
  -webkit-mask-image: linear-gradient(90deg, #000 0px, #000 96px, transparent 184px);
  mask-image: linear-gradient(90deg, #000 0px, #000 96px, transparent 184px);
  pointer-events: none;
}

body.ui-v3 #dash-offline-grid .mini-tile > * { position: relative; }
body.ui-v3 #dash-offline-grid .mini-tile-info { flex-grow: 1; min-width: 0; }


/* Liste des sauvegardes, en grille de dossiers.

   Le panneau vivait dans la colonne d exploitation et y pesait plus du double
   de la colonne d en face : la moitie basse de la page devenait une colonne
   solitaire avec un grand vide a cote. Il est passe en pleine largeur, et ses
   groupes — un par dossier scanne, cinq en production — s alignent desormais
   cote a cote au lieu de s empiler.

   `align-items: start` est indispensable : sans lui, un groupe de deux fichiers
   s etire a la hauteur du plus long et la grille se remplit de vide. */
body.ui-v3 #page-system #sys-backup-list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
  align-items: start;
  gap: 14px 16px;
}

/* La barre de retention pilote tous les groupes a la fois : elle traverse. */
body.ui-v3 #page-system .sys-bk-retention { grid-column: 1 / -1; }
