:root {
  --bg: #100e19;
  --bg-panel: #1c1830;
  --bg-panel-2: #241f3d;
  --border: #322a52;
  --text: #eae6f5;
  --text-dim: #9086b0;
  --accent: #ff5fa2;
  --accent-dim: #7a3357;
  --accent2: #4dd9ff;
  --ready: #7cff6b;
  --warn: #ffcb5c;
  --font-display: "Press Start 2P", monospace;
  --font-body: "Space Grotesk", system-ui, sans-serif;
  --font-mono: "JetBrains Mono", monospace;
  --radius: 10px;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--bg);
  background-image:
    radial-gradient(circle at 15% 0%, rgba(255,95,162,0.08), transparent 40%),
    radial-gradient(circle at 85% 20%, rgba(77,217,255,0.07), transparent 40%);
  color: var(--text);
  font-family: var(--font-body);
  min-height: 100vh;
}

button, input, textarea { font-family: inherit; }

a, .btn-link {
  color: var(--accent2);
  cursor: pointer;
  background: none;
  border: none;
  font-family: inherit;
  font-size: 0.85rem;
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* ---------- Logo & type ---------- */

.logo {
  font-family: var(--font-display);
  font-size: 1.4rem;
  letter-spacing: 1px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 8px;
}
.logo-sm { font-size: 1rem; }
.logo-1 { color: var(--accent); }
.logo-2 { color: var(--accent2); }

.beta-badge {
  font-family: var(--font-mono);
  font-size: 0.62rem;
  font-weight: 700;
  letter-spacing: 0.5px;
  text-transform: uppercase;
  color: var(--accent2);
  border: 1px solid var(--accent2);
  border-radius: 999px;
  padding: 2px 8px;
  margin-left: 2px;
  white-space: nowrap;
}

.site-footer {
  text-align: center;
  font-size: 0.7rem;
  color: var(--text-dim);
  opacity: 0.7;
  margin-top: 18px;
  padding-bottom: 4px;
}

.logo-img {
  height: 34px;
  width: 34px;
  object-fit: cover;
  border-radius: 8px;
  flex-shrink: 0;
}
.logo-sm .logo-img { height: 24px; width: 24px; border-radius: 6px; }
.logo-img:not([src]), .logo-img[src=""] { display: none; }

.eyebrow {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 2px;
  text-transform: uppercase;
  color: var(--text-dim);
  margin: 0 0 14px 0;
  padding-left: 10px;
  border-left: 3px solid var(--accent);
}

.hint {
  font-size: 0.75rem;
  color: var(--text-dim);
  margin: -6px 0 4px 0;
}

.error-text {
  color: var(--warn);
  font-size: 0.85rem;
  background: rgba(255,203,92,0.08);
  border: 1px solid rgba(255,203,92,0.3);
  padding: 8px 10px;
  border-radius: var(--radius);
}

.telegram-link-notice {
  color: var(--accent2);
  font-size: 0.85rem;
  background: rgba(77,217,255,0.08);
  border: 1px solid rgba(77,217,255,0.3);
  padding: 8px 10px;
  border-radius: var(--radius);
  line-height: 1.4;
}

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

/* Specificità pari a quella delle classi sotto: senza questa regola,
   .login-screen{display:flex} e .app-screen{...} vincono sempre su [hidden]
   e gli schermi non si nascondono mai correttamente. */
.login-screen[hidden], .app-screen[hidden] {
  display: none;
}

.login-screen {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
}

.login-card {
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-radius: 16px;
  padding: 36px 32px;
  width: 100%;
  max-width: 360px;
  text-align: center;
  box-shadow: 0 0 0 1px rgba(255,95,162,0.05), 0 20px 60px rgba(0,0,0,0.5);
}

.login-sub {
  color: var(--text-dim);
  font-size: 0.85rem;
  margin: 10px 0 26px 0;
}

.login-form {
  display: flex;
  flex-direction: column;
  gap: 14px;
  text-align: left;
}

/* ---------- Form fields (shared) ---------- */

label {
  display: flex;
  flex-direction: column;
  gap: 6px;
  font-size: 0.8rem;
  color: var(--text-dim);
}

input[type="text"],
input[type="password"],
input[type="date"],
input[type="time"] {
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 12px;
  color: var(--text);
  /* 16px minimo: sotto questa soglia Safari su iPhone zooma automaticamente sul campo al tocco */
  font-size: 16px;
  outline: none;
  transition: border-color 0.15s;
  min-height: 44px;
}

/* I campi data/ora hanno un'icona e un popup disegnati dal browser stesso, non da noi:
   di default escono scuri e diventano invisibili su un sito con sfondo scuro.
   "color-scheme: dark" dice al browser di usare toni chiari per quei controlli nativi. */
input[type="date"],
input[type="time"] {
  color-scheme: dark;
}
input[type="date"]::-webkit-calendar-picker-indicator,
input[type="time"]::-webkit-calendar-picker-indicator {
  filter: invert(0.9) brightness(1.4);
  opacity: 0.85;
  cursor: pointer;
}
input[type="date"]::-webkit-calendar-picker-indicator:hover,
input[type="time"]::-webkit-calendar-picker-indicator:hover {
  opacity: 1;
}
input:focus-visible {
  border-color: var(--accent2);
  outline: 2px solid rgba(77,217,255,0.35);
  outline-offset: 1px;
}

.row-2 {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}

.stack-form { display: flex; flex-direction: column; gap: 12px; }
.stack-form[hidden] { display: none; }

/* ---------- Buttons ---------- */

.btn {
  border: none;
  border-radius: 8px;
  padding: 12px 16px;
  min-height: 44px;
  font-weight: 600;
  font-size: 0.88rem;
  cursor: pointer;
  transition: transform 0.08s ease, filter 0.15s ease;
  -webkit-tap-highlight-color: transparent;
}
a.btn { text-decoration: none; display: inline-block; }
.btn:hover { filter: brightness(1.1); }
.btn:active { transform: scale(0.98); }
.btn-block { width: 100%; display: block; box-sizing: border-box; }

.btn-primary { background: var(--accent); color: #1a0a14; }
.btn-accent { background: var(--accent2); color: #04222b; }
.btn-ghost {
  background: transparent;
  color: var(--text-dim);
  border: 1px solid var(--border);
}
.btn-ghost:hover { color: var(--text); border-color: var(--accent2); }
.btn-danger { background: rgba(255,95,95,0.15); color: #ff9a9a; border: 1px solid rgba(255,95,95,0.3); }

.btn-header {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  white-space: nowrap;
  color: var(--accent2);
  min-height: 35px;
  padding: 10px 13px;
  font-size: 0.7rem;
}
.btn-header:hover { color: var(--accent2); border-color: var(--accent2); }
.btn-header svg { width: 12px; height: 12px; }
.btn-header.discord-linked { color: #5865F2; border-color: rgba(88,101,242,0.4); background: rgba(88,101,242,0.1); }

.header-count-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 16px;
  height: 16px;
  padding: 0 4px;
  border-radius: 999px;
  background: var(--accent);
  color: #1a0a14;
  font-size: 0.62rem;
  font-weight: 700;
  line-height: 1;
}

/* ---------- App shell ---------- */

.app-screen { min-height: 100vh; }

.topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 8px;
  padding: 16px 24px;
  border-bottom: 1px solid var(--border);
  background: rgba(28,24,48,0.6);
  backdrop-filter: blur(6px);
  position: sticky;
  top: 0;
  z-index: 20;
}

.user-chip {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 0.85rem;
  color: var(--text-dim);
}

.dot-online {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--ready);
  box-shadow: 0 0 8px var(--ready);
}

.layout {
  display: grid;
  grid-template-columns: 280px 1fr 280px;
  grid-template-areas: "left main right";
  gap: 20px;
  padding: 20px 24px 60px;
  max-width: 1440px;
  margin: 0 auto;
}

.sidebar-left { grid-area: left; }
.main { grid-area: main; }
.sidebar-right { grid-area: right; }

@media (max-width: 1180px) {
  .layout { grid-template-columns: 280px 1fr; grid-template-areas: "left main" "right right"; }
}

@media (max-width: 880px) {
  .layout { grid-template-columns: 1fr; grid-template-areas: "left" "main" "right"; }
}

@media (max-width: 600px) {
  .topbar { padding: 12px 16px; flex-wrap: wrap; }
  .layout { padding: 14px 14px 40px; gap: 14px; }
  .panel { padding: 16px; }
  .login-card { padding: 28px 22px; }
  .row-2 { grid-template-columns: 1fr; }
  .logo { font-size: 0.95rem; letter-spacing: 0; }
  .eyebrow { font-size: 0.66rem; }
  .event-card-head { gap: 10px; }
  .event-cover { width: 52px; height: 24px; }

  /* La barra con "La mia collezione / Collega / Discord / Esci" non ci sta tutta in
     larghezza su schermi stretti. Invece di lasciarla sforare fuori dallo schermo
     (che disallinea il resto della pagina) o andare a capo su più righe, la rendiamo
     scorrevole in orizzontale col dito, tenendo tutto su un'unica riga ordinata. */
  .user-chip {
    width: 100%;
    flex-wrap: nowrap;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scroll-snap-type: x proximity;
    scrollbar-width: none; /* Firefox */
  }
  .user-chip::-webkit-scrollbar { display: none; } /* Chrome/Safari: scorrevole ma senza barra a vista */
  .user-chip > * { flex-shrink: 0; scroll-snap-align: start; } /* niente testo/pulsanti schiacciati o spezzati */

  /* Calendario più leggibile su schermi stretti: barra a colonne, vista ad agenda */
  .fc .fc-toolbar { flex-direction: column; gap: 8px; align-items: stretch; }
  .fc .fc-toolbar-chunk { display: flex; justify-content: center; }
  .fc .fc-toolbar-title { font-size: 0.95rem; text-align: center; }
  .fc .fc-button { padding: 6px 10px; font-size: 0.8rem; }
}

.sidebar { display: flex; flex-direction: column; gap: 20px; }
.main { display: flex; flex-direction: column; gap: 20px; min-width: 0; }

.panel {
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 20px;
}

/* ---------- Online ora ---------- */

.online-list {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.online-pill {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
  padding: 7px 9px;
  border-radius: var(--radius);
  background: var(--bg);
  border: 1px solid var(--border);
  font-size: 0.7rem;
  color: var(--text);
}
.online-pill .tile-name { white-space: nowrap; }
.online-avatar { width: 38px; height: 38px; border-radius: 6px; object-fit: cover; }
.online-avatar.avatar-fallback,
.online-pill .avatar-fallback { width: 38px; height: 38px; font-size: 0.95rem; }

/* ---------- Online ora (pannello unificato: app + Discord + Steam insieme) ---------- */

.fused-grid { display: flex; flex-wrap: wrap; gap: 8px; }
.fused-card {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
  padding: 7px 9px;
  border-radius: var(--radius);
  background: var(--bg);
  border: 1px solid var(--border);
  font-size: 0.7rem;
  color: var(--text);
  width: 74px;
}
.fused-name { white-space: nowrap; }
.fused-avatar-wrap { position: relative; display: inline-flex; }
/* Riusa esattamente le dimensioni di .online-avatar, per restare coerente col resto
   dell'app anche se qui l'elemento è un div fallback invece di un tag img. */
.fused-avatar { width: 38px; height: 38px; border-radius: 6px; object-fit: cover; }
.fused-avatar.avatar-fallback { width: 38px; height: 38px; font-size: 0.95rem; }
/* Pallini in fila, ancorati al bordo destro della foto (come il singolo pallino che
   c'era prima) invece che centrati — così restano "attaccati" a un punto fisso anche
   quando cambiano di numero da 1 a 3. */
.fused-dots-row { position: absolute; bottom: -4px; right: -3px; display: flex; gap: 3px; }
.fused-dots-row .dot { width: 12px; height: 12px; border-radius: 50%; border: 2px solid var(--bg); }
.dot-online { background: var(--ready); box-shadow: 0 0 4px rgba(124,255,107,0.6); }
.dot-steam { background: #66c0f4; box-shadow: 0 0 4px rgba(102,192,244,0.6); }
.dot-voice { background: #b39ef2; box-shadow: 0 0 4px rgba(179,158,242,0.6); }

/* Badge di stato Steam (occupato/assente/ecc.): sempre blu come il brand Steam, cambia
   solo il simbolo dentro. Angolo opposto ai pallini in basso, per non sovrapporsi. */
.steam-state-badge {
  position: absolute;
  top: -5px;
  right: -5px;
  min-width: 15px;
  height: 13px;
  padding: 0 2px;
  border-radius: 7px;
  background: #66c0f4;
  border: 2px solid var(--bg);
  color: #0a1622;
  font-size: 0.48rem;
  font-weight: 700;
  line-height: 9px;
  text-align: center;
  box-shadow: 0 0 4px rgba(102, 192, 244, 0.6);
}

/* Badge Discord (assente/non disturbare): stesso principio del badge Steam, ma nell'angolo
   OPPOSTO (in alto a sinistra invece che a destra) — una persona può avere entrambi gli
   stati attivi insieme (es. occupata su Steam E assente su Discord), non devono
   sovrapporsi. Riproduce le forme reali di Discord invece di un simbolo di testo: la
   "falce di luna" per assente, il trattino orizzontale (divieto) per non disturbare.*/
.discord-state-badge {
  position: absolute;
  top: -5px;
  left: -5px;
  width: 13px;
  height: 13px;
  border-radius: 50%;
  border: 2px solid var(--bg);
  overflow: hidden;
}
.discord-state-badge.is-idle {
  background: #b39ef2;
  box-shadow: 0 0 4px rgba(179, 158, 242, 0.6);
}
/* La falce si ottiene "mordendo" un cerchio del colore di sfondo, spostato in alto a
   destra rispetto al centro — tecnica classica per una mezzaluna solo in CSS. */
.discord-state-badge.is-idle::after {
  content: '';
  position: absolute;
  width: 100%;
  height: 100%;
  border-radius: 50%;
  background: var(--bg);
  top: -22%;
  left: 32%;
}
.discord-state-badge.is-dnd {
  background: #b39ef2;
  box-shadow: 0 0 4px rgba(179, 158, 242, 0.6);
}
.discord-state-badge.is-dnd::after {
  content: '';
  position: absolute;
  left: 22%;
  right: 22%;
  top: 50%;
  height: 2px;
  background: #1a1116;
  transform: translateY(-50%);
  border-radius: 1px;
}

/* Il pallino verde "online" non ha una riga di testo sotto (è implicito), Steam e
   Discord sì perché il dettaglio (gioco/canale) è informazione utile — la card si
   allunga verticalmente solo in base a quante righe di testo servono davvero. */
.fused-status-list { display: flex; flex-direction: column; align-items: center; gap: 1px; margin-top: 3px; }
.fused-status-list span { font-size: 0.6rem; white-space: nowrap; max-width: 74px; overflow: hidden; text-overflow: ellipsis; }
.st-steam { color: #66c0f4; }
.st-voice { color: #b39ef2; }

/* ---------- Toast "è online" (stile Steam, basso a destra) ---------- */

.presence-toast-stack {
  position: fixed;
  right: 16px;
  bottom: 16px;
  z-index: 500;
  display: flex;
  flex-direction: column-reverse;
  gap: 10px;
  pointer-events: none;
}

.presence-toast {
  pointer-events: auto;
  display: flex;
  align-items: center;
  gap: 10px;
  width: 260px;
  padding: 10px 12px;
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-left: 3px solid var(--ready);
  border-radius: var(--radius);
  box-shadow: 0 8px 24px rgba(0,0,0,0.35);
  animation: presence-toast-in 0.25s ease-out;
}
.presence-toast-leave { border-left-color: var(--text-dim); } /* "se ne è andato" è più neutro/spento, non un allarme */
.presence-toast.presence-toast-out {
  animation: presence-toast-out 0.25s ease-in forwards;
}
.presence-toast-avatar { width: 36px; height: 36px; border-radius: 6px; object-fit: cover; flex-shrink: 0; }
.presence-toast-avatar.avatar-fallback { width: 36px; height: 36px; font-size: 0.9rem; flex-shrink: 0; }
.presence-toast-body { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.presence-toast-name { font-size: 0.8rem; color: var(--text); font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.presence-toast-sub { font-size: 0.7rem; color: var(--text-dim); }

@keyframes presence-toast-in {
  from { opacity: 0; transform: translateX(24px); }
  to { opacity: 1; transform: translateX(0); }
}
@keyframes presence-toast-out {
  from { opacity: 1; transform: translateX(0); }
  to { opacity: 0; transform: translateX(24px); }
}

@media (max-width: 480px) {
  .presence-toast-stack { left: 12px; right: 12px; bottom: 12px; }
  .presence-toast { width: auto; }
}

/* ---------- Banner "partita in corso" (stanza di gioco) ---------- */

.game-room-banner-stack {
  position: fixed;
  left: 16px;
  bottom: 16px;
  z-index: 500;
  display: flex;
  flex-direction: column-reverse;
  gap: 10px;
  pointer-events: none;
}

.game-room-banner {
  pointer-events: auto;
  display: flex;
  align-items: center;
  gap: 12px;
  width: 300px;
  padding: 12px 14px;
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-left: 3px solid #66c0f4; /* azzurro Steam, coerente col resto della presenza Steam */
  border-radius: var(--radius);
  box-shadow: 0 8px 24px rgba(0,0,0,0.35);
  animation: presence-toast-in 0.25s ease-out;
}
.game-room-banner.game-room-banner-out {
  animation: presence-toast-out 0.25s ease-in forwards;
}
.game-room-banner-avatars { display: flex; flex-shrink: 0; }
.game-room-banner-avatars .presence-toast-avatar,
.game-room-banner-avatars .presence-toast-avatar.avatar-fallback {
  width: 32px; height: 32px;
  border: 2px solid var(--bg-panel);
}
.game-room-banner-avatars .presence-toast-avatar:not(:first-child),
.game-room-banner-avatars .presence-toast-avatar.avatar-fallback:not(:first-child) {
  margin-left: -12px;
}
.game-room-banner-body { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
.game-room-banner-title { font-size: 0.78rem; color: var(--text); font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.game-room-banner-sub { font-size: 0.7rem; color: var(--text-dim); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.game-room-banner-actions { display: flex; align-items: center; gap: 6px; flex-shrink: 0; }
.game-room-banner-join {
  background: #66c0f4;
  color: #0b0f14;
  border: none;
  border-radius: var(--radius);
  padding: 6px 10px;
  font-size: 0.75rem;
  font-weight: 700;
  cursor: pointer;
  white-space: nowrap;
}
.game-room-banner-join:hover { filter: brightness(1.08); }
.game-room-banner-dismiss {
  background: none;
  border: none;
  color: var(--text-dim);
  font-size: 1rem;
  line-height: 1;
  cursor: pointer;
  padding: 4px;
}
.game-room-banner-dismiss:hover { color: var(--text); }

@media (max-width: 480px) {
  .game-room-banner-stack { left: 12px; right: 12px; bottom: 12px; }
  .game-room-banner { width: auto; }
  /* Da mobile lo stack dei toast "è online" occupa lo stesso angolo basso: quando
     entrambi sono visibili, il banner stanza si mette sopra invece di sovrapporsi. */
  body:has(.presence-toast-stack .presence-toast) .game-room-banner-stack { bottom: 90px; }
}

.game-room-badge {
  align-self: flex-start;
  pointer-events: auto;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-left: 3px solid #66c0f4; /* stesso accento azzurro del banner esteso */
  box-shadow: 0 4px 14px rgba(0,0,0,0.35);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.1rem;
  cursor: pointer;
  padding: 0;
  animation: presence-toast-in 0.2s ease-out;
}
.game-room-badge:hover { filter: brightness(1.1); }

/* ---------- Next session box ---------- */

.next-session {
  font-size: 0.85rem;
  color: var(--text-dim);
}
.next-session strong { color: var(--text); }

/* ---------- In evidenza e consigliati ---------- */

.panel-featured { padding: 12px; }

.featured-carousel {
  position: relative;
  border-radius: 10px;
  overflow: hidden;
  aspect-ratio: 16 / 8;
  background: var(--bg-panel-2);
}

.featured-slides { position: relative; width: 100%; height: 100%; }

.featured-empty {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
  color: var(--text-dim);
  font-size: 0.85rem;
}

.featured-slide {
  position: absolute;
  inset: 0;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.5s ease;
}
.featured-slide.active { opacity: 1; visibility: visible; }

.featured-slide-img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  z-index: 0;
  background: var(--bg-panel-2);
  opacity: 0;
  transition: opacity 0.35s ease;
}
.featured-slide-img.is-loaded { opacity: 1; }

.img-fade {
  opacity: 0;
  transition: opacity 0.3s ease;
}
.img-fade.is-loaded { opacity: 1; }

.featured-slide::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
  background: linear-gradient(to top, rgba(10,8,17,0.96) 0%, rgba(10,8,17,0.55) 45%, rgba(10,8,17,0.05) 75%);
}

.featured-badge {
  position: absolute;
  top: 12px;
  left: 12px;
  z-index: 2;
  font-family: var(--font-mono);
  font-size: 0.66rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: #1a0a14;
  background: var(--accent);
  padding: 4px 9px;
  border-radius: 4px;
}

/* Il giudizio delle recensioni Steam ("Molto positiva", ecc.) — sopra la fascia dei
   pulsanti, per non finirci addosso. */
.featured-review-badge {
  position: absolute;
  bottom: 92px;
  right: 12px;
  left: 12px;
  z-index: 2;
  font-family: var(--font-mono);
  font-size: 0.64rem;
  font-weight: 700;
  color: var(--ready);
  background: rgba(10,8,17,0.75);
  border: 1px solid var(--ready);
  padding: 4px 9px;
  border-radius: 4px;
  text-align: right;
  max-width: fit-content;
  margin-left: auto;
  white-space: normal;
  line-height: 1.3;
}
.featured-review-badge.is-empty {
  color: var(--text-dim);
  border-color: var(--border);
}

/* Un pulsante invisibile che copre tutta la slide (immagine compresa) per aprire
   l'anteprima con un tap — sotto ai pulsanti veri (che hanno z-index più alto), quindi
   non li blocca. */
.featured-preview-trigger {
  position: absolute;
  inset: 0;
  z-index: 1;
  background: none;
  border: none;
  cursor: pointer;
  padding: 0;
}

.featured-content {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 2;
  padding: 14px 16px;
}

.featured-title {
  font-weight: 700;
  font-size: 1.05rem;
  color: #fff;
  text-shadow: 0 2px 10px rgba(0,0,0,0.6);
  line-height: 1.2;
}

.featured-meta {
  font-size: 0.72rem;
  color: #cfc9e0;
  margin-top: 3px;
}

.featured-price {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-top: 8px;
  background: rgba(10,8,17,0.6);
  border: 1px solid var(--ready);
  color: var(--ready);
  font-family: var(--font-mono);
  font-size: 0.72rem;
  padding: 3px 9px;
  border-radius: 5px;
}
.featured-price s { color: var(--text-dim); font-weight: 400; }

.featured-actions { margin-top: 10px; }
.featured-actions .btn {
  padding: 7px 12px;
  min-height: 0;
  font-size: 0.76rem;
}

.featured-nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 3;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: rgba(10,8,17,0.6);
  border: 1px solid var(--border);
  color: #fff;
  font-size: 1.2rem;
  line-height: 1;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  -webkit-tap-highlight-color: transparent;
}
.featured-nav[hidden] {
  display: none;
}
.featured-nav:hover { background: rgba(10,8,17,0.85); border-color: var(--accent2); }
.featured-nav.prev { left: 10px; }
.featured-nav.next { right: 10px; }

.featured-dots {
  position: absolute;
  bottom: 8px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 3;
  display: flex;
  gap: 6px;
}
.featured-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: rgba(255,255,255,0.35);
  cursor: pointer;
  border: none;
  padding: 0;
}
.featured-dot.active { background: var(--accent); width: 16px; border-radius: 4px; }

@media (max-width: 600px) {
  .featured-carousel { aspect-ratio: 16 / 11; }
  .featured-title { font-size: 0.92rem; }
}

/* ---------- Chi inviti (capsule) ---------- */

.chips {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.chip {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  padding: 6px 8px;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  background: var(--bg);
  color: var(--text-dim);
  font-size: 0.68rem;
  font-weight: 500;
  line-height: 1;
  cursor: pointer;
  user-select: none;
  transition: all 0.15s;
  -webkit-tap-highlight-color: transparent;
}
.chip:hover { border-color: var(--accent2); }
.chip .tile-name { white-space: nowrap; }
.chip-avatar { width: 34px; height: 34px; border-radius: 6px; object-fit: cover; flex-shrink: 0; }
.chip.selected {
  border-color: var(--accent);
  color: var(--text);
  background: rgba(255,95,162,0.12);
}
.chip input { display: none; }

/* "Già in sessione": nessun colore della palette esistente è pensato per un avviso, quindi
   introduciamo un rosso dedicato solo per questo stato — resta selezionabile lo stesso, è
   un avviso preventivo, non un blocco (il blocco vero avviene al salvataggio). */
.chip.chip-busy {
  border-color: #ff6b6b;
  background: rgba(255,107,107,0.12);
}
.chip-busy-label {
  color: #ff6b6b;
  font-size: 0.6rem;
  font-weight: 600;
  text-align: center;
  line-height: 1.2;
  max-width: 70px;
}

/* Un quadrato colorato con l'iniziale, per chi non ha (ancora) una foto profilo — mai
   testo nudo, sempre lo stesso trattamento visivo di chi invece ce l'ha (angoli
   arrotondati come Steam, non un cerchio). */
.avatar-fallback {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 6px;
  font-weight: 700;
  flex-shrink: 0;
}
.chip-avatar.avatar-fallback,
.chip .avatar-fallback { width: 34px; height: 34px; font-size: 0.85rem; border-radius: 6px; }

/* Avatar con un indicatore di stato agganciato all'angolo in basso a destra
   (stile Steam/Discord), invece di un pallino o un'emoji separati accanto al nome. */
.avatar-status-wrap {
  position: relative;
  display: inline-flex;
  flex-shrink: 0;
}
.status-dot {
  position: absolute;
  bottom: -2px;
  right: -2px;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  border: 2px solid var(--bg);
}
.status-online { background: var(--ready); box-shadow: 0 0 5px rgba(124,255,107,0.6); }
.status-voice { background: #5865F2; box-shadow: 0 0 5px rgba(88,101,242,0.6); }
.voice-channel-name { font-size: 0.62rem; color: var(--text-dim); white-space: nowrap; max-width: 80px; overflow: hidden; text-overflow: ellipsis; }
.status-yes { background: var(--ready); }
.status-maybe { background: var(--warn); }
.status-no { background: var(--accent); }
.status-pending { background: var(--text-dim); opacity: 0.6; }

.tz-preview {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.tz-preview:empty { display: none; }
.tz-preview-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 6px 10px;
  background: var(--bg-panel-2);
  border-radius: var(--radius);
  font-size: 0.78rem;
}
.tz-preview-row span:first-child { color: var(--text-dim); }
.tz-preview-row span:last-child { font-family: var(--font-mono); font-weight: 600; }
.tz-preview-unknown { color: var(--text-dim); font-style: italic; font-weight: 400 !important; }

.event-tz-note {
  font-family: inherit;
  font-size: 0.7rem;
  color: var(--text-dim);
  font-style: italic;
}

.participant-empty {
  padding: 8px 10px;
  font-size: 0.8rem;
  color: var(--text-dim);
}

/* ---------- Link amministrazione ---------- */

.admin-link {
  text-align: center;
  margin-top: 18px;
}
.admin-link a {
  font-size: 0.72rem;
  color: var(--text-dim);
  text-decoration: none;
}
.admin-link a:hover { color: var(--accent2); text-decoration: underline; }

/* ---------- Autocomplete gioco ---------- */

.autocomplete-wrap { position: relative; }

.autocomplete-results {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  background: var(--bg-panel-2);
  border: 1px solid var(--border);
  border-radius: 8px;
  margin-top: 4px;
  max-height: 240px;
  overflow-y: auto;
  z-index: 30;
  box-shadow: 0 10px 30px rgba(0,0,0,0.4);
}

.game-result {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  cursor: pointer;
  font-size: 0.85rem;
}
.game-result:hover { background: rgba(255,255,255,0.05); }
.game-result img { width: 32px; height: 15px; object-fit: cover; border-radius: 3px; }

/* ---------- Availability list ---------- */

.avail-list {
  list-style: none;
  margin: 14px 0 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
  max-height: 260px;
  overflow-y: auto;
}

.avail-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 8px 10px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 8px;
  font-size: 0.78rem;
}
.avail-item .avail-meta { color: var(--text-dim); font-family: var(--font-mono); font-size: 0.72rem; }
.avail-item button {
  background: none; border: none; color: var(--text-dim); cursor: pointer; font-size: 0.9rem;
}
.avail-item button:hover { color: var(--warn); }

/* ---------- Calendar ---------- */

#calendar { font-size: 0.85rem; }

.fc {
  --fc-border-color: var(--border);
  --fc-page-bg-color: transparent;
  --fc-neutral-bg-color: var(--bg-panel-2);
  --fc-list-event-hover-bg-color: var(--bg-panel-2);
  --fc-today-bg-color: rgba(255,95,162,0.06);
  color: var(--text);
}
.fc .fc-toolbar-title { font-size: 1.05rem; }
.fc .fc-button {
  background: var(--bg-panel-2);
  border: 1px solid var(--border);
  color: var(--text);
  text-transform: capitalize;
  box-shadow: none;
}
.fc .fc-button:hover { background: var(--accent-dim); }
.fc .fc-button-primary:not(:disabled).fc-button-active { background: var(--accent); color: #1a0a14; border-color: var(--accent); }
.fc-event { cursor: pointer; border: none; }
.fc-daygrid-event { padding: 1px 4px; }

/* Disponibilità dichiarate: veri eventi FullCalendar (vedi eventContent in app.js), non
   semplici elementi aggiunti sopra le celle — così compaiono anche nella vista ad agenda
   di mobile, che mostra solo i giorni con almeno un evento. Nella griglia mensile restano
   un pallino minuscolo senza sfondo/bordo (tolti quelli di default di FullCalendar), nel
   colore distintivo di PTD (--accent2); nell'agenda mostrano nome e orario per esteso. */
.fc-daygrid-event.fc-avail-event {
  background: transparent;
  border: none;
  box-shadow: none;
  margin: 1px 2px 0 0;
  padding: 0;
  min-height: 0;
}
.fc-avail-event .avail-dot {
  display: inline-block;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--accent2);
  box-shadow: 0 0 4px rgba(77,217,255,0.7);
}
.avail-list-row {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 0.85rem;
}
.avail-list-row .avail-dot { flex-shrink: 0; }
.avail-list-time { opacity: 0.7; font-size: 0.8rem; }

/* ---------- RSVP ---------- */

.rsvp-row {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 6px;
}
.rsvp-badge {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  font-size: 0.68rem;
  color: var(--text-dim);
  background: var(--bg-panel-2);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 6px 8px;
  line-height: 1;
}
.rsvp-badge .tile-name { white-space: nowrap; }
.rsvp-avatar { width: 34px; height: 34px; border-radius: 6px; object-fit: cover; }
.rsvp-avatar.avatar-fallback,
.rsvp-badge .avatar-fallback { width: 34px; height: 34px; font-size: 0.85rem; }

.rsvp-actions {
  display: flex;
  gap: 6px;
  margin-top: 10px;
  flex-wrap: wrap;
}
.rsvp-btn {
  flex: 1;
  min-width: 90px;
  background: var(--bg);
  border: 1px solid var(--border);
  color: var(--text-dim);
  border-radius: 7px;
  padding: 7px 8px;
  font-size: 0.74rem;
  font-family: inherit;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: all 0.15s;
}
.rsvp-btn:hover { color: var(--text); }
.rsvp-btn.yes.active { background: rgba(124,255,107,0.15); border-color: var(--ready); color: var(--ready); }
.rsvp-btn.maybe.active { background: rgba(255,203,92,0.15); border-color: var(--warn); color: var(--warn); }
.rsvp-btn.no.active { background: rgba(255,95,162,0.12); border-color: var(--accent); color: var(--accent); }

/* ---------- Event cards / ready-check ---------- */

.events-list {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.event-card {
  background: var(--bg);
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent);
  border-radius: 8px;
  padding: 14px 16px;
}
.event-card.is-feasible { border-left-color: var(--ready); }

.event-card-head {
  display: flex;
  align-items: center;
  gap: 12px;
}

.event-cover {
  width: 64px;
  height: 30px;
  object-fit: cover;
  border-radius: 5px;
  flex-shrink: 0;
  background: var(--bg-panel-2);
  border: 1px solid var(--border);
}

.event-head-text {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.event-title { font-weight: 700; font-size: 1rem; }
.event-confirmed-badge {
  font-family: var(--font-mono);
  font-size: 0.65rem;
  font-weight: 700;
  color: var(--ready);
  background: rgba(124,255,107,0.14);
  border: 1px solid var(--ready);
  border-radius: 999px;
  padding: 2px 8px;
  vertical-align: middle;
  margin-left: 6px;
}
.event-when { font-family: var(--font-mono); font-size: 0.8rem; color: var(--accent2); }

.event-meta {
  font-size: 0.78rem;
  color: var(--text-dim);
  margin-top: 4px;
}
.event-meta.discord-channel-note { color: #5865F2; }

.event-note {
  font-size: 0.82rem;
  color: var(--text-dim);
  margin-top: 6px;
  font-style: italic;
}

/* Ready-check bar: un segmento acceso per ogni partecipante disponibile */
.ready-check {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 10px;
}
.ready-check-label {
  font-family: var(--font-mono);
  font-size: 0.68rem;
  color: var(--text-dim);
  text-transform: uppercase;
  letter-spacing: 1px;
  margin-right: 4px;
  white-space: nowrap;
}
.ready-segment {
  height: 8px;
  flex: 1;
  min-width: 14px;
  border-radius: 3px;
  background: var(--border);
}
.ready-segment.status-yes { background: var(--ready); box-shadow: 0 0 6px rgba(124,255,107,0.5); }
.ready-segment.status-maybe { background: var(--warn); box-shadow: 0 0 6px rgba(255,203,92,0.5); }
.ready-segment.status-no { background: var(--accent); box-shadow: 0 0 6px rgba(255,95,162,0.5); }
.ready-segment.status-pending { background: var(--border); }

.event-actions {
  display: flex;
  gap: 8px;
  margin-top: 12px;
  flex-wrap: wrap;
}
.event-actions .btn { padding: 7px 12px; font-size: 0.78rem; }

.notified-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-mono);
  font-size: 0.68rem;
  color: var(--ready);
  border: 1px solid var(--ready);
  border-radius: 999px;
  padding: 4px 10px;
  line-height: 1;
}

.empty-state {
  color: var(--text-dim);
  font-size: 0.85rem;
  text-align: center;
  padding: 20px 0;
}

/* ---------- Wishlist ---------- */

.panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 14px;
}
.panel-head .eyebrow { margin-bottom: 0; }

.btn-refresh-all {
  background: none;
  border: 1px solid var(--border);
  color: var(--text-dim);
  border-radius: 6px;
  padding: 6px 10px;
  font-size: 0.7rem;
  font-family: inherit;
  cursor: pointer;
  white-space: nowrap;
  flex-shrink: 0;
  -webkit-tap-highlight-color: transparent;
  transition: color 0.15s, border-color 0.15s;
}
.btn-refresh-all:hover { color: var(--text); border-color: var(--accent2); }
.btn-refresh-all:disabled { opacity: 0.55; cursor: default; }
.btn-refresh-all.is-spinning { animation: spin-text 1s steps(4) infinite; }
@keyframes spin-text { to { opacity: 0.4; } }

/* Tooltip generico: aggiungi data-tooltip="testo" a qualunque elemento */
[data-tooltip] { position: relative; }
[data-tooltip]:hover::after,
[data-tooltip]:focus-visible::after {
  content: attr(data-tooltip);
  position: absolute;
  bottom: calc(100% + 9px);
  right: 0;
  width: 210px;
  background: var(--bg-panel-2);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 8px 10px;
  font-size: 0.7rem;
  line-height: 1.35;
  font-family: var(--font-body);
  text-align: left;
  white-space: normal;
  box-shadow: 0 10px 30px rgba(0,0,0,0.45);
  z-index: 40;
  pointer-events: none;
}
[data-tooltip]:hover::before,
[data-tooltip]:focus-visible::before {
  content: '';
  position: absolute;
  bottom: 100%;
  right: 14px;
  border: 5px solid transparent;
  border-top-color: var(--border);
  z-index: 41;
}

.wishlist-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-top: 14px;
  max-height: 520px;
  overflow-y: auto;
}

.wishlist-category { margin-bottom: 2px; }

.wishlist-category-header {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  background: none;
  border: none;
  border-bottom: 1px solid var(--border);
  padding: 8px 2px;
  margin-bottom: 8px;
  cursor: pointer;
  color: var(--text-dim);
  font-family: inherit;
  text-align: left;
  -webkit-tap-highlight-color: transparent;
}
.wishlist-category-header:hover { color: var(--text); }

.wishlist-category-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  border-radius: 4px;
  border: 1px solid var(--border);
  font-size: 0.8rem;
  font-weight: 700;
  flex-shrink: 0;
  color: var(--accent2);
}

.wishlist-category-name {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 1px;
  flex: 1;
}

.wishlist-category-count {
  font-family: var(--font-mono);
  font-size: 0.68rem;
  color: var(--text-dim);
  background: var(--bg-panel-2);
  border-radius: 999px;
  padding: 1px 8px;
}

/* Come sempre quando si usa "display" insieme a [hidden]: serve la regola sotto per
   evitare che il display esplicito vinca sull'attributo hidden e il gruppo non si nasconda. */
.wishlist-category-items {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding-left: 4px;
  margin-bottom: 10px;
}
.wishlist-category-items[hidden] { display: none; }

.wishlist-item {
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 10px;
}
.wishlist-item.on-sale { border-color: var(--ready); box-shadow: 0 0 0 1px rgba(124,255,107,0.25); }

.wishlist-item-top {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  cursor: pointer;
}

.wishlist-cover {
  width: 52px;
  height: 24px;
  object-fit: cover;
  border-radius: 4px;
  flex-shrink: 0;
  background: var(--bg-panel-2);
  border: 1px solid var(--border);
}

.wishlist-info { min-width: 0; flex: 1; }
.wishlist-name { font-size: 0.85rem; font-weight: 600; line-height: 1.25; }

.wishlist-status { margin-top: 4px; font-size: 0.72rem; }

.badge-soon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-mono);
  font-size: 0.68rem;
  color: var(--accent2);
  border: 1px solid var(--accent2);
  border-radius: 999px;
  padding: 3px 9px;
  line-height: 1;
}
.badge-sale {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-mono);
  font-size: 0.68rem;
  font-weight: 700;
  color: #0a2e08;
  background: var(--ready);
  border-radius: 999px;
  padding: 3px 9px;
  line-height: 1;
}
.badge-price {
  font-size: 0.72rem;
  color: var(--text-dim);
}
.badge-error {
  font-size: 0.7rem;
  color: var(--warn);
}

.wishlist-actions {
  display: flex;
  gap: 6px;
  margin-top: 8px;
}
.wishlist-actions button {
  background: none;
  border: 1px solid var(--border);
  color: var(--text-dim);
  border-radius: 6px;
  padding: 4px 8px;
  font-size: 0.7rem;
  cursor: pointer;
}
.wishlist-actions button:hover { color: var(--text); border-color: var(--accent2); }

.vote-wish-btn.active { color: var(--warn); border-color: var(--warn); }

.top3:empty { display: none; }
.top3 {
  margin-bottom: 14px;
  padding: 12px;
  background: var(--bg-panel-2);
  border: 1px solid var(--border);
  border-radius: 8px;
}
.top3-title {
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--text-dim);
  margin: 0 0 10px;
}
.top3-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.top3-item {
  display: flex;
  align-items: center;
  gap: 10px;
}
.top3-medal { font-size: 1.1rem; flex-shrink: 0; }
.top3-cover {
  width: 44px;
  height: 21px;
  object-fit: cover;
  border-radius: 4px;
  flex-shrink: 0;
  background: var(--bg);
}
.top3-name { flex: 1; min-width: 0; font-size: 0.82rem; font-weight: 600; }
.top3-votes { font-family: var(--font-mono); font-size: 0.72rem; color: var(--text-dim); white-space: nowrap; }

/* ---------- La mia collezione ---------- */

.collection-modal-box {
  max-width: 460px;
  max-height: 82vh;
  display: flex;
  flex-direction: column;
  overflow-y: auto;
}
.collection-modal-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 6px;
}
.collection-modal-head h3 { margin: 0; font-size: 1rem; }
.collection-modal-head .btn-link { font-size: 1rem; padding: 2px 6px; }

/* ---------- Impostazioni: aspetto / accessori avatar ---------- */

.settings-section { margin-top: 4px; }
.settings-section-title { font-size: 0.9rem; color: var(--text); margin: 0 0 4px; }
.settings-avatar-preview {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 10px 0 14px;
}
.settings-avatar-preview .avatar-wrap img,
.settings-avatar-preview .avatar-wrap .avatar-fallback { width: 52px; height: 52px; font-size: 1.3rem; }

.settings-accessory-grid { display: flex; flex-wrap: wrap; gap: 8px; }
.accessory-option {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  width: 66px;
  padding: 10px 6px;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  background: var(--bg);
  color: var(--text-dim);
  font-size: 0.66rem;
  line-height: 1.2;
  text-align: center;
  cursor: pointer;
  user-select: none;
  transition: all 0.15s;
  -webkit-tap-highlight-color: transparent;
}
.accessory-option:hover { border-color: var(--accent2); }
.accessory-option.selected {
  border-color: var(--accent);
  color: var(--text);
  background: rgba(255,95,162,0.12);
}
.accessory-option-preview {
  width: 40px;
  height: 40px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 1.3rem;
}
.accessory-option-preview img { width: 100%; height: 100%; object-fit: contain; }

/* Il contenitore che rende un avatar "vestibile" — usato ovunque un avatar compare in
   giro per l'app (online, in vocale, RSVP, toast, ecc.), non solo nel pannello
   impostazioni. Il "vestito" scelto (un file caricato in public/suits) viene sovrapposto
   centrato sopra la foto ma più grande di essa, così una cornice/decorazione può sporgere
   oltre il bordo della figurina invece di restare "imprigionata" dentro il suo quadrato
   (stessa idea delle "avatar decoration" di Discord). */
.avatar-wrap { position: relative; display: inline-flex; flex-shrink: 0; }
.avatar-accessory-overlay {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 130%;
  height: 130%;
  transform: translate(-50%, -50%);
  object-fit: contain;
  pointer-events: none;
}

.collection-my-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-top: 14px;
  overflow-y: auto;
}
.collection-my-item .is-added,
.collection-my-item button.is-added { color: var(--accent); font-weight: 700; cursor: default; opacity: 1; }

