:root {
  --bg: #050310;
  --bg-2: #0a0616;
  --surface: rgba(255,255,255,0.035);
  --surface-strong: rgba(255,255,255,0.06);
  --border: rgba(168,120,255,0.18);
  --border-hover: rgba(168,120,255,0.42);

  --text: #f4eefe;
  --text-dim: #a99bc9;
  --text-faint: #746793;

  --violet: #9b5cff;
  --violet-2: #7c3aed;
  --magenta: #ff53d4;

  --ok: #3cf295;
  --warn: #ffcf4d;
  --down: #ff4d6d;
  /* NACHTRAG (23.08.2026, Nutzer-Wunsch "Icons farbig machen"): zwei
     zusätzliche Akzentfarben, damit nicht jedes Icon nur violett/magenta/
     grün/gelb/rot sein muss - passt zum bestehenden Neon-Farbschema. */
  --cyan: #4de8ff;
  --blue: #5b8dff;

  --radius: 16px;
  --radius-sm: 11px;

  --font-display: 'Unbounded', system-ui, sans-serif;
  --font-body: 'Manrope', system-ui, sans-serif;
}

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

html, body { min-height: 100%; }

/* "color-scheme: dark" allein hat NICHT gereicht (von Nutzer per Screenshot
   bestätigt: Aufklapp-Liste blieb weiß/unlesbar, Browser ignoriert das für
   die Options-Popup teilweise trotzdem). Bleibt als harmloser Fallback
   stehen, die eigentliche Lösung ist jetzt customSelect.js - ersetzt die
   native Aufklapp-Liste komplett durch eine selbst gezeichnete (siehe unten,
   ".custom-select-*"), auf jeder Seite, die customSelect.js einbindet. */
select { color-scheme: dark; }

/* Eigene Dropdown-Liste (customSelect.js) - ersetzt optisch komplett die
   native <select>-Aufklappliste, der echte <select> bleibt nur unsichtbar
   für den Formularwert bestehen. */
.custom-select-wrapper { position: relative; }
.custom-select-native {
  position: absolute;
  inset: 0;
  opacity: 0;
  pointer-events: none;
}
.custom-select-trigger {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  background: var(--surface-strong);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 10px 12px;
  color: var(--text);
  font-family: var(--font-body);
  font-size: 14px;
  cursor: pointer;
  text-align: left;
  margin-top: 4px;
}
.custom-select-trigger:hover { border-color: var(--border-hover); }
.custom-select-trigger.open { border-color: var(--violet); }
.custom-select-trigger::after {
  content: '▾';
  color: var(--text-faint);
  flex-shrink: 0;
}
/* position/top/left/width hier sind nur der Ausgangswert - sobald die
   Liste offen ist, hängt sie per JS (customSelect.js -> openList()) direkt
   an <body> und bekommt eine feste Pixel-Position per Inline-Style, damit
   sie NICHT mehr vom "overflow: hidden" der .glow-card (oder jeder anderen
   Karte) abgeschnitten werden kann (Nutzer-Feedback: "kann man nicht alles
   einsehen"). */
/* NACHTRAG (23.08.2026, Nutzer-Bug "weißer Balken" bei der Musik-Lautstärke):
   <input type="range"> (Lautstärke-Regler auf /panel/music) hatte bisher
   NIRGENDS im Panel-CSS eine eigene Track-Farbe - nur "accent-color" auf
   dem Slider selbst (siehe music.html .music-volume-row-Regel). Chrome/Edge
   färbt per accent-color zwar Thumb + den bereits "gefüllten" Teil links
   vom Thumb ein, der Rest der Leiste bleibt aber Browser-Standard = fast
   immer ein helles/weißes Grau, das im dunklen Marken-Look als Fremdkörper
   auffällt. Fix: Track in beiden Engines (WebKit/Blink + Firefox) explizit
   auf die Marken-Oberfläche setzen, Thumb im Marken-Verlauf - gilt global
   für JEDEN Regler im Panel, nicht nur den einen auf der Musik-Seite. */
input[type="range"] {
  -webkit-appearance: none;
  appearance: none;
  width: 100%;
  height: 5px;
  background: transparent;
  cursor: pointer;
}
input[type="range"]::-webkit-slider-runnable-track {
  height: 5px;
  border-radius: 4px;
  background: var(--surface-strong);
  border: 1px solid var(--border);
}
input[type="range"]::-moz-range-track {
  height: 5px;
  border-radius: 4px;
  background: var(--surface-strong);
  border: 1px solid var(--border);
}
input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 15px;
  height: 15px;
  margin-top: -6px;
  border-radius: 50%;
  background: linear-gradient(135deg, var(--magenta), var(--violet-2));
  border: 2px solid var(--text);
  cursor: pointer;
}
input[type="range"]::-moz-range-thumb {
  width: 15px;
  height: 15px;
  border-radius: 50%;
  background: linear-gradient(135deg, var(--magenta), var(--violet-2));
  border: 2px solid var(--text);
  cursor: pointer;
}
input[type="range"]::-moz-range-progress {
  height: 5px;
  border-radius: 4px 0 0 4px;
  background: linear-gradient(90deg, var(--magenta), var(--violet-2));
}

.custom-select-list {
  display: none;
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  right: 0;
  /* NACHTRAG (17.08.2026, Nutzer-Screenshot "Werbepausen"): war vorher
     "background: var(--surface-strong)" (nur rgba(255,255,255,0.06), also
     94% durchsichtig) - sah bei den meisten Seiten "gut genug" aus, weil
     meist nur der schlichte Seitenhintergrund dahinterliegt, aber die Liste
     wird per JS als "Portal" an <body> gehängt und kann dadurch über JEDEM
     beliebigen Element der Seite aufklappen (hier: direkt über dem lila
     "Werbepause jetzt starten"-Knopf) - bei 94% Durchsichtigkeit schimmerte
     der knallige Knopf-Farbverlauf deutlich sichtbar durch die Liste durch
     (sah aus wie ein kaputtes Stacking, war aber tatsächlich nur fehlende
     Deckkraft). Jetzt eine echte, praktisch blickdichte Hintergrundfarbe,
     die weiterhin zum dunklen Violett-Look passt.
   */
  background: #150c29;
  border: 1px solid var(--border-hover);
  border-radius: 10px;
  box-shadow: 0 10px 30px rgba(0,0,0,0.5);
  z-index: 200;
  max-height: 260px;
  overflow-y: auto;
  padding: 4px;
}
.custom-select-list.open { display: block; }
.custom-select-item {
  padding: 9px 10px;
  font-size: 14px;
  color: var(--text);
  cursor: pointer;
  border-radius: 6px;
}
.custom-select-item:hover { background: rgba(255,255,255,0.07); }
.custom-select-item.selected { background: rgba(139,92,246,0.22); font-weight: 700; }

/* NACHTRAG (17.08.2026, Nutzer-Wunsch "Panel wie NEBULA STREAM CONTROL /
   NEXUS MOD umbauen") - feines Sternenfeld zusätzlich zum bestehenden
   Farbverlauf, rein additiv (mehrere kleine radial-gradient-"Sterne" als
   eigene, sich wiederholende Hintergrund-Ebenen VOR dem bisherigen
   Farbverlauf, der als letzte/unterste Ebene unverändert bestehen bleibt) -
   soll den "im Weltraum"-Eindruck der Vorlage verstärken, ohne die
   bisherige Optik zu ersetzen. */
body {
  background-color: var(--bg);
  background-image:
    radial-gradient(1.4px 1.4px at 40px 60px, rgba(255,255,255,0.5), transparent 60%),
    radial-gradient(1px 1px at 160px 120px, rgba(255,255,255,0.32), transparent 60%),
    radial-gradient(1.4px 1.4px at 260px 40px, rgba(255,255,255,0.4), transparent 60%),
    radial-gradient(1px 1px at 320px 190px, rgba(255,255,255,0.28), transparent 60%),
    radial-gradient(1.4px 1.4px at 90px 230px, rgba(255,255,255,0.35), transparent 60%),
    radial-gradient(1px 1px at 220px 280px, rgba(255,255,255,0.25), transparent 60%),
    radial-gradient(circle at 20% -10%, #1c0f3a 0%, var(--bg) 55%);
  background-repeat: repeat, repeat, repeat, repeat, repeat, repeat, no-repeat;
  background-size: 340px 340px, 340px 340px, 340px 340px, 340px 340px, 340px 340px, 340px 340px, 100% 100%;
  background-attachment: fixed, fixed, fixed, fixed, fixed, fixed, fixed;
  color: var(--text);
  font-family: var(--font-body);
  padding: 32px 20px 80px;
  position: relative;
}

/* ============================================================
   Animiertes Hintergrund-Glow (rein additiv, "position: fixed",
   liegt HINTER allem anderen -- keine bestehende Seite betroffen,
   einfach zwei langsam driftende, leicht pulsierende Farbflecken
   für mehr Tiefe/Atmosphäre, statt eines statischen flachen
   Hintergrunds).
   ============================================================ */
body::before,
body::after {
  content: "";
  position: fixed;
  width: 46vw;
  height: 46vw;
  max-width: 620px;
  max-height: 620px;
  border-radius: 50%;
  filter: blur(90px);
  opacity: 0.22;
  pointer-events: none;
  z-index: -1;
}
body::before {
  background: var(--violet);
  top: -14vw;
  left: -10vw;
  animation: bgDriftA 26s ease-in-out infinite alternate;
}
body::after {
  background: var(--magenta);
  bottom: -16vw;
  right: -12vw;
  animation: bgDriftB 32s ease-in-out infinite alternate;
}
@keyframes bgDriftA {
  from { transform: translate(0, 0) scale(1); opacity: 0.18; }
  to   { transform: translate(4vw, 3vw) scale(1.15); opacity: 0.28; }
}
@keyframes bgDriftB {
  from { transform: translate(0, 0) scale(1); opacity: 0.16; }
  to   { transform: translate(-3vw, -4vw) scale(1.12); opacity: 0.26; }
}
@media (prefers-reduced-motion: reduce) {
  body::before, body::after { animation: none; }
}
/* z-index: -1 oben sorgt dafür, dass die Glow-Flecken IMMER hinter
   allen bisherigen Inhalten (.wrap, .app-shell, ...) liegen, unabhängig
   von deren eigener Stapelreihenfolge -- rein dekorativ, keine
   bestehende Seite muss dafür etwas anpassen. */

/* ============================================================
   ANIMIERTER HEX-HINTERGRUND (ganzes Panel). NACHTRAG (23.08.2026,
   Nutzer-Wunsch anhand Referenzbild: "bekommen wir sowas ähnliches aber
   animiertes im gesammten Panel eingebaut als hintergrund ... Login
   Wartungsarbeiten im Panel selbst und die anderen seiten"): liegt auf
   <html>::before/::after statt auf <body>, weil body::before/::after
   schon für die beiden Glow-Flecken oben belegt sind - html hatte noch
   keine eigenen Pseudo-Elemente. Beide sind "position: fixed" +
   negativer z-index, landen also automatisch HINTER dem propagierten
   body-Hintergrund (Browser-"Canvas") und hinter allen echten Inhalten,
   ohne dass irgendeine der ~34 Panel-Seiten (Login, Wartungsseite
   eingeschlossen, beide laden diese Datei ja bereits) selbst etwas
   einbauen muss - rein additiv, eine einzige Datei.
   html::before = das Hex-Waben-Muster selbst (SVG-Kachel, dieselbe
   violette Randfarbe wie --border), langsam driftend.
   NACHTRAG (23.08.2026, Nutzer-Feedback "bekommen wir die schrägen
   striche da weg? sonst sieht es geil aus"): die zusätzlichen
   diagonalen Cyan/Magenta-Leuchtstreifen (vorher html::after) waren zu
   auffällig/haben gestört - komplett entfernt, es bleibt nur noch das
   ruhige, langsam driftende Hex-Muster übrig.
   ============================================================ */
html::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -3;
  pointer-events: none;
  background-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22138.00%22%20height%3D%2279.67%22%20viewBox%3D%220%200%20138.00%2079.67%22%3E%3Cg%20fill%3D%22none%22%20stroke%3D%22rgba%28155%2C92%2C255%2C0.18%29%22%20stroke-width%3D%221.1%22%3E%3Cpath%20d%3D%22M46.00%2C0.00%20L23.00%2C39.84%20L-23.00%2C39.84%20L-46.00%2C0.00%20L-23.00%2C-39.84%20L23.00%2C-39.84%20Z%22%2F%3E%3Cpath%20d%3D%22M115.00%2C39.84%20L92.00%2C79.67%20L46.00%2C79.67%20L23.00%2C39.84%20L46.00%2C0.00%20L92.00%2C0.00%20Z%22%2F%3E%3Cpath%20d%3D%22M184.00%2C0.00%20L161.00%2C39.84%20L115.00%2C39.84%20L92.00%2C0.00%20L115.00%2C-39.84%20L161.00%2C-39.84%20Z%22%2F%3E%3Cpath%20d%3D%22M-23.00%2C39.84%20L-46.00%2C79.67%20L-92.00%2C79.67%20L-115.00%2C39.84%20L-92.00%2C0.00%20L-46.00%2C0.00%20Z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E");
  background-size: 138px 79.67px;
  background-repeat: repeat;
  opacity: 0.9;
  animation: hexDrift 70s linear infinite;
}
@keyframes hexDrift {
  from { background-position: 0 0; }
  to   { background-position: 276px 159.34px; }
}
@media (prefers-reduced-motion: reduce) {
  html::before { animation: none; }
}

