/* ============================================================
   NIGHTCUBE — vitrine
   Régie de club en orbite : noir spatial, filaire néon cyan.
   ============================================================ */

:root {
  --bg: #05060a;
  --bg-2: #070910;
  --panel: rgba(255, 255, 255, 0.022);
  --panel-solid: #0a0d16;
  --line: rgba(148, 178, 214, 0.13);
  --line-soft: rgba(148, 178, 214, 0.07);
  --ink: #e8eaf2;
  --muted: #8d94ab;
  --faint: #7a8199; /* AA : 5.2:1 sur #05060a, 5.0:1 sur panneau */
  --cyan: #2be2ff;
  --cyan-deep: #0fb8d6;
  --cyan-glow: rgba(43, 226, 255, 0.55);
  --cyan-dim: rgba(43, 226, 255, 0.14);
  --violet: #7c6cff;
  --violet-dim: rgba(124, 108, 255, 0.16);
  --font-display: "Unbounded", sans-serif;
  --font-body: "Space Grotesk", sans-serif;
  --nav-h: 72px;
  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
}

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

html { scroll-behavior: smooth; }

body {
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

::selection { background: var(--cyan); color: #041016; }

a { color: inherit; text-decoration: none; }

:focus-visible {
  outline: 2px solid var(--cyan);
  outline-offset: 3px;
  border-radius: 2px;
}

/* ---------- atmosphère globale ---------- */

.page-glow {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 0;
  background:
    radial-gradient(1200px 640px at 78% -8%, rgba(43, 226, 255, 0.05), transparent 62%),
    radial-gradient(900px 560px at 8% 108%, rgba(124, 108, 255, 0.045), transparent 60%);
}

main { position: relative; z-index: 1; }

.wrap {
  width: min(1200px, calc(100% - 48px));
  margin-inline: auto;
}

.wrap-narrow {
  width: min(560px, calc(100% - 48px));
  margin-inline: auto;
}

/* ---------- connexion / mon espace ---------- */

.auth-card {
  text-align: center;
  padding: 56px 40px;
  background: var(--panel);
  border: 1px solid var(--line-soft);
}

.auth-logo { display: block; margin: 0 auto 24px; filter: drop-shadow(0 0 14px rgba(43, 226, 255, 0.35)); }

.auth-card h1 {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.6rem;
  text-transform: uppercase;
  margin-bottom: 10px;
}

.auth-card .lead { margin-inline: auto; margin-bottom: 32px; }

.auth-discord { width: 100%; justify-content: center; }

.auth-error {
  color: var(--violet);
  font-size: 0.88rem;
  margin-bottom: 20px;
}

.auth-note {
  color: var(--faint);
  font-size: 0.8rem;
  margin-top: 20px;
}

/* ---------- mon espace : layout sidebar ---------- */

/* Sur les dashboards, la nav fixe reçoit un fond + une bordure permanents
   (séparation nette avec le contenu, sans attendre le scroll), et s'étend sur
   toute la largeur : le logo vient s'aligner au-dessus de la colonne du menu,
   comme sur la console KingShot. */
body.dash .nav {
  background: rgba(5, 6, 10, 0.92);
  backdrop-filter: blur(14px);
  border-bottom-color: var(--line-soft);
}

body.dash .nav-inner {
  width: 100%;
  padding-inline: 24px;
}

.dash-layout {
  display: grid;
  grid-template-columns: 240px 1fr;
  align-items: start;
  padding-top: var(--nav-h); /* la nav est fixed : le layout démarre dessous */
  min-height: 100vh;
  transition: grid-template-columns 0.18s ease;
}

.dash-side {
  background: var(--bg-2);
  border-right: 1px solid var(--line-soft);
  padding: 28px 16px;
  display: flex;
  flex-direction: column;
  gap: 22px;
  position: sticky;
  top: var(--nav-h);
  /* max-height + overflow-y (pas min-height) : sur une page longue (ex. Régie
     live, beaucoup de contenu principal), laisser le contenu de la sidebar
     dépasser 100vh la faisait défiler EN MÊME TEMPS que la page — pour
     atteindre le bas du menu, il fallait alors scroller toute la page
     principale (remonté par Marco : pas pratique). La sidebar défile donc
     maintenant dans sa propre zone, indépendamment de la position dans le
     contenu principal ; cf. .dash-side::-webkit-scrollbar ci-dessous pour
     un ascenseur fin plutôt que la barre moche par défaut du navigateur. */
  max-height: calc(100vh - var(--nav-h));
  overflow-y: auto;
  scrollbar-width: thin;
  scrollbar-color: var(--line) transparent;
}

.dash-side::-webkit-scrollbar { width: 6px; }
.dash-side::-webkit-scrollbar-track { background: transparent; }
.dash-side::-webkit-scrollbar-thumb { background: var(--line); border-radius: 3px; }
.dash-side::-webkit-scrollbar-thumb:hover { background: var(--cyan-dim); }

/* Menu replié : plus de place pour le contenu sur les pages denses (ex.
   Régie live avec beaucoup de catégories/effets). État persistant par
   navigateur (voir admin-sidebar.js), pas par page. */
.dash-layout.sidebar-collapsed { grid-template-columns: 64px 1fr; }
.dash-layout.sidebar-collapsed .dash-side { padding: 28px 10px; }
.dash-layout.sidebar-collapsed .dash-brand { justify-content: center; }
.dash-layout.sidebar-collapsed .dash-brand-text,
.dash-layout.sidebar-collapsed .dash-nav-cat,
.dash-layout.sidebar-collapsed .dash-side-foot,
.dash-layout.sidebar-collapsed .dash-nav a span:not(.nico) { display: none; }
.dash-layout.sidebar-collapsed .dash-nav a { justify-content: center; padding: 11px 6px; }
.dash-layout.sidebar-collapsed .dash-side-toggle { transform: rotate(180deg); }

.dash-brand {
  padding: 0 10px;
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 8px;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: 0.72rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--faint);
}

.dash-side-toggle {
  flex: none;
  width: 22px;
  height: 22px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: none;
  border: 1px solid var(--line-soft);
  border-radius: 4px;
  color: var(--faint);
  font-size: 0.85rem;
  line-height: 1;
  cursor: pointer;
  transition: color 0.2s, border-color 0.2s, transform 0.2s;
}

.dash-side-toggle:hover { color: var(--cyan); border-color: rgba(43, 226, 255, 0.35); }

.dash-brand strong {
  display: block;
  color: var(--ink);
  font-size: 0.92rem;
  letter-spacing: normal;
  text-transform: none;
  margin-top: 4px;
}

.dash-nav { display: flex; flex-direction: column; gap: 4px; }

/* Intitulés de catégorie : nettement plus discrets que les pages
   (icônes sur les liens + séparateur + teinte très atténuée) */
.dash-nav-cat {
  font-family: var(--font-display);
  font-size: 0.56rem;
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: rgba(122, 129, 153, 0.55);
  margin: 20px 12px 4px;
  padding-top: 14px;
  border-top: 1px solid var(--line-soft);
}

.dash-nav-cat:first-of-type { margin-top: 12px; }

.dash-nav a .nico {
  display: inline-flex;
  color: var(--faint);
  flex-shrink: 0;
  transition: color 0.2s;
}

.dash-nav a .nico svg { width: 16px; height: 16px; display: block; }

.dash-nav a:hover .nico,
.dash-nav a.on .nico { color: var(--cyan); }

.dash-nav a {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 11px 12px;
  color: var(--muted);
  font-weight: 500;
  font-size: 0.88rem;
  border: 1px solid transparent;
  transition: background 0.2s, color 0.2s, border-color 0.2s;
}

.dash-nav a:hover { background: rgba(255, 255, 255, 0.03); color: var(--ink); }

.dash-nav a.on {
  background: var(--cyan-dim);
  color: var(--ink);
  border-color: rgba(43, 226, 255, 0.35);
  box-shadow: 0 0 16px rgba(43, 226, 255, 0.1);
}

.dash-side-foot {
  margin-top: auto;
  padding: 0 10px;
}

.dash-side-foot a {
  font-size: 0.82rem;
  color: var(--faint);
  transition: color 0.2s;
}

.dash-side-foot a:hover { color: var(--cyan); }

.dash-main {
  padding: 56px 48px 96px;
  min-width: 0;
  width: 100%;
  max-width: 1600px;   /* colle la colonne, pas de grand vide flottant sur les écrans larges */
  margin-inline: auto;
}

.dash-main .section-head { margin-bottom: 40px; }

[data-ajax-region].ajax-loading { opacity: .55; transition: opacity .12s ease; pointer-events: none; }

/* Titres plus mesurés qu'en vitrine : c'est un outil, pas un hero. */
.dash-main .section-title { font-size: clamp(1.5rem, 3vw, 2.2rem); }

/* ---------- admin : cartes stats ---------- */

.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 18px;
  margin-bottom: 48px;
}

.card {
  background: var(--panel);
  border: 1px solid var(--line-soft);
  padding: 22px 24px;
}

.card-label {
  display: block;
  font-family: var(--font-display);
  font-size: 0.68rem;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--faint);
  margin-bottom: 10px;
}

.card-value {
  display: block;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 2rem;
  color: var(--ink);
}

/* ---------- admin : staff, formulaires, tableaux ---------- */

.flash {
  padding: 12px 18px;
  margin-bottom: 28px;
  border: 1px solid;
  font-size: 0.9rem;
}

.flash.ok { color: var(--cyan); border-color: rgba(43, 226, 255, 0.4); background: var(--cyan-dim); }
.flash.err { color: var(--violet); border-color: rgba(124, 108, 255, 0.4); background: var(--violet-dim); }

/* Toast : sur les pages pilotées par admin-ajax.js (data-ajax-region), le
   flash Spring (RedirectAttributes) atterrit toujours en tête du HTML
   remplacé — sur une page longue déjà défilée (ex. fiches d'instances plus
   bas dans /admin/flotte), il restait hors champ après une action. En
   position fixe + auto-disparition (voir admin-ajax.js, mountFlash), il
   reste visible quel que soit le défilement, sans toucher les pages qui
   font un rechargement complet classique (flash inline ci-dessus, où le
   navigateur revient déjà en haut de page tout seul).*/
[data-ajax-region] .flash {
  position: fixed;
  top: calc(var(--nav-h) + 24px);
  right: 24px;
  z-index: 300;
  max-width: 380px;
  margin-bottom: 0;
  box-shadow: 0 16px 40px rgba(0, 0, 0, 0.5);
  animation: flash-pop-in 0.3s ease-out;
  transition: opacity 0.35s ease, transform 0.35s ease;
}

[data-ajax-region] .flash.flash-dismiss { opacity: 0; transform: translateY(-10px); }

@keyframes flash-pop-in {
  from { opacity: 0; transform: translateY(-10px); }
  to { opacity: 1; transform: translateY(0); }
}

@media (max-width: 640px) {
  [data-ajax-region] .flash { left: 16px; right: 16px; max-width: none; }
}

.admin-table {
  width: 100%;
  border-collapse: collapse;
  margin-bottom: 40px;
  font-size: 0.92rem;
}

.admin-table th {
  text-align: left;
  font-family: var(--font-display);
  font-size: 0.66rem;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--faint);
  padding: 10px 14px;
  border-bottom: 1px solid var(--line-soft);
}

.admin-table td {
  padding: 12px 14px;
  border-bottom: 1px solid var(--line-soft);
  color: var(--muted);
}

.admin-table td:first-child, .admin-table th:first-child { color: var(--ink); }