.collection-my-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 8px;
  background: var(--bg-panel-2);
  border-radius: var(--radius);
}
.collection-my-preview-trigger {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 1;
  min-width: 0;
  cursor: pointer;
}
.collection-my-cover { width: 40px; height: 19px; object-fit: cover; border-radius: 4px; flex-shrink: 0; background: var(--bg); }
.collection-my-name { flex: 1; min-width: 0; font-size: 0.82rem; }
.collection-my-remove {
  background: none;
  border: none;
  color: var(--text-dim);
  cursor: pointer;
  font-size: 0.85rem;
  padding: 2px 4px;
}
.collection-my-remove:hover { color: var(--warn); }

.telegram-code-display {
  font-family: var(--font-mono);
  font-size: 1.8rem;
  font-weight: 700;
  letter-spacing: 4px;
  text-align: center;
  color: var(--accent2);
  background: var(--bg-panel-2);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 14px;
  margin: 4px 0 14px;
}
#telegram-confirm-link, #telegram-group-link { margin-bottom: 12px; text-decoration: none; display: block; text-align: center; }

.steam-link-section { margin: 12px 0; }
.steam-hint-spaced { margin-top: 8px; }
.steam-linked-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 8px;
}
.steam-linked-badge { display: inline-flex; align-items: center; gap: 5px; color: var(--accent); font-size: 0.82rem; font-weight: 600; }