a { color: inherit; }

.wrap { max-width: 980px; margin: 0 auto; }

.brand {
  display: flex;
  align-items: center;
  gap: 10px;
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 20px;
  margin-bottom: 32px;
}
.brand .dot { color: var(--magenta); }

.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 24px;
  margin-bottom: 18px;
  /* NACHTRAG (17.08.2026, Redesign): dezenter Tiefen-Schatten in der
     Marken-Farbe statt eines flachen Kartenrands, passend zum "Glow"-Look
     der Vorlage - rein additiv, ändert weder Größe noch Abstand. */
  box-shadow: 0 22px 50px -34px rgba(139,92,246,0.5);
}
.card h2 {
  font-family: var(--font-display);
  font-size: 16px;
  font-weight: 700;
  margin-bottom: 14px;
  color: var(--text);
}

.btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  background: linear-gradient(135deg, var(--violet-2), var(--violet));
  color: #fff;
  border: none;
  border-radius: 999px;
  padding: 12px 22px;
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 14px;
  text-decoration: none;
  cursor: pointer;
  /* NACHTRAG (17.08.2026, Redesign): leuchtender Knopf-Schatten statt eines
     flachen Buttons, passend zum "Glow"-Look der Vorlage. */
  box-shadow: 0 12px 26px -10px rgba(155,92,255,0.6);
  /* NACHTRAG (23.08.2026, Nutzer-Feedback "kein Hover", "helle Farben
     können dunkler sein"): .btn hatte im GESAMTEN Panel bisher gar keine
     :hover-Regel (Ursache für "da ändert sich nichts"). Jetzt: sanfter
     Übergang + beim Hover dunkler statt heller (ruhiger fürs Auge), und
     der Grundverlauf ist jetzt auch im Normalzustand ohnehin schon etwas
     gedämpfter (dunklerer Ton zuerst statt hellerer). */
  transition: filter 0.15s ease, box-shadow 0.15s ease, transform 0.05s ease;
}
/* filter statt background-Überschreibung, weil sehr viele Buttons im Panel
   ihre Farbe per Inline-style setzen (rot fürs Bannen, "Glas"-Grau fürs
   Zurücksetzen usw. - grep bestätigt das für clips/livecontrol/modtools/
   overlay-layout/overlay-editor). Eine :hover-Regel, die nur "background"
   setzt, wird von einem Inline-style NIE überschrieben (Inline gewinnt
   immer) - deshalb hatte bisher NUR ein Teil der Buttons (die ohne Inline-
   Farbe) überhaupt eine Chance auf Hover, und selbst die hatten keine Regel.
   "filter" wird dagegen unabhängig von der Hintergrundquelle immer korrekt
   abgedunkelt (wirkt auch auf den box-shadow-Schein mit) - funktioniert
   dadurch für WIRKLICH jeden Button im Panel gleich, egal welche Farbe. */
.btn:hover { filter: brightness(0.85); }
.btn:active { filter: brightness(0.72); transform: translateY(1px); }
.btn.secondary,
.btn.btn-ghost {
  background: var(--surface-strong);
  border: 1px solid var(--border);
  color: var(--text);
  box-shadow: none;
}
.btn.secondary:hover,
.btn.btn-ghost:hover {
  background: rgba(255,255,255,0.1);
  border-color: var(--border-hover);
  filter: none;
}
.btn.secondary:active,
.btn.btn-ghost:active { background: rgba(255,255,255,0.05); transform: translateY(1px); }
.btn:disabled { opacity: 0.5; cursor: not-allowed; filter: none; transform: none; }

/* NACHTRAG (23.08.2026, 3. Runde, Nutzer-Feedback "ich muss dennoch beim
   Login scrollen"): Ursache gefunden - .login-shell war selbst exakt
   "min-height:100vh" hoch (füllt den Viewport also schon ganz aus), ABER
   direkt danach kommt im HTML noch die Copyright-Zeile (.login-copyright)
   als GESCHWISTER-Element, nicht als Kind - die kommt also oben drauf und
   macht die Seite insgesamt höher als der Viewport (100vh Shell + Footer-
   Höhe), man musste also für ein paar Pixel Fußzeile immer scrollen, egal
   wie klein die Karte selbst war. Fix: body bekommt "auth-page-body"
   (siehe login.html/maintenance.html), macht body selbst zur festen
   100vh-Flexspalte - die Shell füllt darin nur noch den ÜBRIGEN Platz
   (flex:1 statt eigenem min-height:100vh), der Footer kommt normal
   darunter, in Summe bleibt alles exakt bei 100vh statt "100vh + Footer". */
body.auth-page-body { display: flex; flex-direction: column; min-height: 100vh; }
body.auth-page-body .login-shell { min-height: 0; flex: 1; }
.login-shell {
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  /* NACHTRAG (23.08.2026, Nutzer-Wunsch "das man Scrollen muss ... es soll
     wirklich schön aussehen"): vorher "min-height:80vh" ohne eigenes
     Padding - auf kleineren Fenstern klebte die Karte fast am Rand. Jetzt
     echtes 100vh + Innenabstand oben/unten, damit die (jetzt größere)
     Login-Karte immer Luft hat, egal ob sie ins Fenster passt oder man
     dafür scrollen muss. */
  padding: 40px 20px;
  min-height: 100vh;
}
.login-card {
  position: relative;
  background: linear-gradient(155deg, rgba(30,14,58,0.55), rgba(10,6,22,0.5));
  border: 1px solid var(--border-hover);
  border-radius: var(--radius);
  padding: 48px 40px;
  max-width: 420px;
  overflow: hidden;
}
/* Gleicher schimmernder Rand-Verlauf wie bei .glow-card (siehe unten) --
   bewusst eine eigene Regel statt die Klasse zu kombinieren, damit das
   großzügige Login-Padding (48px/40px) unangetastet bleibt. */
.login-card::before {
  content: "";
  position: absolute;
  inset: -1px;
  border-radius: var(--radius);
  padding: 1px;
  background: linear-gradient(120deg, var(--violet), transparent 35%, transparent 65%, var(--magenta));
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask-composite: exclude;
  opacity: 0.6;
  pointer-events: none;
}
.login-card h1 {
  font-family: var(--font-display);
  font-size: 22px;
  margin-bottom: 10px;
}
.login-card p {
  color: var(--text-dim);
  font-size: 14px;
  margin-bottom: 28px;
  line-height: 1.5;
}

/* Login/Willkommens-Seite als richtige kleine Hero-Fläche statt einer engen
   Login-Box (siehe Nutzer-Feedback "eine Willkommen Seite wirklich") -
   eigene Modifier-Klasse auf .login-card, damit die schmale Variante oben
   (falls sie woanders noch gebraucht wird) unangetastet bleibt. */
/* NACHTRAG (23.08.2026, 2. Runde, Nutzer-Feedback "viel zu groß und der
   Hintergrund kann transparent sein"): der erste Anlauf (820px, fast
   blickdichter Glas-Verlauf) war schlicht zu wuchtig für eine Login-Seite -
   jetzt spürbar kompakter (echte Login-Card-Breite statt Dashboard-Hero)
   UND der Kartenhintergrund ist jetzt so transparent, dass das animierte
   Hex-Muster im Hintergrund klar durchscheint statt von einer fast
   blickdichten Fläche verdeckt zu werden - "backdrop-filter" sorgt trotzdem
   für genug Kontrast/Lesbarkeit (leichtes Glas, kein Milchglas). */
.login-card.hero {
  max-width: 460px;
  padding: 44px 38px;
  background: rgba(18,10,36,0.3);
  backdrop-filter: blur(18px) saturate(130%);
  box-shadow: 0 30px 70px -34px rgba(0,0,0,0.5);
}
/* NACHTRAG (23.08.2026, 2. Runde): der Glow-Fleck war für die vorherige
   820px-Karte bemessen (320px Durchmesser) - auf der jetzt kompakten
   460px-Karte eigene, kleinere Maße statt der Dashboard-Größe. */
.login-card.hero .hero-orb { opacity: 0.4; width: 220px; height: 220px; top: -80px; right: -60px; }
.login-card.hero .hero-orb::before { width: 150px; height: 150px; top: 24px; left: -36px; }
.login-card.hero .hero-orb::after { width: 70px; height: 70px; top: 46px; right: 34px; }
/* NACHTRAG (20.08.2026, Logo-Austausch, Nutzer-Wunsch "das Neue log.png
   soll auch zusehen sein beim Login"): großes Logo-Artwork oben auf der
   Login-Hero-Karte, mit sanftem violettem Schein passend zum restlichen
   Glow-Look. */
/* NACHTRAG (23.08.2026, 2. Runde, "viel zu groß"): 128px Logo passte zur
   820px-Karte, wirkt auf der jetzt kompakten 460px-Karte überdimensioniert
   - deutlich kleiner. */
.hero-logo {
  width: 82px;
  height: 82px;
  margin: 0 auto 14px;
  display: block;
  object-fit: contain;
  filter: drop-shadow(0 8px 22px rgba(155,92,255,0.5));
}
.hero-kicker {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 11px;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--magenta);
  margin-bottom: 10px;
}
.hero-title {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 25px;
  line-height: 1.25;
  margin-bottom: 10px;
}
/* NACHTRAG (23.08.2026, "es soll wirklich eine richtige Schöne Anmeldeseite
   werden"): "Mod-Panel" im Titel als sanfter Verlauf statt einfarbig - ein
   kleiner Blickfang, ohne dass der ganze Titel schreit. */