.admin-table .role-tag {
  font-family: var(--font-display);
  font-size: 0.62rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 0.4em 0.8em;
  border: 1px solid rgba(43, 226, 255, 0.35);
  color: var(--cyan);
}

.admin-table .role-tag.owner { border-color: rgba(124, 108, 255, 0.4); color: var(--violet); }

/* État Docker réel d'une instance de flotte (running/exited/inconnu) — réutilise le pill du
   rôle staff : "running" garde l'accent cyan par défaut, tout le reste (arrêté, en cours de
   suppression, Fleet injoignable...) passe en gris discret plutôt que d'ajouter une couleur
   par état, qui serait plus de nuances que ce badge n'a besoin d'en porter. */
.admin-table .role-tag.dim { border-color: var(--line-soft); color: var(--faint); }

/* Actions d'une instance de flotte (start/stop/restart/logs/delete) : groupées avec un
   espacement régulier plutôt que des formulaires "display:inline" livrés à eux-mêmes (collés
   les uns aux autres) ; Supprimer est séparé par une fine bordure — seule action destructive
   de la rangée, elle ne doit pas se confondre visuellement avec les autres. Pas de retour à la
   ligne : 5 boutons empilés verticalement dans une cellule serait pire que le problème
   d'origine — .table-scroll gère le débordement horizontal si la fenêtre est trop étroite.
   Même principe que les tableaux façon Dokploy que Marco a en référence. */
.row-actions { display: flex; align-items: center; gap: 8px; flex-wrap: nowrap; }
.row-actions form { flex-shrink: 0; }
.row-actions-danger { margin-left: 6px; padding-left: 14px; border-left: 1px solid var(--line-soft); flex-shrink: 0; }
/* overflow-x:auto et overflow-y:visible ne peuvent PAS coexister en CSS : dès qu'un axe est
   différent de "visible", l'autre se calcule à "auto" aussi (spec CSS Overflow, pas un bug de
   navigateur) — poser overflow-y:visible ici n'a donc aucun effet, le menu ⋯ (voir
   .row-menu-content) reste rogné verticalement quoi qu'on fasse tant qu'il reste positionné en
   "absolute" DANS ce conteneur. Vraie solution : .row-menu-content en position:fixed,
   repositionné en JS (voir flotte.html, listener "toggle") — échappe à cet ancêtre au lieu
   d'essayer (en vain) de le rendre non-cliquant. */
.table-scroll { overflow-x: auto; }
/* Réduit après le passage des actions Flotte en icônes (5 boutons texte -> 3 icônes +
   menu ⋯) et la fusion RAM+Slots en une colonne Config — le tableau tient sur beaucoup
   plus d'écrans sans scroll horizontal qu'avant. */
.table-scroll .admin-table { min-width: 720px; }

/* Badge OP compact sur la cellule Instance de /admin/flotte — remplace la colonne OP dédiée,
   n'apparaît que si la liste n'est pas vide (voir flotte.html), pseudos complets au survol. */
.op-badge { margin-left: 8px; cursor: default; }

/* Boutons Démarrer/Arrêter/Redémarrer/⋯ en icône seule (SVG + title/aria-label, pas de texte)
   — même traitement .btn-primary / .btn-ghost / .btn-ghost-violet / .btn-ghost-faint / .btn-sm que le reste du site, juste un
   clip-path aux coins plus petits pour rester propre à cette taille compacte. Toujours
   compléter d'un title="" : l'icône seule ne suffit pas à l'accessibilité.
   SVG plutôt que glyphe Unicode (▶ ■ ↻ ⋯) : testé en vrai, chaque glyphe retombe sur une
   police de repli DIFFÉRENTE (aucune des polices du site n'a ces symboles), donc une taille
   et un poids visuel différents d'un bouton à l'autre — le SVG a une taille garantie. */
.btn-primary.btn-icon, .btn-ghost.btn-icon, .btn-ghost-violet.btn-icon, .btn-ghost-faint.btn-icon {
  padding: 0.7em;
  min-width: 36px;
  min-height: 36px;
  gap: 0;
  clip-path: polygon(7px 0, 100% 0, 100% calc(100% - 7px), calc(100% - 7px) 100%, 0 100%, 0 7px);
}

.btn-icon svg { width: 15px; height: 15px; display: block; flex-shrink: 0; }

/* Menu "⋯" (Logs/Supprimer) — <details> natif plutôt que du JS de positionnement custom,
   même esprit que les "Options avancées" repliées du formulaire de création d'instance
   plus haut sur cette page. */
.row-menu { position: relative; flex-shrink: 0; }
.row-menu > summary { list-style: none; }
.row-menu > summary::-webkit-details-marker,
.row-menu > summary::marker { display: none; content: ""; }
.row-menu[open] > summary { background: var(--line-soft); }

/* position:fixed (pas absolute) + top/right posés en JS à l'ouverture (voir flotte.html) :
   un positionnement relatif à .row-menu échapperait au clip vertical de .table-scroll (voir
   commentaire ci-dessus) — fixed sort du flux de TOUS les ancêtres, y compris scrollables. */
.row-menu-content {
  position: fixed;
  min-width: 150px;
  background: var(--panel-solid);
  border: 1px solid var(--line);
  padding: 6px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  z-index: 200;
}

.row-menu-item {
  display: block;
  width: 100%;
  text-align: left;
  padding: 8px 10px;
  background: none;
  border: none;
  color: var(--muted);
  font-family: var(--font-body);
  font-size: 0.82rem;
  cursor: pointer;
}

.row-menu-item:hover { background: var(--line-soft); color: var(--ink); }
.row-menu-item.danger:hover { color: var(--violet); }

.admin-form {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: flex-end;
  padding: 22px 24px;
  background: var(--panel);
  border: 1px solid var(--line-soft);
  margin-bottom: 40px;
}

.admin-form label,
.admin-form .field {
  display: flex;
  flex-direction: column;
  gap: 6px;
  font-size: 0.8rem;
  color: var(--faint);
}

.admin-form input, .admin-form select {
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid var(--line-soft);
  color: var(--ink);
  padding: 0.6em 0.8em;
  font: inherit;
  font-size: 0.9rem;
  min-width: 180px;
  clip-path: polygon(8px 0, 100% 0, 100% calc(100% - 8px), calc(100% - 8px) 100%, 0 100%, 0 8px);
  transition: border-color 0.15s;
}

.admin-form input:focus-visible, .admin-form select:focus-visible {
  outline: none;
  border-color: var(--cyan);
  filter: drop-shadow(0 0 6px var(--cyan-glow));
}

.admin-form button {
  font-family: var(--font-display);
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  padding: 0.75em 1.6em;
  background: var(--cyan);
  color: #03151b;
  border: none;
  cursor: pointer;
  clip-path: polygon(9px 0, 100% 0, 100% calc(100% - 9px), calc(100% - 9px) 100%, 0 100%, 0 9px);
  transition: filter 0.2s;
}

.admin-form button:hover { filter: drop-shadow(0 0 10px var(--cyan-glow)); }

/* État désactivé (ex. Lancer/Arrêter en test de capacité, activé/désactivé selon
   qu'un run tourne déjà) — les boutons custom (clip-path, fond plein) n'héritent
   pas d'un style désactivé lisible du navigateur par défaut. */
.admin-form button:disabled,
.btn:disabled {
  opacity: 0.35;
  cursor: not-allowed;
  filter: none;
}

.btn-remove {
  font-family: var(--font-display);
  font-size: 0.66rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--faint);
  background: none;
  border: 1px solid var(--line-soft);
  padding: 0.4em 0.9em;
  cursor: pointer;
  clip-path: polygon(6px 0, 100% 0, 100% calc(100% - 6px), calc(100% - 6px) 100%, 0 100%, 0 6px);
  transition: color 0.2s, border-color 0.2s;
}

.btn-remove:hover { color: var(--violet); border-color: rgba(124, 108, 255, 0.4); }

.admin-form textarea {
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid var(--line-soft);
  color: var(--ink);
  padding: 0.6em 0.8em;
  font: inherit;
  font-size: 0.9rem;
  min-width: 260px;
  resize: vertical;
  clip-path: polygon(8px 0, 100% 0, 100% calc(100% - 8px), calc(100% - 8px) 100%, 0 100%, 0 8px);
}

.admin-form textarea:focus-visible {
  outline: none;
  border-color: var(--cyan);
  filter: drop-shadow(0 0 6px var(--cyan-glow));
}

.admin-form input[type="file"] {
  min-width: 220px;
  padding: 0;
  border: none;
  background: none;
  color: var(--faint);
  font-size: 0.8rem;
  display: flex;
  align-items: center;
  height: 38px;
}

.admin-form input[type="file"]::file-selector-button {
  font-family: var(--font-display);
  font-size: 0.64rem;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 0.7em 1em;
  margin-right: 12px;
  background: rgba(255, 255, 255, 0.06);
  color: var(--ink);
  border: 1px solid var(--line-soft);
  cursor: pointer;
  clip-path: polygon(6px 0, 100% 0, 100% calc(100% - 6px), calc(100% - 6px) 100%, 0 100%, 0 6px);
  transition: background 0.2s, border-color 0.2s;
}

.admin-form input[type="file"]::file-selector-button:hover {
  background: rgba(255, 255, 255, 0.1);
  border-color: var(--cyan);
}

.admin-form .checkbox-field {
  flex-direction: row;
  align-items: center;
  gap: 8px;
}

.stripe-status {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 0.85rem;
  margin-bottom: 24px;
  color: var(--faint);
}

.stripe-status .dot { width: 8px; height: 8px; border-radius: 50%; background: var(--faint); }
.stripe-status.on { color: var(--cyan); }
.stripe-status.on .dot { background: var(--cyan); box-shadow: 0 0 8px var(--cyan-glow); }

.offer-grid {
  display: grid;
  /* auto-fit, pas auto-fill : avec peu de fiches (ex. une seule map sur /admin/flotte),
     auto-fill réserve quand même des colonnes vides invisibles qui se partagent l'espace
     libre via leur 1fr — la ou les fiches réelles restent coincées à ~220px au lieu de
     s'étirer. auto-fit écarte les colonnes vides du calcul, tout le 1fr libre revient aux
     fiches qui existent vraiment. Se comporte à l'identique dès qu'il y a assez de fiches
     pour remplir la largeur (aucun changement visuel sur les pages déjà denses). */
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 18px;
  margin-bottom: 40px;
}

.offer-card {
  background: var(--panel);
  border: 1px solid var(--line-soft);
  overflow: hidden;
  /* Fiches à hauteur inégale selon le nombre de réglages (Vignette a moins de champs
     que Brume/Confettis) — .offer-grid étire déjà chaque carte à la hauteur de la
     ligne (grille CSS), mais sans ça le bouton "Appliquer" reste juste après le
     dernier champ au lieu de s'aligner en bas partout. */
  display: flex;
  flex-direction: column;
  transition: opacity 0.2s, border-color 0.2s, box-shadow 0.2s;
  /* Plafond nécessaire depuis le passage de .offer-grid en auto-fit (voir sa doc) : avec
     1 ou 2 fiches seulement, auto-fit leur donne TOUT l'espace libre de la ligne via 1fr —
     sans ce max-width, une carte seule s'étire sur toute la largeur du conteneur, et son
     .offer-img (aspect-ratio 16/9, largeur 100%) devient démesurément haute avec elle. */
  max-width: 360px;
}

.offer-card .offer-img {
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  display: block;
  background: var(--bg-2);
}

.offer-card .offer-body { padding: 16px 18px; flex: 1; display: flex; flex-direction: column; }

.offer-card h3 {
  font-family: var(--font-display);
  font-size: 1rem;
  margin-bottom: 6px;
}