.game-preview-box { max-width: 560px; }
.game-preview-reviews {
  font-size: 0.78rem;
  font-weight: 700;
  color: var(--ready);
  margin: 0 0 8px;
}
.game-preview-desc {
  font-size: 0.85rem;
  color: var(--text-dim);
  line-height: 1.55;
  margin: 0 0 14px;
}
.game-preview-shots {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
}
.game-preview-shot {
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  border-radius: 6px;
  cursor: pointer;
  transition: transform 0.15s;
  background: var(--bg-panel-2);
}
.game-preview-shot:hover { transform: scale(1.04); }

#steam-import-wrap { margin: 10px 0; }
#steam-import-list {
  max-height: 260px;
  overflow-y: auto;
  margin-top: 0;
}
/* Come sempre quando si usa "display" insieme a [hidden]: senza questa regola,
   .collection-my-list (display: flex) vince sempre su [hidden] e la lista non si
   comprime mai davvero, anche quando il pulsante +/− dice di sì. */
#steam-import-list[hidden] { display: none; }
#collection-my-list[hidden] { display: none; }

.collection-remove-all {
  display: block;
  margin: 8px auto 0;
  font-size: 0.72rem;
  color: var(--text-dim);
}
.collection-remove-all:hover { color: var(--accent); }

#collection-matches-panel[hidden] { display: none; }
/* Come sempre quando si usa "display" insieme a [hidden]: senza questa regola,
   #collection-matches-list (display: flex) vince sempre su [hidden] e la lista non si
   nasconde mai, anche col toggle -/+ impostato su "chiuso". */
#collection-matches-list[hidden] { display: none; }
#collection-matches-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-top: 10px;
}
.collection-match {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  background: var(--bg-panel-2);
  border-radius: var(--radius);
}
.collection-match-cover { width: 48px; height: 23px; object-fit: cover; border-radius: 4px; flex-shrink: 0; background: var(--bg); }
.collection-match-info { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.collection-match-name { font-size: 0.85rem; font-weight: 600; }
.collection-match-preview-trigger { cursor: pointer; }
.collection-match-preview-trigger:hover { color: var(--accent2); text-decoration: underline; }
.collection-match-owners { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 3px; }
.owner-chip {
  display: inline-flex;
  align-items: baseline;
  gap: 5px;
  background: var(--border);
  border-radius: 999px;
  padding: 2px 9px;
  white-space: nowrap;
}
.owner-chip-name { font-size: 0.72rem; color: var(--text); font-weight: 600; }
.owner-chip-time { font-size: 0.68rem; color: var(--text-dim); }
.collection-match-use { padding: 6px 10px; font-size: 0.72rem; flex-shrink: 0; }

@media (max-width: 600px) {
  .collection-match { flex-wrap: wrap; }
  .collection-match-use,
  .collection-match-buy {
    flex-basis: 100%;
    margin-top: 8px;
  }
}

.collection-matches-count {
  font-family: var(--font-mono);
  font-size: 0.7rem;
  color: var(--text-dim);
  margin-left: auto;
}

/* Stesso bug già preso due volte: display:flex esplicito vince sempre su [hidden] senza
   questa regola — la riga di controlli resterebbe visibile anche col pannello ridotto. */
#collection-matches-controls[hidden] { display: none; }
#collection-matches-controls {
  display: flex;
  gap: 8px;
  margin: 10px 0 4px;
}
#collection-matches-search {
  flex: 1;
  min-width: 0;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 7px 10px;
  font-size: 0.8rem;
  color: var(--text);
  font-family: inherit;
}
#collection-matches-search:focus { outline: none; border-color: var(--accent2); }
#collection-matches-sort {
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 7px 8px;
  font-size: 0.75rem;
  color: var(--text);
  font-family: inherit;
  flex-shrink: 0;
  max-width: 42%;
}

.game-star-btn {
  background: none;
  border: none;
  font-size: 1.15rem;
  line-height: 1;
  color: var(--text-dim);
  cursor: pointer;
  padding: 0;
  -webkit-tap-highlight-color: transparent;
}
.game-star-btn:hover { color: var(--warn); }
.game-star-btn.is-starred { color: var(--warn); }
.game-star-btn:disabled { opacity: 0.5; cursor: default; }

/* Larghezza fissa indipendentemente dal fatto che la stella ci sia o no, così il cerchio
   delle ore resta incolonnato riga dopo riga invece di scivolare a sinistra quando manca. */
.collection-match-star-slot {
  width: 20px;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}
.collection-match-hours {
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: var(--bg);
  border: 1px solid var(--accent2);
  color: var(--accent2);
  font-family: var(--font-mono);
  font-size: 0.68rem;
  font-weight: 700;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.collection-match-owner-badge {
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: var(--bg);
  border: 1px solid var(--accent);
  color: var(--accent);
  font-family: var(--font-mono);
  font-size: 0.68rem;
  font-weight: 700;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

/* ---------- Divisore + card compatta per le sessioni passate ---------- */

.events-divider {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 22px 0 12px;
  color: var(--text-dim);
}
.events-divider::before,
.events-divider::after {
  content: '';
  flex: 1;
  height: 1px;
  background: var(--border);
}
.events-divider span {
  font-family: var(--font-mono);
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 1px;
  white-space: nowrap;
}

.event-card-past {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  background: var(--bg-panel-2);
  border-radius: var(--radius);
  margin-bottom: 8px;
  opacity: 0.85;
}
.event-cover-sm { width: 36px; height: 36px; object-fit: cover; border-radius: 5px; flex-shrink: 0; filter: grayscale(0.3); background: var(--bg); }
.event-past-info { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.event-past-name { font-size: 0.82rem; color: var(--text); }
.event-past-meta { font-size: 0.7rem; color: var(--text-dim); }
.past-status {
  font-size: 0.7rem;
  border-radius: 999px;
  padding: 3px 9px;
  flex-shrink: 0;
  white-space: nowrap;
}
.past-status.confirmed { color: var(--ready); background: rgba(124,255,107,0.12); }
.past-status.confirm-btn {
  background: var(--bg);
  border: 1px solid var(--border);
  color: var(--text-dim);
  cursor: pointer;
  font-family: inherit;
}
.past-status.confirm-btn:hover { color: var(--text); border-color: var(--accent2); }

/* ---------- Sessioni possibili ---------- */

.sessions-possible-count {
  font-family: var(--font-mono);
  font-size: 0.7rem;
  color: var(--text-dim);
  margin-left: auto;
}

/* Come sempre quando si usa "display" insieme a [hidden]: senza questa regola,
   #sessions-possible-list (display: flex) vince sempre su [hidden] e la lista non si
   nasconde mai, anche col toggle -/+ impostato su "chiuso" (stesso bug già preso una
   volta sul pannello Giochi in comune). */
#sessions-possible-list[hidden] { display: none; }
#sessions-possible-list {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.matchlobby-card {
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 10px;
  overflow: hidden;
}
.matchlobby-cover-wrap { position: relative; }
.matchlobby-cover { width: 100%; height: 110px; object-fit: cover; display: block; background: var(--bg-panel-2); }
.matchlobby-cover-logo {
  position: absolute;
  left: 12px;
  top: 50%;
  transform: translateY(-50%);
  max-width: 45%;
  max-height: 46px;
  object-fit: contain;
  pointer-events: none;
}
.matchlobby-rank-badge {
  position: absolute;
  right: 12px;
  top: 50%;
  transform: translateY(-50%);
  background: rgba(16, 14, 25, 0.78);
  border: 1px solid var(--accent);
  color: var(--accent);
  font-family: var(--font-mono);
  font-weight: 700;
  font-size: 0.9rem;
  padding: 3px 9px;
  border-radius: 999px;
  pointer-events: none;
}
.matchlobby-body { padding: 12px 14px 14px; }
.matchlobby-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 10px;
  margin-bottom: 10px;
}
.matchlobby-name { font-weight: 700; font-size: 0.95rem; }
.matchlobby-scheduled-badge {
  font-family: var(--font-mono);
  font-size: 0.62rem;
  font-weight: 700;
  color: var(--accent2);
  background: rgba(77,217,255,0.14);
  border: 1px solid var(--accent2);
  border-radius: 999px;
  padding: 2px 7px;
  vertical-align: middle;
}
.matchlobby-time {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  color: var(--accent2);
  background: var(--bg-panel-2);
  padding: 3px 9px;
  border-radius: 999px;
  white-space: nowrap;
  flex-shrink: 0;
}
.matchlobby-time-day { color: var(--accent); font-weight: 700; }

.matchlobby-day-divider {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 20px 0 12px;
  color: var(--accent);
}
.matchlobby-day-divider:first-child { margin-top: 0; }
.matchlobby-day-divider::before,
.matchlobby-day-divider::after {
  content: '';
  flex: 1;
  height: 3px;
  background: var(--accent-dim);
}
.matchlobby-day-divider span {
  font-family: var(--font-mono);
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 1px;
  white-space: nowrap;
}
.matchlobby-section-label {
  font-family: var(--font-mono);
  font-size: 0.66rem;
  text-transform: uppercase;
  letter-spacing: 1px;
  color: var(--text-dim);
  margin: 0 0 6px;
}
.matchlobby-avatars {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 12px;
  flex-wrap: wrap;
}
.matchlobby-avatar { width: 32px; height: 32px; border-radius: 6px; object-fit: cover; }
.matchlobby-avatar.avatar-fallback,
.matchlobby-avatar.avatar-accessory-overlay { width: 32px; height: 32px; }
.matchlobby-avatar-maybe { opacity: 0.55; }
.matchlobby-avatar-maybe.avatar-fallback { border: 1px dashed var(--border); background: none !important; }
.matchlobby-star-badge {
  position: absolute;
  bottom: -4px;
  right: -4px;
  width: 19px;
  height: 19px;
  border-radius: 50%;
  border: 2px solid var(--bg);
  background: var(--bg-panel-2);
  color: var(--warn);
  font-size: 12px;
  line-height: 15px;
  text-align: center;
}
.matchlobby-join-btn { width: 100%; }
.matchlobby-schedule-btn { width: 100%; margin-top: 8px; }

.empty-state-sub {
  display: block;
  font-size: 0.75rem;
  margin-top: 4px;
  color: var(--text-dim);
}

/* ---------- Pannello di amministrazione ---------- */

.admin-layout {
  display: grid;
  grid-template-columns: 320px 1fr;
  gap: 20px;
  padding: 20px 24px 60px;
  max-width: 900px;
  margin: 0 auto;
}
.panel-wide { grid-column: 1 / -1; }
@media (max-width: 700px) {
  .admin-layout { grid-template-columns: 1fr; }
}
@media (max-width: 600px) {
  .admin-layout { padding: 14px 14px 40px; gap: 14px; }
  .admin-users-list { gap: 10px; }
  .admin-user-row { padding: 10px 12px; }
  .admin-user-actions .btn-ghost { padding: 7px 10px; font-size: 0.72rem; }
  .admin-discord-results { max-height: 200px; }
}

.admin-users-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.admin-user-row {
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 12px 14px;
}

.admin-user-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  flex-wrap: wrap;
}

.admin-user-name {
  font-weight: 700;
  font-size: 0.95rem;
  display: inline-flex;
  align-items: center;
  gap: 8px;
}

.admin-user-avatar {
  width: 24px;
  height: 24px;
  border-radius: 50%;
  object-fit: cover;
  flex-shrink: 0;
}

.admin-steam-preview {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  background: var(--bg-panel-2);
  border-radius: var(--radius);
  margin: -6px 0 4px;
}
.admin-steam-preview img {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  object-fit: cover;
  background: var(--bg);
}
.admin-steam-preview span {
  font-size: 0.85rem;
  font-weight: 600;
}
.admin-steam-preview .btn-link { margin-left: auto; }

.admin-lobby-photo-hint {
  font-size: 0.8rem;
  color: var(--text-dim);
  margin: -4px 0 0;
}
.admin-lobby-photo-preview img { background: var(--bg); }
.admin-lobby-photo-form input[type="file"] {
  font-size: 0.82rem;
  color: var(--text-dim);
}

/* ---------- Ritaglio foto lobby ---------- */
.crop-modal-box { max-width: 420px; }
.crop-viewport {
  width: 260px;
  height: 260px;
  margin: 14px auto;
  border-radius: 8px;
  overflow: hidden;
  position: relative;
  background: var(--bg-panel-2);
  border: 2px solid var(--accent2);
  cursor: grab;
  touch-action: none; /* evita che il trascinamento faccia scorrere la pagina sotto, anche da mobile */
}
.crop-viewport.dragging { cursor: grabbing; }
.crop-viewport img {
  position: absolute;
  top: 0;
  left: 0;
  transform-origin: 0 0;
  pointer-events: none; /* il trascinamento si gestisce sul contenitore, non sull'immagine */
  -webkit-user-drag: none;
}
#crop-zoom {
  width: 260px;
  display: block;
  margin: 0 auto 6px;
  accent-color: var(--accent2);
}

/* Elenco cliccabile dei membri Discord trovati — a differenza di Steam (un link porta a
   UN profilo preciso), una ricerca per nome può dare più risultati, serve poterne
   scegliere uno. */
.admin-discord-results {
  display: flex;
  flex-direction: column;
  gap: 4px;
  max-height: 220px;
  overflow-y: auto;
  margin: -6px 0 4px;
}
.admin-discord-result {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 7px 10px;
  background: var(--bg-panel-2);
  border: 1px solid transparent;
  border-radius: var(--radius);
  cursor: pointer;
  text-align: left;
  color: var(--text);
  font-size: 0.85rem;
}
.admin-discord-result:hover { border-color: var(--border); }
.admin-discord-result img {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  object-fit: cover;
  background: var(--bg);
}