.hero-title .accent {
  background: linear-gradient(120deg, var(--violet), var(--magenta));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.hero-sub {
  color: var(--text-dim);
  font-size: 13.5px;
  line-height: 1.55;
  max-width: 380px;
  margin: 0 auto 22px;
}
.hero-actions { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; margin-bottom: 14px; }
/* NACHTRAG (23.08.2026, Nutzer-Feedback "diese hintergrund farben bei den
   Icons können weg oder dunkler sein, desweiteren bei dem Twitch/Discord
   Button auch dunkler"): die vorher knallig-hellen Marken-Buttons (helles
   Blurple-Blau, magenta/violetter Verlauf) waren zu grell für die sonst
   dunkle, zurückhaltende Optik der Seite - jetzt dunkle "Glas"-Buttons:
   dezenter, halbtransparenter Marken-Farbton als Hintergrund + passender
   Rahmen, Icon/Text in einem helleren Ton derselben Farbe (currentColor
   färbt das SVG-Icon automatisch mit). Deutlich ruhiger, wirkt trotzdem
   klar erkennbar als "Discord" bzw. "Twitch" durch Icon-Form + Farbfamilie. */
.btn-brand { padding: 13px 26px; font-size: 14.5px; border: 1px solid transparent; }
.btn-brand svg { width: 20px; height: 20px; fill: currentColor; flex-shrink: 0; }
.btn-discord {
  background: rgba(88,101,242,0.14);
  border-color: rgba(88,101,242,0.4);
  color: #b8beff;
  box-shadow: none;
}
.btn-discord:hover { background: rgba(88,101,242,0.22); border-color: rgba(88,101,242,0.6); }
.btn-twitch {
  background: rgba(155,92,255,0.14);
  border-color: rgba(155,92,255,0.4);
  color: #d7c2ff;
}
.btn-twitch:hover { background: rgba(155,92,255,0.22); border-color: rgba(155,92,255,0.6); filter: none; }
.hero-hint { font-size: 11.5px; color: var(--text-faint); max-width: 380px; margin: 0 auto 24px; line-height: 1.5; }
/* NACHTRAG (23.08.2026, 2. Runde, "viel zu groß"): die vorherige 2x2-Karten-
   Vorschau (je mit eigener Beschreibungszeile) war der Hauptgrund für die
   Kartenhöhe - jetzt eine einzige schmale Zeile aus kleinen Icon-Chips,
   nur Symbol + Name, deutlich kompakter. Eigene Klassen statt .module-card/
   .module-icon (die sind fürs eingeloggte Panel gedacht und größer/anders
   gebaut), damit hier nichts mitgezogen wird, was nicht passt. */
.hero-preview-strip { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px; }
.preview-chip {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  background: rgba(255,255,255,0.03);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 7px 13px 7px 8px;
  font-size: 12px;
  font-weight: 600;
  color: var(--text-dim);
}
.preview-chip-icon {
  width: 22px;
  height: 22px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: rgba(255,255,255,0.05);
  border: 1px solid var(--border);
  font-size: 12px;
  flex-shrink: 0;
}

/* Kleine Willkommens-Kopfzeile ganz oben im Dashboard (index.html) - nach
   dem Login soll sich die erste Seite nicht wie "einfach nur Dashboard"
   anfühlen, sondern wie eine echte Begrüßung. Nutzt die vorhandene
   .glow-card/.kicker-Basis, nur 2 neue Klassen für Titel/Untertext. */
.welcome-title { font-family: var(--font-display); font-weight: 800; font-size: 19px; margin: 5px 0 7px; }
.welcome-sub { color: var(--text-dim); font-size: 13.5px; line-height: 1.5; }

/* NACHTRAG (23.08.2026, Nutzer-Feedback "sieht nicht mal ansatzweise so aus
   wie die Vorlage"): dichteres Kachel-Raster - vorher min. 220px, dadurch
   passten selbst auf breiten Screens oft nur 3-4 Kacheln pro Zeile und viel
   Luft blieb ungenutzt. Jetzt wie in der "Nexus Mod"-Vorlage: schmalere,
   kompaktere Kacheln, mehr pro Zeile, weniger Innenabstand/kleinere
   Schrift - dieselben echten Werte, nur enger zusammengepackt. */
.grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 10px;
}
.tile {
  background: var(--surface-strong);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 12px 13px;
}
.tile .label { color: var(--text-faint); font-size: 10.5px; text-transform: uppercase; letter-spacing: .04em; }
.tile .value { font-family: var(--font-display); font-size: 17px; margin-top: 5px; }
.tile.ok .value { color: var(--ok); }
.tile.down .value { color: var(--down); }
.tile.streamer .value { color: var(--warn); }

.topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 24px;
}
.user {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 14px;
  color: var(--text-dim);
}
.user img { width: 28px; height: 28px; border-radius: 50%; }

/* Dashboard-Module als kompaktes Karten-Grid statt einer langen Liste
   (Nutzer-Feedback: "sobald man sich eingeloggt hat wird man erschlagen
   von Infos") -- weniger Zeilen auf einen Blick, klarer scanbar, wirkt
   nach echtem Dashboard statt einer Linkliste. */
.module-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 12px; }
.module-card {
  display: flex;
  flex-direction: column;
  gap: 8px;
  background: var(--surface-strong);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 16px;
  text-decoration: none;
  color: inherit;
  transition: border-color .15s ease, transform .15s ease;
}
a.module-card:hover { border-color: var(--border-hover); transform: translateY(-2px); }
.module-card .module-icon {
  width: 34px;
  height: 34px;
  border-radius: 10px;
  background: linear-gradient(135deg, var(--violet), var(--magenta));
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 17px;
}
.module-card .module-title { font-family: var(--font-display); font-weight: 700; font-size: 13.5px; }
.module-card .module-desc { font-size: 11.5px; color: var(--text-dim); line-height: 1.4; }
.module-card.soon { opacity: .5; }
.module-card.soon .module-icon { background: var(--surface-strong); border: 1px solid var(--border); }

/* Live-Übersicht-Kacheln fürs Dashboard (Bans/Timeouts/Subs/Bits/Raids/
   Follows, siehe activityLog.js/panelActivityApi.js) - eigene, größere
   Karten als .module-card, weil hier zusätzlich noch eine kurze
   Ereignis-Liste reinpasst. */