.offer-card p {
  color: var(--muted);
  font-size: 0.85rem;
  margin-bottom: 12px;
  max-width: none;
}

.offer-card .offer-meta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}

.offer-card .offer-actions {
  display: flex;
  gap: 8px;
  margin-top: 14px;
}

.offer-card.inactive { opacity: 0.5; }

/* Régie live (fiches avec toggle "Actif" en data-auto-submit) : état piloté par
   le switch lui-même en direct (:has), pas seulement par la classe .inactive
   rendue côté serveur — sinon la bordure restait "en retard" d'un aller-retour
   réseau entre le clic sur le switch et le swap AJAX qui suit. Contraste plus
   marqué que .inactive seul : bordure + lueur cyan quand actif, fiche et
   aperçu grisés quand inactif. Scopé via [data-auto-submit] (régie live
   uniquement) pour ne rien changer aux autres pages qui réutilisent .offer-card. */
.offer-card:has([data-auto-submit]:checked) {
  border-color: rgba(43, 226, 255, 0.4);
  box-shadow: 0 0 0 1px rgba(43, 226, 255, 0.12) inset, 0 0 26px rgba(43, 226, 255, 0.06);
}

.offer-card:has([data-auto-submit]):not(:has([data-auto-submit]:checked)) {
  opacity: 0.4;
  border-color: var(--line-soft);
  box-shadow: none;
}

.offer-card:has([data-auto-submit]):not(:has([data-auto-submit]:checked)) .effect-mini-preview,
.offer-card:has([data-auto-submit]):not(:has([data-auto-submit]:checked)) .mob-card-icon {
  filter: grayscale(1) brightness(0.7);
}

/* Formulaire d'une fiche étroite (grille .offer-grid, ~220px) : .admin-form est pensé
   pour une barre large (flex-wrap + inputs 180px min) — dans une carte, ça empile les
   champs de façon imprévisible selon leur nombre (1 champ vs 2 pour l'étirement).
   Empilement vertical strict à la place : chaque champ occupe toute la largeur, même
   rythme visuel quel que soit le nombre de réglages de l'effet. */
.player-fx-form {
  flex: 1;
  flex-direction: column;
  align-items: stretch;
  padding: 0;
  background: none;
  border: none;
  margin-bottom: 0;
}

/* "Appliquer" toujours en bas de fiche, quel que soit le nombre de champs au-dessus
   (voir .offer-card/.offer-body ci-dessus) — les autres boutons du formulaire (ex.
   "Modifier les coordonnées") gardent align-self: flex-start via la règle générale. */
.player-fx-form button[type="submit"] {
  margin-top: auto;
  align-self: flex-start;
}

/* Champs compacts côte à côte (X/Y/Z, orientation/échelle/portée...) — même règle
   que .modal-form .row, la fiche d'un personnage a plus de champs qu'un effet joueur. */
.player-fx-form .row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(90px, 1fr));
  gap: 8px;
}

.player-fx-form input, .player-fx-form select {
  min-width: 0;
  width: 100%;
}

.player-fx-form button { align-self: flex-start; }

/* ---------- admin : visiteurs ---------- */

.trend-chart {
  display: flex;
  align-items: flex-end;
  gap: 6px;
  height: 140px;
  margin-bottom: 8px;
  padding-top: 10px;
}

.trend-bar {
  flex: 1;
  min-width: 8px;
  background: var(--cyan-dim);
  border-top: 2px solid var(--cyan);
  position: relative;
}

.trend-labels {
  display: flex;
  gap: 6px;
  margin-bottom: 40px;
}

.trend-labels span {
  flex: 1;
  min-width: 8px;
  text-align: center;
  font-size: 0.62rem;
  color: var(--faint);
}

.online-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 0;
  border-bottom: 1px solid var(--line-soft);
  font-size: 0.88rem;
  color: var(--muted);
}

.online-row .live-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--cyan);
  box-shadow: 0 0 8px var(--cyan-glow);
  flex-shrink: 0;
}

.card-sub {
  display: block;
  margin-top: 6px;
  font-size: 0.76rem;
  color: var(--faint);
}

.card-sub strong { color: var(--muted); }

/* Variante violette du trend-bar cyan existant — utilisée pour le graphique
   compagnon (visiteurs uniques) à côté de celui des pages vues. */
.trend-bar.violet { background: var(--violet-dim); border-top-color: var(--violet); }

.chart-legend {
  display: flex;
  gap: 24px;
  font-size: 0.8rem;
  color: var(--faint);
  margin-bottom: 40px;
}

.chart-legend strong { color: var(--ink); font-family: var(--font-display); }

/* Répartitions en barres horizontales (pages/référents/langues/navigateurs/robots) —
   même piste var(--line-soft) que le reste de l'admin, remplissage cyan/violet en
   alternance pour distinguer les panneaux d'un coup d'œil. */
.bar-row {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 7px 0;
}

.bar-label {
  flex: 0 0 130px;
  font-size: 0.8rem;
  color: var(--muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.bar-track {
  flex: 1;
  height: 7px;
  background: var(--line-soft);
  position: relative;
  overflow: hidden;
}

.bar-fill { position: absolute; inset: 0 auto 0 0; background: var(--cyan); }
.bar-fill.violet { background: var(--violet); }

.bar-n {
  flex: 0 0 auto;
  min-width: 30px;
  text-align: right;
  font-size: 0.8rem;
  color: var(--faint);
  font-family: var(--font-display);
}

.analytics-panels {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: 32px;
  margin-top: 8px;
}

.quick-links {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-bottom: 40px;
}

.quick-links .btn { font-size: 0.68rem; padding: 0.8em 1.4em; }

/* ---------- admin : modales de création/édition ---------- */

/* Cadre HUD : quatre crochets d'angle façon viseur de régie, posés en
   surimpression sur le cadre anguleux (coins coupés) du panneau lui-même —
   remplace le bête rectangle plein d'une modale générique. */
dialog.modal {
  /* Volontairement fixed + inset:0 (comportement natif d'un <dialog> ouvert en modal) :
     un simple "relative" fait perdre le positionnement par rapport au viewport, donc la
     boîte se retrouve posée à sa position dans le flux normal (calque top-layer avec pour
     bloc conteneur le viewport initial) — showModal() y fixe le focus (bouton Annuler) et
     le navigateur scrolle la page tout en haut pour l'amener à l'écran. Repéré via le bouton
     "Redémarrer" de /admin/flotte, tout en bas du tableau : le saut en haut de page était
     spectaculaire, mais le bug touche en réalité TOUTES les modales du site (.modal). */
  position: fixed;
  inset: 0;
  background: var(--panel-solid);
  border: 1px solid var(--line-soft);
  color: var(--ink);
  padding: 0;
  width: min(560px, calc(100vw - 40px));
  max-height: calc(100vh - 80px);
  margin: auto;
  overflow: hidden;
  clip-path: polygon(16px 0, 100% 0, 100% calc(100% - 16px), calc(100% - 16px) 100%, 0 100%, 0 16px);
  box-shadow: 0 30px 80px rgba(0, 0, 0, 0.6), 0 0 40px rgba(43, 226, 255, 0.06);
}

dialog.modal::before,
dialog.modal::after {
  content: "";
  position: absolute;
  width: 22px;
  height: 22px;
  pointer-events: none;
  border: 1px solid var(--cyan);
  opacity: 0.55;
}

dialog.modal::before { top: -1px; left: -1px; border-right: none; border-bottom: none; }
dialog.modal::after { bottom: -1px; right: -1px; border-left: none; border-top: none; }

dialog.modal::backdrop {
  background: rgba(3, 4, 8, 0.72);
  backdrop-filter: blur(4px);
}

dialog.modal[open] { animation: modalIn 0.28s var(--ease-out); }

@keyframes modalIn {
  from { opacity: 0; transform: translateY(16px); }
  to { opacity: 1; transform: translateY(0); }
}

.modal-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 18px 22px;
  border-bottom: 1px solid var(--line-soft);
}

.modal-head h3 {
  font-family: var(--font-display);
  font-size: 0.9rem;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.modal-close {
  background: none;
  border: none;
  color: var(--faint);
  font-size: 1.3rem;
  line-height: 1;
  cursor: pointer;
  padding: 4px 8px;
  transition: color 0.2s, transform 0.25s var(--ease-out);
}

.modal-close:hover { color: var(--cyan); transform: rotate(90deg); }

.modal-body { padding: 22px; overflow-y: auto; max-height: calc(100vh - 180px); }

/* Console de logs (Fleet) — un vrai panneau terminal plutôt qu'une modale de formulaire :
   beaucoup plus large/haut, fond quasi-noir, ANSI converti en couleurs par ansiToHtml() (voir
   flotte.html) au lieu d'afficher les codes d'échappement bruts (illisible sinon). */
dialog.modal-terminal { width: min(1100px, calc(100vw - 40px)); }
dialog.modal-terminal .modal-body { padding: 0; max-height: none; }
.terminal-pane {
  margin: 0;
  padding: 18px 22px;
  background: #04050a;
  color: #c7cdd9;
  font-family: ui-monospace, "SFMono-Regular", "JetBrains Mono", Consolas, monospace;
  font-size: 0.78rem;
  line-height: 1.6;
  white-space: pre-wrap;
  word-break: break-word;
  height: 74vh;
  overflow-y: auto;
}

.modal-form { display: flex; flex-direction: column; gap: 16px; }

.modal-form label,
.modal-form .field {
  display: flex;
  flex-direction: column;
  gap: 6px;
  font-size: 0.8rem;
  color: var(--faint);
}

.modal-form input,
.modal-form select,
.modal-form textarea {
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid var(--line-soft);
  color: var(--ink);
  padding: 0.65em 0.85em;
  font: inherit;
  font-size: 0.9rem;
  width: 100%;
  resize: vertical;
  clip-path: polygon(8px 0, 100% 0, 100% calc(100% - 8px), calc(100% - 8px) 100%, 0 100%, 0 8px);
  transition: border-color 0.15s, box-shadow 0.15s;
}

.modal-form input:focus-visible,
.modal-form select:focus-visible,
.modal-form textarea:focus-visible {
  /* filter (pas box-shadow) : clip-path découpe tout box-shadow au ras des
     coins coupés, une lueur n'y survivrait pas — un drop-shadow s'applique
     lui APRÈS le découpage et peut donc réellement déborder. */
  outline: none;
  border-color: var(--cyan);
  filter: drop-shadow(0 0 6px var(--cyan-glow));
}

.modal-form input[type="file"] {
  padding: 0;
  border: none;
  background: none;
  color: var(--faint);
  font-size: 0.8rem;
}

.modal-form input[type="file"]::file-selector-button {
  font-family: var(--font-display);
  font-size: 0.64rem;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 0.7em 1em;
  margin-right: 12px;
  background: rgba(255, 255, 255, 0.06);
  color: var(--ink);
  border: 1px solid var(--line-soft);
  cursor: pointer;
  clip-path: polygon(6px 0, 100% 0, 100% calc(100% - 6px), calc(100% - 6px) 100%, 0 100%, 0 6px);
}

.modal-form input[type="color"], .admin-form input[type="color"] { padding: 3px; height: 42px; cursor: pointer; }

.modal-form .checkbox-field {
  flex-direction: row;
  align-items: center;
  gap: 10px;
  color: var(--muted);
}

.modal-form .checkbox-field input { width: auto; }

/* Champs compacts côte à côte (X/Y/Z, taille/portée...) */
.modal-form .row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(110px, 1fr));
  gap: 12px;
}

.modal-form fieldset {
  border: 1px solid var(--line-soft);
  padding: 14px 16px;
  display: flex;
  flex-wrap: wrap;
  gap: 6px 16px;
}