.admin-badge {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  font-family: var(--font-mono);
  font-size: 0.65rem;
  font-weight: 700;
  color: var(--accent);
  border: 1px solid var(--accent);
  border-radius: 999px;
  padding: 2px 8px;
  vertical-align: middle;
}
.admin-badge svg { flex-shrink: 0; }
.admin-badge-blocked { color: var(--warn); border-color: var(--warn); margin-left: 4px; }
.admin-badge-steam { color: #66c0f4; border-color: #66c0f4; margin-left: 4px; }
.admin-badge-discord { color: #b39ef2; border-color: #b39ef2; margin-left: 4px; }

.checkbox-row,
.radio-row {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 0.78rem;
  color: var(--text-dim);
  cursor: pointer;
  user-select: none;
}
.checkbox-row input,
.radio-row input {
  width: 15px;
  height: 15px;
  accent-color: var(--accent);
  cursor: pointer;
  flex-shrink: 0;
}
.admin-toggle-row {
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px solid var(--border);
}

.admin-user-actions {
  display: flex;
  gap: 8px;
  flex-wrap: wrap; /* su schermi stretti, 5 bottoni in fila uscirebbero dai bordi invece
    di andare a capo — senza questo, il pannello admin non era davvero adattabile a mobile */
}
.admin-user-actions .btn-ghost {
  padding: 6px 12px;
  font-size: 0.76rem;
  border-radius: 6px;
}
.admin-delete-btn:hover { color: var(--warn); border-color: var(--warn); }

.admin-edit-form {
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1px solid var(--border);
}
.admin-edit-form input {
  width: 100%;
}
.admin-edit-actions {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}
.admin-edit-actions .btn,
.admin-edit-actions .btn-ghost {
  padding: 8px 14px;
  font-size: 0.8rem;
}

/* ---------- Finestre di dialogo (al posto di alert/confirm del browser) ---------- */

.dialog-overlay {
  position: fixed;
  inset: 0;
  z-index: 100;
  background: rgba(6, 5, 11, 0.72);
  backdrop-filter: blur(3px);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
}
.dialog-overlay[hidden] {
  display: none;
}
/* L'anteprima gioco può essere aperta DA DENTRO un altro pannello (wishlist, collezione,
   libreria) — condivide lo stesso z-index base (100) di tutti gli altri .dialog-overlay,
   quindi chi viene scritto per ultimo nell'HTML vince a schermo, indipendentemente da
   quale dei due l'utente ha aperto per ultimo. Un livello dedicato più alto risolve alla
   radice, senza dipendere dall'ordine dei pannelli nel file. */
#game-preview-modal {
  z-index: 110;
}

/* Il visualizzatore di screenshot: sopra a tutto il resto (anche sopra il pannello
   anteprima da cui si apre), niente riquadro — solo l'immagine e la X per chiudere. */
.lightbox-overlay {
  position: fixed;
  inset: 0;
  z-index: 200;
  background: rgba(6, 5, 11, 0.92);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 40px 20px;
}
.lightbox-overlay[hidden] { display: none; }
.lightbox-overlay img {
  max-width: 100%;
  max-height: 100%;
  border-radius: 8px;
  box-shadow: 0 20px 60px rgba(0,0,0,0.6);
}
.lightbox-close {
  position: fixed;
  top: 18px;
  right: 20px;
  z-index: 201;
  background: none;
  border: none;
  color: var(--accent);
  font-size: 1.6rem;
  font-weight: 700;
  cursor: pointer;
  line-height: 1;
  padding: 8px;
  -webkit-tap-highlight-color: transparent;
}
.lightbox-close:hover { filter: brightness(1.3); }

.lightbox-nav {
  position: fixed;
  top: 50%;
  transform: translateY(-50%);
  z-index: 201;
  background: rgba(6, 5, 11, 0.5);
  border: none;
  color: var(--accent);
  font-size: 2.4rem;
  font-weight: 700;
  line-height: 1;
  width: 52px;
  height: 52px;
  border-radius: 50%;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  -webkit-tap-highlight-color: transparent;
}
.lightbox-nav:hover { filter: brightness(1.3); background: rgba(6, 5, 11, 0.75); }
.lightbox-nav[hidden] { display: none; }
.lightbox-prev { left: 16px; }
.lightbox-next { right: 16px; }

.dialog-box {
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 22px;
  width: 100%;
  max-width: 380px;
  box-shadow: 0 20px 60px rgba(0,0,0,0.5);
  animation: dialog-pop 0.15s ease;
}
@keyframes dialog-pop {
  from { transform: scale(0.96); opacity: 0; }
  to { transform: scale(1); opacity: 1; }
}

.dialog-message {
  margin: 0 0 20px 0;
  font-size: 0.92rem;
  line-height: 1.5;
  color: var(--text);
  white-space: pre-line;
}

.dialog-actions {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
}
.dialog-actions .btn {
  min-height: 40px;
  padding: 9px 18px;
}

@media (max-width: 480px) {
  .dialog-actions { flex-direction: column-reverse; }
  .dialog-actions .btn { width: 100%; }
}

/* ---------- Scrollbars ---------- */
::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-thumb { background: var(--border); border-radius: 4px; }

/* ---------- Lobby: stanza 2D con avatar in tempo reale ---------- */

.lobby-modal-box {
  max-width: 900px;
  width: 92vw;
  display: flex;
  flex-direction: column;
  gap: 10px;
  /* Niente pop-in ereditato da .dialog-box: per un riquadro piccolo (conferma,
     avviso) scalare da 0.96 e sfumare l'opacità in 150ms è un tocco gradevole,
     ma per la lobby a schermo intero quei 150ms bastano a intravedere la
     dashboard sfocata dietro attraverso lo sfondo del box ancora trasparente. */
  animation: none;
}

.lobby-head-actions { display: flex; align-items: center; gap: 10px; }

/* Schermo intero "finto" (non usa la Fullscreen API del browser, poco affidabile su
   Safari/iOS per elementi generici): semplicemente la finestra occupa tutto lo spazio
   disponibile invece del riquadro centrato. Funziona identico su PC e mobile. */
.dialog-overlay.lobby-fullscreen-overlay { padding: 0; }
.lobby-modal-box.lobby-fullscreen {
  width: 100vw;
  max-width: 100vw;
  height: 100vh;
  height: 100dvh; /* su mobile evita i salti quando compare/sparisce la barra degli indirizzi */
  max-height: none;
  border-radius: 0;
}
.lobby-modal-box.lobby-fullscreen .lobby-scene {
  flex: 1 1 0;
  min-height: 0; /* permette al flex item di restringersi sotto la sua altezza "naturale" */
  align-self: stretch;
  width: 100%;
  max-width: 100%;
  height: 100%;
  /* Niente più aspect-ratio fissa: era il rapporto dello sfondo 2D (1543/1019),
     ereditato dalla vecchia lobby piatta. In 3D la camera si adatta a qualsiasi
     formato (vedi resize()/applyCameraFraming() in lobby3d/engine.js), quindi la
     scena può riempire davvero tutto lo schermo invece di restare incorniciata
     con bande vuote sopra/sotto su mobile in verticale. */
  aspect-ratio: unset;
}

.lobby-scene {
  position: relative;
  width: 100%;
  aspect-ratio: 1543 / 1019;
  /* Trascinando col dito il gesto deve muovere l'avatar, non far scorrere la pagina. */
  touch-action: none;
  border-radius: var(--radius);
  overflow: hidden;
  background-image: url('lobby/lobby-bg.jpg');
  background-size: cover;
  background-position: center;
  cursor: pointer;
  border: 1px solid var(--border);
  container-type: inline-size; /* così avatar/nome/fumetti sotto possono essere
    dimensionati in "cqw" (% della larghezza di QUESTA scena) invece che in px fissi:
    quando la scena si ingrandisce in fullscreen, crescono insieme a lei invece di
    restare piccoli rispetto allo sfondo che si scala. */
  container-name: lobby-scene;
}

.lobby-avatars {
  position: absolute;
  inset: 0;
  pointer-events: none; /* i click passano attraverso, li gestisce .lobby-scene */
}

/* ---------- Lobby 3D: niente flash della foto 2D ----------
   Queste due regole vivevano in un <style> creato da lobby3d.js: fra il primo
   disegno della pagina e l'esecuzione dello script c'è sempre una finestra,
   anche piccola, in cui la foto di sfondo della 2D fa capolino. Qui invece
   sono nel foglio caricato in <head> PRIMA di qualunque script: valgono già
   al primissimo fotogramma, perché si affidano solo all'attributo che
   server.js scrive sull'HTML (vedi renderIndexHtml), non al JS che deve
   ancora partire.

   Non serve più l'eccezione ":not(.l3d-off)" che c'era prima: la lobby 3D
   non ripiega più sulla 2D quando fallisce (WebGL2 assente, CDN irraggiungibili
   — vedi showUnavailable() in lobby3d.js). Se l'admin ha scelto 3D per tutti,
   la 2D non deve comparire in nessun caso, riuscita o fallita che sia
   l'inizializzazione: "se non regge, semplicemente non parte". */
html[data-lobby-mode="3d"] #lobby-scene {
  background-image: none !important;
  background-color: #0d0a08 !important;
}
html[data-lobby-mode="3d"]:not(.l3d-ready) #lobby-scene > *:not(#lobby3d-loader):not(#lobby3d-canvas) {
  display: none !important;
}