.stat-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 14px; }
.stat-card {
  background: var(--surface-strong);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 16px;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
/* NACHTRAG (23.08.2026, Nutzer-Frage "wieso is das noch da, hat das
   überhaupt Sinn?" zur Live-Übersicht): die Karte HAT einen echten Sinn
   (heutige Aktivität: Follows/Bans/Subs/... - einzige Stelle im Panel, die
   das zeigt), sah an ruhigen Tagen aber wie eine Wand toter Fläche aus,
   weil leere Kacheln ("Keine") genauso groß/hell wirkten wie welche mit
   echten Einträgen. Jetzt spürbar zurückgenommen (dezenter Rahmen, kein
   Icon-Verlauf, gedämpfter Text) statt gleichwertig neben aktiven Kacheln
   zu stehen - lenkt den Blick automatisch auf das, was wirklich passiert
   ist. Panel.js setzt/entfernt ".ok" schon (siehe renderStatCard), hier
   nur der Gegenpart für den Fall OHNE ".ok". */
.stat-card:not(.ok) { opacity: 0.55; }
.stat-card:not(.ok) .stat-icon { background: var(--surface-strong); }

/* NACHTRAG (23.08.2026, 3. Runde): war bisher identisch in giveaway.html
   UND poll.html als eigenes inline <style> dupliziert (Dauer-/Vorankündigungs-
   Buttons) - jetzt hierher verschoben, damit subathon.html (neue
   Ruhezustand-Auswahl) es mitnutzen kann, ohne ein drittes Mal zu
   duplizieren. Reine Verschiebung, kein optischer Unterschied. */
.preset-row { display: flex; flex-wrap: wrap; gap: 8px; margin-top: -4px; }
.preset-btn {
  background: var(--surface-strong);
  border: 1px solid var(--border);
  color: var(--text-dim);
  border-radius: 8px;
  padding: 6px 12px;
  font-size: 12px;
  font-family: var(--font-body);
  cursor: pointer;
}
.preset-btn:hover { border-color: var(--violet); color: var(--text); }
.preset-btn.active { background: linear-gradient(135deg, var(--violet), var(--violet-2)); border-color: transparent; color: #fff; }
/* NACHTRAG (17.08.2026, Redesign): Icon jetzt als kleines, farbig
   hinterlegtes Abzeichen statt nacktem Emoji auf dem Karten-Hintergrund -
   dieselbe Verlaufsfarbe wie .module-icon/.glow-badge, damit alle
   "Icon-in-Kachel"-Stellen im Panel einheitlich aussehen. Reine
   CSS-Änderung, .stat-icon-Element/Inhalt selbst bleibt unverändert. */
.stat-icon {
  width: 30px;
  height: 30px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 9px;
  background: linear-gradient(135deg, rgba(155,92,255,0.28), rgba(255,83,212,0.2));
  border: 1px solid var(--border);
  font-size: 15px;
  margin-bottom: 6px;
}
.stat-label { color: var(--text-faint); font-size: 11px; text-transform: uppercase; letter-spacing: .04em; }
.stat-value { font-family: var(--font-display); font-weight: 800; font-size: 19px; margin-top: 2px; }
.stat-sub { font-size: 11.5px; color: var(--text-dim); margin-bottom: 8px; }
.stat-list { display: flex; flex-direction: column; gap: 5px; }
.stat-list-item {
  display: flex;
  justify-content: space-between;
  gap: 8px;
  font-size: 11.5px;
  color: var(--text-dim);
  border-top: 1px solid var(--border);
  padding-top: 5px;
}
.stat-list-item b { color: var(--text); font-weight: 700; }
.stat-list-item .stat-list-time { color: var(--text-faint); flex-shrink: 0; }
#stat-streamstatus.live .stat-value { color: var(--ok); }
.stat-card.ok .stat-value { color: var(--ok); }

/* Kompakte Live-Chat-Vorschau auf dem Dashboard - eigene, kleinere Variante
   der .chat-box/.chat-msg-Optik von /panel/chat (dort noch als Seiten-
   lokales <style>, hier bewusst geteilt, weil jetzt zwei Stellen dieselbe
   Chat-Nachrichten-Optik brauchen). */
.chat-mini { display: flex; flex-direction: column; gap: 6px; max-height: 260px; overflow-y: auto; padding: 2px; }
.chat-mini .chat-msg {
  display: flex;
  gap: 8px;
  padding: 7px 10px;
  background: var(--surface-strong);
  border-radius: 8px;
  border-left: 3px solid var(--border-hover);
  font-size: 12.5px;
  line-height: 1.4;
  word-break: break-word;
}
.chat-mini .chat-username { font-weight: 700; color: var(--magenta); }
.chat-mini .chat-empty { color: var(--text-faint); font-size: 12.5px; padding: 10px; }

/* Fahrplan-Zeile statt gedimmter "soon"-Kacheln mitten zwischen fertigen
   Funktionen (sah vorher aus wie unfertig hingeworfen) - klar als eigener,
   kleiner Ausblick beschriftet. */
.roadmap-card { padding-bottom: 18px; }
.roadmap-list { display: flex; flex-wrap: wrap; gap: 10px; }
.roadmap-item {
  font-size: 12px;
  color: var(--text-dim);
  background: var(--surface-strong);
  border: 1px dashed var(--border);
  border-radius: 999px;
  padding: 7px 14px;
}

.error-box {
  background: rgba(255,77,109,0.12);
  border: 1px solid rgba(255,77,109,0.4);
  color: #ffb3c1;
  border-radius: var(--radius-sm);
  padding: 14px 16px;
  font-size: 13px;
  margin-bottom: 18px;
}

/* ============================================================
   Sidebar-Navigation (ab hier) - eigene Klasse auf <body>, damit
   die Login-Seite (die KEINE Sidebar hat) von den Padding-Resets
   unten unberührt bleibt.
   ============================================================ */
body.has-sidebar { padding: 0; }
.app-shell { display: flex; min-height: 100vh; align-items: stretch; }
/* Breiter als vorher (232px -> 272px) + mehr Innenabstand - bei 232px
   wirkte der User-Chip (Avatar+Name+Badge+Zahnrad in einer Reihe) und die
   Nav-Einträge (Icon+Text) zusammengequetscht, siehe Nutzer-Feedback
   "sieht eingequetscht aus". */
.sidebar {
  width: 272px;
  flex-shrink: 0;
  background: var(--bg-2);
  border-right: 1px solid var(--border);
  padding: 26px 20px;
  display: flex;
  flex-direction: column;
  gap: 24px;
  position: sticky;
  top: 0;
  align-self: flex-start;
  height: 100vh;
  overflow-y: auto;
}
/* NACHTRAG (17.08.2026, Nutzer-Feedback per Mobil-Screenshot: die feste
   272px-Sidebar hatte auf schmalen Bildschirmen bisher KEINE eigene
   Media-Query - sie blieb immer 272px breit und quetschte den restlichen
   Inhalt in den verbleibenden, viel zu schmalen Rest zusammen (die
   halb abgeschnittenen Karten-Ränder rechts im Screenshot). Ab jetzt auf
   schmalen Bildschirmen eine echte Off-Canvas-Schublade: standardmäßig
   per Klick auf den neuen Menü-Knopf im Topbar (siehe .topbar-menu-btn)
   ein-/ausfahrbar, statt fest die Hälfte des winzigen Bildschirms zu
   belegen. */
@media (max-width: 900px) {
  .sidebar {
    position: fixed;
    inset: 0 auto 0 0;
    z-index: 400;
    transform: translateX(-100%);
    transition: transform .22s ease;
    box-shadow: 20px 0 50px rgba(0,0,0,0.5);
  }
  .sidebar.open { transform: translateX(0); }
  .main-content { width: 100%; }
}
.sidebar-backdrop {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(3,1,10,0.6);
  z-index: 390;
}
@media (max-width: 900px) {
  .sidebar-backdrop.open { display: block; }
}
/* Bug gefixt: .sidebar-brand ist "display:flex" (Reihe), darin macht
   "display:block" auf .sub NICHTS - ein Flex-Item bleibt in derselben
   Reihe, egal welchen display-Wert es selbst hat. Die Unterzeile
   "Mod-Panel" landete dadurch gequetscht NEBEN "Bunnyzudemkushtv" statt
   sauber darunter (siehe Nutzer-Screenshot). Fix: Name+Unterzeile in
   einen eigenen Spalten-Block packen, nur das 🟣-Icon bleibt daneben. */
.sidebar-brand {
  display: flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 15px;
  text-decoration: none;
  line-height: 1.35;
}
.sidebar-brand .brand-text { display: flex; flex-direction: column; min-width: 0; }
.sidebar-brand .dot { color: var(--magenta); flex-shrink: 0; }
.sidebar-brand .sub { display: block; color: var(--text-faint); font-weight: 500; font-size: 11px; }

/* NACHTRAG (17.08.2026, Redesign "Panel wie NEBULA STREAM CONTROL
   umbauen") - rundes Marken-Abzeichen mit Verlauf statt des einfarbigen
   🟣-Emoji-Punkts, angelehnt an das runde Logo-Icon der Vorlage. Wird von
   sidebar.js (Sidebar-Kopf) UND vom neuen Topbar (siehe unten) genutzt,
   damit die Marke überall gleich aussieht. Rein optisch - Link/Ziel der
   Sidebar-Marke bleibt unverändert (führt weiterhin zu /panel/). */
.brand-mark {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  background: radial-gradient(circle at 32% 28%, var(--magenta), var(--violet-2) 75%);
  font-family: var(--font-display);
  font-weight: 900;
  font-size: 13px;
  color: #fff;
  box-shadow: 0 0 0 2px rgba(155,92,255,0.22), 0 8px 18px -6px rgba(255,83,212,0.55);
}
/* NACHTRAG (20.08.2026, Logo-Austausch, Nutzer-Wunsch "bei dem B den Hasen
   nur rein machen"): das kreisrunde Marken-Abzeichen zeigt jetzt das echte
   Maskottchen-Artwork statt des Buchstabens "B" - Kreisform/Glow/Einsatzort
   (Sidebar-Kopf + Topbar, siehe sidebar.js) bleiben unverändert. */
.brand-mark img { width: 100%; height: 100%; object-fit: cover; }
/* NACHTRAG (23.08.2026, Nutzer-Wunsch "Mache das doch im Panel oben
   rechts, da steht doch eh schon der Name"): der frühere eigene User-Chip
   direkt unter der Marke (Avatar/Name/Rolle/Zahnrad, eigene ".sidebar-user"
   Zeile) ist raus - dieselben Infos stehen jetzt oben in der Topbar
   (.topbar-user/.topbar-settings weiter unten in dieser Datei), war sonst
   doppelt zu sehen. */

/* Zwei klar getrennte Bereiche (Mod-Bereich/Streamer-Bereich, siehe
   sidebar.js) statt einer einzigen, gleichförmigen Liste -- eigener,
   farblich unterschiedlicher Kopf pro Bereich, damit sofort klar ist, wo
   die Grenze zwischen "das kann jeder Mod" und "das ist nur für den
   Streamer" verläuft. */
.sidebar-areas { display: flex; flex-direction: column; gap: 26px; flex: 1; }
/* Ersetzt das entfernte "🧩 Mod-Bereich"-Label (siehe sidebar.js) - gleicher
   Abstand wie vorher zwischen User-Chip und der Navigation, nur ohne den
   überflüssigen Text dazwischen. Der Streamer-Bereich unten hat weiterhin
   sein eigenes Label + eigenen padding-top (siehe .streamer-area weiter
   unten), bleibt hier unangetastet. */
.sidebar-area:not(.streamer-area) { padding-top: 20px; }
.sidebar-area-label {
  font-family: var(--font-display);
  font-size: 10px;
  letter-spacing: .07em;
  text-transform: uppercase;
  font-weight: 800;
  padding: 0 10px;
  margin-bottom: 8px;
  display: flex;
  align-items: center;
  gap: 5px;
}
.sidebar-area-label.mod { color: var(--violet); }
.sidebar-area-label.streamer { color: var(--warn); }
.sidebar-area.streamer-area {
  padding-top: 18px;
  border-top: 1px solid var(--border);
}
.sidebar-groups { display: flex; flex-direction: column; gap: 20px; }
.sidebar-group { display: flex; flex-direction: column; gap: 6px; }
.sidebar-section-label {
  font-size: 11px;
  color: var(--text-faint);
  text-transform: uppercase;
  letter-spacing: .06em;
  padding: 0 10px;
}
.sidebar-nav { display: flex; flex-direction: column; gap: 2px; }
.sidebar-nav a {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 10px;
  border-radius: 8px;
  color: var(--text-dim);
  text-decoration: none;
  font-size: 13px;
}
.sidebar-nav a:hover { background: var(--surface-strong); color: var(--text); }
.sidebar-nav a.active { background: linear-gradient(135deg, var(--violet), var(--violet-2)); color: #fff; }
.sidebar-nav a .soon-tag { margin-left: auto; font-size: 9px; color: var(--text-faint); }
.sidebar-nav a.active .soon-tag { color: rgba(255,255,255,0.75); }
/* NACHTRAG (23.08.2026, Nutzer-Wunsch "mehr Leben mehr Struktur Zauber",
   Vergleich mit "Nexus Mod"-Referenzbild: dünne Linien-Icons statt Emoji in
   der Navigation): jeder Link bekommt jetzt zusätzlich zum Text ein
   eigenes, kleines Inline-SVG (siehe ICONS in sidebar.js) - "currentColor"
   sorgt dafür, dass das Icon automatisch dieselbe Farbe wie der Text hat,
   auch im aktiven (weißen) Zustand, ganz ohne eigene Farb-Regel hier. */
.sidebar-nav a svg { width: 17px; height: 17px; flex-shrink: 0; opacity: .85; }
.sidebar-nav a.active svg { opacity: 1; }
.sidebar-nav a:hover svg { opacity: 1; }

/* Logout jetzt als eigene Zeile ganz unten in der Sidebar statt im
   User-Chip mitgequetscht - "margin-top: auto" drückt sie im Flex-Layout
   der Sidebar (.sidebar { display:flex; flex-direction:column; ... })
   an den unteren Rand, solange der Inhalt drüber nicht die volle
   Sidebar-Höhe füllt. */
.sidebar-footer { margin-top: auto; padding-top: 14px; border-top: 1px solid var(--border); }
.sidebar-logout-btn {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 10px;
  border-radius: 8px;
  color: var(--text-faint);
  text-decoration: none;
  font-size: 13px;
}
.sidebar-logout-btn:hover { background: var(--surface-strong); color: var(--down); }
/* NACHTRAG (17.08.2026, Nutzer-Wunsch "Copyright einbauen... im Gesammten
   Panel"), siehe sidebar.js -> renderSidebar(). Bewusst klein/dezent (wie
   ein normaler Footer-Hinweis), nicht als weiterer Nav-Punkt gestaltet. */
.sidebar-copyright { margin-top: 8px; padding: 0 10px; font-size: 10.5px; color: var(--text-faint); text-align: center; }
/* Gleiche Fußzeile wie .sidebar-copyright, für die Login-Seite (siehe
   login.html), die keine Sidebar hat. */
.login-copyright { padding: 24px 10px 32px; font-size: 11px; color: var(--text-faint); text-align: center; }

/* NACHTRAG (23.08.2026, Nutzer-Wunsch "kein Zugriff-Seite neu machen, gute
   Wartungsarbeiten-Seite bauen"): gemeinsamer Baustein für alle "Status"-
   Vollbild-Seiten des Panels (Kein Zugriff, Wartung, künftig auch 404 o.ä.)
   - EIN Satz Klassen statt jede Seite ihr eigenes Inline-Style-Chaos bauen
   zu lassen, damit neue Status-Seiten automatisch gleich hochwertig aussehen. */
.status-page-card {
  text-align: center;
  padding: 56px 40px;
  max-width: 560px;
  margin: 40px auto;
}
.status-page-logo {
  width: 72px;
  height: 72px;
  margin: 0 auto 18px;
  display: block;
  object-fit: contain;
  filter: drop-shadow(0 10px 26px rgba(155,92,255,0.5));
}
.status-page-icon { font-size: 40px; margin-bottom: 10px; }
.status-page-title {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 21px;
  margin-top: 8px;
}
.status-page-text {
  color: var(--text-dim);
  font-size: 14px;
  margin: 16px auto 26px;
  max-width: 440px;
  line-height: 1.65;
}

.main-content { flex: 1; min-width: 0; padding: 22px 22px 70px; }
/* NACHTRAG (19.08.2026, Nutzer-Meldung "die Seiten rechts immer sehr viel
   Platz iss wäre es nicht besser die Seiten vollständig zu füllen"): 1040px
   war ein FESTER Deckel, unabhängig von der tatsächlichen Fensterbreite - auf
   größeren Bildschirmen/Fenstern blieb dadurch rechts einfach dauerhaft
   Leerraum stehen, auch wenn eigentlich Platz für mehr Spalten in den
   bestehenden auto-fit-Grids (siehe .hero-grid/.stat-grid/.module-grid usw.
   weiter unten) gewesen wäre. Jetzt füllt der Inhalt die komplette verfügbare
   Breite (width: 100%) bis zu einem großzügigeren Deckel (1600px, nur damit
   Textzeilen auf sehr breiten Monitoren nicht endlos lang werden) - die
   Grids darunter reagieren automatisch (auto-fit/auto-fill), ohne dass jede
   einzelne Panel-Seite selbst angepasst werden musste. */
.main-content .wrap { max-width: 1600px; width: 100%; margin: 0; }

/* ============================================================
   "Glow"-Design-Bausteine (neu, Redesign 2026) -- rein additiv,
   verändert keine bestehende Klasse. Gedacht als gemeinsame
   Bausteine für Gewinnspiel/Umfrage und später weitere Seiten,
   damit am Ende alles aus einem Guss wirkt statt jede Seite ihr
   eigenes Süppchen kocht.
   ============================================================ */
.glow-card {
  position: relative;
  background: linear-gradient(155deg, rgba(30,14,58,0.55), rgba(10,6,22,0.5));
  border: 1px solid var(--border-hover);
  border-radius: var(--radius);
  /* NACHTRAG (23.08.2026, Nutzer-Feedback "sieht nicht mal ansatzweise so
     aus wie die Vorlage"): weniger Innenabstand/Abstand zwischen Karten -
     die Vorlage packt spürbar mehr Inhalt auf dieselbe Fläche statt große
     Leerflächen um jede Karte zu lassen. */
  padding: 18px;
  margin-bottom: 14px;
  overflow: hidden;
  /* NACHTRAG (17.08.2026, Redesign): sichtbarerer Leucht-Schatten, damit
     Karten optisch etwas vor dem Sternenfeld-Hintergrund "schweben" statt
     flach draufzuliegen. */
  box-shadow: 0 26px 60px -36px rgba(255,83,212,0.4), 0 26px 60px -30px rgba(139,92,246,0.35);
  /* NACHTRAG (23.08.2026, Nutzer-Wunsch "mehr Leben mehr Struktur Zauber",
     Vergleich mit "Nexus Mod"-Referenzbild): sanfter Hover-Lift + kräftigerer
     Schatten, damit sich das Dashboard weniger wie eine statische Liste und
     mehr wie ein echtes "Control Center" anfühlt - rein optisch, kein Klick
     nötig, bricht also auf Karten mit Formularen/Buttons nichts. */
  transition: transform .18s ease, box-shadow .18s ease, border-color .18s ease;
}
.glow-card:hover {
  border-color: rgba(255,83,212,0.4);
  box-shadow: 0 30px 70px -34px rgba(255,83,212,0.5), 0 30px 70px -28px rgba(139,92,246,0.45);
}
.glow-card::before {
  content: "";
  position: absolute;
  inset: -1px;
  border-radius: var(--radius);
  padding: 1px;
  background: linear-gradient(120deg, var(--violet), transparent 35%, transparent 65%, var(--magenta));
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask-composite: exclude;
  opacity: 0.6;
  pointer-events: none;
}
.glow-card-head {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 12px;
  position: relative;
}
/* NACHTRAG (23.08.2026, Nutzer-Feedback "die ganzen Icons blenden zu
   sehr"): .glow-badge ist der Kopf-Icon in praktisch JEDER Kartenüber-
   schrift im ganzen Panel (~90 Stellen, ~30 Seiten) - der volle, satte
   Violett-Magenta-Verlauf + kräftiger Leucht-Schatten summierte sich auf
   Seiten mit mehreren Karten zu ziemlich viel Knalligkeit auf einmal.
   Jetzt gedämpfter: durchsichtigere Verlaufsfarbe (wie schon bei
   .stat-icon) statt voller Sättigung, dünner Rahmen statt starkem Glow-
   Schatten - Symbol bleibt genauso gut lesbar, blendet aber nicht mehr. */
.glow-badge {
  width: 30px;
  height: 30px;
  border-radius: 9px;
  background: linear-gradient(135deg, rgba(155,92,255,0.32), rgba(255,83,212,0.24));
  border: 1px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 15px;
  box-shadow: none;
  flex-shrink: 0;
}
.kicker {
  font-family: var(--font-display);
  font-size: 10.5px;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--magenta);
  font-weight: 700;
}

.live-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 11px;
  font-weight: 700;
  padding: 6px 12px;
  border-radius: 999px;
  background: rgba(60,242,149,0.12);
  border: 1px solid rgba(60,242,149,0.35);
  color: var(--ok);
}
.live-pill.pending {
  background: rgba(255,207,77,0.12);
  border-color: rgba(255,207,77,0.4);
  color: var(--warn);
}
.live-pill.pending::before { background: var(--warn); box-shadow: 0 0 8px var(--warn); }
.live-pill::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--ok);
  box-shadow: 0 0 8px var(--ok);
  animation: livePulse 1.6s ease-in-out infinite;
}
@keyframes livePulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50% { opacity: 0.45; transform: scale(0.75); }
}