.modal-form fieldset legend { padding: 0 8px; color: var(--faint); font-size: 0.78rem; }

.modal-actions {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: 10px;
  padding-top: 4px;
}

.visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
}

/* ---------- sélecteur de forme (grille de vignettes animées) ---------- */

.shape-live-preview {
  display: block;
  width: 100%;
  aspect-ratio: 1.6;
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid var(--line-soft);
  margin-bottom: 4px;
}

.shape-live-preview-hint {
  font-size: 0.7rem;
  color: var(--faint);
  text-align: center;
  margin-bottom: 12px;
}

.field-group-hint {
  font-size: 0.72rem;
  color: var(--faint);
  margin: 4px 0 -4px;
}

/* ---------- aperçu en jeu éphémère ---------- */

.preview-toggle-row {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 8px;
}

.preview-toggle-btn {
  font-family: var(--font-display);
  font-size: 0.68rem;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  padding: 0.7em 1.4em;
  background: none;
  color: var(--faint);
  border: 1px solid var(--line-soft);
  cursor: pointer;
  clip-path: polygon(7px 0, 100% 0, 100% calc(100% - 7px), calc(100% - 7px) 100%, 0 100%, 0 7px);
  transition: color 0.15s, border-color 0.15s, background 0.15s;
}

.preview-toggle-btn:hover { border-color: var(--cyan); color: var(--ink); }

.preview-toggle-btn.active {
  background: rgba(43, 226, 255, 0.12);
  border-color: var(--cyan);
  color: var(--cyan);
}

.preview-status {
  font-size: 0.74rem;
  color: var(--cyan);
}

.preview-status.err { color: var(--violet); }

.shape-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(84px, 1fr));
  gap: 8px;
  max-height: 260px;
  overflow-y: auto;
  padding: 10px;
  background: rgba(255, 255, 255, 0.02);
  border: 1px solid var(--line-soft);
}

.shape-tile {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  width: 100%;
  min-width: 0;
  background: none;
  border: 1px solid transparent;
  padding: 6px 4px;
  cursor: pointer;
  color: var(--faint);
  font-size: 0.62rem;
  text-align: center;
  line-height: 1.2;
  transition: border-color 0.15s, color 0.15s;
}

.shape-tile span {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow: hidden;
  word-break: break-word;
  max-width: 100%;
}

.shape-tile:hover { border-color: var(--line-soft); color: var(--ink); }

.shape-tile.selected {
  border-color: var(--cyan);
  color: var(--ink);
  background: rgba(43, 226, 255, 0.08);
}

.shape-tile-canvas {
  width: 100%;
  aspect-ratio: 1;
  background: rgba(0, 0, 0, 0.25);
}

/* mini-aperçu réutilisé sur les cartes d'effet (régie live) */
.effect-mini-preview {
  width: 100%;
  aspect-ratio: 1.4;
  background: rgba(0, 0, 0, 0.25);
  border: 1px solid var(--line-soft);
  margin-bottom: 10px;
}

/* ---------- sélecteur de monstre (vraies textures Minecraft recadrées
   sur la tête/le visage, pas de vrai rendu 3D — voir mob-icons.js/
   mob-picker.js) ---------- */

@keyframes mob-spin {
  from { transform: rotateY(0deg); }
  to { transform: rotateY(360deg); }
}

.mob-grid {
  display: flex;
  flex-direction: column;
  gap: 10px;
  max-height: 320px;
  overflow-y: auto;
  padding: 10px;
  background: rgba(255, 255, 255, 0.02);
  border: 1px solid var(--line-soft);
}

.mob-grid-group {
  font-family: var(--font-display);
  font-size: 0.66rem;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--faint);
}

.mob-grid-row {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(74px, 1fr));
  gap: 8px;
}

.mob-tile {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  width: 100%;
  min-width: 0;
  background: none;
  border: 1px solid transparent;
  padding: 6px 4px;
  cursor: pointer;
  color: var(--faint);
  font-size: 0.62rem;
  text-align: center;
  line-height: 1.2;
  transition: border-color 0.15s, color 0.15s;
}

.mob-tile span {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow: hidden;
  word-break: break-word;
  max-width: 100%;
}

.mob-tile:hover { border-color: var(--line-soft); color: var(--ink); }

.mob-tile.selected {
  border-color: var(--cyan);
  color: var(--ink);
  background: rgba(43, 226, 255, 0.08);
}

.mob-tile-icon {
  width: 100%;
  aspect-ratio: 1;
  background-color: rgba(0, 0, 0, 0.25);
  background-repeat: no-repeat;
  image-rendering: pixelated;
}

.mob-tile.selected .mob-tile-icon { outline: 1px solid var(--cyan); outline-offset: -1px; }

/* .mob-icon-frame/.mob-icon-img : conteneurs réutilisés par les mini-icônes de
   fiche — vraie texture Minecraft recadrée sur la tête/le visage, en couleurs
   naturelles (background-image posé par mob-picker.js). Pas de calque de
   teinte couleur : essayé en mix-blend-mode:multiply, mais une texture sombre
   (Ender Dragon, Enderman, Warden...) multipliée par une couleur reste sombre,
   illisible quelle que soit la taille (retour de Marco) — seul le bouton
   "Aperçu en jeu" montre la vraie teinte configurée, en jeu. */
.mob-icon-frame {
  position: relative;
  overflow: hidden;
}

.mob-icon-img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  background-repeat: no-repeat;
  image-rendering: pixelated;
}

/* mini-icône statique réutilisée sur chaque fiche de monstre placé */
.mob-card-icon {
  width: 48px;
  height: 48px;
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  perspective: 300px;
  margin-bottom: 6px;
}

.mob-card-icon-tilt,
.mob-card-icon-spin {
  transform-style: preserve-3d;
}

.mob-card-icon-spin {
  animation-name: mob-spin;
  animation-timing-function: linear;
  animation-iteration-count: infinite;
}

.mob-card-icon .mob-icon-frame {
  width: 40px;
  height: 40px;
}

/* Compact dans la rail-list (à côté du nom, comme .rail-item canvas). */
.rail-item .mob-card-icon {
  width: 22px;
  height: 22px;
  margin-bottom: 0;
}
.rail-item .mob-card-icon .mob-icon-frame { width: 18px; height: 18px; }

/* Lisibilité des <select> natifs restants (Windows/Chrome applique sinon un
   popover clair par défaut, illisible sur ce thème sombre). */
select {
  color-scheme: dark;
}
select option {
  background: var(--panel-solid);
  color: var(--ink);
}

/* ---------- interrupteur (remplace les cases à cocher "Actif") ---------- */

.toggle-field {
  display: flex !important;
  flex-direction: row !important;
  align-items: center;
  gap: 10px;
  color: var(--muted);
  cursor: pointer;
}

.toggle-switch {
  position: relative;
  display: inline-block;
  width: 54px;
  height: 30px;
  flex: none;
}

.toggle-switch input {
  position: absolute;
  opacity: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  cursor: pointer;
}

.toggle-switch .track {
  position: absolute;
  inset: 0;
  background: rgba(255, 255, 255, 0.08);
  border: 1px solid var(--line-soft);
}

.toggle-switch .thumb {
  position: absolute;
  top: 3px;
  left: 3px;
  width: 22px;
  height: 22px;
  background: var(--faint);
}

.toggle-switch input:checked ~ .track { background: rgba(43, 226, 255, 0.14); border-color: var(--cyan); }
.toggle-switch input:checked ~ .thumb { transform: translateX(24px); background: var(--cyan); box-shadow: 0 0 8px var(--cyan-glow); }
.toggle-switch input:focus-visible ~ .track { outline: 1px solid var(--cyan); outline-offset: 2px; }

/* ---------- contrôle segmenté (remplace le <select> "Sens de rotation") ---------- */

.segmented {
  display: flex;
  border: 1px solid var(--line-soft);
  background: rgba(255, 255, 255, 0.03);
}

.segmented button {
  flex: 1;
  background: none;
  border: none;
  color: var(--faint);
  font: inherit;
  font-size: 0.78rem;
  padding: 0.65em 0.5em;
  cursor: pointer;
  border-right: 1px solid var(--line-soft);
  transition: background 0.15s, color 0.15s;
  /* Isole le contexte de peinture de chaque bouton : la règle générique
     ".admin-form button:hover { filter: drop-shadow(...) }" (pensée pour
     les gros boutons submit) s'applique aussi ici sans le vouloir, et un
     filter sans isolation peut, sur certains moteurs de rendu, fuiter
     visuellement sur les boutons voisins d'un même conteneur flex. */
  isolation: isolate;
}

.segmented button:last-child { border-right: none; }
/* hover: hover exclut les écrans tactiles, où :hover reste "collé" sur le
   dernier bouton touché tant qu'on ne touche pas ailleurs — imite un hover
   permanent sur un bouton qu'on n'a pourtant plus sous le doigt/la souris. */
@media (hover: hover) and (pointer: fine) {
  .segmented button:hover { color: var(--ink); filter: none; }
}
.segmented button.active { background: rgba(43, 226, 255, 0.1); color: var(--cyan); }

/* ---------- case à cocher angulaire (remplace la case native du navigateur) ---------- */

.checkbox-field input[type="checkbox"] {
  appearance: none;
  -webkit-appearance: none;
  width: 18px;
  height: 18px;
  flex: none;
  margin: 0;
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid var(--line-soft);
  clip-path: polygon(5px 0, 100% 0, 100% 100%, 0 100%, 0 5px);
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s;
}

.checkbox-field input[type="checkbox"]:hover { border-color: var(--cyan); }

.checkbox-field input[type="checkbox"]:checked {
  background-color: var(--cyan);
  border-color: var(--cyan);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='none' stroke='%2303151b' stroke-width='2.4' stroke-linecap='square' d='M3 8.5l3 3 7-7'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: center;
  background-size: 12px;
}

.checkbox-field input[type="checkbox"]:focus-visible {
  outline: none;
  filter: drop-shadow(0 0 6px var(--cyan-glow));
}

/* ---------- liste de cases à cocher scrollable (remplace un <select multiple> natif —
   les <option> d'un multi-select ne sont quasi pas stylables, contrairement à ces cases) ---------- */
.checkbox-list {
  max-height: 190px;
  overflow-y: auto;
  border: 1px solid var(--line-soft);
  background: rgba(255, 255, 255, 0.03);
  clip-path: polygon(8px 0, 100% 0, 100% calc(100% - 8px), calc(100% - 8px) 100%, 0 100%, 0 8px);
  padding: 10px 14px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-top: 4px;
}

.checkbox-list .checkbox-field {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 10px;
}

.checkbox-list .checkbox-field label {
  font-size: 0.85rem;
  color: var(--ink);
  cursor: pointer;
}

/* ---------- sélecteur de fichier HUD (remplace le bouton gris natif) ---------- */

.hud-file {
  display: flex;
  align-items: center;
  gap: 12px;
  cursor: pointer;
  border: 1px solid var(--line-soft);
  padding: 5px 14px 5px 5px;
  clip-path: polygon(8px 0, 100% 0, 100% calc(100% - 8px), calc(100% - 8px) 100%, 0 100%, 0 8px);
  background: rgba(255, 255, 255, 0.02);
  transition: border-color 0.15s;
}

.hud-file:hover { border-color: rgba(43, 226, 255, 0.35); }