.lobby-pedestals {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

/* Livello decorativo SEMPRE in primo piano (lanterne/bonsai sui due tavolini della lobby):
   a differenza dei piedistalli, che usano uno z-index calcolato sulla posizione Y per farsi
   attraversare correttamente in profondità dagli avatar, qui non c'è nessun calcolo — lo
   z-index è fisso e più alto di qualunque avatar possa mai raggiungere (max ~1000, dato che
   usano "y in percentuale * 10"), quindi l'avatar ci finisce SEMPRE dietro, in ogni punto
   della scena. Nessuna zona di collisione: si può camminare "sotto" senza restare bloccati.
   Mostrato solo nella stanza "lobby" (vedi updateLobbyForegroundVisibility in app.js), dato
   che i tavolini che decora non esistono nella scena della Hall of Fame. */
.lobby-foreground {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 2000;
  pointer-events: none;
}

/* ==========================================================================
   ATMOSFERA DELLA LOBBY — petali, luci e neon animati
   --------------------------------------------------------------------------
   Livello puramente decorativo che "anima" lo sfondo, che altrimenti resta una
   foto ferma: petali di ciliegio che scendono dal giardino oltre le porte,
   alone pulsante intorno a lanterne e lampade, insegne al neon che ogni tanto
   fanno contatto e sfarfallano, pulviscolo dorato sospeso nell'aria.

   Tutto viene generato via JS (vedi buildLobbyAmbience in app.js) a partire da
   una tabella di coordinate IN PERCENTUALE misurate sull'immagine di sfondo:
   così l'effetto resta incollato ai punti giusti a qualunque dimensione la
   scena venga scalata — fullscreen compreso — senza toccare una riga di CSS.
   Le dimensioni "fisiche" (raggio dei petali, ampiezza dell'oscillazione) sono
   invece in "cqw", cioè in percentuale della larghezza della scena, per lo
   stesso motivo per cui lo sono già gli avatar.

   NOTA SUI CONTESTI DI IMPILAMENTO — importante, non toccare a cuor leggero:
   gli aloni usano "mix-blend-mode: screen" per SOMMARSI davvero alla luce già
   presente nella foto, invece di stenderle sopra un velo colorato. Perché la
   fusione funzioni, fra l'alone e lo sfondo non deve esserci nessun elemento
   che crei un proprio contesto di impilamento: altrimenti la somma avviene
   contro il vuoto trasparente del contenitore e l'effetto additivo si perde.
   Per questo i due contenitori .lobby-ambience / .lobby-ambience-front NON
   hanno z-index, opacity < 1, filter o transform — sono volutamente "invisibili"
   allo stack. Chi deve stare davanti al livello in primo piano porta lo z-index
   sui PROPRI figli (vedi .lobby-glow-front), mai sul contenitore.
   ========================================================================== */

.lobby-ambience,
.lobby-ambience-front {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none; /* non deve mai rubare i click di movimento alla scena */
  /* niente z-index / opacity / filter / transform qui: vedi nota sopra */
}

/* Chi appartiene al livello davanti al primo piano (le lanterne sui due tavolini
   della lobby, che nell'immagine sono dentro lobby-foreground a z-index 2000)
   porta lo z-index su di sé, non sul contenitore. */
.lobby-glow-front,
.lobby-petal-field-front {
  z-index: 2100;
}

/* ---------- Aloni di luce (lanterne, lampade, vetrine) ---------- */

/* Un cerchio sfumato centrato sul punto x/y assegnato. Il gradiente si spegne
   ben prima del bordo, così non si vede mai il "taglio" del riquadro. */
.lobby-glow {
  position: absolute;
  left: var(--g-x);
  top: var(--g-y);
  width: var(--g-size);
  aspect-ratio: 1; /* larghezza in % della scena, altezza a seguire: sempre un cerchio */
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: radial-gradient(
    circle,
    rgba(var(--g-rgb), 0.85) 0%,
    rgba(var(--g-rgb), 0.42) 26%,
    rgba(var(--g-rgb), 0.14) 50%,
    rgba(var(--g-rgb), 0) 72%
  );
  mix-blend-mode: screen;
  opacity: var(--g-op);
  animation: lobby-glow-breathe var(--g-dur) ease-in-out var(--g-delay) infinite alternate;
}

/* Variante "fiamma": stessa idea, ma con sbalzi irregolari invece di un respiro
   regolare — è quella che si usa per le lanterne a candela, le più piccole. */
.lobby-glow.lobby-glow-flicker {
  animation: lobby-glow-flicker var(--g-dur) ease-in-out var(--g-delay) infinite;
}

@keyframes lobby-glow-breathe {
  0%   { opacity: calc(var(--g-op) * 0.7); transform: translate(-50%, -50%) scale(0.93); }
  100% { opacity: var(--g-op);             transform: translate(-50%, -50%) scale(1.07); }
}

/* I passaggi sono volutamente a intervalli non regolari: un ciclo "a onda"
   perfetto si legge subito come animazione, uno sbilenco sembra una fiamma. */
@keyframes lobby-glow-flicker {
  0%   { opacity: calc(var(--g-op) * 0.86); transform: translate(-50%, -50%) scale(1); }
  9%   { opacity: var(--g-op);              transform: translate(-50%, -50%) scale(1.06); }
  17%  { opacity: calc(var(--g-op) * 0.68); transform: translate(-50%, -50%) scale(0.95); }
  26%  { opacity: calc(var(--g-op) * 0.95); transform: translate(-50%, -50%) scale(1.03); }
  38%  { opacity: calc(var(--g-op) * 0.74); transform: translate(-50%, -50%) scale(0.97); }
  47%  { opacity: var(--g-op);              transform: translate(-50%, -50%) scale(1.05); }
  55%  { opacity: calc(var(--g-op) * 0.82); transform: translate(-50%, -50%) scale(0.99); }
  68%  { opacity: calc(var(--g-op) * 0.62); transform: translate(-50%, -50%) scale(0.94); }
  79%  { opacity: calc(var(--g-op) * 0.97); transform: translate(-50%, -50%) scale(1.04); }
  88%  { opacity: calc(var(--g-op) * 0.78); transform: translate(-50%, -50%) scale(0.98); }
  100% { opacity: calc(var(--g-op) * 0.86); transform: translate(-50%, -50%) scale(1); }
}

/* ---------- Insegne al neon ---------- */

/* Ogni insegna è fatta di DUE elementi fratelli, non di pseudo-elementi:
   - .lobby-neon-glow  somma luce intorno all'insegna (mix-blend-mode: screen)
   - .lobby-neon-off   spegne l'insegna scurendo ciò che ha dietro (backdrop-filter)
   Devono essere fratelli perché entrambi hanno bisogno di fondersi con lo SFONDO
   della scena: dentro un genitore con un transform proprio si fonderebbero solo
   col genitore (vedi la nota sui contesti di impilamento in cima alla sezione).
   Condividono --n-dur e --n-delay, quindi i due effetti restano sincronizzati:
   quando l'alone crolla, il rettangolo di buio si accende, e viceversa. */

.lobby-neon-glow {
  position: absolute;
  left: var(--n-x);
  top: var(--n-y);
  width: var(--n-w);
  height: var(--n-h);
  transform: translate(-50%, -50%);
  background: radial-gradient(
    ellipse at center,
    rgba(var(--n-rgb), 0.7) 0%,
    rgba(var(--n-rgb), 0.28) 38%,
    rgba(var(--n-rgb), 0) 72%
  );
  mix-blend-mode: screen;
  opacity: var(--n-op);
  animation: lobby-neon-glow var(--n-dur) linear var(--n-delay) infinite;
}

/* Il "vero" spegnimento: invece di provare a coprire il neon (impossibile, è
   dipinto dentro il jpg) si scurisce al volo la zona che gli sta dietro. La
   maschera radiale serve a non far vedere il bordo netto del rettangolo: il
   buio sfuma verso l'esterno, così sembra che sia la luce del neon a mancare
   sulla parete e non che ci sia una toppa scura sopra. */
/* Attivo SOLO dove il browser sa fare entrambe le cose: scurire ciò che sta dietro
   e sfumarne i bordi con una maschera. Senza la maschera si vedrebbe lampeggiare un
   rettangolo netto sulla parete, molto peggio del non avere l'effetto: in quel caso
   si rinuncia allo spegnimento e resta solo l'alone che sfarfalla, che da solo si
   legge comunque come "il neon fa contatto". */
.lobby-neon-off {
  display: none;
}

@supports (
  ((backdrop-filter: brightness(0.5)) or (-webkit-backdrop-filter: brightness(0.5)))
  and ((mask-image: radial-gradient(#000, transparent)) or (-webkit-mask-image: radial-gradient(#000, transparent)))
) {
  .lobby-neon-off {
    display: block;
    position: absolute;
    left: var(--n-x);
    top: var(--n-y);
    width: calc(var(--n-w) * 0.82);
    height: calc(var(--n-h) * 0.82);
    transform: translate(-50%, -50%);
    -webkit-backdrop-filter: brightness(0.4) saturate(0.45);
    backdrop-filter: brightness(0.4) saturate(0.45);
    -webkit-mask-image: radial-gradient(ellipse at center, #000 38%, transparent 78%);
    mask-image: radial-gradient(ellipse at center, #000 38%, transparent 78%);
    opacity: 0;
    /* nascosto per il 95% del ciclo: un backdrop-filter anche solo trasparente
       costerebbe comunque un ricalcolo a ogni frame, visibility: hidden no. */
    visibility: hidden;
    animation: lobby-neon-off var(--n-dur) linear var(--n-delay) infinite;
  }
}

/* Il grosso del ciclo l'insegna è accesa e "respira" appena (il ronzio del gas).
   Il contatto vero e proprio è concentrato tutto nell'ultimo 4% del ciclo: con
   una durata di ~15s vuol dire una scarica di sfarfallio di mezzo secondo ogni
   quarto d'ora scarso di orologio della scena — abbastanza raro da sorprendere. */
@keyframes lobby-neon-glow {
  0%,  36%   { opacity: var(--n-op); }
  44%        { opacity: calc(var(--n-op) * 0.78); }
  52%, 95.4% { opacity: var(--n-op); }
  95.6%      { opacity: 0.04; }
  96.1%      { opacity: var(--n-op); }
  96.4%      { opacity: 0.06; }
  96.7%      { opacity: var(--n-op); }
  97.3%      { opacity: 0.04; }
  97.9%      { opacity: calc(var(--n-op) * 0.45); }
  98.3%      { opacity: 0.05; }
  98.9%, 100% { opacity: var(--n-op); }
}

@keyframes lobby-neon-off {
  0%,  95.4% { opacity: 0; visibility: hidden; }
  95.6%      { opacity: 1; visibility: visible; }
  96.1%      { opacity: 0; visibility: visible; }
  96.4%      { opacity: 0.9; visibility: visible; }
  96.7%      { opacity: 0; visibility: visible; }
  97.3%      { opacity: 1; visibility: visible; }
  97.9%      { opacity: 0.4; visibility: visible; }
  98.3%      { opacity: 0.95; visibility: visible; }
  98.9%      { opacity: 0; visibility: visible; }
  99%, 100%  { opacity: 0; visibility: hidden; }
}

/* ---------- Petali di ciliegio ---------- */

/* Il "campo" è il rettangolo entro cui i petali vivono: per quelli lontani è
   esattamente il vano delle porte aperte sul giardino (così non si vedono mai
   cadere "dentro" al legno delle pareti), per quelli vicini è tutta la scena.
   overflow: hidden è quello che li fa comparire e sparire ai bordi del vano. */
.lobby-petal-field {
  position: absolute;
  overflow: hidden;
  pointer-events: none;
}

/* Ogni petalo è una colonna invisibile ALTA QUANTO IL CAMPO. Serve a poter
   esprimere la caduta come translateY in percentuale: le percentuali di un
   transform si riferiscono all'elemento stesso, quindi facendolo alto quanto il
   campo, "translateY(112%)" significa esattamente "attraversa tutto il campo e
   un po' oltre" — qualunque sia la dimensione della scena. */
.lobby-petal {
  position: absolute;
  top: 0;
  left: var(--pf-x);
  width: 0;
  height: 100%;
  will-change: transform;
  animation: lobby-petal-fall var(--pf-dur) linear var(--pf-delay) infinite;
}

/* Le tre trasformazioni stanno su tre elementi annidati diversi perché agiscono
   tutte sulla stessa proprietà (transform) con tempi diversi: la caduta sul
   contenitore, l'ondeggiamento laterale qui, la rotazione sul petalo vero.
   Metterle insieme significherebbe farle litigare. */
.lobby-petal-sway {
  position: absolute;
  top: 0;
  left: 0;
  animation: lobby-petal-sway var(--ps-dur) ease-in-out var(--ps-delay) infinite alternate;
}

.lobby-petal-shape {
  width: var(--pt-size);
  height: calc(var(--pt-size) * 0.78);
  background: radial-gradient(
    120% 130% at 28% 18%,
    rgba(255, 244, 250, 0.98) 0%,
    rgba(255, 196, 226, 0.95) 45%,
    rgba(246, 138, 190, 0.9) 100%
  );
  /* Forma "a petalo": una punta netta in alto a sinistra e tre angoli morbidi.
     A queste dimensioni (pochi pixel) non serve di più, la silhouette basta. */
  border-radius: 100% 0 62% 38% / 100% 0 38% 62%;
  opacity: var(--pf-op);
  animation: lobby-petal-spin var(--pt-dur) linear var(--pt-delay) infinite;
}

@keyframes lobby-petal-fall {
  0%   { transform: translate3d(0, -14%, 0); }
  100% { transform: translate3d(0, 112%, 0); }
}

@keyframes lobby-petal-sway {
  0%   { transform: translate3d(calc(var(--ps-amp) * -1), 0, 0); }
  100% { transform: translate3d(var(--ps-amp), 0, 0); }
}

/* rotateY senza prospettiva schiaccia il petalo in orizzontale invece di girarlo
   in profondità: è esattamente l'effetto "si rigira su sé stesso mentre cade"
   che serve, e costa molto meno di una vera scena 3D. */
@keyframes lobby-petal-spin {
  0%   { transform: rotateZ(0deg) rotateY(0deg); }
  100% { transform: rotateZ(360deg) rotateY(720deg); }
}

/* ---------- Pulviscolo sospeso ---------- */

/* Granelli di polvere che galleggiano nei coni di luce. Sono il dettaglio che
   costa meno di tutti e che più di tutti toglie la sensazione di "foto ferma":
   anche quando nessuno si muove, nella stanza qualcosa continua a respirare. */
.lobby-mote {
  position: absolute;
  left: var(--m-x);
  top: var(--m-y);
  width: var(--m-size);
  aspect-ratio: 1;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(255, 224, 168, 0.95) 0%, rgba(255, 196, 118, 0) 70%);
  mix-blend-mode: screen;
  opacity: 0;
  animation:
    lobby-mote-drift var(--m-dur) ease-in-out var(--m-delay) infinite alternate,
    lobby-mote-twinkle var(--m-tw) ease-in-out var(--m-delay) infinite alternate;
}

@keyframes lobby-mote-drift {
  0%   { transform: translate3d(0, 0, 0); }
  100% { transform: translate3d(var(--m-dx), var(--m-dy), 0); }
}

@keyframes lobby-mote-twinkle {
  0%   { opacity: 0.06; }
  100% { opacity: var(--m-op); }
}

/* Chi ha chiesto al sistema operativo meno animazioni possibili non deve
   ritrovarsi una stanza intera che pulsa: si torna alla foto ferma di prima. */
@media (prefers-reduced-motion: reduce) {
  .lobby-ambience,
  .lobby-ambience-front {
    display: none;
  }
}

/* Piedistallo: stesso ancoraggio "ai piedi" degli avatar (translate -50%,-100%), così
   la base dell'immagine poggia esattamente sul punto x/y assegnato. La larghezza è in
   percentuale della scena (non px fissi) per restare coerente se la finestra cambia
   dimensione o va in fullscreen. */
.hall-pedestal {
  position: absolute;
  transform: translate(-50%, -100%);
  max-width: 30%; /* rete di sicurezza: anche in caso di dato mancante non deve mai occupare mezza stanza */
}

.hall-pedestal-base {
  display: block;
  width: 100%;
  height: auto;
}

/* La zona foto è posizionata in percentuale DENTRO al piedistallo stesso (non della
   scena) — le percentuali sono quelle misurate sulla vetrina nell'immagine sorgente,
   quindi restano corrette qualunque sia la larghezza a cui il piedistallo viene
   scalato in scena. */
.hall-pedestal-photo-frame {
  position: absolute;
  overflow: hidden;
}

.hall-pedestal-photo {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  /* Effetto "dietro al vetro": leggermente sbiadita e desaturata, come se la si
     guardasse attraverso lo spessore del vetro fumé invece che a nudo. */
  opacity: 0.82;
  filter: saturate(0.85) brightness(0.92) contrast(0.95);
}

/* Riflesso caldo sopra la foto, coerente con le luci ambrate del piedistallo — una
   sfumatura diagonale molto leggera, non un vero riflesso fotorealistico, giusto
   quel tanto che serve a "legare" la foto al resto della scena. */
.hall-pedestal-glass-sheen {
  position: absolute;
  inset: 0;
  background: linear-gradient(135deg, rgba(240, 200, 105, 0.22) 0%, rgba(240, 200, 105, 0) 35%, rgba(0, 0, 0, 0.12) 100%);
  box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.35);
  pointer-events: none;
}

/* Ogni figurina: ancorata per il "punto dei piedi" (translate -50%,-100%), non per
   l'angolo — così quando cambia la posizione (percentuale su x/y) sembra davvero
   poggiare sul pavimento nel punto giusto invece di fluttuare. La transizione su
   left/top/transform è quello che fa vedere il movimento "camminato" invece di un
   teletrasporto istantaneo quando arriva un aggiornamento dagli altri. */
.lobby-avatar-token {
  position: absolute;
  transform: translate(-50%, -100%);
  /* Niente transition su left/top: la posizione la scrive fotogramma per fotogramma
     il ciclo di movimento in app.js. Una transizione qui la combatterebbe, aggiungendo
     un'inerzia che rende impossibile cambiare bersaglio a metà strada. */
  display: flex;
  flex-direction: column;
  align-items: center;
  pointer-events: none;
}
/* Effetto "teletrasporto" quando qualcuno entra/esce dalla lobby in tempo reale.
   È su un wrapper dedicato (.lobby-teleport-fx), separato sia da .avatar-wrap (che ha
   già il suo transform per la scala di profondità, impostato via JS) sia da
   .lobby-bounce (che ha la sua animazione del rimbalzo mentre si cammina) — così le tre
   animazioni non si pestano i piedi a vicenda sulla stessa proprietà CSS. */
.lobby-teleport-fx {
  position: relative;
  /* Larghezza di UN fotogramma del fulmine così com'è mostrato in scena (l'altezza segue
     da sola via aspect-ratio; ogni fotogramma sorgente è 130x287px, ricentrato sul
     contenuto reale del fulmine — nello sprite originale il disegno non era nel centro
     esatto del riquadro. 6 fotogrammi in tutto: l'ultimo è vuoto e serve da dissolvenza
     finale. Deliberatamente MOLTO più grande dell'avatar stesso (che è
     clamp(56px,6.54cqw,120px)): deve essere un effetto che lo sovrasta, non uno che ci
     sta dentro. Con "cqw" cresce insieme alla scena anche in fullscreen. */
  --lt-frame-w: clamp(150px, 18cqw, 340px);
}
.lobby-teleport-fx::before {
  content: '';
  position: absolute;
  left: 50%;
  bottom: -8%; /* scende leggermente sotto i piedi, così il "colpo" avvolge tutta la figurina */
  width: var(--lt-frame-w);
  aspect-ratio: 130 / 287;
  transform: translateX(-50%);
  background-image: url('lobby/lightning-sprite.png');
  background-repeat: no-repeat;
  /* Lo sprite è una striscia di 6 fotogrammi uguali affiancati (il 6° è vuoto, dissolvenza
     finale): allargando lo sfondo a 6 volte la larghezza del riquadro e spostandolo di un
     fotogramma alla volta (vedi i keyframes sotto) si vede sempre un solo fotogramma per
     volta, mai una via di mezzo sfocata tra due. */
  background-size: calc(var(--lt-frame-w) * 6) 100%;
  opacity: 0;
  pointer-events: none;
  z-index: 5; /* ben sopra l'avatar: è un effetto che lo avvolge, non un dettaglio dietro */
}
.lobby-teleport-fx.lobby-teleport-in::before {
  animation: lobby-lightning-in 0.75s steps(5) forwards;
}
.lobby-teleport-fx.lobby-teleport-out::before {
  animation: lobby-lightning-out 0.7s steps(5) forwards;
}
@keyframes lobby-lightning-in {
  0% { opacity: 1; background-position-x: 0; }
  100% { opacity: 1; background-position-x: calc(var(--lt-frame-w) * -5); }
}
@keyframes lobby-lightning-out {
  /* La stessa sequenza di fotogrammi, ma percorsa al contrario. */
  0% { opacity: 1; background-position-x: calc(var(--lt-frame-w) * -5); }
  100% { opacity: 1; background-position-x: 0; }
}
.lobby-teleport-fx.lobby-teleport-in {
  animation: lobby-teleport-in 0.75s cubic-bezier(0.25, 0.9, 0.3, 1) both;
}
.lobby-teleport-fx.lobby-teleport-out {
  animation: lobby-teleport-out 0.7s ease-in forwards;
}
@keyframes lobby-teleport-in {
  0% { opacity: 0; transform: scale(0.4); filter: brightness(2.6) saturate(1.6) drop-shadow(0 0 22px rgba(57, 184, 222, 0.9)); }
  55% { opacity: 1; transform: scale(1.08); filter: brightness(1.5) saturate(1.2) drop-shadow(0 0 14px rgba(57, 184, 222, 0.55)); }
  100% { opacity: 1; transform: scale(1); filter: brightness(1) saturate(1) drop-shadow(0 0 0px rgba(57, 184, 222, 0)); }
}
@keyframes lobby-teleport-out {
  0% { opacity: 1; transform: scale(1); filter: brightness(1) drop-shadow(0 0 0px rgba(57, 184, 222, 0)); }
  35% { opacity: 0.85; transform: scale(1.06); filter: brightness(2.4) saturate(1.5) drop-shadow(0 0 20px rgba(57, 184, 222, 0.85)); }
  100% { opacity: 0; transform: scale(0.35); filter: brightness(3) drop-shadow(0 0 10px rgba(57, 184, 222, 0.4)); }
}

/* Deformazione "cartoon" (squash & stretch) dell'avatar, indipendente dal fulmine: entra
   cadendo da un po' più in alto di dove atterra, allungato in caduta e schiacciato
   all'impatto; esce allungandosi verso l'alto come se decollasse. È su .lobby-bounce
   (solo avatar+nome), non su .lobby-teleport-fx (che ha già il fulmine): le due
   animazioni si sommano invece di sovrascriversi, il fulmine resta identico a prima. */
.lobby-teleport-fx.lobby-teleport-in .lobby-bounce {
  animation: lobby-fall-in 0.75s cubic-bezier(0.25, 0.9, 0.3, 1) both;
}
.lobby-teleport-fx.lobby-teleport-out .lobby-bounce {
  animation: lobby-launch-out 0.7s ease-in forwards;
}
@keyframes lobby-fall-in {
  0%   { transform: translateY(-70px) scaleX(0.75) scaleY(1.35); }
  55%  { transform: translateY(4px) scaleX(1.2) scaleY(0.82); } /* impatto: schiacciato */
  100% { transform: translateY(0) scaleX(1) scaleY(1); }
}
@keyframes lobby-launch-out {
  0%   { transform: translateY(0) scaleX(1) scaleY(1); }
  20%  { transform: translateY(3px) scaleX(1.18) scaleY(0.85); } /* rincorsa: si schiaccia un attimo prima di partire */
  100% { transform: translateY(-80px) scaleX(0.7) scaleY(1.4); }
}

/* ==========================================================================
   IL PUPAZZO A PEZZI (rig)
   --------------------------------------------------------------------------
   L'avatar non è più una foto con un nome sotto: è una figura articolata di sei
   pezzi (busto, due braccia, due gambe, testa) dove la testa è la foto profilo.
   Le proporzioni qui sotto arrivano dal tuner (lobby-rig-tuner.html): si tarano
   là guardandole e si incolla il blocco, senza toccare il resto della sezione.

   REGOLA DA NON PERDERE: tutto ciò che appartiene al MONDO — ombra, nome, badge
   di stato — sta FUORI da .lobby-rig, altrimenti eredita il rimbalzo e
   l'inclinazione della camminata (un'ombra che saltella insieme ai piedi smette
   di leggersi come ombra). Ciò che appartiene al CORPO sta dentro. I gesti tenuti
   in mano sono l'eccezione voluta: quelli devono seguire il braccio.

   Ogni variabile porta con sé la propria unità (3.8cqw, 24deg, 0.46s) e non è mai
   un numero nudo da moltiplicare dopo: un var() che si risolve in un valore senza
   unità dentro una scorciatoia "animation" la rende invalida, e il browser la
   scarta in silenzio — l'animazione non parte e in console non compare nulla.
   ========================================================================== */

.lobby-figure {
  /* --- Taratura (export del tuner) --- */
  --head: 3.8cqw;
  --torso-w: 3.3cqw;
  --torso-h: 3.5cqw;
  --arm-w: 1.1cqw;
  --arm-h: 2.5cqw;
  --leg-w: 1.1cqw;
  --leg-h: 2.3cqw;
  --neck: 0.4cqw;
  --shoulder-x: 2.2cqw;
  --shoulder-y: 0.4cqw;
  --hip-x: 1.1cqw;
  --hand-y: 103%;
  --leg-swing: 46deg;
  --arm-swing: 28deg;
  --step-dur: 0.19s;
  --bob: 0.5cqw;
  --lean: 3deg;
  --idle-dur: 2.4s;
  --idle-arm: 0deg;
  --idle-sway: 1.3deg;
  --arm-raise: 148deg; /* posa del braccio che regge il razzo */
  --shadow-w: 4.4cqw;
  --shadow-op: 0.26;
  --col-torso: #30395f;
  --col-arm: #24253d;
  --col-leg: #24253d;

  position: relative;
  /* La scala di profondità (lobbyDepthScale) è impostata da JS QUI, non più su
     .avatar-wrap: adesso il corpo esiste, e scalando solo la testa la figura si
     deformerebbe man mano che si allontana. L'ancoraggio è ai piedi, così il
     bordo inferiore resta fermo dove sta il nome sottostante. */
  transform-origin: center bottom;
  /* Come sopra: la scala la aggiorna il ciclo di movimento a ogni fotogramma, quindi
     segue la profondità con precisione al pixel invece di rincorrerla con 0.6s di
     ritardo. Una transizione qui la farebbe arrivare sempre in ritardo sul movimento. */
}

/* Su scene strette (telefono) il pupazzo in cqw diventerebbe minuscolo. "scale" è
   una proprietà a sé, distinta da "transform": si moltiplica a quella scritta da JS
   invece di sovrascriverla, quindi le due convivono senza doversi coordinare. */
@container lobby-scene (max-width: 620px) {
  .lobby-figure { scale: 1.45; }
}

.lobby-facing { display: block; }
/* Verso di marcia: si specchia il corpo, non la figura intera.
   Nota il "right" e non "left": il rig così com'è disegnato — con braccio e gamba
   davanti dalla parte destra dell'immagine — si legge come una figura rivolta a
   SINISTRA. Quindi è camminando verso destra che va ribaltata. Il codice non ha modo
   di saperlo da solo: il pupazzo è geometricamente simmetrico e l'oscillazione è un
   pendolo identico se lo specchi, l'unico indizio di direzione è quale arto sta
   davanti. Se un giorno cambi l'ordine di disegno dei pezzi, ricontrolla anche questo. */
.lobby-avatar-token[data-facing="right"] .lobby-facing { transform: scaleX(-1); }
/* ...e la testa si ri-specchia per conto suo, perché una foto di una faccia vera
   ribaltata si nota subito e mette a disagio. Un paio di gambe ribaltate no. */
.lobby-avatar-token[data-facing="right"] .lobby-rig-head { transform: translateX(-50%) scaleX(-1); }

.lobby-rig {
  position: relative;
  margin: 0 auto;
  width: var(--torso-w);
  height: calc(var(--torso-h) + var(--leg-h));
  transform-origin: center bottom;
}

.lobby-rig-torso {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: var(--torso-h);
  background-color: var(--col-torso);
  background-size: 100% 100%;
  background-repeat: no-repeat;
  border-radius: 0.5cqw 0.5cqw 0.25cqw 0.25cqw;
  transform-origin: center bottom;
}

/* ---- La maglietta del gioco ----
   Quando qualcuno sta giocando a qualcosa su Steam, la copertina del gioco gli
   compare stampata sul petto. Non riempie tutto il busto: resta un margine del
   colore della maglia tutt'intorno, ed è quel margine a far leggere l'immagine
   come una STAMPA su una maglietta invece che come un busto ritagliato da una
   foto. Senza, sembra un errore di ritaglio.

   Sta su uno pseudo-elemento e non sul background del busto perché quel livello è
   già riservato ai costumi: un domani si potranno indossare insieme, maglietta
   sopra la giacca. Eredita da solo il respiro del torace, quindi la stampa si
   dilata col petto senza bisogno di animarla a parte. */
.lobby-rig-torso::before {
  content: '';
  position: absolute;
  inset: 14% 16%;
  background-image: var(--shirt, none);
  background-size: cover;
  background-position: center;
  border-radius: 0.12cqw;
  /* Le copertine Steam sono sature e luminose: a queste dimensioni brillerebbero
     più della lanterna che hanno accanto. Un filo di desaturazione le riporta
     dentro la scena. */
  filter: saturate(0.88) brightness(0.92);
}

/* La stampa si ri-specchia per conto suo, esattamente come fa la testa: sta dentro
   .lobby-facing, quindi senza questo verrebbe ribaltata insieme al corpo ogni volta
   che si cammina dall'altra parte. Su gambe e braccia il ribaltamento non si nota,
   su una copertina con un titolo scritto sopra sì — e una scritta allo specchio si
   legge come un errore, non come un personaggio girato. */
.lobby-avatar-token[data-facing="right"] .lobby-rig-torso::before {
  transform: scaleX(-1);
}

.lobby-rig-head {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  bottom: calc(var(--torso-h) + var(--leg-h) - var(--neck));
  line-height: 0; /* niente spazio fantasma sotto l'immagine inline */
}

.lobby-rig-leg {
  position: absolute;
  top: var(--torso-h);
  width: var(--leg-w);
  height: var(--leg-h);
  background-color: var(--col-leg);
  background-size: 100% 100%;
  background-repeat: no-repeat;
  border-radius: 0 0 0.25cqw 0.25cqw;
  transform-origin: 50% 0; /* il perno è l'anca, in cima al pezzo */
}
.lobby-rig-leg-back { left: calc(50% - var(--hip-x) - var(--leg-w) / 2); }
.lobby-rig-leg-front { left: calc(50% + var(--hip-x) - var(--leg-w) / 2); }

.lobby-rig-arm {
  position: absolute;
  top: var(--shoulder-y);
  width: var(--arm-w);
  height: var(--arm-h);
  background-color: var(--col-arm);
  background-size: 100% 100%;
  background-repeat: no-repeat;
  border-radius: 0.25cqw;
  transform-origin: 50% 0; /* il perno è la spalla */
  transition: transform 0.22s ease; /* il braccio si alza, non scatta */
}
.lobby-rig-arm-back { left: calc(50% - var(--shoulder-x) - var(--arm-w) / 2); }
.lobby-rig-arm-front { left: calc(50% + var(--shoulder-x) - var(--arm-w) / 2); }

/* Punto d'aggancio dei gesti tenuti in mano: un punto di dimensione zero in fondo
   al braccio. Quello che gli si appende dentro eredita rotazione e scala del
   braccio da solo, senza ricalcoli in JS a ogni fotogramma. */
.lobby-rig-hand {
  position: absolute;
  left: 50%;
  top: var(--hand-y);
  width: 0;
  height: 0;
}

/* Fuori dal rig: non rimbalza, non si inclina, non si specchia. */
.lobby-rig-shadow {
  position: absolute;
  left: 50%;
  bottom: 0;
  width: var(--shadow-w);
  height: calc(var(--shadow-w) * 0.24);
  transform: translate(-50%, 50%);
  border-radius: 50%;
  background: rgba(0, 0, 0, var(--shadow-op));
}

/* ---- Camminata ---- */
.lobby-avatar-token.walking .lobby-rig {
  animation: lobby-rig-bob var(--step-dur) ease-in-out infinite,
             lobby-rig-lean calc(var(--step-dur) * 2) ease-in-out infinite;
}
.lobby-avatar-token.walking .lobby-rig-leg-back { animation: lobby-rig-swing-leg var(--step-dur) ease-in-out infinite alternate; }
.lobby-avatar-token.walking .lobby-rig-leg-front { animation: lobby-rig-swing-leg var(--step-dur) ease-in-out infinite alternate-reverse; }
.lobby-avatar-token.walking .lobby-rig-arm-back { animation: lobby-rig-swing-arm var(--step-dur) ease-in-out infinite alternate-reverse; }
.lobby-avatar-token.walking .lobby-rig-arm-front { animation: lobby-rig-swing-arm var(--step-dur) ease-in-out infinite alternate; }
.lobby-avatar-token.walking .lobby-rig-shadow { animation: lobby-rig-shadow-step var(--step-dur) ease-in-out infinite; }

@keyframes lobby-rig-swing-leg {
  from { transform: rotate(calc(var(--leg-swing) * -1)); }
  to { transform: rotate(var(--leg-swing)); }
}
@keyframes lobby-rig-swing-arm {
  from { transform: rotate(calc(var(--arm-swing) * -1)); }
  to { transform: rotate(var(--arm-swing)); }
}
@keyframes lobby-rig-bob {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(calc(var(--bob) * -1)); }
}
/* L'inclinazione gira su "rotate", il rimbalzo su "transform": sono due proprietà
   distinte, quindi possono avere durate diverse (l'inclinazione dura due passi,
   cioè un ciclo completo) senza pestarsi i piedi sullo stesso elemento. */
@keyframes lobby-rig-lean {
  0%, 100% { rotate: calc(var(--lean) * -1); }
  50% { rotate: var(--lean); }
}
@keyframes lobby-rig-shadow-step {
  0%, 100% { transform: translate(-50%, 50%) scale(1); }
  50% { transform: translate(-50%, 50%) scale(0.88); }
}

/* ---- Fermo ----
   Conta quanto la camminata, anzi di più: gli avatar stanno fermi la maggior parte
   del tempo. Respiro e oscillazione hanno periodi diversi (l'oscillazione dura 2.4
   volte il respiro) così sfasano di continuo e non si vede mai un ciclo ripetersi
   identico — è quello che distingue "sta respirando" da "sta facendo un'animazione". */
.lobby-avatar-token:not(.walking) .lobby-rig {
  animation: lobby-rig-breathe var(--idle-dur) ease-in-out infinite,
             lobby-rig-sway calc(var(--idle-dur) * 2.4) ease-in-out infinite;
}
.lobby-avatar-token:not(.walking) .lobby-rig-torso {
  animation: lobby-rig-chest var(--idle-dur) ease-in-out infinite;
}
.lobby-avatar-token:not(.walking) .lobby-rig-arm-back { transform: rotate(calc(var(--idle-arm) * -1)); }
.lobby-avatar-token:not(.walking) .lobby-rig-arm-front { transform: rotate(var(--idle-arm)); }

@keyframes lobby-rig-breathe {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-0.18cqw); }
}
/* Da -oscillazione a +oscillazione: il peso passa da un piede all'altro. Partendo
   da 0 penderebbe sempre dallo stesso lato e sembrerebbe sul punto di cadere. */
@keyframes lobby-rig-sway {
  0%, 100% { rotate: calc(var(--idle-sway) * -1); }
  50% { rotate: var(--idle-sway); }
}
@keyframes lobby-rig-chest {
  0%, 100% { transform: scaleY(1); }
  50% { transform: scaleY(1.035); }
}

/* Posa "braccio alzato": mentre si tiene un razzo, il braccio corrispondente smette di
   oscillare e resta fermo in alto. Serve a due cose. La prima è che il razzo appare
   sollevato come chi sta per lanciare, invece che penzolante lungo il fianco. La
   seconda è più pratica: con il braccio immobile il punto d'aggancio della mano non si
   sposta più a ogni fotogramma, quindi il razzo ci resta incollato senza sobbalzi.

   Deve stare DOPO le regole di camminata e di riposo: ha la loro stessa specificità
   (tre classi contro classe + attributo + classe), quindi a decidere è l'ordine.

   Il segno della rotazione è opposto fra i due bracci perché il perno è la spalla e il
   pezzo pende verso il basso: ruotando in senso orario la mano va a sinistra, quindi il
   braccio destro va alzato con un angolo negativo per portarlo in fuori e non davanti
   al petto.

   Un attributo per mano, non uno solo con dentro il lato: si possono tenere due razzi
   contemporaneamente, e con un attributo unico il secondo lancio cancellerebbe la posa
   del primo, riabbassando un braccio che sta ancora reggendo qualcosa.

   Questi bracci stanno DENTRO .lobby-facing, quindi girandosi si specchiano insieme al
   resto del corpo e restano alzati verso l'esterno da soli, senza calcoli. */
.lobby-avatar-token[data-raise-sx] .lobby-rig-arm-back,
.lobby-avatar-token[data-raise-dx] .lobby-rig-arm-front {
  animation: none;
}
.lobby-avatar-token[data-raise-sx] .lobby-rig-arm-back {
  transform: rotate(var(--arm-raise));
}
.lobby-avatar-token[data-raise-dx] .lobby-rig-arm-front {
  transform: rotate(calc(var(--arm-raise) * -1));
}

/* ==========================================================================
   POSE DEL CORPO
   --------------------------------------------------------------------------
   Salutare, indicare, sedersi, sdraiarsi: nessuna immagine nuova, sono i sei
   pezzi del rig che ruotano attorno ai perni che hanno già. È il motivo per cui
   valeva la pena costruire il pupazzo articolato invece di disegnare sprite.

   ORIENTAMENTO: le pose che coinvolgono UN braccio solo (saluto, indica) sono
   definite sulla figura NON specchiata, e il JS forza data-facing di conseguenza
   prima di applicarle. Senza quel blocco, "indica a destra" punterebbe a sinistra
   ogni volta che l'avatar sta camminando dall'altra parte, perché la specchiatura
   ribalta anche il segno delle rotazioni. Sedersi e sdraiarsi non hanno questo
   problema: sono simmetriche, e anzi sdraiarsi nel verso in cui si stava andando
   è più naturale che sdraiarsi sempre dalla stessa parte.

   Le rotazioni: il perno di braccia e gambe è in cima al pezzo (spalla, anca) e il
   pezzo pende verso il basso, quindi un angolo POSITIVO porta l'estremità verso
   sinistra e uno NEGATIVO verso destra. Zero è "lungo il fianco", ±90 è "teso in
   orizzontale", ±150 è "alzato in alto e in fuori".
   ========================================================================== */

/* Le pose si dividono in due famiglie, e la differenza non è estetica ma di quanto
   corpo occupano.

   Quelle DI SOLE BRACCIA (saluto, indicazioni) sospendono soltanto le braccia: gambe,
   busto e rimbalzo continuano per conto loro, quindi si può salutare o indicare
   camminando, che è esattamente quello che si fa nella vita.

   Quelle DI TUTTO IL CORPO (seduto, sdraiato) sospendono tutto, e sono incompatibili
   col camminare: si prendono da fermi e il primo passo le scioglie.

   Devono stare dopo le regole di .walking, di :not(.walking) e di data-raise, perché
   hanno la loro stessa specificità e a decidere è l'ordine. */
.lobby-avatar-token[data-pose="saluto"] .lobby-rig-arm,
.lobby-avatar-token[data-pose="indica_dx"] .lobby-rig-arm,
.lobby-avatar-token[data-pose="indica_sx"] .lobby-rig-arm {
  animation: none;
}

.lobby-avatar-token[data-pose="seduto"] .lobby-rig,
.lobby-avatar-token[data-pose="seduto"] .lobby-rig-torso,
.lobby-avatar-token[data-pose="seduto"] .lobby-rig-leg,
.lobby-avatar-token[data-pose="seduto"] .lobby-rig-arm,
.lobby-avatar-token[data-pose="sdraiato"] .lobby-rig,
.lobby-avatar-token[data-pose="sdraiato"] .lobby-rig-torso,
.lobby-avatar-token[data-pose="sdraiato"] .lobby-rig-leg,
.lobby-avatar-token[data-pose="sdraiato"] .lobby-rig-arm {
  animation: none;
}
.lobby-avatar-token[data-pose="seduto"] .lobby-rig,
.lobby-avatar-token[data-pose="sdraiato"] .lobby-rig { rotate: 0deg; }

/* Le pose vanno prese e lasciate con un movimento, non con uno scatto. Le braccia
   hanno già la loro transizione (serviva al braccio che regge il razzo). */
.lobby-avatar-token[data-pose="seduto"] .lobby-rig,
.lobby-avatar-token[data-pose="seduto"] .lobby-rig-leg,
.lobby-avatar-token[data-pose="sdraiato"] .lobby-rig,
.lobby-avatar-token[data-pose="sdraiato"] .lobby-rig-leg {
  transition: transform 0.3s ease;
}

/* ---- Saluto: braccio alzato sul lato destro dello schermo, che si agita ---- */
.lobby-avatar-token[data-pose="saluto"] .lobby-rig-arm-front {
  animation: lobby-pose-wave 0.34s ease-in-out infinite alternate;
}
@keyframes lobby-pose-wave {
  from { transform: rotate(-134deg); }
  to { transform: rotate(-168deg); }
}
/* L'altro braccio resta appena staccato dal corpo, altrimenti la figura sembra
   sull'attenti proprio mentre saluta. */
.lobby-avatar-token[data-pose="saluto"] .lobby-rig-arm-back { transform: rotate(9deg); }

/* ---- Indicare: braccio teso, appena sopra l'orizzontale ---- */
.lobby-avatar-token[data-pose="indica_dx"] .lobby-rig-arm-front { transform: rotate(-97deg); }
.lobby-avatar-token[data-pose="indica_dx"] .lobby-rig-arm-back { transform: rotate(7deg); }
.lobby-avatar-token[data-pose="indica_sx"] .lobby-rig-arm-back { transform: rotate(97deg); }
.lobby-avatar-token[data-pose="indica_sx"] .lobby-rig-arm-front { transform: rotate(-7deg); }

/* ---- Seduto a gambe incrociate ----
   Le gambe ruotano quasi in orizzontale e si accorciano un po': viste di fronte,
   due gambe piegate in fuori leggono come "incrociate" senza bisogno di disegnare
   l'incrocio. Tutto il rig scende, perché con le gambe ripiegate i fianchi
   arrivano a terra: senza lo spostamento la figura resterebbe sospesa in aria
   all'altezza a cui stava in piedi. */
.lobby-avatar-token[data-pose="seduto"] .lobby-rig {
  transform: translateY(calc(var(--leg-h) * 0.78));
}
/* Segni invertiti rispetto alla prima versione: la gamba di destra ruota VERSO
   SINISTRA e viceversa, così le due si accavallano al centro invece di aprirsi a V.
   Quella davanti resta disegnata sopra, ed è l'accavallamento a leggersi. */
.lobby-avatar-token[data-pose="seduto"] .lobby-rig-leg-front { transform: rotate(74deg) scaleY(0.84); }
.lobby-avatar-token[data-pose="seduto"] .lobby-rig-leg-back { transform: rotate(-70deg) scaleY(0.84); }
.lobby-avatar-token[data-pose="seduto"] .lobby-rig-arm-front { transform: rotate(-24deg); }
.lobby-avatar-token[data-pose="seduto"] .lobby-rig-arm-back { transform: rotate(24deg); }

/* ---- Sdraiato per lungo ----
   Il perno del rig è già ai piedi, quindi basta coricarlo: ruotando di 84 gradi il
   corpo si distende sul pavimento a partire dal punto dove stava in piedi. Anche la
   testa ruota, ed è giusto così — chi è sdraiato ha la testa di lato. */
/* La rotazione avviene attorno ai piedi, quindi da sola stenderebbe tutto il corpo
   da una parte sola del punto in cui ci si trovava. Lo spostamento orizzontale lo
   riporta a cavallo di quel punto: metà figura di qua, metà di là. La lunghezza da
   compensare è busto + gambe + testa, cioè l'ingombro della figura distesa. */
.lobby-avatar-token[data-pose="sdraiato"] .lobby-rig {
  transform:
    translate(
      calc((var(--torso-h) + var(--leg-h) + var(--head)) * -0.42),
      calc(var(--torso-w) * 0.45)
    )
    rotate(-84deg);
}
.lobby-avatar-token[data-pose="sdraiato"] .lobby-rig-leg-front { transform: rotate(-4deg); }
.lobby-avatar-token[data-pose="sdraiato"] .lobby-rig-leg-back { transform: rotate(4deg); }
.lobby-avatar-token[data-pose="sdraiato"] .lobby-rig-arm-front { transform: rotate(-16deg); }
.lobby-avatar-token[data-pose="sdraiato"] .lobby-rig-arm-back { transform: rotate(16deg); }
/* L'ombra segue il corpo: si allunga quanto la figura distesa e si sposta verso il
   lato dove il corpo si è coricato, invece di restare un ovale sotto i piedi. */
.lobby-avatar-token[data-pose="sdraiato"] .lobby-rig-shadow {
  width: calc((var(--torso-h) + var(--leg-h) + var(--head)) * 0.92);
  transition: width 0.3s ease;
}

/* I livelli di gesti e stato erano ancorati all'intero token e scalati a parte da
   JS. Ora vivono dentro .lobby-figure e coprono esattamente il riquadro della testa
   — che è la vecchia "scatola avatar" — così le percentuali già tarate dei gesti
   restano valide, e la scala di profondità la ereditano invece di riceverla due
   volte. Stanno fuori da .lobby-facing di proposito: uno scoppio o delle stelline
   non devono specchiarsi quando la figura si gira. */
.lobby-figure > .lobby-gesture-layer,
.lobby-figure > .lobby-status-layer,
.lobby-figure > .lobby-bubble-layer {
  inset: auto;
  left: 50%;
  bottom: calc(var(--torso-h) + var(--leg-h) - var(--neck));
  width: var(--head);
  height: var(--head);
  transform: translateX(-50%);
  transition: none;
}
.lobby-bubble-layer {
  position: absolute;
  pointer-events: none;
  z-index: 8;
}

.lobby-bounce {
  display: flex;
  flex-direction: column;
  align-items: center;
  transform-origin: center bottom; /* lo schiacciamento/allungamento di ingresso-uscita parte dai piedi, non dal centro */
}
/* Il rimbalzo della camminata ora lo fa il rig (vedi lobby-rig-bob): un rimbalzo qui
   su .lobby-bounce si sommerebbe a quello, e la figura ballerebbe il doppio.
   .lobby-bounce resta perché serve ancora allo squash & stretch di entrata/uscita. */
/* La testa è la foto profilo, e prende la misura dal rig: se cambi --head nel tuner
   cambiano insieme immagine, fallback con l'iniziale e riquadro dei gesti. */
.lobby-avatar-img { width: var(--head); height: var(--head); border-radius: 6px; object-fit: cover; display: block; }
.lobby-avatar-img.avatar-fallback,
.lobby-avatar-token .avatar-fallback { width: var(--head); height: var(--head); font-size: calc(var(--head) * 0.4); border-radius: 6px; }
.lobby-avatar-name {
  margin-top: 2px;
  font-size: clamp(0.62rem, 1.16cqw, 1.3rem);
  font-weight: 600;
  color: #fff;
  background: rgba(0,0,0,0.55);
  padding: 1px 6px;
  border-radius: 8px;
  white-space: nowrap;
  text-shadow: 0 1px 2px rgba(0,0,0,0.5);
}

/* Il fumetto: ancorato sopra la testa, sparisce da solo con l'animazione. */
.lobby-bubble {
  position: absolute;
  bottom: 100%;
  left: 50%;
  transform: translateX(-50%);
  margin-bottom: 4px;
  background: #fff;
  color: #1a1a1a;
  font-size: clamp(1.1rem, 2.06cqw, 2.2rem);
  line-height: 1;
  padding: 5px 8px;
  border-radius: 10px;
  box-shadow: 0 4px 10px rgba(0,0,0,0.35);
  animation: lobby-bubble-in 0.2s ease-out;
  white-space: nowrap;
}
.lobby-bubble.lobby-bubble-text {
  font-size: clamp(0.72rem, 1.35cqw, 1.4rem);
  font-weight: 600;
  line-height: 1.3;
  white-space: normal;
  max-width: clamp(140px, 16.36cqw, 260px);
  width: max-content;
  text-align: center;
  overflow-wrap: anywhere; /* una stringa lunga senza spazi (es. "aaaaaaa...") va comunque a capo invece di uscire dal fumetto */
  word-break: break-word; /* stessa cosa, per i browser che non conoscono ancora overflow-wrap: anywhere */
}
.lobby-bubble::after {
  content: '';
  position: absolute;
  top: 100%;
  left: 50%;
  transform: translateX(-50%);
  border: 5px solid transparent;
  border-top-color: #fff;
}
.lobby-bubble.lobby-bubble-out { animation: lobby-bubble-out 0.2s ease-in forwards; }
@keyframes lobby-bubble-in { from { opacity: 0; transform: translateX(-50%) translateY(4px); } to { opacity: 1; transform: translateX(-50%) translateY(0); } }
@keyframes lobby-bubble-out { from { opacity: 1; } to { opacity: 0; transform: translateX(-50%) translateY(-4px); } }

/* Bubble dei trofei del piedistallo: stesso linguaggio visivo della bubble di chat
   (stesso fumetto bianco con codina), ma ancorata al piedistallo invece che a un
   avatar, e pensata per contenuto multi-riga invece di un messaggio breve. */
.hall-pedestal-bubble {
  position: absolute;
  bottom: 100%;
  left: 50%;
  transform: translateX(-50%);
  margin-bottom: 8px;
  background: linear-gradient(165deg, #2c1d10 0%, #1a1108 100%);
  border: 1px solid #caa25c;
  color: #f1e2c0;
  padding: 10px 14px;
  border-radius: 8px;
  box-shadow: 0 8px 20px rgba(0, 0, 0, 0.55), inset 0 0 14px rgba(240, 200, 105, 0.08);
  white-space: normal;
  width: max-content;
  max-width: clamp(150px, 19cqw, 250px);
  text-align: center;
  animation: lobby-bubble-in 0.2s ease-out;
  z-index: 5;
}
.hall-pedestal-bubble::before {
  /* Sottile bordo dorato interno, per dare un accenno di "targa incorniciata" invece di
     un semplice riquadro piatto — coerente con le cornici dorate dei piedistalli. */
  content: '';
  position: absolute;
  inset: 3px;
  border: 1px solid rgba(240, 200, 105, 0.25);
  border-radius: 5px;
  pointer-events: none;
}
.hall-pedestal-bubble::after {
  content: '';
  position: absolute;
  top: 100%;
  left: 50%;
  transform: translateX(-50%);
  border: 6px solid transparent;
  border-top-color: #241708;
}
.hall-pedestal-bubble.hall-pedestal-bubble-out { animation: lobby-bubble-out 0.2s ease-in forwards; }
.hall-pedestal-bubble-name {
  font-size: clamp(0.8rem, 1.5cqw, 1.4rem);
  font-weight: 700;
  letter-spacing: 0.03em;
  color: #f0c869;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);
  margin: 0 0 6px;
  padding-bottom: 5px;
  border-bottom: 1px solid rgba(240, 200, 105, 0.3);
}
.hall-pedestal-bubble-hint {
  font-size: clamp(0.68rem, 1.2cqw, 1.1rem);
  color: #b9a37c;
  font-style: italic;
  margin: 0;
}
.hall-pedestal-bubble-trophy {
  display: flex;
  align-items: center;
  gap: 8px;
  text-align: left;
  padding: 5px 0;
}
.hall-pedestal-bubble-trophy + .hall-pedestal-bubble-trophy {
  border-top: 1px solid rgba(240, 200, 105, 0.15);
}
.hall-pedestal-bubble-icon {
  width: clamp(18px, 2.6cqw, 28px);
  height: clamp(18px, 2.6cqw, 28px);
  flex-shrink: 0;
  border-radius: 4px;
  border: 1px solid rgba(240, 200, 105, 0.4);
}
.hall-pedestal-bubble-trophy-text { min-width: 0; }
.hall-pedestal-bubble-trophy-name {
  font-size: clamp(0.7rem, 1.25cqw, 1.15rem);
  font-weight: 600;
  color: #f1e2c0;
  margin: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.hall-pedestal-bubble-trophy-meta {
  font-size: clamp(0.62rem, 1.05cqw, 0.95rem);
  color: #b9a37c;
  margin: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.lobby-countdown {
  position: absolute;
  top: 10px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 20;
  background: rgba(20,16,28,0.78);
  backdrop-filter: blur(4px);
  border: 1px solid rgba(255,255,255,0.15);
  border-radius: 999px;
  padding: 6px 16px;
  font-size: 0.72rem;
  color: #fff;
  white-space: nowrap;
  text-align: center;
  pointer-events: none;
}
.lobby-countdown strong { color: var(--accent2); font-weight: 700; }

/* ==========================================================================
   FOGLIO DELLE AZIONI
   --------------------------------------------------------------------------
   Prima emoji e gesti erano due righe di bottoni SOTTO la scena: sempre presenti
   anche quando non servivano, e su un telefono in verticale sottraevano un buon
   terzo dell'altezza alla stanza. Ora vivono sovrapposti dentro la scena, in un
   pannello che si apre e si richiude.

   Niente numeri fissi in questa sezione: i gesti vanno a capo da soli, le emoji
   stanno in una griglia che riempie la larghezza disponibile, e se un giorno le
   azioni diventeranno il triplo il pannello si limiterà a scorrere. Aggiungere un
   gesto lato server non richiede di toccare una riga di CSS.
   ========================================================================== */

.lobby-actions-fab {
  position: absolute;
  right: 12px;
  bottom: 12px;
  z-index: 3000;
  width: clamp(34px, 3.4cqw, 52px);
  aspect-ratio: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, 0.22);
  background: rgba(14, 10, 18, 0.62);
  color: var(--accent2);
  cursor: pointer;
  transition: background 0.15s, transform 0.15s, opacity 0.2s;
}
.lobby-actions-fab:hover { background: rgba(14, 10, 18, 0.85); transform: scale(1.06); }
.lobby-actions-fab svg { width: 62%; height: 62%; }

.lobby-actions-sheet {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 3001;
  max-height: 64%;
  overflow-y: auto;
  padding: 22px 14px 14px;
  display: flex;
  flex-direction: column;
  gap: 12px;
  background: rgba(14, 10, 18, 0.55);
  /* Il bordo superiore sfuma invece di essere tagliato da una riga netta: un
     pannello sfumato sembra appoggiato sulla stanza, uno con il bordo dritto
     sembra una seconda finestra incollata sopra. */
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 22px);
  mask-image: linear-gradient(to bottom, transparent 0, #000 22px);
  transform: translateY(100%);
  visibility: hidden; /* niente attributo hidden: così il pannello può scivolare
                         invece di comparire di colpo, e resta fuori dal giro dei
                         tab quando è chiuso */
  transition: transform 0.22s ease, visibility 0.22s;
}
.lobby-actions-sheet.open {
  transform: translateY(0);
  visibility: visible;
}

/* La sfocatura dello sfondo è ciò che rende leggibile il pannello: con la sola
   trasparenza, lanterne e neon sbucano da sotto e mangiano le icone. Sta dietro a
   @supports perché dove manca è meglio un vetro un po' più opaco che un effetto a
   metà — vedi la stessa scelta fatta per lo spegnimento dei neon. */
@supports ((backdrop-filter: blur(4px)) or (-webkit-backdrop-filter: blur(4px))) {
  .lobby-actions-sheet {
    -webkit-backdrop-filter: blur(12px) saturate(0.85);
    backdrop-filter: blur(12px) saturate(0.85);
  }
}
@supports not ((backdrop-filter: blur(4px)) or (-webkit-backdrop-filter: blur(4px))) {
  .lobby-actions-sheet { background: rgba(14, 10, 18, 0.88); }
}

/* Mentre il pannello è aperto l'atmosfera si ferma. Un backdrop-filter su un'area
   grande deve ricampionare a ogni fotogramma tutto ciò che ha sotto, e sotto ci
   sono una quarantina di aloni in mix-blend-mode più petali e pulviscolo: è la
   combinazione più cara che il compositore possa incontrare. Metà di quella roba
   è comunque coperta dal vetro, quindi nessuno si accorge che è in pausa. */
.lobby-scene.lobby-actions-open .lobby-ambience *,
.lobby-scene.lobby-actions-open .lobby-ambience-front * {
  animation-play-state: paused;
}

.lobby-actions-section {
  display: flex;
  flex-direction: column;
  gap: 7px;
}

/* Modo "solo scrittura": appena il cursore entra nel campo, gesti ed emoji si
   ritirano e del foglio resta una striscia sottile. Risolve due cose insieme —
   sul telefono la tastiera deve scavalcare pochi pixel invece di mezzo pannello,
   e soprattutto il fumetto del messaggio appena mandato resta visibile sopra
   l'avatar invece di finire dietro al vetro. */
.lobby-actions-sheet.typing .lobby-actions-section {
  display: none;
}
.lobby-actions-sheet .lobby-chat-form {
  margin-top: 2px;
}
/* Sul vetro scuro il campo deve staccarsi: i colori di sistema del modulo sono
   pensati per il fondo della finestra, non per una superficie semitrasparente. */
.lobby-actions-sheet .lobby-chat-input {
  background: rgba(0, 0, 0, 0.45);
  border-color: rgba(255, 255, 255, 0.2);
}
.lobby-actions-sheet .lobby-chat-input:focus {
  border-color: var(--accent2);
}
.lobby-actions-title {
  margin: 0;
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.45);
}

/* I gesti hanno l'etichetta accanto all'icona: sono pochi e con nomi non ovvi, e
   un domani ce ne saranno altri di cui nessuno indovinerebbe l'icona. Vanno a capo
   da soli man mano che crescono. */
.lobby-gesture-bar {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.lobby-gesture-btn {
  display: flex;
  align-items: center;
  gap: 6px;
  min-height: 34px;
  padding: 5px 10px 5px 6px;
  border-radius: var(--radius);
  border: 1px solid rgba(255, 255, 255, 0.16);
  background: rgba(255, 255, 255, 0.09);
  color: #fff;
  font-size: 0.78rem;
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s;
}
.lobby-gesture-btn:hover { border-color: var(--accent); background: rgba(255, 79, 163, 0.3); }
.lobby-gesture-btn:disabled {
  opacity: 0.35;
  cursor: not-allowed;
}
.lobby-gesture-btn:disabled:hover { border-color: rgba(255, 255, 255, 0.16); background: rgba(255, 255, 255, 0.09); }
.lobby-gesture-btn img {
  width: 24px;
  height: 24px;
  object-fit: contain;
  display: block;
  flex-shrink: 0;
  /* la sigaretta nell'immagine è in diagonale: ruotata resta leggibile anche in un
     riquadro piccolo invece di occupare solo l'angolo */
  transform: rotate(-20deg) scale(1.15);
}
/* Ripiego per un gesto aggiunto lato server prima che esista la sua icona: resta
   comunque cliccabile e riconoscibile dall'etichetta, invece di comparire come un
   bottone vuoto. */
.lobby-gesture-glyph {
  width: 24px;
  text-align: center;
  flex-shrink: 0;
  color: var(--accent2);
}

/* auto-fill invece di un numero di colonne: la griglia si adatta alla larghezza
   della scena, e con più emoji aggiunge righe da sola. */
.lobby-emoji-bar {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(40px, 1fr));
  gap: 6px;
}
.lobby-emoji-btn {
  font-size: 1.15rem;
  line-height: 1;
  padding: 7px 0;
  border-radius: var(--radius);
  border: 1px solid rgba(255, 255, 255, 0.14);
  background: rgba(255, 255, 255, 0.08);
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s;
}
.lobby-emoji-btn:hover { border-color: var(--accent); background: rgba(255, 79, 163, 0.3); }

/* ---------- Gesto "sigaretta": sigaretta + fumo animato sovrapposti all'avatar ---------- */
/* .lobby-gesture-layer è un contenitore vuoto finché nessun gesto è in corso — creato una
   volta per ogni avatar (vedi createLobbyAvatarToken) e riempito/svuotato da
   spawnLobbyGesture(). È un livello indipendente da .lobby-teleport-fx e .avatar-wrap,
   così non entra in conflitto con le loro animazioni/transform. */
.lobby-gesture-layer {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 6;
  transition: transform 0.6s ease;
  transform-origin: center bottom; /* stesso ancoraggio di .avatar-wrap, per scalare in sync con l'avatar */
}
.lobby-gesture-cigarette {
  position: absolute;
  left: 9%;
  top: 55%;
  width: 60%;
  aspect-ratio: 1.8279;
  background-image: url('gestures/cigarette.png');
  background-size: contain;
  background-repeat: no-repeat;
  background-position: center;
  transform-origin: 50% 50%;
  transform: translate(-50%, -50%) rotate(0deg) scale(1.00);
  opacity: 0; /* resta 0 a riposo: l'apparizione/sparizione la fanno .active/.fading sotto */
  z-index: 2;
}
.lobby-gesture-cigarette.active { animation: lobby-gesture-cig-in 0.35s ease-out forwards; }
.lobby-gesture-cigarette.fading { animation: lobby-gesture-cig-out 0.4s ease-in forwards; }
@keyframes lobby-gesture-cig-in {
  from { opacity: 0; transform: translate(-50%, -50%) rotate(0deg) scale(0.5); }
  to   { opacity: 1; transform: translate(-50%, -50%) rotate(0deg) scale(1.00); }
}
@keyframes lobby-gesture-cig-out {
  from { opacity: 1; transform: translate(-50%, -50%) rotate(0deg) scale(1.00); }
  to   { opacity: 0; transform: translate(-50%, -50%) rotate(0deg) scale(0.6); }
}

.lobby-gesture-erba {
  position: absolute;
  left: -6%;
  top: 46%;
  width: 37%;
  aspect-ratio: 0.7408;
  background-image: url('gestures/erba.png');
  background-repeat: no-repeat;
  background-size: contain;
  background-position: center;
  transform-origin: 50% 50%;
  transform: translate(-50%, -50%) rotate(-32deg) scale(1.25);
  opacity: 0; /* resta 0 a riposo: l'apparizione/sparizione la fanno .active/.fading sotto */
  z-index: 2;
}
.lobby-gesture-erba.active { animation: lobby-gesture-erba-in 0.35s ease-out forwards; }
.lobby-gesture-erba.fading { animation: lobby-gesture-erba-out 0.4s ease-in forwards; }
@keyframes lobby-gesture-erba-in {
  from { opacity: 0; transform: translate(-50%, -50%) rotate(-32deg) scale(0.6); }
  to   { opacity: 1; transform: translate(-50%, -50%) rotate(-32deg) scale(1.25); }
}
@keyframes lobby-gesture-erba-out {
  from { opacity: 1; transform: translate(-50%, -50%) rotate(-32deg) scale(1.25); }
  to   { opacity: 0; transform: translate(-50%, -50%) rotate(-32deg) scale(0.75); }
}

/* ---------- Fuoco d'artificio: proiettile mirato, attraversa l'intera scena ---------- */
/* A differenza dei gesti sopra, questi elementi sono figli diretti di #lobby-avatars
   (stesso sistema di coordinate percentuali dei token), non del .lobby-gesture-layer di
   un singolo avatar: devono poter viaggiare da un token all'altro. */
.lobby-firework-rocket {
  position: absolute;
  /* 60% larghezza token x scale 0.38 (valori tarati sull'avatar) = 22.8% della larghezza
     avatar reale — stessa formula di .lobby-avatar-img, così scala insieme a lui invece
     di restare fisso in px indipendentemente da quanto è grande la scena. */
  width: calc(clamp(56px, 6.54cqw, 120px) * 0.228);
  aspect-ratio: 0.2958; /* proporzioni reali di gestures/fw.png (210x710) */
  background-image: url('gestures/fw.png');
  background-repeat: no-repeat;
  background-size: contain;
  background-position: center;
  pointer-events: none;
  z-index: 50;
  transition-property: left, top, transform;
  transition-timing-function: linear; /* la durata viene impostata via JS in base alla distanza */
}
/* Lanciato con la sinistra: punta verso sinistra durante il volo. */
.lobby-firework-rocket-s { transform: translate(-50%, -50%) rotate(-79deg); }
/* Lanciato con la destra: stessa inclinazione specchiata, punta verso destra. */
.lobby-firework-rocket-d { transform: translate(-50%, -50%) rotate(79deg) scaleX(-1); }

.lobby-firework-spark {
  position: absolute;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: radial-gradient(circle, #fff6c8 0%, #ffb347 60%, transparent 100%);
  pointer-events: none;
  z-index: 49;
  animation: lobby-firework-spark-fade 0.4s ease-out forwards;
}
@keyframes lobby-firework-spark-fade {
  from { opacity: 1; transform: translate(-50%, -50%) scale(var(--depth-scale, 1)); }
  to   { opacity: 0; transform: translate(-50%, -50%) scale(calc(var(--depth-scale, 1) * 0.3)); }
}

.lobby-firework-smoke-puff {
  position: absolute;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(220, 220, 225, 0.55) 0%, rgba(200, 200, 205, 0.25) 55%, transparent 80%);
  pointer-events: none;
  z-index: 48;
  animation: lobby-firework-smoke-fade 0.9s ease-out forwards;
}
@keyframes lobby-firework-smoke-fade {
  from { opacity: 1; transform: translate(-50%, -50%) scale(calc(var(--depth-scale, 1) * 0.6)); }
  to   { opacity: 0; transform: translate(-50%, -50%) scale(calc(var(--depth-scale, 1) * 2.2)); }
}

/* Bagliore giallo dietro allo scoppio: stesse proporzioni relative al token dello scoppio
   stesso (non più in px fissi), così scala insieme a lui quando l'avatar è più lontano
   nella scena. Parte insieme alla prima sequenza dei fotogrammi e si dissolve con essa. */
.lobby-gesture-scoppio-glow {
  position: absolute;
  left: 47%;
  top: 43%;
  width: 95%;
  aspect-ratio: 1;
  border-radius: 50%;
  transform: translate(-50%, -50%);
  background: radial-gradient(circle, rgba(255, 221, 120, 0.9) 0%, rgba(255, 180, 60, 0.5) 40%, transparent 75%);
  opacity: 0;
  pointer-events: none;
  z-index: 1;
}
.lobby-gesture-scoppio-glow.active { animation: lobby-gesture-scoppio-glow-fade 0.34s ease-out forwards; }
@keyframes lobby-gesture-scoppio-glow-fade {
  0%   { opacity: 0; transform: translate(-50%, -50%) scale(0.3); }
  15%  { opacity: 1; transform: translate(-50%, -50%) scale(1); }
  100% { opacity: 0; transform: translate(-50%, -50%) scale(1.3); }
}

/* Impostazioni esatte tarate col gesture-tuner: NON toccare le percentuali/keyframes
   sotto senza ripassare dal tool, sono state allineate a mano fotogramma per fotogramma. */
.lobby-gesture-scoppio {
  position: absolute;
  left: 47%;
  top: 43%;
  width: 63%;
  aspect-ratio: 0.8763;
  background-image: url('gestures/scoppio.png');
  background-repeat: no-repeat;
  background-size: 800% 100%;
  transform-origin: 50% 50%;
  transform: translate(-50%, -50%) rotate(0deg) scale(2.19);
  clip-path: inset(2% 2%); /* nasconde il filo di fotogramma adiacente che sborda per arrotondamento sub-pixel */
  opacity: 1;
  z-index: 2;
}
.lobby-gesture-scoppio.active {
  animation: lobby-gesture-scoppio-frames 0.3s linear infinite;
}
@keyframes lobby-gesture-scoppio-frames {
  0.000% { background-position: -3.500% 0.000%; animation-timing-function: steps(1); }
  14.286% { background-position: 9.786% 0.000%; animation-timing-function: steps(1); }
  28.571% { background-position: 23.571% 0.000%; animation-timing-function: steps(1); }
  42.857% { background-position: 41.857% 0.000%; animation-timing-function: steps(1); }
  57.143% { background-position: 57.143% 0.000%; animation-timing-function: steps(1); }
  71.429% { background-position: 71.429% 0.000%; animation-timing-function: steps(1); }
  85.714% { background-position: 85.714% 0.000%; animation-timing-function: steps(1); }
  100.000% { background-position: 100.000% 0.000%; }
}

/* Contenitore "fantasma": usato SOLO quando il razzo non colpisce nessuno (si spegne nel
   vuoto). Riproduce le stesse proporzioni di un .lobby-avatar-token (vedi .lobby-avatar-img,
   clamp(56px,6.54cqw,120px)) così .lobby-gesture-scoppio — pensato per stare in un box di
   quel tipo — si vede alla stessa dimensione di quando colpisce un avatar vero. */
.lobby-firework-ghost {
  position: absolute;
  transform: translate(-50%, -100%);
  display: flex;
  flex-direction: column;
  align-items: center;
  pointer-events: none;
  z-index: 50;
}
.lobby-firework-ghost-spacer {
  width: clamp(56px, 6.54cqw, 120px);
  height: clamp(56px, 6.54cqw, 120px);
  visibility: hidden;
}

/* ---------- Stordimento: stelline rotanti sopra la testa del bersaglio colpito ---------- */
/* Layer separato da .lobby-gesture-layer (quello dei gesti "personali" come sigaretta ed
   erba): sono cose concettualmente diverse — uno stato subito, non un'azione scelta —
   e tenerli distinti evita che si accavallino o si cancellino a vicenda per errore. */
.lobby-status-layer {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 7;
  transition: transform 0.6s ease;
  transform-origin: center bottom; /* stesso ancoraggio di .avatar-wrap, per scalare in sync con l'avatar */
}
/* NOTA: non abbiamo ancora un asset dedicato per le stelline — placeholder con emoji in
   attesa dell'immagine definitiva. Quando arriva, basta sostituire il contenuto del
   ::before con un background-image (eventualmente a sprite, se vuoi farle "sfarfallare"). */
.lobby-stun-stars {
  position: absolute;
  left: 50%;
  top: -4%;
  width: 60%;
  aspect-ratio: 1;
  transform: translate(-50%, -50%);
  opacity: 0;
}
.lobby-stun-stars.active {
  opacity: 1;
  animation: lobby-stun-spin 0.9s linear infinite;
}
.lobby-stun-stars::before {
  content: '✨';
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.4rem;
  filter: drop-shadow(0 0 2px rgba(255, 220, 120, 0.9));
}
@keyframes lobby-stun-spin {
  from { transform: translate(-50%, -50%) rotate(0deg); }
  to   { transform: translate(-50%, -50%) rotate(360deg); }
}
.lobby-gesture-smoke {
  position: absolute;
  left: -19%;
  top: 23%;
  width: 60%;
  aspect-ratio: 0.6006; /* dimensioni di UN fotogramma dello sprite del fumo */
  transform: translate(-50%, -50%);
  background-image: url('gestures/smoke-sprite.png');
  background-repeat: no-repeat;
  /* striscia di 10 fotogrammi affiancati: allargando lo sfondo a 10 volte la larghezza
     del riquadro si vede sempre un solo fotogramma alla volta (vedi i keyframes sotto) */
  background-size: 1000% 100%;
  opacity: 0;
  z-index: 1;
}
.lobby-gesture-smoke.active {
  animation:
    lobby-gesture-smoke-puff 1.7s steps(9) infinite,
    lobby-gesture-smoke-fade-in 0.4s ease-out forwards;
}
.lobby-gesture-smoke.fading { animation: lobby-gesture-smoke-fade-out 0.4s ease-in forwards; }
@keyframes lobby-gesture-smoke-puff {
  /* 0% -> 100% di background-position, su uno sfondo largo 10 volte il riquadro, sposta
     l'immagine di esattamente 9 "larghezze di riquadro": un fotogramma per ogni step,
     dal primo all'ultimo, senza calcoli in pixel legati a una dimensione fissa. */
  from { background-position-x: 0%; }
  to   { background-position-x: 100%; }
}
@keyframes lobby-gesture-smoke-fade-in {
  from { opacity: 0; transform: translate(-50%, -50%) scale(0.9); }
  to   { opacity: 0.85; transform: translate(-50%, -50%) scale(1); }
}
@keyframes lobby-gesture-smoke-fade-out {
  from { opacity: 0.85; }
  to   { opacity: 0; }
}

/* Particelle delle reazioni con effetto (es. 🎉): nascono nel punto esatto di chi ha
   reagito e "esplodono" verso l'esterno dissolvendosi, poi si autodistruggono dal DOM. */
.lobby-particle {
  position: absolute;
  pointer-events: none;
  font-size: 1.1rem;
  line-height: 1;
  animation: lobby-particle-fly 0.9s ease-out forwards;
  z-index: 999;
  --dx: 0px;
  --dy: 0px;
}
@keyframes lobby-particle-fly {
  0% { transform: translate(-50%, -50%) scale(1); opacity: 1; }
  100% { transform: translate(calc(-50% + var(--dx)), calc(-50% + var(--dy))) scale(0.6); opacity: 0; }
}

.lobby-chat-form { display: flex; gap: 8px; }
.lobby-chat-input {
  flex: 1;
  min-width: 0;
  padding: 9px 12px;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  background: var(--bg);
  color: var(--text);
  font-size: 0.85rem;
  font-family: inherit;
}
.lobby-chat-input:focus { outline: none; border-color: var(--accent2); }
.lobby-chat-send { padding: 9px 18px; font-size: 0.8rem; flex-shrink: 0; }

@media (max-width: 600px) {
  .lobby-modal-box { width: 96vw; padding: 12px; }
  .lobby-countdown { font-size: 0.62rem; padding: 5px 12px; }
  .lobby-emoji-btn { padding: 5px 7px; font-size: 1.05rem; }
}

/* ---------- L'Oracolo ---------- */

.oracle-modal-box {
  max-width: 460px;
  width: 92vw;
  height: 78vh; /* tolto il fallback dvh: risultava calcolato in modo inconsistente su
    alcuni browser/webview, causando lo stesso problema di scroll visto nella libreria */
  max-height: 720px; /* su schermi molto alti (desktop, tablet verticali) non deve diventare
    esageratamente lungo */
  min-height: 420px; /* su schermi molto bassi (orizzontale su telefono) resta comunque
    utilizzabile, non si schiaccia */
  display: flex;
  flex-direction: column;
}

/* Ritratto composito: base (l'Oracolo con la sfera "vuota" bianca) + copertina del gioco
   che l'utente sta giocando ora (ritagliata a cerchio, esattamente dove sta la sfera) +
   sfera di vetro trasparente sopra a tutto, per l'effetto "vede dentro il tuo gioco".
   Le percentuali sotto sono calcolate sulle coordinate reali del cerchio nelle due
   immagini originali (centro 49.5%/64.2%, diametro 22.6% del lato) — se in futuro si
   sostituiscono le immagini con altre versioni, vanno ricalcolate insieme, non a occhio. */
.oracle-portrait {
  position: relative;
  width: 100%;
  max-width: 260px;
  aspect-ratio: 1 / 1;
  margin: 0 auto 18px;
  flex-shrink: 0;
}

/* Separatore decorativo tra il ritratto e la chat: una linea sottile con un piccolo
   ornamento al centro, invece di un semplice spazio vuoto — coerente con lo stile
   mistico del personaggio. */
.oracle-divider {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0 4px 14px;
  flex-shrink: 0;
  color: rgba(180, 120, 255, 0.55);
  font-size: 0.7rem;
}
.oracle-divider::before,
.oracle-divider::after {
  content: '';
  flex: 1;
  height: 1px;
  background: linear-gradient(90deg, transparent, rgba(180, 120, 255, 0.35), transparent);
}
.oracle-portrait-fade {
  position: absolute;
  inset: 0;
  border-radius: 20px;
  overflow: hidden;
  /* Sfuma verso i bordi (in tutte e tre le immagini insieme, così restano allineate):
     il centro resta pieno, gli angoli/lati svaniscono nello sfondo della pagina invece
     di avere un taglio netto rettangolare. Solo le immagini stanno qui dentro — le luci
     (sotto) restano fuori da questo contenitore, altrimenti la stessa sfumatura le
     spegnerebbe proprio vicino ai bordi, dove servono di più (sfera e candele).
     "circle" invece di "ellipse": resta simmetrica in pixel reali anche se il
     contenitore non fosse perfettamente quadrato a runtime. */
  -webkit-mask-image: radial-gradient(circle at center, #000 46%, transparent 72%);
  mask-image: radial-gradient(circle at center, #000 46%, transparent 72%);
}
.oracle-portrait-base,
.oracle-portrait-glass {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  pointer-events: none;
}
.oracle-portrait-base { z-index: 1; }
.oracle-portrait-glass { z-index: 3; }

/* Copertina del gioco: più piccola del vuoto della sfera (lascia un margine di alone
   viola visibile tutto intorno, invece di riempirlo bordo a bordo) e con due effetti
   che simulano la curvatura del vetro invece di un adesivo piatto sopra l'immagine:
   1) un'ombra interna che scurisce i bordi (vignettatura, tipica di una superficie
      sferica ripresa di fronte); 2) un riflesso di luce in alto a sinistra, dove
      cadrebbe la luce delle candele nell'illustrazione originale. */
.oracle-portrait-cover-wrap {
  position: absolute;
  z-index: 2;
  left: 41.2%;
  top: 55.9%;
  width: 17%;
  height: 17%;
  border-radius: 50%;
  overflow: hidden;
  box-shadow:
    inset 0 0 10px 3px rgba(20, 5, 30, 0.75),
    inset 4px -4px 10px rgba(0, 0, 0, 0.45);
}
.oracle-portrait-cover-wrap[hidden] { display: none; }

/* Effetto di comparsa: la copertina "sboccia" con un piccolo rimbalzo invece di apparire
   di colpo, un raggio circolare pulsa verso l'esterno, e un bagliore ampio investe tutto
   il ritratto — quest'ultimo è il pezzo più importante: si nota anche se l'attenzione in
   quel momento è già sul testo che inizia a comparire, non serve guardare esattamente la
   sfera. Tutto scatta SUBITO quando i dati arrivano dal server (nessuna pausa aggiunta). */
.oracle-portrait-cover-wrap.is-revealing {
  animation: oracle-cover-reveal 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);
}
@keyframes oracle-cover-reveal {
  0% { opacity: 0; transform: scale(0.6); }
  60% { opacity: 1; transform: scale(1.12); }
  100% { opacity: 1; transform: scale(1); }
}

.oracle-portrait-reveal-ring {
  position: absolute;
  left: 49.5%;
  top: 64.2%;
  width: 17%;
  height: 17%;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  border: 3px solid rgba(200, 150, 255, 0.95);
  box-shadow: 0 0 24px 4px rgba(180, 120, 255, 0.75);
  pointer-events: none;
  z-index: 5;
  opacity: 0;
}
.oracle-portrait-reveal-ring.is-active {
  animation: oracle-reveal-ring 1.3s ease-out;
}
@keyframes oracle-reveal-ring {
  0% { transform: translate(-50%, -50%) scale(0.6); opacity: 1; }
  100% { transform: translate(-50%, -50%) scale(3.2); opacity: 0; }
}

.oracle-portrait-flash {
  position: absolute;
  inset: -8%;
  border-radius: 24px;
  background: radial-gradient(circle at 49.5% 64.2%, rgba(180, 120, 255, 0.45), transparent 68%);
  pointer-events: none;
  z-index: 4;
  opacity: 0;
}
.oracle-portrait-flash.is-active {
  animation: oracle-portrait-flash 1s ease-out;
}
@keyframes oracle-portrait-flash {
  0% { opacity: 0; }
  25% { opacity: 1; }
  100% { opacity: 0; }
}
.oracle-portrait-cover-wrap::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: radial-gradient(circle at 30% 26%, rgba(255,255,255,0.55) 0%, rgba(255,255,255,0.12) 28%, rgba(255,255,255,0) 55%);
  mix-blend-mode: screen;
  pointer-events: none;
}
.oracle-portrait-cover {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Luci pulsanti sopra al ritratto: una viola dalla sfera, due calde dalle fiamme delle
   candele (posizioni misurate sui pixel reali dell'immagine, non a occhio). Leggerissime
   apposta — devono dare vita all'illustrazione, non diventare il centro dell'attenzione. */
.oracle-glow {
  position: absolute;
  border-radius: 50%;
  pointer-events: none;
  mix-blend-mode: screen;
  transform: translate(-50%, -50%);
  z-index: 4;
}
.oracle-glow-ball {
  left: 49.5%;
  top: 64.2%;
  width: 26%;
  height: 26%;
  background: radial-gradient(circle, rgba(180, 120, 255, 0.62) 0%, rgba(180, 120, 255, 0.22) 42%, transparent 72%);
  animation: oracle-pulse-purple 3.2s ease-in-out infinite;
}
.oracle-glow-candle {
  width: 13%;
  height: 13%;
  background: radial-gradient(circle, rgba(255, 180, 90, 0.62) 0%, rgba(255, 140, 50, 0.22) 45%, transparent 75%);
  animation: oracle-pulse-flame 2.4s ease-in-out infinite;
}
.oracle-glow-candle-left { left: 10.1%; top: 32.3%; animation-delay: 0.4s; }
.oracle-glow-candle-right { left: 90.7%; top: 50.3%; animation-delay: 1.1s; }

@keyframes oracle-pulse-purple {
  0%, 100% { opacity: 0.5; transform: translate(-50%, -50%) scale(0.92); }
  50% { opacity: 0.88; transform: translate(-50%, -50%) scale(1.08); }
}
@keyframes oracle-pulse-flame {
  0%, 100% { opacity: 0.45; transform: translate(-50%, -50%) scale(0.85); }
  50% { opacity: 0.82; transform: translate(-50%, -50%) scale(1.1); }
}

.oracle-messages {
  flex: 1;
  height: 0;
  min-height: 0;
  max-height: 50vh;
  overflow-y: scroll;
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 4px 2px 10px;
  margin-bottom: 8px;
}
.oracle-messages::-webkit-scrollbar-thumb { background: var(--accent2); }
.oracle-messages { scrollbar-color: var(--accent2) transparent; }

.oracle-msg {
  max-width: 82%;
  padding: 10px 14px;
  border-radius: 15px;
  font-size: 0.85rem;
  line-height: 1.45;
  white-space: pre-wrap;
  word-break: break-word;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.18);
  animation: oracle-msg-in 0.25s ease-out;
}

@keyframes oracle-msg-in {
  from { opacity: 0; transform: translateY(6px); }
  to { opacity: 1; transform: translateY(0); }
}

.oracle-msg-user {
  align-self: flex-end;
  background: var(--accent);
  color: #1a0a14;
  border-right: 3px solid var(--accent-dim); /* stesso principio dell'accento a sinistra
    sulla bolla dell'Oracolo, ma con una tonalità della stessa famiglia rosa già in uso
    per questa bolla, non un colore nuovo */
  border-bottom-right-radius: 4px; /* la "punta" del fumetto, verso chi scrive */
}

.oracle-msg-oracle {
  align-self: flex-start;
  background: var(--bg);
  border: 1px solid var(--border);
  border-left: 3px solid rgba(180, 120, 255, 0.55); /* stesso viola della sfera nel ritratto */
  color: var(--text);
  border-bottom-left-radius: 4px;
}

/* Mentre la bolla sta ancora "scrivendo" un tocco/clic in qualunque punto della chat la
   completa subito (vedi typewriteIntoBubble in app.js) — il cursore a manina è l'unico
   indizio visivo di questo, dato che l'area cliccabile è l'intero contenitore, non solo la
   bolla stessa. */
.oracle-messages:has(.is-typing) { cursor: pointer; }

/* Indicatore "sta scrivendo": tre puntini che pulsano in sequenza, al posto del "..."
   statico di prima — mostrato mentre si aspetta la risposta, poi sostituito dal testo
   vero che appare gradualmente (vedi typewriteIntoBubble in app.js). */
.oracle-typing {
  display: inline-flex;
  gap: 4px;
  align-items: center;
  padding: 2px 0;
}
.oracle-typing span {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--text-dim);
  animation: oracle-typing-dot 1.1s infinite ease-in-out;
}
.oracle-typing span:nth-child(2) { animation-delay: 0.15s; }
.oracle-typing span:nth-child(3) { animation-delay: 0.3s; }
@keyframes oracle-typing-dot {
  0%, 60%, 100% { opacity: 0.25; transform: translateY(0); }
  30% { opacity: 1; transform: translateY(-3px); }
}

@media (max-width: 600px) {
  .oracle-modal-box { width: 96vw; height: 88vh; min-height: 380px; padding: 12px; }
}

/* ---------- La Biblioteca dell'Oracolo ---------- */

.library-modal-box {
  max-width: 560px;
  width: 92vw;
  height: 78vh; /* tolto il fallback dvh: su alcuni browser/webview (incluso quello di
    Telegram) sembra calcolato in modo inconsistente, ed era il sospetto più concreto
    rimasto per il pannello che non si riduceva mai davvero all'altezza dichiarata */
  max-height: 720px;
  min-height: 420px;
  display: flex;
  flex-direction: column;
}

.library-search-input { flex: none; margin-bottom: 12px; }

.library-modal-box { overflow-y: hidden; } /* lo scroll deve stare solo in .library-content,
  non anche sul box esterno (ereditato da .collection-modal-box) — altrimenti i due
  scroll vanno in conflitto e il contenuto finisce per far crescere tutto il box invece
  di scorrere al suo interno. */

.library-content {
  max-height: 62vh; /* alzato da 45vh: era il vero motivo dello spazio vuoto sotto — un
    limite troppo basso rispetto allo spazio realmente disponibile nel pannello (che è alto
    78vh). Resta un limite fisso e diretto (non "riempi lo spazio rimanente", che aveva
    dato altri problemi) — semplicemente calibrato più vicino allo spazio vero. */
  min-height: 0;
  overflow-y: scroll; /* "scroll" invece di "auto": la barra è sempre riservata quando il
    contenuto eccede, invece di lasciare al browser la decisione automatica */
  display: flex;
  flex-direction: column;
  gap: 16px;
  padding-right: 2px;
}
/* La scrollbar del sito è globalmente scura (var(--border), #322a52) e su questo pannello
   si confonde con lo sfondo — qui la rendiamo più chiara e visibile, solo in questa zona. */
.library-content::-webkit-scrollbar-thumb { background: var(--accent2); }
.library-content { scrollbar-color: var(--accent2) transparent; } /* Firefox */

.library-game-group {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
  flex-shrink: 0; /* senza questo, quando il contenuto totale eccede lo spazio disponibile
    i gruppi flessibili tendono a "stringersi" per cercare di stare tutti nello spazio
    invece di restare della loro dimensione naturale e lasciare che sia il contenitore a
    scorrere — è quello che causava i gruppi chiusi schiacciati/illeggibili durante lo scroll. */
}

.library-game-head {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 12px;
  background: var(--bg-panel-2);
  font-size: 0.85rem;
  font-weight: 700;
  cursor: pointer;
  user-select: none;
  flex-shrink: 0;
}
.library-game-head span.library-game-title { flex: 1; }
.library-game-count {
  font-weight: 400;
  color: var(--text-dim);
  font-size: 0.72rem;
}
.library-game-toggle {
  font-family: var(--font-mono);
  color: var(--accent2);
  font-size: 0.9rem;
  flex-shrink: 0;
}
.library-entries[hidden] { display: none; }
.library-game-head img {
  width: 40px;
  height: 19px;
  object-fit: cover;
  border-radius: 4px;
  flex-shrink: 0;
  background: var(--bg);
  cursor: pointer;
}

.library-entries {
  display: flex;
  flex-direction: column;
}

.library-entry {
  padding: 10px 12px;
  border-top: 1px solid var(--border);
}
.library-question {
  margin: 0 0 4px;
  font-size: 0.82rem;
  font-weight: 700;
  color: var(--accent2);
}
.library-answer {
  margin: 0 0 6px;
  font-size: 0.8rem;
  line-height: 1.45;
  color: var(--text);
  white-space: pre-wrap;
}
.library-entry-meta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 0.68rem;
  color: var(--text-dim);
}

@media (max-width: 600px) {
  .library-modal-box { width: 96vw; height: 88vh; min-height: 380px; padding: 12px; }
}

/* ---------- Debug Oracolo (pannello admin) ---------- */

.admin-oracle-suspend-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-top: 14px;
  padding-top: 14px;
  border-top: 1px solid var(--border);
}
.admin-oracle-suspend-row.is-suspended #admin-oracle-suspend-label,
#admin-oracle-suspend-label.is-suspended {
  color: #ff6b6b;
}