.chip-list {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  max-height: 220px;
  overflow-y: auto;
  padding: 2px;
}
.chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  background: rgba(155,92,255,0.12);
  border: 1px solid rgba(155,92,255,0.28);
  color: #e4d7ff;
  border-radius: 999px;
  padding: 5px 11px 5px 8px;
  font-size: 12.5px;
  font-weight: 600;
}
.chip .dot { width: 5px; height: 5px; border-radius: 50%; background: var(--magenta); flex-shrink: 0; }
.chip-empty { color: var(--text-faint); font-size: 13px; padding: 6px 2px; }

/* ============================================================
   Topbar (NEU, 17.08.2026, Nutzer-Wunsch "Bekommen wir mein panel in
   sowas ähnlichem Umgebaut" -> NEBULA STREAM CONTROL-Vorlage) - schmale
   Kopfzeile oben im Content-Bereich, auf jeder Panel-Seite zusätzlich zur
   bestehenden Sidebar (die bleibt unverändert). Zeigt Seitentitel,
   Live-Status, Uhrzeit und den eingeloggten User auf einen Blick - genau
   die Elemente, die die Vorlage oben quer über die ganze Seite zeigt.
   Rein additiv: Markup kommt aus sidebar.js -> renderTopbar(), befüllt nur
   <header id="topbar">, das jetzt auf jeder Panel-Seite als erstes Element
   in .main-content steht. Seiten ohne dieses Element wären unberührt.
   ============================================================ */
.topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  padding: 14px 20px;
  margin-bottom: 22px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: 0 22px 50px -34px rgba(139,92,246,0.5);
}
.topbar-left { display: flex; align-items: center; gap: 12px; min-width: 0; }
/* Menü-Knopf für die neue Off-Canvas-Sidebar (siehe .sidebar
   @media (max-width: 900px) oben) - nur auf schmalen Bildschirmen
   sichtbar, auf breiten Bildschirmen bleibt die Sidebar wie gehabt immer
   sichtbar, kein Knopf nötig. */
.topbar-menu-btn {
  display: none;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border-radius: 8px;
  background: var(--surface-strong);
  border: 1px solid var(--border);
  color: var(--text);
  font-size: 15px;
  cursor: pointer;
  flex-shrink: 0;
}
@media (max-width: 900px) {
  .topbar-menu-btn { display: flex; }
}
.topbar-title {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 15px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.topbar-right { display: flex; align-items: center; gap: 14px; flex-shrink: 0; flex-wrap: wrap; }
.topbar-bell {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--surface-strong);
  border: 1px solid var(--border);
  text-decoration: none;
  font-size: 14px;
}
.topbar-bell:hover { border-color: var(--border-hover); }
.topbar-clock {
  font-family: var(--font-display);
  font-size: 12.5px;
  color: var(--text-dim);
  display: flex;
  align-items: center;
  gap: 6px;
  white-space: nowrap;
}
.topbar-user { display: flex; align-items: center; gap: 8px; font-size: 12.5px; color: var(--text-dim); }
.topbar-user img,
.topbar-user .avatar-fallback {
  width: 26px;
  height: 26px;
  border-radius: 50%;
  flex-shrink: 0;
  border: 1px solid var(--border-hover);
}
.topbar-user .avatar-fallback {
  display: flex;
  align-items: center;
  justify-content: center;
  background: linear-gradient(135deg, var(--violet), var(--magenta));
  color: #fff;
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 11px;
}
/* NACHTRAG (23.08.2026): Rolle-Badge (Owner/Mod) jetzt hier statt im
   entfernten Sidebar-User-Chip, gleiche Optik wie vorher. */
.topbar-user .role-badge {
  font-size: 9px;
  text-transform: uppercase;
  letter-spacing: .05em;
  font-weight: 800;
  color: var(--violet);
  background: rgba(155,92,255,0.14);
  border-radius: 5px;
  padding: 1px 6px;
}
.topbar-user .role-badge.owner { color: var(--warn); background: rgba(255,207,77,0.14); }

/* NACHTRAG (24.08.2026, Nutzer-Wunsch "im Mein Profil ... vielleicht auch
   in Farben mit so einem animierten Hallo Emoji"): gemeinsame Bausteine für
   den Zuschauer-Bereich (Startseite + Mein Profil) - VIPs bekommen ihren
   Anzeigenamen in einem Verlauf aus den Marken-Farben statt in normalem
   Text (siehe auch die VIP-Idee "farbiger Name/Badge" aus dem Brainstorming),
   alle anderen bleiben bei normaler Textfarbe. Das winkende Emoji bekommt
   eine sanfte, sich wiederholende Dreh-Animation - rein kosmetisch, pausiert
   automatisch bei "prefers-reduced-motion". */