.hud-file-btn {
  flex: none;
  font-family: var(--font-display);
  font-size: 0.64rem;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 0.7em 1em;
  background: rgba(255, 255, 255, 0.06);
  color: var(--ink);
  border: 1px solid var(--line-soft);
  clip-path: polygon(6px 0, 100% 0, 100% calc(100% - 6px), calc(100% - 6px) 100%, 0 100%, 0 6px);
  transition: border-color 0.15s, color 0.15s;
}

.hud-file:hover .hud-file-btn { border-color: var(--cyan); color: var(--cyan); }

.hud-file-name {
  font-size: 0.78rem;
  color: var(--faint);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.hud-file-name.chosen { color: var(--ink); }

/* ---------- Maps & Effets : espace de travail (édition au centre, hiérarchie à droite) ---------- */

.effets-workspace {
  display: grid;
  grid-template-columns: 1fr 360px;
  gap: 32px;
  align-items: start;
}

.effets-editor {
  background: var(--panel);
  border: 1px solid var(--line-soft);
  padding: 36px;
  min-height: 320px;
}

.effets-editor .modal-form { max-width: 860px; }

.editor-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 6px 16px;
  margin-bottom: 20px;
}

.editor-head h3 { margin: 0; min-width: 0; overflow-wrap: break-word; }

.editor-actions {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: 12px;
  padding-top: 8px;
}

.editor-actions button[type="submit"] {
  font-family: var(--font-display);
  font-size: 0.8rem;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  padding: 1em 2.4em;
  background: var(--cyan);
  color: #03151b;
  border: none;
  cursor: pointer;
  clip-path: polygon(11px 0, 100% 0, 100% calc(100% - 11px), calc(100% - 11px) 100%, 0 100%, 0 11px);
  transition: filter 0.25s, transform 0.25s var(--ease-out);
}

.editor-actions button[type="submit"]:hover {
  filter: drop-shadow(0 0 20px var(--cyan-glow));
  transform: translateY(-1px);
}

.effets-rail {
  display: flex;
  flex-direction: column;
  gap: 20px;
  position: sticky;
  top: calc(var(--nav-h) + 24px);
}

.rail-section {
  background: var(--panel);
  border: 1px solid var(--line-soft);
  padding: 16px;
}

.rail-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 8px;
  margin-bottom: 10px;
}

.rail-head h4 {
  font-family: var(--font-display);
  font-size: 0.7rem;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--faint);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.rail-add {
  flex: none;
  background: none;
  border: 1px solid var(--line-soft);
  color: var(--cyan);
  width: 24px;
  height: 24px;
  line-height: 1;
  cursor: pointer;
  font-size: 1rem;
  transition: border-color 0.15s;
}

.rail-add:hover { border-color: var(--cyan); }

.rail-list {
  display: flex;
  flex-direction: column;
  gap: 2px;
  max-height: 260px;
  overflow-y: auto;
  /* Explicite : overflow-y:auto seul suffit à faire calculer overflow-x en
     auto aussi (spec CSS Overflow), ce qui affichait une barre de défilement
     horizontale moche dès qu'une ligne débordait un peu (ex. badge de groupe
     + icône Dupliquer) — chaque .rail-item doit rétrécir/tronquer plutôt que
     défiler, voir .rail-item-link et le badge de groupe (ellipsis + largeur
     plafonnée). Même piège que .table-scroll, résolu autrement ici : pas de
     défilement horizontal voulu du tout dans un rail vertical étroit.  */
  overflow-x: hidden;
  /* Barre de défilement fine plutôt que la grosse barre système par défaut —
     même patron que .dash-side ci-dessus (deux propriétés Firefox + trio
     Webkit, aucun raccourci n'existe pour couvrir les deux moteurs). */
  scrollbar-width: thin;
  scrollbar-color: var(--line) transparent;
}

.rail-list::-webkit-scrollbar { width: 6px; }
.rail-list::-webkit-scrollbar-track { background: transparent; }
.rail-list::-webkit-scrollbar-thumb { background: var(--line); border-radius: 3px; }
.rail-list::-webkit-scrollbar-thumb:hover { background: var(--cyan-dim); }

.rail-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 8px;
  transition: background 0.15s;
}

.rail-item:hover { background: rgba(255, 255, 255, 0.03); }
.rail-item.active { background: rgba(43, 226, 255, 0.08); }
.rail-item.active .rail-item-link { color: var(--cyan); }

.rail-item-link {
  flex: 1;
  min-width: 0;
  color: var(--muted);
  font-size: 0.82rem;
  text-decoration: none;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.rail-item canvas {
  width: 22px;
  height: 22px;
  flex: none;
  background: rgba(0, 0, 0, 0.25);
}

.rail-del, .rail-dup, .rail-eye {
  flex: none;
  background: none;
  border: none;
  color: var(--faint);
  cursor: pointer;
  font-size: 0.75rem;
  padding: 2px 5px;
  text-decoration: none;
  line-height: 1;
}

.rail-del:hover, .rail-dup:hover, .rail-eye:hover { color: var(--cyan); }

/* Glyphe SVG plutôt qu'un caractère Unicode "œil" (👁 tombe dans la plage
   emoji : rendu multicolore selon la police système, au lieu d'une icône fine
   assortie à ⧉/✕ — même piège que les glyphes de la page Flotte, déjà réglé
   une fois cette session) — currentColor pour hériter de la couleur/hover
   ci-dessus sans dupliquer de règle. */
.rail-eye svg { width: 13px; height: 13px; display: block; }

.rail-empty { color: var(--faint); font-size: 0.78rem; }

@media (max-width: 1080px) {
  .effets-workspace { grid-template-columns: 1fr; }
  .effets-rail { position: static; }
}

/* ---------- Régie live : recherche + navigation rapide (catégories/projecteurs/monstres) ---------- */

.regie-search { display: block; margin-bottom: 24px; }

.regie-search input {
  width: 100%;
  max-width: 420px;
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid var(--line-soft);
  color: var(--ink);
  padding: 0.7em 1em;
  font: inherit;
  font-size: 0.9rem;
  clip-path: polygon(8px 0, 100% 0, 100% calc(100% - 8px), calc(100% - 8px) 100%, 0 100%, 0 8px);
  transition: border-color 0.15s;
}

.regie-search input:focus-visible {
  outline: none;
  border-color: var(--cyan);
  filter: drop-shadow(0 0 6px var(--cyan-glow));
}

.regie-workspace {
  display: grid;
  grid-template-columns: 1fr 240px;
  gap: 32px;
  align-items: start;
}

.regie-nav { position: sticky; top: calc(var(--nav-h) + 24px); }

.rail-toggle {
  flex: none;
  background: none;
  border: none;
  color: var(--faint);
  cursor: pointer;
  font-size: 0.65rem;
  padding: 2px 5px;
  line-height: 1;
  transition: color 0.15s, transform 0.15s;
}

.rail-toggle:hover { color: var(--cyan); }
.rail-toggle.collapsed { transform: rotate(-90deg); }

.regie-group { scroll-margin-top: calc(var(--nav-h) + 16px); }
.regie-group.collapsed .regie-group-body { display: none; }

.panel-subhead {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 0 0 14px;
}

.panel-subhead h4 {
  margin: 0;
  font-family: var(--font-display);
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--cyan);
  white-space: nowrap;
}

.panel-subhead::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--line-soft);
}

@media (max-width: 1080px) {
  .regie-workspace { grid-template-columns: 1fr; }
  .regie-nav { position: static; }
}

.modal-actions button[type="submit"] {
  font-family: var(--font-display);
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  padding: 0.8em 1.8em;
  background: var(--cyan);
  color: #03151b;
  border: none;
  cursor: pointer;
  clip-path: polygon(9px 0, 100% 0, 100% calc(100% - 9px), calc(100% - 9px) 100%, 0 100%, 0 9px);
  transition: filter 0.25s, transform 0.25s var(--ease-out);
}

.modal-actions button[type="submit"]:hover {
  filter: drop-shadow(0 0 10px var(--cyan-glow));
  transform: translateY(-1px);
}

/* En-tête de section : titre + bouton d'action à droite */
.panel-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 16px;
  margin-bottom: 16px;
  flex-wrap: wrap;
}

.panel-head h3 { margin: 0; }

.btn-sm { font-size: 0.64rem; padding: 0.75em 1.4em; }

/* ---------- admin : monitoring ---------- */

.gauge {
  margin-bottom: 22px;
}

.gauge-label {
  display: flex;
  justify-content: space-between;
  font-size: 0.82rem;
  color: var(--muted);
  margin-bottom: 6px;
}

.gauge-label strong { color: var(--ink); font-weight: 500; }

.gauge-track {
  height: 6px;
  background: rgba(255, 255, 255, 0.05);
  overflow: hidden;
}

.gauge-fill {
  height: 100%;
  background: var(--cyan);
  box-shadow: 0 0 10px var(--cyan-glow);
  transition: width 0.4s var(--ease-out);
}

.gauge-fill.warn { background: var(--violet); box-shadow: 0 0 10px rgba(124, 108, 255, 0.4); }

/* Joueurs actuellement en ligne (monitoring) */
.player-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.player-chip {
  padding: 5px 12px;
  font-size: 0.8rem;
  color: var(--ink);
  border: 1px solid rgba(77, 232, 255, 0.25);
  background: rgba(77, 232, 255, 0.06);
  border-radius: 999px;
}

@media (max-width: 900px) {
  .dash-layout, .dash-layout.sidebar-collapsed { grid-template-columns: 1fr; }
  .dash-side {
    position: static;
    height: auto;
    max-height: none;
    overflow-y: visible;
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
    border-right: none;
    border-bottom: 1px solid var(--line-soft);
    padding: 18px 20px;
  }
  .dash-brand { display: none; }
  .dash-nav { flex-direction: row; flex-wrap: wrap; }
  .dash-side-foot { margin: 0 0 0 auto; padding: 0; }
  .dash-main { padding: 40px 24px 72px; }

  /* Le bouton de repli est masqué ici (dans .dash-brand, display:none) : pas
     de piège possible où le menu resterait replié sans moyen de le rouvrir
     sur mobile — on neutralise entièrement l'état "sidebar-collapsed". */
  .dash-layout.sidebar-collapsed .dash-side { padding: 18px 20px; }
  .dash-layout.sidebar-collapsed .dash-nav-cat,
  .dash-layout.sidebar-collapsed .dash-side-foot { display: block; }
  .dash-layout.sidebar-collapsed .dash-side-foot { margin: 0 0 0 auto; padding: 0; }
  .dash-layout.sidebar-collapsed .dash-nav a { justify-content: flex-start; padding: 11px 12px; }
  .dash-layout.sidebar-collapsed .dash-nav a span:not(.nico) { display: inline; }
}

/* ---------- typo utilitaires ---------- */

.overline {
  font-family: var(--font-display);
  font-size: 0.68rem;
  font-weight: 500;
  letter-spacing: 0.42em;
  text-transform: uppercase;
  color: var(--cyan);
}

.overline .dot { color: var(--faint); padding-inline: 0.55em; }

.section-head {
  display: flex;
  align-items: baseline;
  gap: 28px;
  margin-bottom: 56px;
}

.section-head .num {
  font-family: var(--font-display);
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.3em;
  color: var(--faint);
  white-space: nowrap;
}

.section-head .num b {
  color: var(--cyan);
  font-weight: 500;
}

.section-title {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.7rem, 4.2vw, 2.9rem);
  line-height: 1.08;
  letter-spacing: 0.01em;
  text-transform: uppercase;
}

.section-title em {
  font-style: normal;
  color: var(--cyan);
  text-shadow: 0 0 22px var(--cyan-glow);
}

.lead {
  color: var(--muted);
  max-width: 62ch;
  font-size: 1.05rem;
}

.lead b { color: var(--ink); font-weight: 500; }