.admin-oracle-debug { margin-top: 14px; }
.admin-oracle-debug-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 6px;
}
.admin-oracle-debug-content {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  color: var(--text-dim);
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 10px 12px;
  white-space: pre-wrap;
  word-break: break-word;
  margin: 0;
}

.admin-oracle-log { margin-top: 14px; }
.admin-oracle-log-content {
  max-height: 340px;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.admin-oracle-log-entry {
  background: var(--bg);
  border: 1px solid var(--border);
  border-left: 3px solid var(--text-dim);
  border-radius: var(--radius);
  padding: 8px 10px;
  font-size: 0.72rem;
}
.admin-oracle-log-entry.is-ok { border-left-color: var(--ready); }
.admin-oracle-log-entry.is-warn { border-left-color: #ff6b6b; }
.admin-oracle-log-entry-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 4px;
  color: var(--text-dim);
  font-family: var(--font-mono);
  font-size: 0.66rem;
  margin-bottom: 4px;
}
.admin-oracle-log-question {
  margin: 0 0 3px;
  color: var(--text);
  word-break: break-word;
}
.admin-oracle-log-outcome {
  margin: 0;
  color: var(--text-dim);
  font-size: 0.68rem;
}

/* ---------- Collezione (uso interno, pannello admin) ---------- */

.admin-steamlib-actions { display: flex; gap: 8px; flex-wrap: wrap; }

.admin-steamlib-content {
  margin-top: 12px;
  max-height: 340px;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.admin-steamlib-group {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
  flex-shrink: 0;
}
.admin-steamlib-head {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 12px;
  background: var(--bg-panel-2);
  cursor: pointer;
  user-select: none;
  flex-shrink: 0;
}
.admin-steamlib-name { font-weight: 700; font-size: 0.85rem; }
.admin-steamlib-head .hint { flex: 1; text-align: right; font-size: 0.7rem; }
.admin-steamlib-toggle { font-family: var(--font-mono); color: var(--accent2); flex-shrink: 0; }
.admin-steamlib-list {
  max-height: 220px;
  overflow-y: auto;
  padding: 4px 0;
}
.admin-steamlib-item {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 2px 10px;
  padding: 4px 12px;
  font-size: 0.76rem;
  color: var(--text-dim);
  border-top: 1px solid var(--border);
}
.admin-steamlib-item:first-child { border-top: none; }
.admin-steamlib-item-name { flex-shrink: 0; }
.admin-steamlib-item-meta {
  flex: 1 1 auto;
  min-width: 0;
  font-family: var(--font-mono);
  font-size: 0.68rem;
  color: var(--accent2);
  text-align: right;
}

/* ---------- Algoritmo (pannello admin) ---------- */

#admin-algorithm-search {
  display: block;
  width: 100%;
  box-sizing: border-box;
  margin: 10px 0 0;
}
.admin-algo-toggles {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 16px;
  margin: 8px 0 0;
}
.admin-algo-solo-filter {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 0.78rem;
  color: var(--text-dim);
  cursor: pointer;
  user-select: none;
}
.admin-algo-solo-filter input[type="checkbox"] { accent-color: var(--accent2); cursor: pointer; }

.admin-algo-total-badge {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: 0.62rem;
  font-weight: 400;
  letter-spacing: normal;
  text-transform: none;
  color: var(--accent2);
  border: 1px solid var(--accent2);
  border-radius: 999px;
  padding: 2px 9px;
  vertical-align: middle;
  margin-left: 8px;
}

.admin-algorithm-content {
  margin-top: 12px;
  max-height: 340px;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.admin-algorithm-content.hide-categories .admin-algo-tags-categories { display: none; }
.admin-algorithm-content.hide-content-flags .admin-algo-tags-content-flags { display: none; }
.admin-algo-row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px 10px;
  padding: 8px 12px;
  background: var(--bg-panel-2);
  border-radius: var(--radius);
  flex-shrink: 0;
}
.admin-algo-name { font-weight: 700; font-size: 0.85rem; flex: 1; min-width: 140px; }
.admin-algo-count {
  font-family: var(--font-mono);
  font-size: 0.7rem;
  color: var(--accent2);
  border: 1px solid var(--accent2);
  border-radius: 999px;
  padding: 2px 8px;
  flex-shrink: 0;
}
.admin-algo-categories {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  width: 100%;
}
.admin-algo-category-tag {
  font-family: var(--font-mono);
  font-size: 0.62rem;
  color: var(--ready);
  border: 1px solid var(--ready);
  border-radius: 999px;
  padding: 1px 7px;
}
/* "Solo" è rumore per il matchmaking di gruppo, non un pregio: lo teniamo visibile ma
   volutamente spento, per distinguerlo a colpo d'occhio dalle modalità che contano davvero. */
.admin-algo-category-tag.is-solo {
  color: var(--text-dim);
  border-color: var(--border);
}
.admin-algo-genre-tag {
  font-family: var(--font-mono);
  font-size: 0.62rem;
  color: var(--accent2);
  border: 1px solid var(--accent2);
  border-radius: 999px;
  padding: 1px 7px;
  opacity: 0.85;
}
.admin-algo-flag-tag {
  font-family: var(--font-mono);
  font-size: 0.62rem;
  color: var(--accent);
  border: 1px solid var(--accent);
  border-radius: 999px;
  padding: 1px 7px;
  opacity: 0.65;
}
.admin-algo-owners {
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.admin-algo-owner {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 2px 10px;
  font-size: 0.74rem;
  color: var(--text-dim);
}
.admin-algo-owner-name { font-weight: 600; flex-shrink: 0; }
.admin-algo-owner-meta {
  flex: 1 1 auto;
  min-width: 0;
  font-family: var(--font-mono);
  font-size: 0.68rem;
  color: var(--accent2);
  text-align: right;
}