.vip-name {
  background: linear-gradient(135deg, var(--violet), var(--magenta, #ff53d4));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  font-weight: 800;
}
.wave-emoji {
  display: inline-block;
  animation: wave-hello 2.4s ease-in-out infinite;
  transform-origin: 70% 70%;
}
@keyframes wave-hello {
  0%, 60%, 100% { transform: rotate(0deg); }
  10% { transform: rotate(14deg); }
  20% { transform: rotate(-8deg); }
  30% { transform: rotate(14deg); }
  40% { transform: rotate(-4deg); }
  50% { transform: rotate(10deg); }
}
@media (prefers-reduced-motion: reduce) {
  .wave-emoji { animation: none; }
}

/* NACHTRAG (24.08.2026, Nutzer-Wunsch "der Owner eine Krone hat und auch
   einen Animierten Namen Gold usw ... was bessonderes"): eigene Optik für
   den Owner/Streamer, DEUTLICH von der VIP-Farbe (violet/magenta) getrennt -
   goldener, sanft "schimmernder" Namensverlauf + Kronen-Icon, statt wie
   bisher einfach als VIP mitzulaufen (siehe checkVipAccess()/isOwnerLogin()
   in panelAccountAuth.js). */
.owner-name {
  background: linear-gradient(90deg, #ffd76a, #fff3c4, #ffb84d, #ffd76a);
  background-size: 300% 100%;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  font-weight: 800;
  animation: owner-name-shimmer 4s linear infinite;
}
@keyframes owner-name-shimmer {
  0% { background-position: 0% 50%; }
  100% { background-position: 300% 50%; }
}
.owner-crown-icon {
  display: inline-block;
  filter: drop-shadow(0 0 4px rgba(255,207,77,0.6));
}
.topbar-user .role-badge.owner-crown { color: #3a2400; background: linear-gradient(135deg, #ffe08a, #ffb84d); }
@media (prefers-reduced-motion: reduce) {
  .owner-name { animation: none; }
}

/* Login-Seite hat keine Sidebar/Topbar - hier nichts zu tun, .topbar wird
   dort schlicht nie gerendert. Auf sehr schmalen Fenstern darf der
   User-Name im Topbar-Chip verschwinden (Avatar reicht als Wiedererkennung),
   Titel/Live/Uhrzeit bleiben wichtiger. */
@media (max-width: 560px) {
  .topbar-user span:not(.avatar-fallback) { display: none; }
}

/* NACHTRAG (23.08.2026, Nutzer-Wunsch "Einstellungen kompakter, einfach
   nur aufs Zahnrad klicken müssen"): Dropdown-Menü fürs Zahnrad oben
   rechts, gleiches Prinzip wie .quick-actions-dropdown auf dem Dashboard. */
.topbar-settings { position: relative; }
.topbar-gear-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  background: var(--surface-strong);
  border: 1px solid var(--border);
  border-radius: 50%;
  color: var(--text-dim);
  font-size: 14px;
  cursor: pointer;
}
.topbar-gear-btn:hover { border-color: var(--border-hover); color: var(--text); }
.topbar-settings.open .topbar-gear-btn { border-color: var(--magenta); color: var(--text); }
.topbar-gear-menu {
  display: none;
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  min-width: 230px;
  max-height: 60vh;
  overflow-y: auto;
  background: #150c29;
  border: 1px solid var(--border-hover);
  border-radius: 10px;
  box-shadow: 0 10px 30px rgba(0,0,0,0.5);
  padding: 6px;
  z-index: 60;
}
.topbar-settings.open .topbar-gear-menu { display: block; }
.topbar-gear-menu a {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 8px 10px;
  border-radius: 6px;
  color: var(--text);
  text-decoration: none;
  font-size: 13px;
}
.topbar-gear-menu a:hover { background: rgba(255,255,255,0.07); }
.topbar-gear-menu a svg { width: 16px; height: 16px; flex-shrink: 0; opacity: .85; }
.topbar-gear-sep { height: 1px; background: var(--border); margin: 6px 4px; }

/* ============================================================
   Feine, zum Look passende Scrollbar (WebKit) statt der grauen
   Standard-Leiste - rein kosmetisch, betrifft nur die Optik der
   Scrollbar selbst, kein Layout/Verhalten ändert sich.
   ============================================================ */
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: rgba(155,92,255,0.35);
  border-radius: 999px;
  border: 2px solid transparent;
  background-clip: padding-box;
}
::-webkit-scrollbar-thumb:hover { background: rgba(155,92,255,0.55); background-clip: padding-box; }

/* ============================================================
   Dashboard-Hero-Orb (ÜBERARBEITET, 18.08.2026, Nutzer-Feedback "das soll
   was animiertes sein, aber das sieht ja schrecklich aus") - der alte
   Versuch war eine einzelne, hart abgegrenzte 380px-Kugel mit dünnen
   Ring-Linien, die groß genug war, um den Untertitel der Karte komplett zu
   überdecken (siehe Screenshot). Kompletter Neuansatz: statt EINER harten
   Kugel jetzt zwei weich verlaufende, unterschiedlich timende Glow-Flecken
   ("Aurora"-Look) mit starkem Weichzeichner (filter: blur) statt scharfer
   Kante - dadurch nie eine erkennbare "Scheibe", sondern ambientes Licht,
   das sich langsam verschiebt/pulsiert. Beide Flecken sitzen bewusst
   weiter oben rechts UND kleiner, damit die Untertitel-Zeile darunter frei
   bleibt. "z-index: 0" auf .hero-welcome erzeugt weiterhin einen eigenen
   Stapelkontext, damit die Flecken (z-index:-1) zuverlässig HINTER dem
   Karten-Text bleiben. Rein additiv/optisch, kein Einfluss auf Text/
   Buttons/IDs in der Karte.
   ============================================================ */
.glow-card.hero-welcome { position: relative; z-index: 0; }
.hero-orb {
  position: absolute;
  top: -120px;
  right: -100px;
  width: 320px;
  height: 320px;
  border-radius: 50%;
  background: radial-gradient(circle at 42% 40%, rgba(255,255,255,0.4), var(--magenta) 30%, transparent 68%);
  opacity: 0.45;
  z-index: -1;
  pointer-events: none;
  filter: blur(46px);
  mix-blend-mode: screen;
  animation: heroOrbDrift1 16s ease-in-out infinite alternate;
}
/* Zweiter, kleinerer und andersfarbiger Fleck (violett/blau) mit eigenem
   Timing statt eines starr mitrotierenden Rings - überlappt den ersten
   Fleck teilweise, dadurch wirkt die Mischfarbe an der Überlappung lebendig
   statt wie ein statisches Verlaufsbild. */
.hero-orb::before {
  content: "";
  position: absolute;
  top: 40px;
  left: -60px;
  width: 220px;
  height: 220px;
  border-radius: 50%;
  background: radial-gradient(circle at 50% 50%, var(--violet-2), transparent 70%);
  opacity: 0.55;
  filter: blur(38px);
  animation: heroOrbDrift2 12s ease-in-out infinite alternate;
}
/* Sehr feiner Kern-Glanz - deutlich kleiner/blasser als beim alten
   Versuch, sorgt nur noch für einen dezenten Lichtpunkt statt einer
   sichtbaren zweiten Kugel. */
.hero-orb::after {
  content: "";
  position: absolute;
  top: 70px;
  right: 60px;
  width: 90px;
  height: 90px;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(255,255,255,0.5), transparent 72%);
  opacity: 0.5;
  filter: blur(12px);
  animation: heroOrbPulse 5s ease-in-out infinite;
}
/* Einzelner, sehr dezenter Außenring statt der beiden harten Doppel-Ringe
   von vorher - weit draußen, kaum sichtbar, nur als leiser Akzent. */
.hero-orb-ring2 {
  position: absolute;
  top: -70px;
  right: -50px;
  width: 260px;
  height: 260px;
  border-radius: 50%;
  border: 1px solid rgba(255,255,255,0.08);
  pointer-events: none;
  z-index: -1;
}
@keyframes heroOrbDrift1 {
  from { transform: translate(0, 0) scale(1); }
  to   { transform: translate(-18px, 14px) scale(1.08); }
}
@keyframes heroOrbDrift2 {
  from { transform: translate(0, 0) scale(1); }
  to   { transform: translate(16px, -10px) scale(0.92); }
}
@keyframes heroOrbPulse {
  0%, 100% { opacity: 0.35; transform: scale(1); }
  50% { opacity: 0.6; transform: scale(1.15); }
}
@media (prefers-reduced-motion: reduce) {
  .hero-orb, .hero-orb::before, .hero-orb::after { animation: none; }
}
@media (max-width: 640px) {
  /* Auf schmalen Bildschirmen (bzw. wenn die Karte durch .hero-grid
     schmaler als die Vorlage-Breite wird) insgesamt kleiner/dezenter,
     damit auch dort garantiert kein Text überdeckt wird. */
  .hero-orb { width: 190px; height: 190px; top: -70px; right: -50px; opacity: 0.35; }
  .hero-orb::before { width: 130px; height: 130px; top: 20px; left: -30px; }
  .hero-orb::after { width: 60px; height: 60px; top: 40px; right: 30px; }
  .hero-orb-ring2 { display: none; }
}

/* ============================================================
   Dashboard-Komposition (NEU, 17.08.2026, Redesign Runde 2 - Nutzer-
   Feedback "sieht 0 danach aus wie auf dem Bild") - die erste Runde hat
   nur Farben/Glow angepasst, aber am bisherigen Seitenaufbau nichts
   geändert. Diesmal wird die tatsächliche ANORDNUNG des Dashboards an
   die Vorlage angeglichen (Hero + Stream-Status nebeneinander, KPI-
   Kachelreihe, Chat + Schnellzugriff nebeneinander, Ereignisse +
   Bot-Module nebeneinander, Stream-Ziel-Balken) - ausschließlich mit
   ECHTEN, bereits vorhandenen Daten (activityLog/Follower-Overlay-API/
   Stream-Ziele), keine erfundenen Platzhalter-Zahlen.
   ============================================================ */
.hero-grid {
  display: grid;
  grid-template-columns: 2fr 1fr;
  gap: 18px;
  align-items: stretch;
}
@media (max-width: 860px) {
  .hero-grid { grid-template-columns: 1fr; }
}
/* NACHTRAG (23.08.2026, Nutzer-Feedback "Da würde ich einfach nur was man
   kennt machen sowas wie willkommen usw aber hat ja nichts mit dem Quick
   Actions/Bot-Betriebszeit/Discord-Ping zutun"): die Willkommens-Karte
   zeigt jetzt nur noch den Begrüßungstext - Quick Actions + Bot-Kennzahlen
   sitzen in einer eigenen, kleinen zweiten Karte direkt darunter, beide
   zusammen in dieser linken Spalte (bleibt bei 2fr Breite wie vorher). */
.hero-left-col { display: flex; flex-direction: column; gap: 18px; }
.hero-quickbar { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 12px; padding: 16px 20px; }
.hero-quickbar .hero-quickstats { margin-top: 0; }
/* NACHTRAG (23.08.2026, Nutzer-Feedback "Quick Actions ich sehe nichts"):
   .glow-card setzt "overflow:hidden" (für den abgerundeten Rand-Verlauf),
   das schneidet aber auch das aufklappende .quick-actions-menu ab, weil es
   sich per "position:absolute" NACH UNTEN über den Kartenrand hinaus
   öffnen will - die Karte selbst ist nur so hoch wie ihr Inhalt, also
   landete das Menü komplett unsichtbar außerhalb der eigenen Karte.
   Einzige Karte, die das braucht (keine eigenen abgerundeten Deko-
   Elemente drin, die das Clipping bräuchten), deshalb hier gezielt
   überschrieben statt an .glow-card selbst zu ändern. */
.hero-quickbar { overflow: visible; }
/* Drei-Spalten-Zeile (Neueste Ereignisse / Bot-Module / Bot-Verbindungen,
   angelehnt an die Vorlage) - eigene Klasse statt .hero-grid
   wiederzuverwenden, weil hier alle drei Spalten gleich breit sein sollen. */
.tri-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 14px;
  align-items: stretch;
}
@media (max-width: 1100px) {
  .tri-grid { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 700px) {
  .tri-grid { grid-template-columns: 1fr; }
}

/* NACHTRAG (23.08.2026, Nutzer-Frage "meinste das alles hat was auf der
   Startseite zu suchen?"): .tri-grid hatte fest 3 Spalten für "Neueste
   Ereignisse / Bot-Module / Bot-Verbindungen" - erste Karte ist raus, jetzt
   nur noch 2 Karten. Eigener Modifikator statt die Basis-Klasse
   umzuschreiben (falls an anderer Stelle doch nochmal 3 Karten reinkommen). */
.tri-grid.two-col { grid-template-columns: 1fr 1fr; }
@media (max-width: 700px) {
  .tri-grid.two-col { grid-template-columns: 1fr; }
}

/* Socials-Kachel "Unsere Kanäle" (NACHTRAG 23.08.2026, Nutzer-Wunsch "wenn
   die Mods mal schnell ein Link brauchen"), angelehnt an
   https://bunnyzudemkushtv.de/#socials - Icon-Kachel + Name + Handle + CTA,
   ein Klick öffnet den echten Kanal in einem neuen Tab. */
.socials-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
  gap: 12px;
}
.social-card {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 4px;
  padding: 16px 14px;
  border-radius: var(--radius-sm);
  background: var(--surface-strong);
  border: 1px solid var(--border);
  text-decoration: none;
  color: var(--text);
  transition: transform .15s ease, border-color .15s ease, background .15s ease;
}
.social-card:hover {
  transform: translateY(-2px);
  border-color: var(--border-hover);
  background: var(--surface);
}
.social-card.primary { border-color: rgba(145,70,255,0.5); box-shadow: 0 0 0 1px rgba(145,70,255,0.25); }
.social-icon {
  width: 42px;
  height: 42px;
  border-radius: 12px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  margin-bottom: 4px;
}
.social-icon svg { width: 22px; height: 22px; }
.social-name { font-family: var(--font-display); font-weight: 800; font-size: 13px; letter-spacing: .02em; }
.social-handle { font-size: 11.5px; color: var(--text-dim); }
.social-cta { font-size: 11.5px; font-weight: 700; color: var(--magenta); text-decoration: none; }
/* NACHTRAG (23.08.2026, Nutzer-Wunsch "bei den Links, das man den Link auch
   kopieren kann wäre gut"): .social-card ist jetzt kein <a> mehr (war davor
   die ganze Kachel ein einziger Link) - stattdessen eine <div> mit zwei
   eigenen, unabhängig klickbaren Elementen unten: dem echten Öffnen-Link
   (.social-cta) und einem eigenen Kopieren-Knopf, der die URL per
   Zwischenablage-API kopiert, ohne die Seite zu verlassen. */
.social-card { cursor: default; }
.social-card-footer { display: flex; align-items: center; justify-content: space-between; width: 100%; margin-top: 4px; gap: 6px; }
.social-copy-btn {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text-dim);
  border-radius: 8px;
  padding: 3px 7px;
  font-size: 11px;
  cursor: pointer;
  line-height: 1.4;
  transition: border-color .15s ease, color .15s ease, background .15s ease;
}
.social-copy-btn:hover { border-color: var(--border-hover); color: var(--text); background: var(--surface); }
.social-copy-btn.copied { color: var(--ok); border-color: var(--ok); }

/* Schnellzugriff-Zeile in der Willkommens-Karte (echte Links zu
   bestehenden Seiten, keine neue Funktion). */
.hero-quick-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 18px; position: relative; }
.hero-quick-actions a.pill-link {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12.5px;
  font-weight: 700;
  color: var(--text);
  background: var(--surface-strong);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 8px 14px;
  text-decoration: none;
}
.hero-quick-actions a.pill-link:hover { border-color: var(--border-hover); }

/* Stream-Status-Karte (rechte Hero-Spalte) - #stat-streamstatus bleibt
   inhaltlich exakt dasselbe Element wie vorher (siehe panel.js ->
   loadStreamStatus()), nur optisch prominenter als eigene Karte statt
   eine von 8 gleich großen Kacheln im Aktivitäts-Raster. */
.stream-status-card { display: flex; flex-direction: column; }
.stream-status-card .stat-card {
  background: transparent;
  border: none;
  padding: 0;
  margin-bottom: 14px;
}
.stream-status-card .stat-icon { width: 34px; height: 34px; font-size: 17px; }
.stream-status-card .stat-value { font-size: 22px; }

/* Rein dekorative "Audio-Wellenform" - reagiert auf die echte .live-
   Klasse, die panel.js bereits auf #stat-streamstatus setzt (siehe
   loadStreamStatus()), pulsiert nur, wenn wirklich live. */
.waveform { display: flex; align-items: flex-end; gap: 3px; height: 40px; margin: 4px 0 14px; }
.waveform span {
  flex: 1;
  min-width: 2px;
  border-radius: 2px;
  background: linear-gradient(180deg, var(--magenta), var(--violet-2));
  opacity: 0.35;
  height: 30%;
}
#stat-streamstatus.live ~ .waveform span,
.stream-status-card:has(#stat-streamstatus.live) .waveform span {
  opacity: 0.9;
  animation: waveformBounce 1.1s ease-in-out infinite;
}
.waveform span:nth-child(1) { animation-delay: -1.0s; }
.waveform span:nth-child(2) { animation-delay: -0.8s; }
.waveform span:nth-child(3) { animation-delay: -0.6s; }
.waveform span:nth-child(4) { animation-delay: -0.4s; }
.waveform span:nth-child(5) { animation-delay: -0.2s; }
.waveform span:nth-child(6) { animation-delay: -0.9s; }
.waveform span:nth-child(7) { animation-delay: -0.5s; }
.waveform span:nth-child(8) { animation-delay: -0.1s; }
.waveform span:nth-child(9) { animation-delay: -0.7s; }
.waveform span:nth-child(10) { animation-delay: -0.3s; }
@keyframes waveformBounce {
  0%, 100% { height: 25%; }
  50% { height: 90%; }
}
@media (prefers-reduced-motion: reduce) {
  .waveform span { animation: none !important; }
}
.stream-status-totals { display: flex; gap: 18px; margin-top: auto; padding-top: 14px; border-top: 1px solid var(--border); }
.stream-status-totals div { display: flex; flex-direction: column; gap: 2px; }
.stream-status-totals .n { font-family: var(--font-display); font-weight: 800; font-size: 16px; }
.stream-status-totals .l { font-size: 10.5px; color: var(--text-faint); text-transform: uppercase; letter-spacing: .04em; }

/* NACHTRAG (23.08.2026, Nutzer-Wunsch "Follower-Ziel diese kannste doch
   oben rechts reinmachen ... kannste diese ja klein bei machen"): Bits +
   Gesamtstatus (vorher eigene "Kanal-Überblick"-Karte, siehe kpi-bits/
   kpi-systemhealth) jetzt als zwei kleine, liegende Mini-Kacheln direkt
   in der Stream-Status-Karte - ".mini" überschreibt nur die Größe, die
   Basis-".stat-card"-Klasse (inkl. der von panel.js gesetzten .ok/.down-
   Farbklassen) bleibt unverändert bestehen. */
.stream-status-mini-row { display: flex; gap: 10px; margin-top: 14px; }
.stat-card.mini {
  flex: 1;
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
  background: var(--surface-strong);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}
.stat-card.mini .stat-icon { width: 26px; height: 26px; font-size: 14px; margin-bottom: 0; flex-shrink: 0; }
/* NACHTRAG: bei so wenig Platz reichen Icon + Wert (z.B. "💎 0", "🛰️
   Optimal") völlig zum Verständnis - Titel + Unterzeile (die in der
   großen Kachel Sinn ergaben) würden hier nur überlaufen, deshalb beide
   ausgeblendet statt sie irgendwie reinzuquetschen. */