/* ---------- boutons ---------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  font-family: var(--font-display);
  font-size: 0.78rem;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  padding: 1.05em 2.1em;
  border: 1px solid transparent;
  cursor: pointer;
  position: relative;
  transition: box-shadow 0.35s var(--ease-out), background 0.35s, color 0.35s,
    border-color 0.35s, transform 0.35s var(--ease-out);
}

.btn-primary {
  background: var(--cyan);
  color: #03151b;
  clip-path: polygon(14px 0, 100% 0, 100% calc(100% - 14px), calc(100% - 14px) 100%, 0 100%, 0 14px);
}

.btn-primary:hover,
.btn-primary:focus-visible {
  background: #6fefff;
  box-shadow: 0 0 34px var(--cyan-glow), 0 0 90px rgba(43, 226, 255, 0.25);
  transform: translateY(-2px);
}

.btn-primary:active { transform: translateY(0); }

.btn-ghost {
  border-color: rgba(43, 226, 255, 0.4);
  color: var(--cyan);
  background: transparent;
  clip-path: polygon(14px 0, 100% 0, 100% calc(100% - 14px), calc(100% - 14px) 100%, 0 100%, 0 14px);
}

.btn-ghost:hover,
.btn-ghost:focus-visible {
  border-color: var(--cyan);
  background: var(--cyan-dim);
  box-shadow: 0 0 24px rgba(43, 226, 255, 0.22), inset 0 0 24px rgba(43, 226, 255, 0.06);
  transform: translateY(-2px);
}

.btn-ghost:active { transform: translateY(0); }

/* Variantes de .btn-ghost — même contour, couleur différente (voir /admin/flotte :
   Redémarrer reste cyan/.btn-ghost, Arrêter passe en violet, Logs en gris neutre).
   Toujours les 2 seuls accents du site (cyan/violet) + gris --faint, jamais de
   nouvelle teinte (voir CLAUDE.md : éviter un rendu façon "arc-en-ciel"). */
.btn-ghost-violet {
  border-color: rgba(124, 108, 255, 0.4);
  color: var(--violet);
  background: transparent;
  clip-path: polygon(14px 0, 100% 0, 100% calc(100% - 14px), calc(100% - 14px) 100%, 0 100%, 0 14px);
}

.btn-ghost-violet:hover,
.btn-ghost-violet:focus-visible {
  border-color: var(--violet);
  background: var(--violet-dim);
  box-shadow: 0 0 24px rgba(124, 108, 255, 0.22), inset 0 0 24px rgba(124, 108, 255, 0.06);
  transform: translateY(-2px);
}

.btn-ghost-violet:active { transform: translateY(0); }

.btn-ghost-faint {
  border-color: var(--line-soft);
  color: var(--faint);
  background: transparent;
  clip-path: polygon(14px 0, 100% 0, 100% calc(100% - 14px), calc(100% - 14px) 100%, 0 100%, 0 14px);
}

.btn-ghost-faint:hover,
.btn-ghost-faint:focus-visible {
  border-color: var(--faint);
  background: rgba(122, 129, 153, 0.12);
  transform: translateY(-2px);
}

.btn-ghost-faint:active { transform: translateY(0); }

.btn .arrow { transition: transform 0.3s var(--ease-out); }
.btn:hover .arrow { transform: translateX(5px); }

/* ---------- nav ---------- */

.nav {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 50;
  height: var(--nav-h);
  display: flex;
  align-items: center;
  border-bottom: 1px solid transparent;
  transition: background 0.4s, border-color 0.4s;
}

.nav.scrolled {
  background: rgba(5, 6, 10, 0.82);
  backdrop-filter: blur(14px);
  border-bottom-color: var(--line-soft);
}

.nav-inner {
  display: flex;
  align-items: center;
  gap: 40px;
}

/* Desktop : 3 zones — logo à gauche, liens VRAIMENT centrés, actions à droite. */
@media (min-width: 821px) {
  .nav-inner {
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    gap: 20px;
  }
  .nav-inner > .brand { justify-self: start; }
  .nav-inner > nav { justify-self: center; }
  .nav-inner > .nav-actions { justify-self: end; }
}

.nav-actions {
  display: flex;
  align-items: center;
  gap: 12px;
}

.brand {
  display: flex;
  align-items: center;
  gap: 14px;
  margin-right: auto;
}

.brand canvas { display: block; }

.brand-logo {
  display: block;
  filter: drop-shadow(0 0 10px rgba(43, 226, 255, 0.35));
}

.brand .wordmark {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 0.95rem;
  letter-spacing: 0.26em;
  color: var(--ink);
}

.brand .wordmark span { color: var(--cyan); }

.nav-links {
  display: flex;
  align-items: center;
  gap: 8px;
  list-style: none;
}

/* Apparition en cascade au chargement */
.nav-links li { animation: rise 0.55s var(--ease-out) both; }
.nav-links li:nth-child(1) { animation-delay: 0.05s; }
.nav-links li:nth-child(2) { animation-delay: 0.12s; }
.nav-links li:nth-child(3) { animation-delay: 0.19s; }
.nav-links li:nth-child(4) { animation-delay: 0.26s; }

/* Vrais boutons : chip avec icône, halo néon au survol */
.nav-links a {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  padding: 9px 15px;
  font-size: 0.76rem;
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
  border: 1px solid transparent;
  transition: color 0.25s, border-color 0.25s, background 0.25s,
    transform 0.25s var(--ease-out), box-shadow 0.25s;
}

.nav-links a .nico {
  display: inline-flex;
  color: var(--faint);
  transition: color 0.25s, transform 0.3s var(--ease-out);
}

.nav-links a .nico svg { width: 15px; height: 15px; display: block; }

.nav-links a:hover,
.nav-links a:focus-visible {
  color: var(--ink);
  border-color: rgba(43, 226, 255, 0.35);
  background: var(--cyan-dim);
  transform: translateY(-1px);
  box-shadow: 0 0 16px rgba(43, 226, 255, 0.14);
}

.nav-links a:hover .nico,
.nav-links a:focus-visible .nico {
  color: var(--cyan);
  transform: scale(1.18);
}

/* Page courante (ex. Launcher sur /launcher) */
.nav-links a[aria-current="page"] {
  color: var(--cyan);
  border-color: rgba(43, 226, 255, 0.35);
  background: var(--cyan-dim);
}

.nav-links a[aria-current="page"] .nico { color: var(--cyan); }

.nav .btn-login {
  padding: 0.7em 1.6em;
  font-size: 0.68rem;
}

.admin-btn {
  display: inline-flex;
  align-items: center;
  height: 34px;
  padding: 0 14px;
  font-family: var(--font-display);
  font-size: 0.68rem;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--violet);
  border: 1px solid rgba(124, 108, 255, 0.4);
  background: var(--violet-dim);
  transition: border-color 0.25s, box-shadow 0.25s;
}

.admin-btn:hover {
  border-color: var(--violet);
  box-shadow: 0 0 14px rgba(124, 108, 255, 0.25);
}

.nav-burger {
  display: none;
  background: none;
  border: 1px solid var(--line);
  width: 44px;
  height: 44px;
  cursor: pointer;
  position: relative;
}

.nav-burger span,
.nav-burger::before,
.nav-burger::after {
  content: "";
  position: absolute;
  left: 11px;
  right: 11px;
  height: 1.5px;
  background: var(--cyan);
  transition: transform 0.3s var(--ease-out), opacity 0.3s;
}

/* ---------- sélecteur de langue ---------- */

.dropdown { position: relative; }

.dropdown > summary {
  list-style: none;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  height: 34px;
  padding: 0 12px;
  border: 1px solid var(--line-soft);
  color: var(--muted);
  font-size: 0.78rem;
  font-weight: 500;
  letter-spacing: 0.08em;
  background: rgba(255, 255, 255, 0.02);
  transition: border-color 0.25s, color 0.25s;
}

.dropdown > summary::-webkit-details-marker { display: none; }
.dropdown > summary::marker { content: ""; }
.dropdown > summary:hover,
.dropdown[open] > summary { border-color: var(--cyan); color: var(--ink); }

.dropdown .caret { color: var(--faint); font-size: 0.6rem; transition: transform 0.2s; }
.dropdown[open] .caret { transform: rotate(180deg); }

.lang-label { text-transform: uppercase; }

.flag-svg {
  display: inline-flex;
  width: 20px;
  height: 14px;
  overflow: hidden;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.14);
  flex-shrink: 0;
}

.flag-svg svg { width: 100%; height: 100%; display: block; }

.dd-menu {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  min-width: 180px;
  z-index: 60;
  background: var(--panel-solid);
  border: 1px solid var(--line-soft);
  padding: 6px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  box-shadow: 0 20px 50px rgba(0, 0, 0, 0.5);
  max-height: 60vh;
  overflow-y: auto;
}

.dd-menu a {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  color: var(--muted);
  font-size: 0.85rem;
  transition: background 0.2s, color 0.2s;
}

.dd-menu a:hover { background: rgba(43, 226, 255, 0.06); color: var(--ink); }
.dd-menu a.active { color: var(--cyan); }

.dd-form { margin: 0; border-top: 1px solid var(--line-soft); margin-top: 4px; padding-top: 4px; }

.dd-menu .dd-form button {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 8px 10px;
  color: var(--muted);
  font-size: 0.85rem;
  background: none;
  border: none;
  cursor: pointer;
  font: inherit;
  text-align: left;
  transition: background 0.2s, color 0.2s;
}

.dd-menu .dd-form button:hover { background: rgba(43, 226, 255, 0.06); color: var(--ink); }

.user-dd > summary { padding: 4px 10px 4px 4px; }

.nav-avatar {
  width: 26px;
  height: 26px;
  border-radius: 50%;
  display: block;
  box-shadow: 0 0 0 1px var(--line-soft);
}

.uname {
  max-width: 120px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

@media (max-width: 820px) {
  .user-dd .uname { display: none; }
}

.nav-burger::before { top: 15px; }
.nav-burger span { top: 21px; }
.nav-burger::after { top: 27px; }

body.menu-open .nav-burger::before { transform: translateY(6px) rotate(45deg); }
body.menu-open .nav-burger span { opacity: 0; }
body.menu-open .nav-burger::after { transform: translateY(-6px) rotate(-45deg); }

/* menu mobile plein écran */
.mobile-menu {
  position: fixed;
  inset: 0;
  z-index: 40;
  background: rgba(5, 6, 10, 0.96);
  backdrop-filter: blur(18px);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  padding: 24vh 10vw;
  gap: 8px;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.35s, visibility 0.35s;
}

body.menu-open .mobile-menu { opacity: 1; visibility: visible; }

.mobile-menu a {
  font-family: var(--font-display);
  font-size: clamp(1.4rem, 6vw, 2rem);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ink);
  padding-block: 10px;
  transform: translateY(18px);
  opacity: 0;
  transition: transform 0.45s var(--ease-out), opacity 0.45s, color 0.25s;
}

.mobile-menu a:hover { color: var(--cyan); }

.mobile-menu a { display: flex; align-items: center; gap: 16px; }

.mobile-menu .nico { display: inline-flex; color: var(--cyan); }
.mobile-menu .nico svg { width: 22px; height: 22px; display: block; }

body.menu-open .mobile-menu a {
  transform: translateY(0);
  opacity: 1;
}

body.menu-open .mobile-menu a:nth-child(1) { transition-delay: 0.05s; }
body.menu-open .mobile-menu a:nth-child(2) { transition-delay: 0.1s; }
body.menu-open .mobile-menu a:nth-child(3) { transition-delay: 0.15s; }
body.menu-open .mobile-menu a:nth-child(4) { transition-delay: 0.2s; }
body.menu-open .mobile-menu a:nth-child(5) { transition-delay: 0.25s; }