.stat-card.mini .stat-label,
.stat-card.mini .stat-sub { display: none; }
.stat-card.mini .stat-value { font-size: 13px; margin-top: 0; line-height: 1.2; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Follower-Ziel, jetzt klein direkt unter den Mini-Kacheln statt einer
   eigenen Karte - derselbe Radial-Ring wie vorher (.radial-progress), nur
   über ".small" verkleinert, dieselben Element-IDs wie vorher (siehe
   loadTotals() in panel.js), also keine JS-Änderung nötig. */
.goal-compact { display: flex; align-items: center; gap: 12px; margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--border); }
.goal-compact-info { flex: 1; min-width: 0; }
.goal-compact-label { font-family: var(--font-display); font-weight: 800; font-size: 12px; color: var(--magenta); margin-bottom: 6px; }
.goal-compact .goal-track { margin: 6px 0; height: 7px; }
.goal-compact-stats { font-size: 11px; color: var(--text-dim); }
.goal-compact-stats span { color: var(--text); font-weight: 700; }
.radial-progress.small { width: 48px; height: 48px; }
.radial-progress.small .radial-progress-inner { width: 38px; height: 38px; font-size: 10.5px; }

/* Quick-Control-Knopf-Raster (NACHTRAG 23.08.2026, Nutzer-Wunsch "Quick
   Stream Control" nach Nexus-Mod-Referenz, zuerst auf /panel/livecontrol
   gebaut) - Icon oben, Label darunter, reine Kacheloptik statt langer
   Formulare/vieler Karten. NACHTRAG (23.08.2026, "Mod-Tools ... auch
   verschönern mit buttons"): von livecontrol.html hierher verschoben
   (gemeinsame Datei), weil jetzt auch /panel/modtools dasselbe Muster
   nutzt - vorher nur in einer einzigen Seite definiert. */
.quick-control-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  gap: 10px;
  margin-top: 16px;
}
.quick-control-btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding: 14px 10px;
  background: var(--surface-strong);
  border: 1px solid var(--border);
  border-radius: 12px;
  color: var(--text);
  font-family: var(--font-body);
  cursor: pointer;
  transition: border-color .15s ease, transform .15s ease, background .15s ease;
}
/* .quick-control-btn wird teils auch als <a> für reine Sprungmarken genutzt
   (z.B. Bingo/Win-Challenge/Umfrage/Gewinnspiel öffnen) - Browser-Standard-
   Linkfarbe/-Unterstreichung hier explizit aus. */
a.quick-control-btn { text-decoration: none; }
.quick-control-btn:hover { border-color: var(--border-hover); transform: translateY(-2px); }
.quick-control-btn.open { border-color: var(--violet); background: rgba(145,70,255,0.12); }
.quick-control-btn.danger:hover { border-color: rgba(255,77,109,0.6); }
.qc-icon { font-size: 22px; line-height: 1; }
.qc-label { font-size: 12px; font-weight: 700; text-align: center; }
.quick-control-panel {
  margin-top: 14px;
  padding-top: 14px;
  border-top: 1px solid var(--border);
}

/* Ereignis-Liste "Neueste Ereignisse" (echte Daten aus derselben
   activityCache wie die Live-Übersicht-Kacheln, siehe panel.js ->
   renderRecentAlerts()). */
.alert-list { display: flex; flex-direction: column; gap: 8px; }
.alert-item { display: flex; align-items: center; gap: 10px; padding: 8px 4px; border-top: 1px solid var(--border); }
.alert-item:first-child { border-top: none; }
.alert-icon {
  width: 28px; height: 28px; flex-shrink: 0;
  border-radius: 8px;
  background: linear-gradient(135deg, rgba(155,92,255,0.28), rgba(255,83,212,0.2));
  border: 1px solid var(--border);
  display: flex; align-items: center; justify-content: center;
  font-size: 13px;
}
.alert-body { min-width: 0; flex: 1; }
.alert-title { font-size: 12.5px; font-weight: 700; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.alert-time { font-size: 11px; color: var(--text-faint); }

/* Stream-Ziel-Fortschrittsbalken - nutzt dieselben Werte wie das
   bestehende Follower-Ziel (/panel/settings, /api/followercount),
   bleibt per JS versteckt, solange kein Ziel gesetzt ist (siehe
   panel.js -> loadTotals()), damit hier nie ein irreführendes "0 von 0"
   auftaucht. */
.goal-track { position: relative; height: 10px; border-radius: 999px; background: var(--surface-strong); border: 1px solid var(--border); overflow: hidden; margin: 14px 0; }
.goal-fill { height: 100%; border-radius: 999px; background: linear-gradient(90deg, var(--violet), var(--magenta)); width: 0%; transition: width .6s ease; }
.goal-stats { display: flex; flex-wrap: wrap; gap: 22px; }
.goal-stats div { display: flex; flex-direction: column; gap: 2px; }
.goal-stats .n { font-family: var(--font-display); font-weight: 800; font-size: 18px; }
.goal-stats .l { font-size: 10.5px; color: var(--text-faint); text-transform: uppercase; letter-spacing: .04em; }
/* NACHTRAG (23.08.2026): Radial-Ring (.radial-progress, siehe oben) links
   neben dem bestehenden linearen Balken statt ihn zu ersetzen - .goal-track
   bekommt dadurch keine margin-top mehr von sich aus, der Abstand kommt
   jetzt von .goal-visual-track. */
.goal-visual { display: flex; align-items: center; gap: 20px; }
.goal-visual-track { flex: 1; min-width: 0; }
.goal-visual-track .goal-track { margin-top: 0; }
@media (max-width: 640px) {
  .goal-visual { flex-direction: column; align-items: stretch; }
}

/* Sidebar-Maskottchen ganz unten (rein dekorativ, angelehnt an die
   Vorlage) - zeigt bewusst KEINEN erfundenen "Online"-Status (dafür
   müsste jede Seite zusätzlich den Bot-Verbindungsstatus abfragen),
   nur die Marke selbst. */
.sidebar-mascot { display: flex; flex-direction: column; align-items: center; gap: 6px; padding: 18px 10px 6px; text-align: center; }
/* NACHTRAG (20.08.2026, Logo-Austausch): der Orb zeigt jetzt das echte
   Maskottchen-Artwork (logo-mark.png, aus Logo.png freigestellt) statt des
   platzhalter 🐰-Emojis - Kreisform/Glow-Rahmen bleiben identisch. */
.sidebar-mascot .mascot-orb {
  width: 56px; height: 56px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  overflow: hidden;
  background: radial-gradient(circle at 35% 30%, rgba(255,255,255,0.25), var(--magenta) 30%, var(--violet-2) 75%);
  box-shadow: 0 0 0 3px rgba(155,92,255,0.15), 0 10px 26px -8px rgba(255,83,212,0.55);
}
.sidebar-mascot .mascot-orb img { width: 100%; height: 100%; object-fit: cover; }
.sidebar-mascot .mascot-label { font-family: var(--font-display); font-weight: 800; font-size: 11px; letter-spacing: .04em; color: var(--text-dim); text-transform: uppercase; }

/* NACHTRAG (17.08.2026, Nutzer-Feedback "zu 100% wie auf dem Bild"):
   Sidebar-/Topbar-Unterzeile jetzt wie in der Vorlage klein, in Großbuchstaben
   und in der Marken-Farbe statt schlicht grau. */
.sidebar-brand .sub, .topbar-title-sub {
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--violet) !important;
  font-weight: 700;
}

/* Quick-Actions-Dropdown in der Willkommens-Karte - ein einzelner Knopf
   statt mehrerer loser Pills, öffnet per Klick eine kleine Liste
   derselben echten Links (siehe panel.js -> Quick-Actions-Handler).
   Rein clientseitig, keine neue Funktion, nur eine andere Darstellung. */
.quick-actions-dropdown { position: relative; display: inline-block; margin-top: 18px; z-index: 1; }
.quick-actions-btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  background: var(--surface-strong);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 10px 18px;
  color: var(--text);
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 13px;
  cursor: pointer;
}
.quick-actions-btn:hover { border-color: var(--border-hover); }
.quick-actions-btn .chev { font-size: 10px; transition: transform .15s ease; }
.quick-actions-dropdown.open .quick-actions-btn .chev { transform: rotate(180deg); }
.quick-actions-menu {
  display: none;
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  min-width: 220px;
  background: #150c29;
  border: 1px solid var(--border-hover);
  border-radius: 10px;
  box-shadow: 0 10px 30px rgba(0,0,0,0.5);
  padding: 6px;
  z-index: 50;
}
.quick-actions-dropdown.open .quick-actions-menu { display: block; }
.quick-actions-menu a {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 9px 10px;
  border-radius: 6px;
  color: var(--text);
  text-decoration: none;
  font-size: 13px;
}
.quick-actions-menu a:hover { background: rgba(255,255,255,0.07); }

/* Bot-Module - echter Ein/Aus-Umschalter der Overlays direkt im Dashboard
   (siehe /panel/settings, GET/POST /api/panel/settings/overlays-enabled/:key/toggle).
   NACHTRAG (23.08.2026, Nutzer-Wunsch "mehr Leben mehr Struktur Zauber",
   angelehnt an "Nexus Mod"-Referenzbild "Active Overlays" mit echten
   Schaltern statt reiner Anzeige): war bisher bewusst nur Anzeige (siehe
   alter Kommentar unten), jetzt echte Schalter über denselben, bereits
   bestehenden Endpunkt wie /panel/settings - KEIN zweiter
   Umschalt-Mechanismus, nur ein zweiter, schnellerer Zugang zum
   bestehenden. */
.module-status-list { display: flex; flex-direction: column; gap: 4px; }
.module-status-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 8px 4px;
  border-top: 1px solid var(--border);
  font-size: 12.5px;
}
.module-status-item:first-child { border-top: none; }
.module-status-pill {
  font-size: 10px;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: .04em;
  padding: 3px 9px;
  border-radius: 999px;
  background: rgba(60,242,149,0.12);
  border: 1px solid rgba(60,242,149,0.35);
  color: var(--ok);
}
.module-status-pill.off { background: var(--surface-strong); border-color: var(--border); color: var(--text-faint); }
.module-status-footer { margin-top: 10px; text-align: right; }
.module-status-footer a { font-size: 12px; color: var(--violet); text-decoration: none; font-weight: 700; }
.module-status-footer a:hover { text-decoration: underline; }

/* NACHTRAG (23.08.2026, "mehr Leben mehr Struktur Zauber", Top-Clips-Kachel
   auf dem Dashboard): kompakte Karten mit echtem Thumbnail + Aufrufzahl,
   Klick öffnet den echten Clip direkt auf Twitch (neuer Tab). */