/* ---------- hero ---------- */

.hero {
  position: relative;
  min-height: 100svh;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}

.hero-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
}

.hero::after {
  /* vignette pour asseoir le texte */
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(ellipse 70% 55% at 50% 52%, rgba(5, 6, 10, 0.55), transparent 70%),
    linear-gradient(to bottom, rgba(5, 6, 10, 0.5), transparent 22%, transparent 72%, var(--bg) 100%);
  pointer-events: none;
}

.hero-content {
  position: relative;
  z-index: 2;
  text-align: center;
  padding-inline: 24px;
  max-width: 1100px;
}

.hero .overline {
  display: inline-block;
  animation: rise 1s var(--ease-out) 0.15s both;
}

.hero-title {
  font-family: var(--font-display);
  font-weight: 900;
  font-size: clamp(2.6rem, 11vw, 8.2rem);
  line-height: 1;
  letter-spacing: 0.045em;
  text-transform: uppercase;
  margin-block: 20px 26px;
  color: var(--ink);
  text-shadow:
    0 0 18px rgba(43, 226, 255, 0.35),
    0 0 60px rgba(43, 226, 255, 0.28),
    0 0 140px rgba(43, 226, 255, 0.2);
  animation: rise 1.1s var(--ease-out) 0.3s both;
}

.hero-title .cube-char { color: var(--cyan); }

.hero-tagline {
  font-size: clamp(1rem, 2vw, 1.3rem);
  color: var(--muted);
  letter-spacing: 0.04em;
  animation: rise 1.1s var(--ease-out) 0.5s both;
}

.hero-tagline strong { color: var(--ink); font-weight: 500; }

.hero-ctas {
  margin-top: 44px;
  display: flex;
  gap: 18px;
  justify-content: center;
  flex-wrap: wrap;
  animation: rise 1.1s var(--ease-out) 0.68s both;
}

@keyframes rise {
  from { opacity: 0; transform: translateY(28px); }
  to { opacity: 1; transform: translateY(0); }
}

.scroll-hint {
  position: absolute;
  bottom: 30px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  color: var(--faint);
  font-size: 0.62rem;
  letter-spacing: 0.4em;
  text-transform: uppercase;
  animation: rise 1s var(--ease-out) 1.1s both;
}

.scroll-hint .line {
  width: 1px;
  height: 44px;
  background: linear-gradient(to bottom, var(--cyan), transparent);
  overflow: hidden;
  position: relative;
}

.scroll-hint .line::after {
  content: "";
  position: absolute;
  top: -100%;
  left: 0;
  width: 100%;
  height: 100%;
  background: linear-gradient(to bottom, transparent, #bff4ff);
  animation: scrolldrop 2.2s ease-in-out infinite;
}

@keyframes scrolldrop {
  0% { top: -100%; }
  60%, 100% { top: 100%; }
}

/* ---------- sections ---------- */

section { position: relative; }

.section-pad { padding-block: 130px; }

/* fine ligne de séparation façon truss */
.rule {
  height: 1px;
  background: linear-gradient(to right, transparent, var(--line) 18%, var(--line) 82%, transparent);
  position: relative;
}

.rule::before,
.rule::after {
  content: "";
  position: absolute;
  top: -2.5px;
  width: 6px;
  height: 6px;
  background: var(--cyan);
  box-shadow: 0 0 10px var(--cyan-glow);
  transform: rotate(45deg);
}

.rule::before { left: 18%; }
.rule::after { right: 18%; }

/* ---------- concept ---------- */

.concept-grid {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: 22px;
}

.concept-card {
  position: relative;
  grid-column: span 6;
  background: var(--panel);
  border: 1px solid var(--line-soft);
  padding: 34px 34px 38px;
  overflow: hidden;
  transition: border-color 0.4s, box-shadow 0.4s, transform 0.4s var(--ease-out),
    background 0.4s;
}

/* décrochage de grille : rythme asymétrique */
.concept-card:nth-child(1) { grid-column: 1 / span 7; }
.concept-card:nth-child(2) { grid-column: 8 / span 5; margin-top: 56px; }
.concept-card:nth-child(3) { grid-column: 1 / span 5; align-self: start; }
.concept-card:nth-child(4) { grid-column: 6 / span 7; margin-top: 56px; }

.concept-card:hover {
  border-color: rgba(43, 226, 255, 0.45);
  background: rgba(43, 226, 255, 0.03);
  box-shadow: 0 0 40px rgba(43, 226, 255, 0.09), inset 0 0 60px rgba(43, 226, 255, 0.03);
  transform: translateY(-4px);
}

/* coins « repères de scène » */
.concept-card::before,
.concept-card::after {
  content: "";
  position: absolute;
  width: 14px;
  height: 14px;
  border: 1px solid rgba(43, 226, 255, 0.55);
  transition: opacity 0.4s;
  opacity: 0.5;
}

.concept-card::before {
  top: -1px;
  left: -1px;
  border-right: none;
  border-bottom: none;
}

.concept-card::after {
  bottom: -1px;
  right: -1px;
  border-left: none;
  border-top: none;
}

.concept-card:hover::before,
.concept-card:hover::after { opacity: 1; }

.concept-card .mini-wire {
  width: 92px;
  height: 92px;
  margin-bottom: 22px;
  display: block;
}

.concept-card .tag {
  font-size: 0.62rem;
  font-weight: 500;
  letter-spacing: 0.34em;
  text-transform: uppercase;
  color: var(--faint);
  margin-bottom: 10px;
}

.concept-card h3 {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.12rem;
  line-height: 1.3;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  margin-bottom: 14px;
}

.concept-card p {
  color: var(--muted);
  font-size: 0.96rem;
  max-width: 46ch;
}

.concept-card p b { color: var(--ink); font-weight: 500; }

/* ---------- soirées ---------- */

.events-note {
  display: flex;
  align-items: center;
  gap: 12px;
  color: var(--muted);
  font-size: 0.9rem;
  margin-top: 34px;
}

.events-note .pulse {
  width: 8px;
  height: 8px;
  background: var(--cyan);
  transform: rotate(45deg);
  box-shadow: 0 0 12px var(--cyan-glow);
  animation: pulse 2.4s ease-in-out infinite;
  flex-shrink: 0;
}

@keyframes pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.35; }
}

.events-empty {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 18px;
  padding-block: 48px;
  border-top: 1px solid var(--line-soft);
  border-bottom: 1px solid var(--line-soft);
}

.events-empty .pulse {
  width: 8px;
  height: 8px;
  background: var(--cyan);
  transform: rotate(45deg);
  box-shadow: 0 0 12px var(--cyan-glow);
  animation: pulse 2.4s ease-in-out infinite;
}

.events-empty p {
  color: var(--muted);
  font-size: 1rem;
  max-width: 52ch;
  margin: 0;
}

.event-row {
  display: grid;
  grid-template-columns: 150px 1fr auto auto;
  align-items: center;
  gap: 32px;
  padding-block: 34px;
  border-top: 1px solid var(--line-soft);
  position: relative;
  transition: background 0.35s, padding-left 0.35s var(--ease-out);
}

.event-row:last-of-type { border-bottom: 1px solid var(--line-soft); }

.event-row::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  height: 1px;
  width: 0;
  background: var(--cyan);
  box-shadow: 0 0 12px var(--cyan-glow);
  transition: width 0.5s var(--ease-out);
}

.event-row:hover { background: rgba(43, 226, 255, 0.025); padding-left: 14px; }
.event-row:hover::before { width: 100%; }

.event-date {
  font-family: var(--font-display);
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
  line-height: 1.7;
}

.event-date b {
  display: block;
  color: var(--cyan);
  font-size: 0.85rem;
  font-weight: 700;
}

.event-name {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.3rem, 3.4vw, 2.2rem);
  text-transform: uppercase;
  letter-spacing: 0.02em;
  line-height: 1.15;
}

.event-dj {
  display: block;
  font-family: var(--font-body);
  font-size: 0.92rem;
  font-weight: 400;
  letter-spacing: 0.08em;
  text-transform: none;
  color: var(--muted);
  margin-top: 6px;
}

.event-dj::before {
  content: "⌁ ";
  color: var(--cyan);
}

.badge {
  font-family: var(--font-display);
  font-size: 0.6rem;
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  padding: 0.75em 1.4em;
  border: 1px solid;
  white-space: nowrap;
}

.badge-open {
  color: var(--cyan);
  border-color: rgba(43, 226, 255, 0.5);
  background: var(--cyan-dim);
  box-shadow: 0 0 16px rgba(43, 226, 255, 0.12);
}

.badge-full {
  color: var(--violet);
  border-color: rgba(124, 108, 255, 0.5);
  background: var(--violet-dim);
}

.event-arrow {
  font-size: 1.3rem;
  color: var(--faint);
  transition: color 0.3s, transform 0.3s var(--ease-out);
}

.event-row:hover .event-arrow {
  color: var(--cyan);
  transform: translateX(6px);
}

/* ---------- bandeau launcher ---------- */

.launcher-band {
  position: relative;
  overflow: hidden;
  border-block: 1px solid var(--line-soft);
  background:
    radial-gradient(700px 320px at 85% 50%, rgba(43, 226, 255, 0.07), transparent 70%),
    var(--bg-2);
}

/* grille perspective façon dancefloor */
.launcher-band::before {
  content: "";
  position: absolute;
  inset: 0;
  background:
    repeating-linear-gradient(to right, rgba(43, 226, 255, 0.05) 0 1px, transparent 1px 90px),
    repeating-linear-gradient(to bottom, rgba(43, 226, 255, 0.05) 0 1px, transparent 1px 90px);
  mask-image: radial-gradient(70% 90% at 70% 50%, black, transparent 78%);
  -webkit-mask-image: radial-gradient(70% 90% at 70% 50%, black, transparent 78%);
  pointer-events: none;
}

.launcher-band .wrap {
  position: relative;
  display: grid;
  grid-template-columns: 1.25fr 0.75fr;
  gap: 60px;
  align-items: center;
  padding-block: 96px;
}

.launcher-band h2 {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.6rem, 3.6vw, 2.6rem);
  text-transform: uppercase;
  line-height: 1.15;
  margin-block: 14px 18px;
}

.launcher-band h2 em {
  font-style: normal;
  color: var(--cyan);
  text-shadow: 0 0 20px var(--cyan-glow);
}

.launcher-points {
  list-style: none;
  margin: 26px 0 0;
  display: grid;
  gap: 12px;
  color: var(--muted);
  font-size: 0.96rem;
}

.launcher-points li { display: flex; gap: 14px; align-items: flex-start; }

.launcher-points .tick {
  color: var(--cyan);
  font-family: var(--font-display);
  font-size: 0.7rem;
  flex-shrink: 0;
  margin-top: 0.35em;
}

.launcher-points b {
  display: block;
  color: var(--ink);
  font-weight: 500;
  margin-bottom: 4px;
}

.launcher-points .pt-desc {
  display: block;
  color: var(--muted);
  font-size: 0.88rem;
  line-height: 1.55;
}

.launcher-cta-zone {
  display: flex;
  flex-direction: column;
  gap: 16px;
  align-items: flex-start;
}

.launcher-cta-zone .ver {
  font-size: 0.72rem;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--faint);
}

/* ---------- contact ---------- */

.contact { text-align: center; }

.contact .section-title { margin-block: 18px 22px; }

.contact .lead { margin-inline: auto; }

.contact-ctas {
  margin-top: 44px;
  display: flex;
  gap: 18px;
  justify-content: center;
  flex-wrap: wrap;
}