.top-clips-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 12px; }
.top-clip-card { display: block; text-decoration: none; border: 1px solid var(--border); border-radius: 12px; overflow: hidden; background: var(--surface-strong); transition: border-color .15s ease, transform .15s ease; }
.top-clip-card:hover { border-color: var(--magenta); transform: translateY(-2px); }
.top-clip-thumb { width: 100%; aspect-ratio: 16/9; object-fit: cover; display: block; background: var(--surface); }
.top-clip-body { padding: 8px 10px; }
.top-clip-title { font-size: 12.5px; font-weight: 700; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.top-clip-meta { font-size: 11px; color: var(--text-faint); margin-top: 3px; }

/* NACHTRAG (23.08.2026, Nutzer-Wunsch "bei den ganzen sehen können wie es
   wirklich aussieht bevor man es live macht"): gemeinsamer Rahmen für die
   Live-Vorschau-iframes (zeigen exakt das echte OBS-Overlay) - vorher nur
   auf Subathon/Bingo/Win-Challenge einzeln inline gestylt, jetzt eine
   Klasse für alle Overlay-Seiten (siehe giveaway.html/poll.html/
   wheel.html/subathon.html). */
.overlay-preview-frame {
  margin-bottom: 16px;
  padding: 16px;
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: 12px;
  display: flex;
  justify-content: center;
}
.overlay-preview-frame iframe { width: 100%; max-width: 420px; height: 280px; border: 0; background: transparent; }

/* NACHTRAG (23.08.2026, Nutzer-Wunsch "Ankündigung kann man ja in die
   Startseite einbauen"): dieselbe Post-Karten-Optik wie /panel/news, hier
   global statt nur in news.html's eigenem <style>-Block, damit die neue
   Ankündigungen-Kachel auf der Startseite (index.html) genauso aussieht. */
.news-post { background: var(--surface-strong); border: 1px solid var(--border); border-left: 3px solid var(--border); border-radius: 12px; padding: 14px 16px; margin-bottom: 10px; }
.news-post:last-child { margin-bottom: 0; }
.news-post-today { border-left-color: #c4a5ff; }
.news-post-update { border-left-color: var(--ok); }
.news-post-bugfix { border-left-color: var(--down); }
.news-post-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 10px; margin-bottom: 6px; }
.news-post-badge { font-size: 11px; padding: 3px 9px; border-radius: 20px; font-weight: 700; white-space: nowrap; }
.news-post-badge.today { background: rgba(124,58,237,0.18); color: #c4a5ff; }
.news-post-badge.update { background: rgba(60,242,149,0.15); color: var(--ok); }
.news-post-badge.bugfix { background: rgba(255,77,109,0.15); color: var(--down); }
.news-post-title { font-family: var(--font-display); font-weight: 800; font-size: 14px; color: var(--text); }
.news-post-meta { font-size: 11px; color: var(--text-faint); }
/* NACHTRAG (23.08.2026, 2. Runde, "kann man immer noch nicht richtig
   lesen"): "white-space:pre-wrap" ist raus - panel.js baut jetzt echte
   <p>/<ul><li>-Elemente (siehe renderMarkdownLiteStart), Zeilen mit
   führendem "-"/"*" werden also zu richtigen Aufzählungspunkten statt als
   wörtlicher Bindestrich-Text durchgereicht zu werden. */
.news-post-body { font-size: 13px; color: var(--text-dim); margin-top: 6px; line-height: 1.5; }
.news-post-body p { margin: 0 0 8px; }
.news-post-body p:last-child { margin-bottom: 0; }
.news-post-body ul { margin: 0 0 8px; padding-left: 18px; }
.news-post-body ul:last-child { margin-bottom: 0; }
.news-post-body li { margin-bottom: 3px; }
.news-post-body li::marker { color: var(--magenta); }
.news-post-body strong { color: var(--text); font-weight: 800; }
.news-post-body code { background: rgba(255,255,255,0.08); padding: 1px 6px; border-radius: 5px; font-size: 11.5px; font-family: 'Courier New', monospace; color: #ffd479; }

/* NACHTRAG (23.08.2026, "genau wie die Nexus-Mod-Vorlage", Live-Poll-
   Widget auf dem Dashboard): echte Stimmen als Balken, prozentual zur
   höchsten Option skaliert (kein fester Gesamt-Skala-Wert nötig). */
.poll-bar-row { margin-bottom: 10px; }
.poll-bar-label { display: flex; justify-content: space-between; font-size: 12.5px; color: var(--text-dim); margin-bottom: 4px; }
.poll-bar-label b { color: var(--text); }
.poll-bar-track { height: 8px; border-radius: 5px; background: var(--surface-strong); border: 1px solid var(--border); overflow: hidden; }
.poll-bar-fill { height: 100%; border-radius: 5px; background: linear-gradient(90deg, var(--violet), var(--magenta)); transition: width .3s ease; }

/* NACHTRAG (23.08.2026, "genau wie die Nexus-Mod-Vorlage"): Gewinnspiel-
   Status + Wortfilter-Kachel auf dem Dashboard. */
.giveaway-stat { display: flex; flex-direction: column; gap: 2px; }
.giveaway-stat .label { color: var(--text-faint); font-size: 10.5px; text-transform: uppercase; letter-spacing: .04em; }
.giveaway-stat .value { font-family: var(--font-display); font-size: 18px; font-weight: 800; }
.word-filter-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 2px; }
.word-filter-chip { background: var(--surface-strong); border: 1px solid var(--border); border-radius: 20px; padding: 4px 11px; font-size: 12px; color: var(--text-dim); font-family: 'Courier New', monospace; }
.word-filter-meta { font-size: 12px; color: var(--text-faint); margin-top: 10px; display: flex; gap: 14px; flex-wrap: wrap; }
.word-filter-meta b { color: var(--text-dim); }

/* Echter Klick-Schalter (statt der reinen Pill oben) - ersetzt
   .module-status-pill innerhalb von .module-status-item, wenn JS ihn
   erzeugt (siehe loadOverlayModules() in panel.js). Eigene Klasse statt
   die Pill umzubauen, damit andere Seiten, die .module-status-pill evtl.
   noch woanders read-only nutzen, unangetastet bleiben. */
.module-toggle {
  position: relative;
  width: 38px;
  height: 21px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--surface-strong);
  cursor: pointer;
  flex-shrink: 0;
  padding: 0;
  transition: background .18s ease, border-color .18s ease;
}
.module-toggle::before {
  content: "";
  position: absolute;
  top: 2px; left: 2px;
  width: 15px; height: 15px;
  border-radius: 50%;
  background: var(--text-faint);
  transition: transform .18s ease, background .18s ease;
}
.module-toggle.on {
  background: rgba(60,242,149,0.18);
  border-color: rgba(60,242,149,0.5);
}
.module-toggle.on::before {
  transform: translateX(17px);
  background: var(--ok);
  box-shadow: 0 0 8px rgba(60,242,149,0.6);
}
.module-toggle:disabled { opacity: .5; cursor: wait; }
.module-toggle:focus-visible { outline: 2px solid var(--magenta); outline-offset: 2px; }

/* Radial-Fortschrittsring fürs Follower-Ziel (NACHTRAG 23.08.2026, gleicher
   Nutzer-Wunsch wie oben) - zusätzlich zum bestehenden linearen Balken
   (.goal-track bleibt unverändert bestehen), rein per conic-gradient +
   CSS-Variable --pct (0-100, wird von panel.js gesetzt), kein SVG/Canvas
   nötig. Zeigt ausschließlich echte, bereits berechnete Prozentzahlen aus
   loadTotals() - keine erfundenen Werte. */
/* NACHTRAG (23.08.2026, 2. Runde, Nutzer-Feedback "Follower-Ziel hängt
   manchmal"): ohne registrierten Typ behandelt der Browser "--pct" als
   reinen Text, nicht als Zahl - "transition: background" auf einem
   conic-gradient, der so eine Variable nutzt, kann dadurch je nach
   Browser/Timing hängenbleiben bzw. gar nicht sauber neu zeichnen, bis
   irgendwas anderes einen Reflow auslöst (z.B. Fenster-Resize). "@property"
   registriert --pct fest als Zahl, damit der Ring bei jedem
   loadTotals()-Update zuverlässig neu berechnet/animiert wird. */
@property --pct {
  syntax: '<number>';
  inherits: true;
  initial-value: 0;
}
.radial-progress {
  --pct: 0;
  width: 84px;
  height: 84px;
  border-radius: 50%;
  background: conic-gradient(var(--magenta) calc(var(--pct) * 1%), var(--surface-strong) 0);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  transition: background 1s ease;
}
.radial-progress::before {
  content: "";
  position: absolute;
}
.radial-progress-inner {
  width: 66px;
  height: 66px;
  border-radius: 50%;
  background: var(--bg);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 15px;
  color: var(--text);
}

/* Kleine, echte Kennzahlen-Chips im Willkommens-Card (Bot-Uptime,
   Discord-Ping) - NACHTRAG (23.08.2026): nutzt Felder, die
   /api/panel/dashboard schon immer zurückgibt (botStartTime, discord.ping),
   bisher aber nirgends im UI angezeigt wurden - füllt die vorher recht
   leere Fläche der Willkommens-Karte mit echten statt erfundenen Daten. */
.hero-quickstats { display: flex; gap: 8px; margin-top: 12px; flex-wrap: wrap; }
.hero-quickstat {
  display: flex;
  align-items: center;
  gap: 7px;
  background: rgba(255,255,255,0.04);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 7px 12px;
  font-size: 12px;
  color: var(--text-dim);
}
.hero-quickstat b { color: var(--text); font-family: var(--font-display); }

/* Quick Mod Tools - echte Timeout/Bann-Aktionen über die bestehende
   /api/panel/modtools-API (dieselbe wie /panel/modtools), nur direkt vom
   Dashboard aus erreichbar statt erst dorthin wechseln zu müssen. */
.quick-mod-form { display: flex; flex-direction: column; gap: 10px; }
.quick-mod-input {
  width: 100%;
  background: var(--surface-strong);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 10px 12px;
  color: var(--text);
  font-family: var(--font-body);
  font-size: 13.5px;
}
.quick-mod-input:focus { outline: none; border-color: var(--border-hover); }
.quick-mod-actions { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.quick-mod-actions .btn { justify-content: center; padding: 10px 14px; font-size: 13px; }
.quick-mod-actions .btn.danger { background: linear-gradient(135deg, var(--down), #c62a49); }
.quick-mod-hint { font-size: 11px; color: var(--text-faint); }
.quick-mod-links { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 4px; }
.quick-mod-links a {
  font-size: 11.5px;
  color: var(--text-dim);
  background: var(--surface-strong);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 5px 11px;
  text-decoration: none;
}
.quick-mod-links a:hover { border-color: var(--border-hover); color: var(--text); }

/* Echte Benachrichtigungs-Zahl an der Topbar-Glocke (siehe sidebar.js ->
   renderTopbar()) - zählt echte, kürzlich passierte Ereignisse aus
   /api/panel/activity, keine erfundene Zahl. Bleibt unsichtbar, solange
   es nichts Neues gibt. */
.topbar-bell { position: relative; }
.topbar-bell .bell-badge {
  position: absolute;
  top: -4px;
  right: -4px;
  min-width: 15px;
  height: 15px;
  padding: 0 3px;
  border-radius: 999px;
  background: var(--magenta);
  color: #fff;
  font-size: 9px;
  font-weight: 800;
  display: flex;
  align-items: center;
  justify-content: center;
  line-height: 1;
  box-shadow: 0 0 0 2px var(--bg-2);
}
/* NACHTRAG (23.08.2026, Nutzer-Wunsch "gibt's da nicht eine Möglichkeit,
   dass bei neuen Infos/Updates ein Ping an der Glocke kommt"): sanftes
   Pulsieren des Badges, solange etwas Ungelesenes da ist - reine Optik,
   kein Ton (Autoplay-Sound wäre im Browser ohnehin unzuverlässig/nervig). */
.topbar-bell.has-ping .bell-badge { animation: bellPing 1.6s ease-in-out infinite; }
@keyframes bellPing {
  0%, 100% { box-shadow: 0 0 0 2px var(--bg-2), 0 0 0 0 rgba(255,83,212,0.55); }
  50% { box-shadow: 0 0 0 2px var(--bg-2), 0 0 0 5px rgba(255,83,212,0); }
}
@media (prefers-reduced-motion: reduce) {
  .topbar-bell.has-ping .bell-badge { animation: none; }
}

/* ============================================================
   PANEL-CONFIRM (NACHTRAG 23.08.2026, Nutzer-Feedback "Beim chat leeren
   kommt die standart anzeige"): ersetzt den nativen, browser-eigenen
   confirm()-Dialog (der aussieht wie eine System-Warnmeldung und nicht zum
   Panel-Design passt) durch ein eigenes, dunkles Modal im Glow-Card-Look -
   siehe panelConfirm() in sidebar.js, wird auf jeder Seite geladen und
   liefert genau wie confirm() ein Promise<boolean> zurück, nur eben schön.
   ============================================================ */
.panel-confirm-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(3,1,10,0.72);
  backdrop-filter: blur(3px);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 9999;
  padding: 20px;
  animation: panelConfirmFadeIn .15s ease;
}
@keyframes panelConfirmFadeIn { from { opacity: 0; } to { opacity: 1; } }
.panel-confirm-box {
  width: 100%;
  max-width: 400px;
  background: var(--bg-2);
  border: 1px solid var(--border-hover);
  border-radius: var(--radius);
  padding: 22px;
  box-shadow: 0 30px 70px -20px rgba(0,0,0,0.6), 0 0 0 1px rgba(155,92,255,0.08);
  animation: panelConfirmPop .18s ease;
}
@keyframes panelConfirmPop { from { transform: scale(.94) translateY(6px); opacity: 0; } to { transform: scale(1) translateY(0); opacity: 1; } }
.panel-confirm-title {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 15px;
  margin-bottom: 10px;
  display: flex;
  align-items: center;
  gap: 8px;
}
.panel-confirm-msg { color: var(--text-dim); font-size: 13.5px; line-height: 1.5; margin-bottom: 20px; }
.panel-confirm-actions { display: flex; justify-content: flex-end; gap: 10px; }
.panel-confirm-actions .btn { padding: 10px 20px; font-size: 13.5px; }
.panel-confirm-actions .btn.danger { background: linear-gradient(135deg, var(--down), #c62a49); }