.contact-canvas {
  width: 150px;
  height: 150px;
  margin-inline: auto;
  display: block;
  margin-bottom: 8px;
}

/* ---------- footer ---------- */

.footer {
  border-top: 1px solid var(--line-soft);
  padding-block: 44px;
  position: relative;
  z-index: 1;
}

.footer-inner {
  display: flex;
  align-items: center;
  gap: 32px;
  flex-wrap: wrap;
}

.footer .brand { margin-right: 0; }

.footer-links {
  display: flex;
  gap: 26px;
  list-style: none;
  margin-right: auto;
}

.footer-links a {
  font-size: 0.78rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
  transition: color 0.25s;
}

.footer-links a:hover { color: var(--cyan); }

.footer .colophon {
  font-size: 0.78rem;
  color: var(--faint);
  letter-spacing: 0.06em;
  text-align: right;
}

.footer .colophon b { color: var(--muted); font-weight: 500; }

/* ---------- reveals au scroll ---------- */

.reveal {
  opacity: 0;
  transform: translateY(34px);
  transition: opacity 0.9s var(--ease-out), transform 0.9s var(--ease-out);
  transition-delay: var(--d, 0s);
}

/* transform: none (pas translateY(0)) : visuellement identique une fois l'animation
   terminée (les navigateurs interpolent proprement translateY(34px) -> none), mais
   translateY(0) reste une valeur de transform "active" au sens CSS — n'importe quelle
   valeur de transform différente de "none" crée un nouveau bloc de positionnement pour
   les descendants position:fixed, qui se retrouvent alors ancrés sur CET élément au lieu
   du viewport. Piège découvert via .row-menu-content (menu ⋯ de /admin/flotte, dans un
   <table class="reveal">) : une fois "revealed", le tableau piégeait tout position:fixed
   en son sein. Même valeur déjà utilisée dans le bloc prefers-reduced-motion ci-dessous
   (recherche ".reveal { opacity: 1; transform: none; }") — on aligne juste le cas normal. */
.reveal.visible {
  opacity: 1;
  transform: none;
}

/* Contenu ré-affiché après un swap AJAX admin (admin-ajax.js::revealNow) : état
   final appliqué sans rejouer le fondu de 0.9s pensé pour l'arrivée au scroll. */
.reveal.reveal-instant { transition: none !important; }

/* ============================================================
   Page launcher
   ============================================================ */

.sub-hero {
  position: relative;
  min-height: 68svh;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  text-align: center;
  padding-top: var(--nav-h);
}

.sub-hero .hero-canvas { position: absolute; inset: 0; }

.sub-hero::after {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(ellipse 65% 55% at 50% 55%, rgba(5, 6, 10, 0.5), transparent 72%),
    linear-gradient(to bottom, rgba(5, 6, 10, 0.55), transparent 25%, transparent 70%, var(--bg) 100%);
  pointer-events: none;
}

.sub-hero .hero-content { max-width: 900px; }

.sub-hero h1 {
  font-family: var(--font-display);
  font-weight: 900;
  font-size: clamp(2rem, 7vw, 4.6rem);
  line-height: 1.05;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  margin-block: 20px 24px;
  text-shadow:
    0 0 18px rgba(43, 226, 255, 0.3),
    0 0 70px rgba(43, 226, 255, 0.22);
  animation: rise 1.1s var(--ease-out) 0.3s both;
}

.sub-hero h1 em {
  font-style: normal;
  color: var(--cyan);
}

.sub-hero .hero-tagline { animation-delay: 0.45s; }
.sub-hero .hero-ctas { animation-delay: 0.6s; margin-top: 36px; }

.dl-meta {
  margin-top: 18px;
  font-size: 0.72rem;
  letter-spacing: 0.26em;
  text-transform: uppercase;
  color: var(--faint);
  animation: rise 1.1s var(--ease-out) 0.75s both;
}

/* étapes */
.steps {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 22px;
  counter-reset: step;
}

.step {
  position: relative;
  border: 1px solid var(--line-soft);
  background: var(--panel);
  padding: 38px 32px;
  transition: border-color 0.4s, transform 0.4s var(--ease-out), box-shadow 0.4s;
}

.step:hover {
  border-color: rgba(43, 226, 255, 0.4);
  transform: translateY(-4px);
  box-shadow: 0 0 34px rgba(43, 226, 255, 0.08);
}

.step .step-num {
  font-family: var(--font-display);
  font-weight: 900;
  font-size: 2.6rem;
  line-height: 1;
  color: transparent;
  -webkit-text-stroke: 1px rgba(43, 226, 255, 0.65);
  margin-bottom: 20px;
}

.step h3 {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  margin-bottom: 12px;
}

.step p { color: var(--muted); font-size: 0.94rem; }

.step .connector {
  position: absolute;
  top: 50%;
  right: -22px;
  width: 22px;
  height: 1px;
  background: linear-gradient(to right, rgba(43, 226, 255, 0.5), transparent);
}

.step:last-child .connector { display: none; }

/* config requise */
.specs {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 22px;
}

.spec {
  border: 1px solid var(--line-soft);
  border-left: 2px solid var(--cyan);
  background: var(--panel);
  padding: 26px 28px;
}

.spec .spec-k {
  font-size: 0.64rem;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--faint);
  margin-bottom: 8px;
}

.spec .spec-v {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: 0.95rem;
  letter-spacing: 0.04em;
}

.spec .spec-note { color: var(--muted); font-size: 0.85rem; margin-top: 6px; }

/* FAQ */
.faq { max-width: 780px; }

.faq details {
  border-top: 1px solid var(--line-soft);
}

.faq details:last-child { border-bottom: 1px solid var(--line-soft); }

.faq summary {
  cursor: pointer;
  list-style: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  padding-block: 26px;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: 0.95rem;
  letter-spacing: 0.03em;
  transition: color 0.25s;
}

.faq summary::-webkit-details-marker { display: none; }

.faq summary:hover { color: var(--cyan); }

.faq summary .plus {
  color: var(--cyan);
  font-size: 1.2rem;
  font-weight: 400;
  transition: transform 0.35s var(--ease-out);
  flex-shrink: 0;
}

.faq details[open] summary .plus { transform: rotate(45deg); }

.faq .faq-body {
  color: var(--muted);
  padding-bottom: 26px;
  max-width: 62ch;
}

.faq .faq-body b { color: var(--ink); font-weight: 500; }

/* ---------- responsive ---------- */

@media (max-width: 960px) {
  .concept-card:nth-child(n) {
    grid-column: 1 / -1;
    margin-top: 0;
  }

  .launcher-band .wrap {
    grid-template-columns: 1fr;
    gap: 40px;
    padding-block: 72px;
  }

  .steps, .specs { grid-template-columns: 1fr; }

  .step .connector { display: none; }

  .event-row {
    grid-template-columns: 1fr auto;
    gap: 10px 18px;
    padding-block: 26px;
  }

  .event-date { grid-column: 1 / -1; display: flex; gap: 14px; align-items: baseline; }
  .event-date b { display: inline; }
  .event-arrow { display: none; }
}

@media (max-width: 820px) {
  .nav-links, .nav .btn-login { display: none; }
  .nav-burger { display: block; }
  .lang-dd .lang-label { display: none; }
  .dropdown > summary { padding: 0 9px; }

  .section-pad { padding-block: 84px; }

  .section-head {
    flex-direction: column;
    gap: 14px;
    margin-bottom: 40px;
  }
}

@media (min-width: 821px) {
  .mobile-menu { display: none; }
}

/* ---------- accessibilité mouvement ---------- */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }

  .reveal { opacity: 1; transform: none; }
}

/* ---------- avantages / paliers de dons (/admin/avantages) ---------- */

/* Puce compacte "icône + libellé" pour un avantage (vol/vaisseau/tag/priorité) — réutilisée sur
   chaque palier de don, aussi bien en admin (/admin/avantages) que côté joueur (/me/soirees,
   page publique). */
.perk-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 0.4em 0.85em;
  font-family: var(--font-display);
  font-size: 0.66rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  border: 1px solid rgba(124, 108, 255, 0.35);
  color: var(--violet);
  background: rgba(124, 108, 255, 0.06);
}

.perk-chip svg { width: 13px; height: 13px; flex: none; }
.perk-chip.dim { border-color: var(--line-soft); color: var(--faint); background: none; }

/* Ligne de puces d'avantages, dans chaque palier de don (.tier-body) — admin, /me/soirees et
   page publique. */
.perk-row { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 14px; }

/* Paliers de donation — ligne verticale néon reliant chaque palier (façon jalons de la
   référence Marco), reskinnée dans la DA cube filaire cyan/violet plutôt que copiée telle
   quelle. Le connecteur est un simple gradient vertical posé en ::before sur la liste, chaque
   palier ancre son nœud via ::before positionné en absolu sur .tier-node. */
.tier-list {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 0;
  margin-left: 18px;
  padding-left: 34px;
  border-left: 1px solid var(--line-soft);
}

.tier-row {
  position: relative;
  padding: 22px 0;
  border-bottom: 1px solid var(--line-soft);
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 20px;
  flex-wrap: wrap;
}

.tier-row:last-child { border-bottom: none; }

.tier-node {
  position: absolute;
  left: -41px;
  top: 26px;
  width: 15px;
  height: 15px;
  background: var(--panel-solid);
  border: 2px solid var(--cyan);
  box-shadow: 0 0 10px var(--cyan-glow);
  transform: rotate(45deg);
}

.tier-row.inactive .tier-node { border-color: var(--faint); box-shadow: none; }

.tier-amount {
  font-family: var(--font-display);
  font-size: 1.3rem;
  color: var(--cyan);
  white-space: nowrap;
  min-width: 110px;
}

.tier-row.inactive .tier-amount { color: var(--faint); }

.tier-body { flex: 1; min-width: 220px; }
.tier-body h4 { font-size: 0.95rem; margin-bottom: 4px; }
.tier-body p { font-size: 0.82rem; color: var(--muted); margin-bottom: 10px; max-width: none; }

.tier-actions { display: flex; gap: 8px; flex: none; align-self: flex-start; }

@media (max-width: 640px) {
  .tier-list { margin-left: 4px; padding-left: 26px; }
  .tier-node { left: -33px; }
}

/* ---------- barre de progression des dons (fragment fragments.html :: donationProgress) ---------- */
/* Page publique (index.html, anonyme) ET /me/soirees (connecté) — voir le fragment pour le
   choix de la donnée (agrégée vs personnelle). overflow:hidden sur .donation-bar-track suffit à
   clamper visuellement un fillPct > 100% (total déjà au-delà du dernier palier connu), sans
   calcul de clamp côté Thymeleaf. */
.donation-progress { margin-top: 14px; }

.donation-bar-track {
  position: relative;
  height: 10px;
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid var(--line-soft);
  overflow: hidden;
}

.donation-bar-fill {
  height: 100%;
  background: linear-gradient(90deg, var(--violet), var(--cyan));
  box-shadow: 0 0 10px var(--cyan-glow);
  transition: width 0.4s var(--ease-out);
}

.donation-bar-tick {
  position: absolute;
  top: -3px;
  width: 2px;
  height: 16px;
  background: var(--faint);
  transform: translateX(-1px);
}

.donation-bar-tick.reached { background: var(--cyan); box-shadow: 0 0 6px var(--cyan-glow); }

.donation-bar-caption {
  margin-top: 8px;
  font-size: 0.78rem;
  color: var(--faint);
  max-width: none;
}

.donation-bar-caption strong { color: var(--ink); font-family: var(--font-display); font-weight: 500; }
