/* ── Reset & Base ── */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html { touch-action: manipulation; }
button, a, input, select, label { touch-action: manipulation; user-select: none; }

:root {
  --bg:          #f4f6fa;
  --surface:     #ffffff;
  --sidebar-bg:  #1a1f2e;
  --sidebar-txt: #a0aec0;
  --sidebar-active-bg: #2d3748;
  --sidebar-active-txt: #ffffff;
  --accent:      #4f6ef7;
  --accent-dark: #3b55d4;
  --danger:      #e53e3e;
  --text:        #1a202c;
  --text-muted:  #718096;
  --border:      #e2e8f0;
  --radius:      12px;
  --shadow:      0 2px 12px rgba(0,0,0,.08);
  --transition:  .2s ease;
  /* Spacing tokens — overridden per breakpoint */
  --space-content: 28px;
  --space-card:    24px;
  /* Erfolgs-Stufen (Iron…Diamant) — feste Farben, bewusst wie bei den
     ELO-Rating-Stufen (js/elo.js) unabhängig vom Hell/Dunkel-Theme, damit
     die Stufenfarbe als Wiedererkennungsmerkmal in beiden Themes gleich bleibt. */
  --tier-iron:     #8a8f98;
  --tier-bronze:   #b3702f;
  --tier-silver:   #9aa5b1;
  --tier-gold:     #d7a233;
  --tier-platinum: #4fb8c4;
  --tier-diamond:  #6f8cf7;
  /* Kreative Stufenrahmen (Aufgabe 2, Nutzer-Vorgabe "wie League-of-Legends-
     Ligenrahmen"): steigende Wertigkeit über mehrfarbige Verläufe statt eines
     einzelnen Rahmenfarbtons. Eisen bleibt bewusst einfarbig/matt (siehe
     .ach-item--family.ach-item--unlocked.tier-iron weiter unten) — ab Bronze
     übernehmen diese Verläufe den Rahmen (Gradient-Border-Technik, siehe dort).
     Feste Farben unabhängig vom Hell/Dunkel-Theme, aus demselben Grund wie die
     --tier-* Basisfarben oben (Wiedererkennungsmerkmal bleibt gleich). */
  --tier-bronze-grad:   linear-gradient(135deg, #7a4e22, #d99a4e, #8a5a26 60%, #d99a4e);
  --tier-silver-grad:   linear-gradient(135deg, #6b7783, #eef2f5, #9aa5b1 55%, #eef2f5);
  --tier-gold-grad:     linear-gradient(135deg, #9c6f1a, #f6d780, #d7a233 55%, #fbe7ad);
  --tier-platinum-grad: linear-gradient(120deg, #1f6e78, #a6f0f5, #4fb8c4 50%, #eafeff);
  --tier-diamond-grad:  linear-gradient(115deg, #5c7ef2, #b18cf7, #f78cd8, #8cf7ea, #5c7ef2);
}

body.dark {
  --bg:          #0f1117;
  --surface:     #1a1f2e;
  --sidebar-bg:  #0d1117;
  --sidebar-active-bg: #1a1f2e;
  --border:      #2d3748;
  --text:        #e2e8f0;
  --text-muted:  #718096;
}

html { height: 100%; background: var(--sidebar-bg); }
body { height: 100%; font-family: 'Segoe UI', system-ui, sans-serif; background: var(--bg); color: var(--text); }

/* ── Layout ── */
.app {
  display: flex;
  height: 100vh;
  height: 100dvh; /* Dynamic viewport: passt sich Browser-Chrome auf iOS/Android an */
  overflow: hidden;
  /* Safe-area für iPhone Notch / Home-Indicator */
  padding-bottom: env(safe-area-inset-bottom, 0px);
  padding-left:   env(safe-area-inset-left,   0px);
  padding-right:  env(safe-area-inset-right,  0px);
  background: var(--bg);
}

/* ── Sidebar ── */
.sidebar {
  width: 220px;
  background: var(--sidebar-bg);
  display: flex;
  flex-direction: column;
  flex-shrink: 0;
  padding: 20px 0;
  transition: width .25s ease;
  overflow-x: hidden;
  overflow-y: auto;
  scrollbar-width: none;
  position: relative;
  z-index: 100;
}
.sidebar::-webkit-scrollbar { display: none; }

/* Eingeklappt */
.app.sidebar-collapsed .sidebar { width: 44px; }
.app.sidebar-collapsed .logo-text,
.app.sidebar-collapsed .nav-label { display: none; }
.app.sidebar-collapsed .sidebar-header { justify-content: center; padding: 0 0 20px; }
.app.sidebar-collapsed .nav-item { justify-content: center; padding: 12px; }
.app.sidebar-collapsed .sidebar-toggle-btn { justify-content: center; }

/* Toggle-Button */
.sidebar-toggle-btn {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 8px;
  padding: 10px 12px;
  border-radius: 8px;
  border: none;
  background: transparent;
  color: var(--sidebar-txt);
  font-size: 1rem;
  font-weight: 700;
  cursor: pointer;
  transition: background var(--transition), color var(--transition);
  white-space: nowrap;
  user-select: none;
}
.sidebar-toggle-btn:hover { background: rgba(255,255,255,.06); color: #fff; }

.sidebar-header {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 0 20px 28px;
  border-bottom: 1px solid rgba(255,255,255,.06);
}
.logo { font-size: 1.6rem; }
.logo-text { color: #fff; font-size: 1.1rem; font-weight: 700; letter-spacing: .3px; }

.nav-list { list-style: none; padding: 16px 0; flex: 1; }
.nav-footer { flex: 0; padding: 4px 0 0; border-top: 1px solid rgba(255,255,255,.08); }
.nav-footer-item { font-size: .8rem; opacity: .65; }
.nav-footer-item:hover { opacity: 1; }

/* ── Legal Pages (Impressum / Datenschutz) ── */
.legal-card { max-width: 100%; grid-column: 1 / -1; }
.legal-card h1 { font-size: 1.4rem; margin-bottom: 20px; }
.legal-card h2 { font-size: 1.05rem; margin: 24px 0 8px; color: var(--text); }
.legal-card h3 { font-size: .95rem; margin: 16px 0 6px; color: var(--text); }
.legal-card p  { font-size: .88rem; color: var(--text-muted); line-height: 1.6; margin-bottom: 10px; }
.legal-card ul { font-size: .88rem; color: var(--text-muted); line-height: 1.6; padding-left: 20px; margin-bottom: 10px; }
.legal-card ul.index { list-style: none; padding-left: 0; }
.legal-card ul.index li { margin-bottom: 4px; }
.legal-card .index-link { color: var(--accent); text-decoration: none; font-size: .88rem; }
.legal-card .index-link:hover { text-decoration: underline; }
.legal-card a { color: var(--accent); word-break: break-all; }
.legal-card .seal { margin-top: 24px; font-size: .8rem; }
.legal-card .seal a { font-size: .8rem; }

.nav-item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 20px;
  cursor: pointer;
  color: var(--sidebar-txt);
  border-radius: 0;
  transition: background var(--transition), color var(--transition);
  margin: 2px 8px;
  border-radius: 8px;
  user-select: none;
}
.nav-item:hover { background: rgba(255,255,255,.06); color: #fff; }
.nav-item.active { background: var(--accent); color: #fff; }

.nav-icon { font-size: 1.1rem; width: 22px; text-align: center; }
.nav-label { font-size: .9rem; font-weight: 500; }

.nav-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--accent);
  color: #fff;
  border-radius: 10px;
  font-size: .65rem;
  font-weight: 700;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  margin-left: 4px;
  line-height: 1;
  vertical-align: middle;
}

/* ── Main ── */
.main { flex: 1; display: flex; flex-direction: column; overflow: hidden; }

.topbar {
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  padding: 11px 28px;
  box-shadow: 0 1px 4px rgba(0,0,0,.04);
}
/* Gibt bei enger Topbar den Platz her, damit der Profil-Knopf rechts nie
   schrumpft und der Benutzername vollstaendig lesbar bleibt (siehe
   .topbar-profile-btn: flex-shrink: 0). min-width: 0 ist noetig, weil ein
   Flex-Item sonst nicht unter seine Inhaltsbreite schrumpfen kann. */
.page-title {
  font-size: 1.1rem;
  font-weight: 700;
  color: var(--text);
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.content { flex: 1; min-width: 0; overflow-y: auto; padding: var(--space-content); }
.content.game-active { overflow-y: auto; padding: 16px; display: flex; flex-direction: column; min-height: 0; }

/* ── Tab Content ── */
.tab-content { display: none; }
.tab-content.active { display: block; }
#game-view.active { display: flex; flex-direction: column; flex: 1; min-height: 0; }

/* ── Card Grid ── */
.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
  gap: 20px;
}
.card {
  background: var(--surface);
  border-radius: var(--radius);
  padding: var(--space-card);
  box-shadow: var(--shadow);
  border: 1px solid var(--border);
}
.card h2 { font-size: 1rem; font-weight: 600; margin-bottom: 18px; color: var(--text); }
.card-header-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 18px; }
.card.full-width { grid-column: 1 / -1; display: flex; justify-content: center; }
/* Karten, die nicht ueber die ganze Seitenbreite laufen, aber linksbuendig
   bleiben sollen (Spieler, Rangliste): ihr Inhalt sind Listenzeilen, die auf
   einem grossen Monitor sonst auseinandergerissen wirken — Name links,
   Knoepfe ganz rechts. margin-right:auto haelt sie am linken Rand.
   Obergrenze wie bei #config-gametype (Neues Spiel) und
   #tournament-settings-card (Turnier), damit alle Karten der App im gleichen
   Raster stehen. Frueher 65 % der Seitenbreite, was je nach Monitor eine
   andere Breite ergab als bei den beiden anderen. */
.card.full-width.card-narrow {
  /* width:100% ist hier ZWINGEND, nicht nur Kosmetik: die Karte ist ein
     Grid-Element mit `grid-column: 1 / -1`. Ein automatischer Seitenrand
     (frueher margin-right:auto fuer die Linksbuendigkeit) hebt bei
     Grid-Elementen das Strecken auf — die Karte richtete sich dann nach ihrem
     INHALT und war je Reiter unterschiedlich breit (Freundesliste schmaler
     als die Tabelle der lokalen Spieler), die Obergrenze wurde nie erreicht.
     Mit einer festen Breite fuellt sie ihren Bereich und wird von max-width
     begrenzt; linksbuendig steht sie ueber justify-self. */
  width: 100%;
  max-width: 760px;
  justify-self: start;
  justify-content: flex-start;
}
/* .card.full-width ist ein Flex-Container — der Inhalt muss die schmalere
   Karte trotzdem ausfuellen, sonst schrumpft die Liste auf ihre Textbreite. */
.card.full-width.card-narrow > * { flex: 1; min-width: 0; }
/* Die frueher noetige Freigabe ab 1100px abwaerts entfaellt: 760px ist keine
   Einschraenkung mehr, sobald der Inhaltsbereich selbst schmaler ist. */
.card-pair {
  grid-column: 1 / -1;
  display: flex;
  gap: 20px;
  align-items: stretch;
}
.card-pair > .card { flex: 1; min-width: 0; margin: 0; }
.card-tabs {
  display: flex;
  gap: 0;
  margin-bottom: 20px;
  border-bottom: 2px solid var(--border);
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.card-tabs::-webkit-scrollbar { display: none; }
.card-tab { padding: 6px 16px 10px; cursor: pointer; border: none; background: none; font-size: .9rem; font-weight: 500; color: var(--text-muted); border-bottom: 2px solid transparent; margin-bottom: -2px; transition: color var(--transition), border-color var(--transition); white-space: nowrap; flex-shrink: 0; min-height: 44px; display: inline-flex; align-items: center; }
.card-tab:hover { color: var(--text); }
.card-tab.active { color: var(--accent); border-bottom-color: var(--accent); }
#config-players-row { grid-column: 1 / -1; display: flex; gap: 20px; align-items: stretch; }
#config-players-row > .card { margin: 0; }
/* Seit der Start-Knopf im Fuss der Karte steht, ist die Konfiguration das
   einzige Element der Zeile. Ohne feste Breite haengt sie an ihrem Inhalt und
   springt beim Wechsel des Spieltyps in der Breite; die Obergrenze verhindert,
   dass die schmalen Zaehler auf grossen Monitoren auseinandergezogen werden. */
#config-gametype { flex: 1 1 auto; min-width: 0; max-width: 760px; }
#new-game-players { flex: 0 0 auto; display: flex; flex-direction: column; }
#player-selection-row { flex: 1; min-height: 0; }
#new-game-players .saved-players-chips {
  display: grid;
  grid-auto-flow: column;
  grid-template-rows: repeat(var(--chip-rows, 3), auto);
  gap: 8px;
  align-content: start;
}

/* Turnier-Tab: Einstellungen + aktive Turniere als eigene Zeile statt als
   zwei gleich breite Rasterzellen — die Einstellungen brauchen mehr Platz
   (Modus- und Check-Out-Knopfreihen), die Liste daneben weniger. Breiten
   bewusst wie bei #config-gametype im Tab "Neues Spiel".
   flex-wrap statt eigenem Breakpoint: reicht der Platz nicht mehr fuer beide,
   rutscht die Liste von selbst unter die Einstellungen. */
#tournament-config-row {
  grid-column: 1 / -1;
  display: flex;
  flex-wrap: wrap;
  gap: 20px;
  align-items: stretch;
}
#tournament-config-row > .card { margin: 0; }
#tournament-settings-card { flex: 1 1 480px; min-width: 0; max-width: 760px; }
/* Bewusst schmal: die Liste traegt nur Turniernamen und einen Knopf. Ohne
   Obergrenze bekaeme sie den gesamten Rest der Zeile und waere damit fast so
   breit wie die Einstellungen daneben. */
#tournament-active-card   { flex: 1 1 300px; min-width: 0; max-width: 360px; }

#tv-info-players-row { grid-column: 1 / -1; display: flex; gap: 20px; align-items: stretch; }
#tv-info-players-row > .card { margin: 0; }
#tv-player-card { flex: 0 0 auto; display: flex; flex-direction: column; }
#tv-chips-row { flex: 1; min-height: 0; gap: 24px; }
#tv-player-card .saved-players-chips {
  display: grid;
  grid-auto-flow: column;
  grid-template-rows: repeat(var(--tv-chip-rows, 3), auto);
  gap: 8px;
  align-content: start;
}

/* ── Buttons ── */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 10px 20px;
  border-radius: 8px;
  font-size: .9rem;
  font-weight: 600;
  cursor: pointer;
  border: none;
  transition: background var(--transition), opacity var(--transition), transform .1s;
}
.btn:active { transform: scale(.97); }
.btn-primary { background: var(--accent); color: #fff; }
.btn-primary:hover { background: var(--accent-dark); }
.btn-primary:disabled { opacity: .45; cursor: not-allowed; transform: none; }
.btn-secondary { background: var(--border); color: var(--text); }
/* Hover aus dem Farbschema ableiten statt fest zu verdrahten. Vorher stand
   hier #d1d9e6 — ein helles Grau. Im dunklen Design sprang der Knopf beim
   Ueberfahren damit von #2d3748 auf fast Weiss. Der Grundzustand nutzt
   var(--border) und passt sich an, der Hover tat es nicht.
   Die Beimischung von --text macht die Flaeche im hellen Design etwas dunkler
   und im dunklen etwas heller — in beiden Faellen also dezent abgesetzt. */
.btn-secondary:hover { background: color-mix(in srgb, var(--border) 85%, var(--text)); }
.btn-secondary:focus,
.btn-secondary:focus-visible { background: var(--border); color: var(--text); outline: none; }
.btn:focus:not(:focus-visible) { outline: none; }
.btn-danger { background: var(--danger); color: #fff; }
.btn-danger:hover { background: #c53030; }
.btn-large { padding: 14px 40px; font-size: 1rem; min-width: 200px; }
.btn-sm { padding: 4px 10px; font-size: .8rem; min-width: unset; }
.btn-group { display: flex; gap: 12px; flex-wrap: wrap; }

/* ── Mode Buttons ── */
.mode-buttons { display: flex; gap: 10px; }
.mode-btn {
  flex: 1;
  min-width: 0;
  padding: 12px;
  border-radius: 8px;
  border: 2px solid var(--border);
  background: transparent;
  font-size: 1rem;
  font-weight: 700;
  cursor: pointer;
  color: var(--text-muted);
  transition: all var(--transition);
}
.mode-btn:hover { border-color: var(--accent); color: var(--accent); }
.mode-btn.selected { border-color: var(--accent); background: var(--accent); color: #fff; }

/* ── Input ── */
.input {
  width: 100%;
  padding: 10px 14px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--bg);
  color: var(--text);
  font-size: .9rem;
  outline: none;
  transition: border-color var(--transition);
}
.input:focus { border-color: var(--accent); }

.form-group { margin-bottom: 14px; }
.label { display: block; font-size: .8rem; font-weight: 600; color: var(--text-muted); margin-bottom: 6px; text-transform: uppercase; letter-spacing: .4px; }

/* ── Player Add Row ── */
.player-add-row { display: flex; gap: 10px; margin-bottom: 14px; }
.player-add-row .input { flex: 1; }

/* ── Player List (in game) ── */
.player-list { list-style: none; display: flex; flex-direction: column; gap: 8px; }
.player-list-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  background: var(--bg);
  padding: 10px 14px;
  border-radius: 8px;
  font-size: .9rem;
  font-weight: 500;
}
.remove-btn {
  background: none;
  border: none;
  cursor: pointer;
  color: var(--text-muted);
  font-size: 1rem;
  line-height: 1;
  transition: color var(--transition);
}
.remove-btn:hover { color: var(--danger); }

/* ── Table ── */
.table-wrapper {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  /* Scroll shadow hint */
  background:
    linear-gradient(to right, var(--surface) 30%, rgba(255,255,255,0)),
    linear-gradient(to right, rgba(255,255,255,0), var(--surface) 70%) 100% 0,
    linear-gradient(to right, rgba(0,0,0,.07), transparent),
    linear-gradient(to left,  rgba(0,0,0,.07), transparent) 100% 0;
  background-repeat: no-repeat;
  background-size: 40px 100%, 40px 100%, 14px 100%, 14px 100%;
  background-attachment: local, local, scroll, scroll;
}
body.dark .table-wrapper {
  background:
    linear-gradient(to right, var(--surface) 30%, rgba(26,31,46,0)),
    linear-gradient(to right, rgba(26,31,46,0), var(--surface) 70%) 100% 0,
    linear-gradient(to right, rgba(0,0,0,.2), transparent),
    linear-gradient(to left,  rgba(0,0,0,.2), transparent) 100% 0;
  background-repeat: no-repeat;
  background-size: 40px 100%, 40px 100%, 14px 100%, 14px 100%;
  background-attachment: local, local, scroll, scroll;
}
/* ── Datentabellen: EIN Layout fuer alle Tabellen der App ───────────────────
   Vorlage ist die Kennzahlen-Tabelle im Statistik-Tab. Statt jede Tabelle
   einzeln zu stylen (frueher sieben verschiedene Bloecke mit abweichenden
   Abstaenden, Schriftgroessen und Ausrichtungen) definiert dieser eine Block
   den gemeinsamen Look; die alten Klassennamen bleiben als Selektorliste
   erhalten, damit das vorhandene Markup unveraendert bleibt. Nur echt
   tabellenspezifische Ergaenzungen (fixierte Spalte, Spaltentrenner,
   Gruppen-Zebrastreifen) stehen weiter unten bei der jeweiligen Tabelle.

   Bausteine:
     .table-wrapper / .*-wrap   waagerechter Scroll-Container (die SEITE scrollt nie)
     thead th                   gedaempft, Grossbuchstaben, doppelte Trennlinie
     .data-table-group          Zwischenueberschrift als Akzentband ueber die Zeile
     .data-table-label          Beschriftungsspalte (erste Spalte)
     .data-table-best           hervorgehobener Bestwert
     .data-table--text          Modifier: linksbuendig statt Zahlenausrichtung
   Ausrichtung: erste Spalte links (Bezeichnung/Name), alle weiteren rechts —
   so stehen Zahlen unter Zahlen. Textlastige Tabellen nutzen --text. */
.table, .stats-cmp-table, .stats-compare-table, .stats-leg-table,
.standings-table, .rl-table, .admin-table {
  width: 100%;
  border-collapse: collapse;
  font-size: .88rem;
}
.table th, .stats-cmp-table th, .stats-compare-table th, .stats-leg-table th,
.standings-table th, .rl-table th, .admin-table th,
.table td, .stats-cmp-table td, .stats-compare-table td, .stats-leg-table td,
.standings-table td, .rl-table td, .admin-table td {
  padding: 9px 12px;
  text-align: right;
  white-space: nowrap;
  border-bottom: 1px solid var(--border);
  vertical-align: middle;
}
.table thead th, .stats-cmp-table thead th, .stats-compare-table thead th,
.stats-leg-table thead th, .standings-table thead th, .rl-table thead th,
.admin-table thead th {
  color: var(--text-muted);
  font-weight: 700;
  font-size: .74rem;
  text-transform: uppercase;
  letter-spacing: .06em;
  border-bottom: 2px solid var(--border);
}
.table th:first-child, .stats-cmp-table th:first-child, .stats-compare-table th:first-child,
.stats-leg-table th:first-child, .standings-table th:first-child, .rl-table th:first-child,
.admin-table th:first-child,
.table td:first-child, .stats-cmp-table td:first-child, .stats-compare-table td:first-child,
.stats-leg-table td:first-child, .standings-table td:first-child, .rl-table td:first-child,
.admin-table td:first-child { text-align: left; }
.table tbody tr:last-child td, .stats-cmp-table tbody tr:last-child td,
.stats-compare-table tbody tr:last-child td, .stats-leg-table tbody tr:last-child td,
.standings-table tbody tr:last-child td, .rl-table tbody tr:last-child td,
.admin-table tbody tr:last-child td { border-bottom: none; }
.table tbody tr:hover, .stats-cmp-table tbody tr:hover,
.stats-compare-table tbody tr:hover, .stats-leg-table tbody tr:hover,
.standings-table tbody tr:hover, .admin-table tbody tr:hover { background: var(--bg); }
/* Die Zwischenueberschrift ist keine Datenzeile — sie soll nicht hervorheben. */
.data-table-group:hover { background: none !important; }

/* Textlastige Tabellen (E-Mails, IDs, Freitext): durchgehend linksbuendig. */
.data-table--text th, .data-table--text td { text-align: left; white-space: normal; }

.data-table-label, .stats-cmp-label, .stats-compare-label { color: var(--text-muted); }
.data-table-best, .stats-cmp-best, .stats-compare-winner { color: var(--accent); font-weight: 700; }

/* Zwischenueberschrift innerhalb einer Tabelle ("Averages", "Scoring",
   "Gruppe A", "Set 1" …). Als reine Grossbuchstaben-Zeile in der Farbe der
   Beschriftungsspalte ging sie zwischen den Datenzeilen unter — deshalb ein
   eigenes Band ueber die volle Zeilenbreite mit Akzentbalken links. */
.data-table-group td, .stats-cmp-group td {
  text-align: left;
  padding: 10px 10px 10px 14px;
  font-size: .78rem;
  font-weight: 800;
  letter-spacing: .1em;
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--text);
  background: color-mix(in srgb, var(--accent) 12%, var(--surface));
  border-bottom: 1px solid var(--border);
  /* Luft zur vorherigen Datenzeile. Tabellenzeilen kennen kein margin, deshalb
     ein durchsichtiger oberer Rahmen: background-clip haelt den farbigen
     Streifen aus diesem Bereich heraus, sodass echter Leerraum entsteht.
     Akzentlinie oben und Balken links liegen als innere Schatten darin — die
     werden am Innenrand gezeichnet und laufen dadurch nicht in den Abstand. */
  border-top: 26px solid transparent;
  background-clip: padding-box;
  box-shadow: inset 4px 0 0 var(--accent), inset 0 2px 0 var(--accent);
}
/* Steht die Gruppe ganz oben, waere der Abstand nur ein Loch unter der Kopfzeile. */
tbody tr.data-table-group:first-child td,
tbody tr.stats-cmp-group:first-child td { border-top-width: 0; }
/* Erste Datenzeile einer Gruppe etwas Luft geben */
.data-table-group + tr td, .stats-cmp-group + tr td { padding-top: 10px; }

/* Dieselbe Optik ausserhalb von Tabellen (z. B. ueber den Kennzahlzeilen einer
   Partie-Karte in der Turnierstatistik). */
.data-group-band {
  margin: 18px -14px 8px;
  padding: 8px 10px 8px 14px;
  font-size: .74rem;
  font-weight: 800;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--text);
  background: color-mix(in srgb, var(--accent) 12%, var(--surface));
  border-top: 2px solid var(--accent);
  border-bottom: 1px solid var(--border);
  box-shadow: inset 4px 0 0 var(--accent);
}
.data-group-band:first-child { margin-top: 0; }

/* Gruppenband als SPALTEN-Ueberschrift (Kopfzeile mit colspan) — gleiche
   Optik wie .data-table-group, nur mittig und ohne oberen Abstand. */
.data-table-group-head {
  text-align: center !important;
  color: var(--text) !important;
  background: color-mix(in srgb, var(--accent) 12%, var(--surface));
  box-shadow: inset 0 2px 0 var(--accent);
  font-weight: 800;
  letter-spacing: .06em;
}

/* ── Turnier-Bestenliste (Nutzer-Feedback: „erstmal alles einfügen, was
   Sinn für ein Turnier macht") — durch die vielen Kennzahl-Spalten breiter
   als der Bildschirm. Scrollt waagerecht INNERHALB von .table-wrapper (s.o.,
   bereits overflow-x:auto), NICHT die Seite. Die Spielerspalte bleibt dabei
   fixiert sichtbar, damit eine Zeile beim Scrollen weiter zuordenbar ist. ── */
.tv-stats-sticky-col {
  position: sticky;
  left: 0;
  background: var(--surface);
  z-index: 1;
  border-right: 1px solid var(--border);
}
.tv-stats-table tbody tr:hover .tv-stats-sticky-col { background: var(--bg); }
/* Bei 15 Kennzahl-Spalten verschwimmen die Werte ohne senkrechte Trenner.
   Gestrichelt (Nutzer-Vorgabe), damit das Raster die Zeilenlinien nicht
   optisch überlagert. Die letzte Spalte bekommt keinen Trenner. */
.tv-stats-table th:not(:last-child),
.tv-stats-table td:not(:last-child) {
  border-right: 1px dashed var(--border);
}
/* Ausrichtung kommt aus dem gemeinsamen Datentabellen-Block (Bezeichnung
   links, Werte rechts). Seit die Tabelle transponiert ist, ist die fixierte
   erste Spalte die KENNWERT-Spalte, nicht mehr die Spielerspalte. Sie behält
   ihre durchgezogene Kante als klare Grenze zum scrollenden Teil. */
.tv-stats-table .tv-stats-sticky-col {
  border-right: 1px solid var(--border);
  text-align: left;
}
/* Das Gruppenband laeuft ueber die ganze Breite und braucht keinen Trenner. */
.tv-stats-table .data-table-group td { border-right: none; }
/* Icon-Knopf ausserhalb von Tabellen (Spieler bearbeiten in .players-row).
   Ohne eigene Regel stand dort ein Knopf im Browser-Standardlook. */
.icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: none;
  border: none;
  border-radius: 8px;
  cursor: pointer;
  color: var(--text-muted);
  padding: 6px;
  min-width: 32px;
  min-height: 32px;
  transition: color var(--transition), background var(--transition);
}
.icon-btn:hover {
  color: var(--accent);
  background: color-mix(in srgb, var(--accent) 12%, transparent);
}

.table .icon-btn {
  background: none;
  border: none;
  cursor: pointer;
  color: var(--text-muted);
  font-size: .95rem;
  transition: color var(--transition);
  padding: 8px;
  min-width: 36px;
  min-height: 36px;
}
.table .icon-btn:hover { color: var(--danger); }
.icon-btn-sep {
  display: inline-block;
  width: 1px;
  height: 14px;
  background: var(--border);
  vertical-align: middle;
  margin: 0 8px;
}
.table .icon-btn-danger { color: var(--danger); opacity: .45; }
.table .icon-btn-danger:hover { opacity: 1; }

/* ── Tournament List ── */
.tournament-list { display: flex; flex-direction: column; gap: 10px; }
.tournament-card {
  background: var(--bg);
  border-radius: 8px;
  padding: 14px 16px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  cursor: pointer;
  border: 1px solid transparent;
  transition: border-color var(--transition), background var(--transition);
}
.tournament-card:hover { border-color: var(--accent); background: rgba(79,110,247,.04); }
.tournament-card .t-name { font-weight: 600; }
.tournament-card .t-meta { font-size: .8rem; color: var(--text-muted); margin-top: 2px; }
.badge {
  display: inline-block;
  padding: 3px 10px;
  border-radius: 20px;
  font-size: .75rem;
  font-weight: 600;
  background: var(--accent);
  color: #fff;
}
.badge-ended { background: var(--text-muted); }

/* ── Toggle Switch ── */
.setting-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px 0;
  border-bottom: 1px solid var(--border);
  font-size: .9rem;
}
.setting-row:last-child { border-bottom: none; }

.toggle { position: relative; display: inline-block; width: 44px; height: 24px; }
.toggle input { opacity: 0; width: 0; height: 0; }
.toggle-slider {
  position: absolute;
  inset: 0;
  background: var(--border);
  border-radius: 24px;
  cursor: pointer;
  transition: background var(--transition);
}
.toggle-slider::before {
  content: '';
  position: absolute;
  width: 18px; height: 18px;
  left: 3px; top: 3px;
  background: #fff;
  border-radius: 50%;
  transition: transform var(--transition);
}
.toggle input:checked + .toggle-slider { background: var(--accent); }
.toggle input:checked + .toggle-slider::before { transform: translateX(20px); }

/* ── Dark Mode Time Inputs ── */
.dark-time-inputs {
  display: flex;
  align-items: center;
  gap: 6px;
}
.dark-time-inputs input[type="time"] {
  width: 110px;
  padding: 4px 8px;
  font-size: .875rem;
}

/* ── Voice Select Row (inline-style replaced) ── */
.voice-select-row {
  flex-direction: column;
  align-items: flex-start;
  gap: 8px;
}
.voice-select-inner {
  display: flex;
  gap: 8px;
  align-items: center;
  width: 100%;
}

/* ── Voice Volume Row ── */
.voice-volume-row {
  flex-direction: column;
  align-items: flex-start;
  gap: 8px;
}
.voice-volume-inner {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
}
.voice-volume-inner input[type="range"] {
  flex: 1;
  accent-color: var(--accent);
  height: 4px;
  cursor: pointer;
}
#voice-volume-label {
  font-size: .85rem;
  color: var(--text-muted);
  min-width: 36px;
  text-align: right;
}

/* ── Helper text ── */
.helper-text {
  color: var(--text-muted);
  font-size: .88rem;
  margin-bottom: 12px;
}

/* ── Counter center ── */
.counter-center {
  display: flex;
  justify-content: center;
  margin: 20px 0;
}

/* ── Game Options ── */
.game-options { margin-top: 20px; display: flex; flex-direction: column; gap: 16px; }

/* Nur der obere Abstand von .game-options, ohne dessen Flex-Layout. Fuer
   einzelne Optionsbloecke, die selbst schon eine .form-group sind — dort
   wuerde der gap sonst zwischen Ueberschrift und Bedienelement wirken und den
   Abstand groesser machen als in den benachbarten Bloecken. */
.game-options-spacing { margin-top: 20px; }

.sets-legs-row { display: flex; gap: 16px; flex-wrap: wrap; }
.sets-legs-row .form-group { flex: 1; margin-bottom: 0; min-width: 100px; }
/* Die Zeile selbst hat keinen Abstand nach unten — im Tab "Neues Spiel"
   steht sie im Flex-Container .game-options, der den Abstand ueber `gap`
   setzt. In den Turniereinstellungen folgt "Format" direkt darauf und klebte
   dadurch an den Zaehlern; dort also denselben Abstand wie zwischen zwei
   .form-group nachtragen. */
#turnier-tab-erstellen .sets-legs-row { margin-bottom: 14px; }
/* Turniername und Format-Auswahl nicht ueber die volle Kartenbreite ziehen —
   seit die Karte breiter ist, wirkte ein 700px breites Auswahlfeld mit einem
   kurzen Eintrag darin auseinandergezogen. */
#turnier-tab-erstellen .input { max-width: 420px; }

.counter {
  display: flex;
  align-items: center;
  gap: 0;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 8px;
  overflow: hidden;
  width: fit-content;
}
.counter-btn {
  width: 44px; height: 44px;
  border: none;
  background: transparent;
  font-size: 1.2rem;
  font-weight: 700;
  cursor: pointer;
  color: var(--text-muted);
  transition: background var(--transition), color var(--transition);
  line-height: 1;
}
.counter-btn:hover { background: var(--border); color: var(--accent); }
.counter-val {
  min-width: 42px;
  text-align: center;
  font-size: 1rem;
  font-weight: 700;
  color: var(--text);
  border-left: 1px solid var(--border);
  border-right: 1px solid var(--border);
  padding: 0 4px;
  line-height: 38px;
}

/* ── Saved Player Chips ── */
.saved-players-chips { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 6px; }
.player-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 14px;
  border-radius: 20px;
  border: 2px solid var(--border);
  background: var(--bg);
  font-size: .85rem;
  font-weight: 500;
  cursor: pointer;
  color: var(--text);
  transition: all var(--transition);
  user-select: none;
}
.player-chip:hover { border-color: var(--accent); color: var(--accent); }
.player-chip.in-game { border-color: var(--accent); background: var(--accent); color: #fff; cursor: pointer; }
.player-chip.in-game:hover { opacity: .85; }
.guest-chips { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }
.guest-chips:empty { display: none; }

/* ── Empty State ── */
.empty-state { color: var(--text-muted); font-size: .88rem; padding: 12px 0; }

/* ── Topbar with back button ── */
.topbar { display: flex; align-items: center; gap: 14px; }
.topbar #back-btn { flex-shrink: 0; padding: 7px 14px; font-size: .85rem; }

/* ── Game Layout ── */
.game-layout {
  display: flex;
  flex-direction: column;
  gap: 12px;
  flex: 1;
  min-height: 0;
}

/* Spieler Score Cards */
.game-scores {
  display: flex;
  gap: 16px;
  flex-wrap: nowrap;
  overflow-x: auto;
  scrollbar-width: none;
  flex-shrink: 0;
  min-height: 80px; /* Sicherheitsnetz: immer sichtbar */
  align-items: stretch;
}
.game-scores::-webkit-scrollbar { display: none; }

.game-score-card {
  flex: 1;
  min-width: 0;
  background: var(--surface);
  border: 2px solid var(--border);
  border-radius: var(--radius);
  padding: 5px 10px;
  text-align: center;
  box-shadow: var(--shadow);
  transition: border-color var(--transition), box-shadow var(--transition);
  overflow: hidden;
}
.game-score-card.active {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(79,110,247,.15), var(--shadow);
}
.game-score-card .player-name {
  font-size: clamp(0.85rem, 2.0vh, 1.8rem);
  font-weight: 700;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: .4px;
  line-height: 1.1;
}
.game-score-card .player-nick {
  font-size: clamp(0.95rem, 2.0vh, 1.52rem);
  font-weight: 500;
  color: var(--text-muted);
  opacity: .65;
  font-style: italic;
  margin-top: 1px;
  margin-bottom: 4px;
}
.game-score-card .player-score {
  font-size: clamp(1.85rem, 5.0vh, 3.9rem);
  font-weight: 800;
  color: var(--text);
  line-height: 1;
  text-align: center;
  flex: 0 0 auto;
  padding: 0 12px;
}
.game-score-card.active .player-score { color: var(--accent); }
.score-card-top {
  display: flex;
  align-items: center;
  margin-bottom: 4px;
}
.score-card-name {
  flex: 1;
  min-width: 0;
  text-align: left;
}
.game-score-card .player-meta {
  font-size: clamp(0.85rem, 1.7vh, 1.75rem);
  color: var(--text-muted);
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 2px;
  flex: 1;
}
.player-live-stats {
  display: flex;
  gap: 16px;
  font-size: .82rem;
  color: var(--text-muted);
  margin-bottom: 2px;
  justify-content: center;
}
.player-live-stats span { font-weight: 600; }

/* In-Card Dart Tracker */
.dart-tracker-area {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  margin-bottom: 2px;
}
.dart-and-total {
  display: flex;
  align-items: flex-start;
  gap: 20px;
}
.dart-slots-row {
  display: flex;
  gap: 6px;
}
/* checkout-hints-row ist immer sichtbar – reserviert konstant Höhe.
   Inhalt (Dart-Vorschläge) erscheint nur im Checkout-Bereich. */
.checkout-hints-row {
  display: flex;
  align-items: center;
  gap: 6px;
  min-height: 1.1em;
}
.checkout-tracker-label {
  display: flex;
  align-items: center;
  font-size: .62rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .3px;
  color: var(--accent);
  white-space: nowrap;
}
.checkout-tracker-label.co-hidden { visibility: hidden; }
.slot-checkout {
  font-size: .96rem;
  font-weight: 700;
  color: var(--accent);
  text-align: center;
  flex: 1;
  min-width: 0;
  min-height: 1em;
}
.dart-slots-with-hints {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.player-dart-slot {
  display: flex;
  flex-direction: column;
  align-items: center;
  min-width: 64px;
  background: var(--bg);
  border-radius: 6px;
  padding: 4px 14px;
  border: 1px solid var(--border);
}
.player-dart-slot .slot-label { font-size: .62rem; color: var(--text-muted); font-weight: 600; text-transform: uppercase; letter-spacing: .3px; }
.player-dart-slot .slot-val { font-size: 1.9rem; font-weight: 800; color: var(--text); line-height: 1; }
.player-dart-slot.filled .slot-val { color: var(--accent); }
.player-dart-slot.bust-slot .slot-val { color: var(--danger); }
.player-dart-slot.bust-slot { border-color: var(--danger); opacity: .7; }
.turn-total-box {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-width: 72px;
  min-height: calc(1.7rem + 8px);
  background: var(--bg);
  border-radius: 6px;
  padding: 4px 16px;
  border: 2px solid var(--accent);
}
.turn-total-box .slot-val { font-size: 1.9rem; font-weight: 800; color: var(--accent); line-height: 1; }
.turn-total-box .slot-val.bust-text { font-size: 1.24rem; }
.turn-total-box.bust-slot { border-color: var(--danger); }
.turn-total-box.bust-slot .slot-label { color: var(--danger); }
.turn-total-box.bust-slot .slot-val { color: var(--danger); }
.player-score-stats {
  display: flex;
  justify-content: center;
  gap: 16px;
  font-size: .88rem;
  color: var(--text-muted);
  margin: 2px 0 6px;
  font-weight: 500;
}

/* History in der Score-Card */
.player-history { display: flex; flex-direction: column; gap: 3px; margin-top: 0; }
.history-row {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 4px;
}
.history-entry {
  display: flex;
  align-items: center;
  gap: 6px;
  background: var(--bg);
  border-radius: 6px;
  padding: 8px;
  font-size: .82rem;
  flex: 0 0 auto;
}
.h-label {
  font-size: .62rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .3px;
  color: var(--text-muted);
  white-space: nowrap;
  flex-shrink: 0;
  margin-right: 2px;
}
.h-darts { display: flex; gap: 5px; flex-wrap: nowrap; }
.h-stats {
  margin-left: auto;
  display: flex;
  gap: 16px;
  align-items: center;
  background: var(--bg);
  border-radius: 6px;
  padding: 2px 16px;
  font-size: .72rem;
  color: var(--text-muted);
  white-space: nowrap;
  flex-shrink: 0;
}
.history-entry.bust { opacity: .6; }
.bust-score { color: var(--danger); }
.h-dart {
  background: var(--border);
  border-radius: 4px;
  padding: 2px 7px;
  font-weight: 700;
  font-size: .85rem;
  color: var(--text);
}
.history-entry.bust .h-dart { background: rgba(229,62,62,.15); color: var(--danger); }
.h-right { display: flex; gap: 10px; align-items: center; }
.h-score { font-weight: 700; font-size: .95rem; }
.history-entry.bust .h-score { color: var(--danger); }
.h-rest { color: var(--text-muted); font-size: .85rem; }

/* ── Spectator Mode ── */
.spectator-banner {
  display: flex;
  align-items: center;
  gap: 8px;
  background: var(--accent);
  color: #fff;
  border-radius: 10px;
  padding: 8px 14px;
  font-size: .9rem;
  font-weight: 600;
}
.spectator-icon { font-size: 1.1rem; }
.spectator-mode .numpad-area { display: none; }

/* ── Numpad ── */
.numpad-area {
  display: flex;
  flex-direction: column;
  gap: 8px;
  flex: 1;
  min-height: 0;
}

/* Dart-Tracker */
.dart-tracker { display: flex; flex-direction: column; align-items: center; gap: 6px; }
.checkout-hint {
  font-size: .85rem;
  font-weight: 600;
  color: var(--accent);
  min-height: 18px;
  text-align: center;
}
.dart-slots {
  display: flex;
  gap: 10px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 10px 16px;
  box-shadow: var(--shadow);
}
.dart-slot {
  display: flex;
  flex-direction: column;
  align-items: center;
  min-width: 60px;
}
.dart-slot.dart-total { border-left: 1px solid var(--border); padding-left: 14px; margin-left: 4px; }
.slot-label { font-size: .7rem; color: var(--text-muted); font-weight: 600; text-transform: uppercase; letter-spacing: .3px; }
.slot-val { font-size: 1.3rem; font-weight: 800; color: var(--text); margin-top: 2px; }
.dart-slot.dart-total .slot-val { color: var(--accent); }
.dart-slot.filled .slot-val { color: var(--accent); }

/* Tabelle Single / Double / Triple */
.numpad-table {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 6px;
  flex: 1;
  min-height: 200px;
}
.numpad-col {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-template-rows: repeat(5, 1fr);
  gap: 4px;
}
.num-btn {
  padding: clamp(5px, 1.1vh, 12px) 4px;
  border-radius: 6px;
  border: 1px solid var(--border);
  background: var(--surface);
  font-size: clamp(1.1rem, 2.28vh, 1.44rem);
  font-weight: 700;
  cursor: pointer;
  color: var(--text);
  transition: all var(--transition);
  box-shadow: 0 1px 3px rgba(0,0,0,.06);
  min-height: 0;
}
.num-btn:hover { border-color: var(--accent); color: var(--accent); background: rgba(79,110,247,.06); }
.num-btn:active { transform: scale(.95); }
.num-btn.disabled-btn { opacity: .35; cursor: not-allowed; pointer-events: none; }
.num-btn-double { border-color: #38a169; color: #38a169; }
.num-btn-double:hover { border-color: #276749; background: rgba(56,161,105,.08); color: #276749; }
.num-btn-triple { border-color: #e53e3e; color: #e53e3e; }
.num-btn-triple:hover { border-color: #c53030; background: rgba(229,62,62,.08); color: #c53030; }

/* Sonderwürfe */
.numpad-special {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 6px;
}
.numpad-miss { display: grid; gap: 6px; }
.special-btn { font-size: .92rem; min-height: 46px; }

/* Aktionen */
.numpad-actions { display: flex; gap: 8px; }
#undo-btn { flex: 1; min-height: 46px; border: 1px solid var(--border); }
#undo-btn:hover,
#undo-btn:focus { border-color: var(--accent); color: var(--accent); background: rgba(79,110,247,.06); outline: none; }
#next-btn { flex: 0 0 25%; min-height: 46px; }

/* ── Autoscorer aktiv: Numpad ausblenden, Spielerkarten vergrößern ─────────── */
#game-view.autoscorer-running .numpad-table,
#game-view.autoscorer-running .numpad-special { display: none; }

#game-view.autoscorer-running .numpad-area  { flex: 0 0 auto; }

#game-view.autoscorer-running .game-scores {
  flex: 1;
  min-height: 0;
}

#game-view.autoscorer-running .game-score-card {
  display: flex;
  flex-direction: column;
  justify-content: center;
  overflow: hidden;
}

#game-view.autoscorer-running .game-score-card .player-score {
  font-size: clamp(2.5rem, 12vh, 8rem);
  padding: 0 6px;
}
#game-view.autoscorer-running .game-score-card .player-name {
  font-size: clamp(1rem, 3vh, 2.5rem);
}
#game-view.autoscorer-running .game-score-card .player-nick {
  font-size: clamp(0.9rem, 2.5vh, 2rem);
}
#game-view.autoscorer-running .game-score-card .player-meta {
  font-size: clamp(0.8rem, 2vh, 1.5rem);
}
#game-view.autoscorer-running .game-score-card .player-score-stats {
  font-size: 1.1rem;
}
#game-view.autoscorer-running .game-score-card .player-dart-slot .slot-label,
#game-view.autoscorer-running .game-score-card .checkout-tracker-label {
  font-size: 0.78rem;
}
#game-view.autoscorer-running .game-score-card .player-dart-slot .slot-val,
#game-view.autoscorer-running .game-score-card .turn-total-box .slot-val {
  font-size: 2.375rem;
}
#game-view.autoscorer-running .game-score-card .slot-checkout {
  font-size: 1.2rem;
}

/* ── Korrektur an den Pfeil-Feldern ──────────────────────────────────────────
   Mit laufendem Autoscorer sind die Pfeil-Felder die Korrektur-Oberflaeche.
   Sie muessen dafuer sichtbar bleiben, auch dort wo sie sonst der Kompaktheit
   zum Opfer fallen (viele Spieler auf dem Handy, Landscape mit wenig Hoehe) —
   die hoehere Spezifitaet setzt sich gegen die display:none-Regeln durch. */
#game-view.autoscorer-running .player-dart-slot.korrigierbar {
  display: flex;
  position: relative;
  cursor: pointer;
}
#game-view.autoscorer-running .player-dart-slot.korrigierbar:hover,
#game-view.autoscorer-running .player-dart-slot.korrigierbar:focus-within {
  border-color: var(--accent);
}

/* Marke: dieser Wurf liegt im Trainingsdatensatz. Mitlernen soll waehrend des
   Spiels sichtbar sein und nicht unbemerkt nebenherlaufen. */
.player-dart-slot.mitgeschnitten::after {
  content: '';
  position: absolute;
  top: 3px;
  right: 3px;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--accent);
  opacity: .6;
}

/* Eingabefeld liegt genau ueber dem Feld, damit die Karte nicht springt. */
.slot-korrektur {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  box-sizing: border-box;
  border: 1px solid var(--accent);
  border-radius: 6px;
  background: var(--bg);
  color: var(--text);
  font-size: 1.1rem;
  font-weight: 800;
  text-align: center;
  text-transform: uppercase;
  outline: none;
}

/* Verlauf + Statistiken */
.game-bottom {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 20px;
}

/* Hier stand ein ZWEITER .history-entry-Block samt Kindregeln .h-player /
   .h-score / .h-rest / .bust. Diese Klassen werden nirgends mehr erzeugt —
   Ueberbleibsel einer entfernten Verlaufsliste.
   Er ueberschrieb aber weiterhin den ersten .history-entry-Block weiter oben
   (~Zeile 827), der die Wurfanzeige der Cricket-Karte gestaltet: padding wurde
   von 8px auf "6px 0" gesetzt (Text klebte dadurch seitlich am Rand der
   eingefaerbten Flaeche) und eine untere Trennlinie ergaenzt, die unter einem
   einzelnen Kaestchen frei schwebte. Ersatzlos entfernt. */

.stat-row {
  display: flex;
  justify-content: space-between;
  padding: 7px 0;
  border-bottom: 1px solid var(--border);
  font-size: .88rem;
}
.stat-row:last-child { border-bottom: none; }
.stat-row .stat-label { color: var(--text-muted); }
.stat-row .stat-val { font-weight: 700; }

/* ── Auth Overlay ── */
.auth-overlay {
  display: flex;
  position: fixed;
  inset: 0;
  z-index: 9999;
  background: var(--sidebar-bg);
  align-items: center;
  justify-content: center;
  padding: 16px;
}

/* Das Login-Overlay traegt seit dem Startseiten-Text mehr Inhalt, als auf einen
   Handybildschirm passt, muss also scrollen. Ein Flex-Container mit
   `align-items:center` schneidet ueberlaufenden Inhalt aber OBEN ab — der
   abgeschnittene Teil ist dann auch durch Scrollen nicht erreichbar. Deshalb
   scrollt hier der Block selbst und das Zentrieren uebernimmt .auth-layout
   darin. Nur per ID, damit #verify-overlay (gleiche Klasse, wird von
   js/app.js auf display:flex gesetzt) unveraendert bleibt. */
#auth-overlay {
  display: block;
  overflow-y: auto;
  padding: 24px 16px;
  /* Zweite Absicherung: Sollte doch wieder jemand von aussen display:flex
     setzen (inline schlaegt diese Regel), sorgt flex-start dafuer, dass der
     Inhalt am oberen Rand beginnt statt zentriert zu ueberlaufen. Nichts darf
     oberhalb des Scrollbereichs landen — dorthin kommt man nie zurueck. */
  align-items: flex-start;
}
.auth-layout {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 40px;
  min-height: 100%;
  max-width: 960px;
  margin: 0 auto;
}
.auth-layout > .auth-card { flex: 0 0 auto; }

/* ── Startseiten-Text (nur sichtbar, solange niemand angemeldet ist) ── */
.landing {
  flex: 1 1 380px;
  max-width: 520px;
  /* Der Overlay-Hintergrund ist in BEIDEN Themes dunkel (--sidebar-bg), die
     Textfarben also bewusst fest und nicht ueber --text: im hellen Theme waere
     --text fast schwarz und damit unlesbar. */
  color: #e2e8f0;
}
.landing-title {
  font-size: 1.7rem;
  line-height: 1.25;
  font-weight: 700;
  margin-bottom: 12px;
  color: #fff;
}
.landing-lead {
  font-size: 1rem;
  line-height: 1.55;
  color: rgba(226, 232, 240, .78);
  margin-bottom: 24px;
}
.landing-features {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 14px;
  margin: 0 0 22px;
  padding: 0;
}
.landing-features li {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  font-size: .9rem;
  line-height: 1.5;
  color: rgba(226, 232, 240, .72);
}
.landing-features strong {
  display: block;
  color: #fff;
  font-weight: 600;
  margin-bottom: 2px;
}
.landing-icon {
  flex: 0 0 auto;
  font-size: 1.15rem;
  line-height: 1.4;
}
.landing-note {
  font-size: .85rem;
  line-height: 1.5;
  color: rgba(226, 232, 240, .55);
  border-left: 3px solid var(--accent);
  padding-left: 12px;
}

/* Schmale Bildschirme: das Anmeldeformular gehoert nach OBEN — wer die App
   schon kennt, soll nicht erst an der Werbung vorbeiscrollen. Umgestellt wird
   ueber `order`, NICHT ueber `column-reverse`.
   Grund: Bei `column-reverse` liegt der Anfang der Flex-Achse unten, also
   laeuft zu hoher Inhalt oben aus dem Kasten heraus — und dorthin laesst sich
   nicht scrollen (Scrollpositionen sind nie negativ). Mit `column` + `order`
   sieht man dieselbe Reihenfolge, der Ueberlauf geht aber nach unten, wo er
   erreichbar bleibt.
   `flex-wrap` muss hier ebenfalls aus: in Spaltenrichtung wuerde Inhalt sonst
   in eine zweite Spalte NEBEN die erste umbrechen statt weiterzulaufen.
   Die Reihenfolge im HTML (Text zuerst) bleibt fuer Suchmaschinen erhalten. */
@media (max-width: 860px) {
  .auth-layout {
    flex-direction: column;
    flex-wrap: nowrap;
    gap: 32px;
  }
  .auth-layout > .auth-card { order: -1; }
  .landing { flex: 0 0 auto; max-width: 420px; }
  .landing-title { font-size: 1.35rem; }
  .landing-lead { font-size: .93rem; margin-bottom: 20px; }
}
.auth-card {
  background: var(--surface);
  border-radius: var(--radius);
  padding: 32px 28px;
  width: 100%;
  max-width: 340px;
  box-shadow: var(--shadow);
  text-align: center;
}
.auth-card-icon { font-size: 2rem; margin-bottom: 8px; }
.auth-card h2 { margin-bottom: 6px; color: var(--text); }
.auth-card p { color: var(--text-muted); font-size: .9rem; margin-bottom: 20px; }
.auth-card input {
  width: 100%;
  padding: 10px 14px;
  border: 1px solid var(--border);
  border-radius: 8px;
  font-size: 1rem;
  background: var(--bg);
  color: var(--text);
  outline: none;
  margin-bottom: 8px;
  box-sizing: border-box;
  transition: border-color var(--transition);
}
.auth-card input:focus { border-color: var(--accent); }
.auth-error {
  color: #e53e3e;
  font-size: .85rem;
  min-height: 1.2em;
  margin-bottom: 10px;
}
.auth-btn {
  width: 100%;
  padding: 11px;
  border-radius: 8px;
  font-size: 1rem;
  cursor: pointer;
  margin-bottom: 8px;
  border: none;
  transition: background var(--transition), opacity var(--transition);
}
.auth-btn-primary { background: var(--accent); color: #fff; }
.auth-btn-primary:hover { background: var(--accent-dark); }
.auth-btn-outline { background: transparent; color: var(--accent); border: 1px solid var(--accent) !important; }
.auth-btn-outline:hover { background: rgba(79,110,247,.08); }
.auth-tabs {
  display: flex;
  gap: 0;
  border-bottom: 2px solid var(--border);
  margin-bottom: 20px;
}
.auth-tab {
  flex: 1;
  padding: 8px 12px 10px;
  cursor: pointer;
  border: none;
  background: none;
  font-size: .9rem;
  font-weight: 500;
  color: var(--text-muted);
  border-bottom: 2px solid transparent;
  margin-bottom: -2px;
  transition: color var(--transition), border-color var(--transition);
}
.auth-tab:hover { color: var(--text); }
.auth-tab.active { color: var(--accent); border-bottom-color: var(--accent); }
.auth-link-btn {
  background: none;
  border: none;
  color: var(--accent);
  font-size: .85rem;
  cursor: pointer;
  padding: 4px 0;
  margin-top: 2px;
  text-decoration: underline;
  display: block;
  width: 100%;
  text-align: center;
}
.auth-link-btn:hover { opacity: .75; }
.auth-tos-label {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  font-size: .82rem;
  color: var(--text-muted);
  text-align: left;
  margin-bottom: 10px;
  cursor: pointer;
}
/* width:auto überschreibt .auth-card input { width: 100% }, das die Checkbox sonst auf volle Zeilenbreite zieht */
.auth-tos-label input[type="checkbox"] { margin-top: 2px; flex-shrink: 0; width: auto; }
.auth-tos-text { min-width: 0; flex: 1; overflow-wrap: break-word; }
.auth-tos-link { color: var(--accent); text-decoration: underline; }
.auth-view-desc {
  font-size: .88rem;
  color: var(--text-muted);
  margin-bottom: 16px;
  text-align: left;
  line-height: 1.5;
}
.konto-user-info {
  background: var(--bg);
  border-radius: 8px;
  padding: 4px 0;
  margin-bottom: 16px;
}
.konto-info-row {
  display: flex;
  align-items: baseline;
  gap: 12px;
  padding: 7px 14px;
  border-bottom: 1px solid var(--border);
}
.konto-info-row:last-child { border-bottom: none; }
.konto-info-label {
  font-size: .8rem;
  color: var(--text-muted);
  font-weight: 500;
  min-width: 108px;
  flex-shrink: 0;
}
.konto-info-value {
  font-size: .95rem;
  color: var(--text);
  font-weight: 600;
  word-break: break-all;
}
.konto-actions {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.player-type-badge {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 20px;
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .03em;
  white-space: nowrap;
}
.badge-local  { background: var(--bg); color: var(--text-muted); border: 1px solid var(--border); }
.badge-friend { background: rgba(79,110,247,.12); color: var(--accent); border: 1px solid rgba(79,110,247,.3); }
.friend-invite-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 8px 0;
  border-bottom: 1px solid var(--border);
}
.friend-invite-row:last-child { border-bottom: none; }
.friend-invite-name { font-size: .9rem; color: var(--text); flex: 1; min-width: 0; }
.invite-status {
  font-size: .8rem;
  font-weight: 600;
  padding: 3px 10px;
  border-radius: 20px;
  white-space: nowrap;
}
.invite-status-pending  { background: rgba(237,137,54,.12); color: #c05621; }
.invite-status-joined   { background: rgba(56,161,105,.15); color: #276749; }
.invite-status-declined { background: rgba(229,62,62,.12);  color: var(--danger, #c53030); }

/* Leerer Freunde-Abschnitt: im Turnier bleibt der Abschnitt sichtbar (anders
   als im normalen Spiel), damit erkennbar ist, dass es hier ueberhaupt
   Freunde geben koennte. */
.players-row-empty {
  padding: 8px 2px;
  font-size: .85rem;
  color: var(--text-muted);
}

/* ── Turnier-Rollen: einheitliches Personen-Grid (Block A, Aufgabe 1) ───── */
.tv-role-badge {
  font-size: .75rem;
  font-weight: 700;
  padding: 2px 9px;
  border-radius: 20px;
  white-space: nowrap;
}
.tv-role-player    { background: rgba(79,110,247,.12); color: var(--accent); }
.tv-role-scorer     { background: rgba(237,137,54,.15); color: #c05621; }
.tv-role-spectator  { background: rgba(113,128,150,.15); color: var(--text-muted); }

/* Teilnehmer nach Rolle getrennt (Nutzer-Vorgabe): eigener Block je Rolle
   statt einer gemischten Liste mit Etikett an jeder Zeile. Die Ueberschrift
   traegt die Rolle, die Zeilen darunter nur noch Name und ✕. Ein Block wird
   gar nicht erst erzeugt, wenn er leer ist (siehe membersGridHtml). */
.tv-role-group + .tv-role-group { margin-top: 22px; }
/* Ueberschrift der Rollengruppe im selben Stil wie ein Abschnitt im Popup. */
.tv-role-group > .label {
  display: block;
  padding-bottom: 7px;
  margin-bottom: 10px;
  border-bottom: 1px solid var(--border, rgba(127,127,127,.22));
}
/* Mehrspaltig, sobald Platz ist — bei acht Spielern waere eine einspaltige
   Liste unnoetig lang. Zeilenweise gefuellt (Grid), nicht spaltenweise. */
.tv-role-group-list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: 0 18px;
}
.friend-request-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 0;
  border-bottom: 1px solid var(--border);
}
.friend-request-row:last-child { border-bottom: none; }
.friend-request-info { flex: 1; min-width: 0; }
.friend-request-name { font-weight: 600; font-size: .95rem; color: var(--text); }
.friend-request-actions { display: flex; gap: 8px; flex-shrink: 0; }

/* ── Ausbullen Overlay ── */
.bulloff-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,.6);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 600;
  padding: 12px;
}
.bulloff-card {
  background: var(--surface);
  border-radius: var(--radius);
  padding: 36px 40px;
  width: 90%;
  max-width: 400px;
  box-shadow: 0 8px 40px rgba(0,0,0,.3);
  text-align: center;
}
.bulloff-card h2 { font-size: 1.4rem; margin-bottom: 8px; }
.bulloff-instruction { font-size: .9rem; color: var(--text-muted); margin-bottom: 20px; }
.bulloff-players { display: flex; gap: 12px; margin-bottom: 14px; }
.bulloff-player-btn {
  flex: 1;
  padding: 18px 12px;
  border-radius: 10px;
  border: 2px solid var(--border);
  background: var(--bg);
  font-size: 1rem;
  font-weight: 700;
  cursor: pointer;
  color: var(--text);
  transition: all var(--transition);
}
.bulloff-player-btn:hover { border-color: var(--accent); color: var(--accent); }
.bulloff-player-btn.selected { border-color: var(--accent); background: var(--accent); color: #fff; }
.bulloff-error { font-size: .82rem; color: var(--danger); min-height: 18px; margin-bottom: 12px; }

/* ── Leg-Win Overlay ── */
.leg-win-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,.55);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 400;
  padding: 12px;
}
.leg-win-card {
  background: var(--surface);
  border-radius: var(--radius);
  padding: 36px 44px;
  text-align: center;
  box-shadow: 0 8px 40px rgba(0,0,0,.25);
  max-width: 340px;
  width: 90%;
}
.leg-win-headline {
  font-size: .9rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .6px;
  color: var(--text-muted);
  margin-bottom: 6px;
}
.leg-win-name {
  font-size: 2rem;
  font-weight: 800;
  color: var(--accent);
  margin-bottom: 20px;
}
.leg-standings {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-bottom: 24px;
}
.leg-standing {
  display: flex;
  justify-content: space-between;
  padding: 8px 14px;
  background: var(--bg);
  border-radius: 8px;
  font-size: .9rem;
  font-weight: 600;
  color: var(--text-muted);
}
.leg-standing.leg-standing-winner {
  background: rgba(79,110,247,.1);
  color: var(--accent);
  border: 1px solid rgba(79,110,247,.3);
}
.leg-win-continue { width: 100%; }

/* Set-Gewinn hebt sich vom blossen Leg-Gewinn ab: ein Set faellt seltener und
   ist der groessere Moment, sah vorher aber genauso aus wie jedes Leg. */
.leg-win-card--set {
  border: 2px solid var(--accent);
  box-shadow: 0 8px 40px rgba(79,110,247,.35);
}
.leg-win-card--set .leg-win-headline { color: var(--accent); }
.leg-win-sub {
  font-size: .82rem;
  color: var(--text-muted);
  margin: -12px 0 18px;
}

/* Zielwert hinter dem Stand ("2/3"), damit erkennbar ist, wie viel noch fehlt. */
.meta-ziel { opacity: .5; font-weight: 600; }

/* ── Statistik eines Freundes ────────────────────────────────────────────────
   Die abgesetzte Hinweisleiste ist entfallen: wessen Zahlen man sieht, sagt
   jetzt die Kopfzeile ("X's Statistik-Übersicht"), und zurueck geht es ueber
   den Pfeil in der Topbar. Nur die Unterzeile bleibt — sie wird in der
   Detailansicht der Partien weiterverwendet. */
.stats-friend-bar-sub { font-size: .8rem; font-weight: 400; color: var(--text-muted); }

/* ── Filter: Voreinstellungen + Erweitert ───────────────────────────────────
   Der Alltagsfall laeuft ueber die Voreinstellungen; die einzelnen Ebenen
   liegen darunter und erscheinen erst auf Wunsch. Vorher standen alle vier
   dauerhaft offen. */
.stats-preset-tabs { flex-wrap: wrap; }
/* Kein Knopf, sondern Anzeige: "Eigene Auswahl" laesst sich nicht anklicken,
   es beschreibt nur, dass keine Voreinstellung mehr passt. */
.stats-preset-custom {
  cursor: default;
  font-style: italic;
  opacity: .7;
}
/* .stats-advanced entfaellt mit dem Ausklapper „Erweitert": darin lag zuletzt
   nur noch der Zeitraum, und der steht jetzt gleichrangig in der Leiste. */
.stats-range-label,
.stats-gametype-computer {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: .85rem;
  color: var(--text-muted);
}
.stats-range-label .input,
.stats-gametype-computer .input { width: auto; }
.stats-gametype-computer {
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1px solid var(--border);
  width: 100%;
  justify-content: space-between;
}
/* Sammelzeile "X01 (alle Varianten)": setzt sich leicht von den einzelnen
   Varianten darunter ab, damit erkennbar ist, dass sie alle drei umfasst. */
.stats-facet-row--all .players-row-name { font-weight: 700; }
.stats-facet-row--all { border-bottom: 1px solid var(--border); }

/* Gewinner-Overlay */
.game-over-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,.55);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 500;
  padding: 12px;
}
/* Kompakter gehalten, damit der Abschlussbildschirm ohne Scrollen auf den Schirm
   passt (Nutzerwunsch). Der groesste Platzfresser war der Siegername mit 2rem
   plus 40/48px Innenabstand; die Erfolge sind zusaetzlich aus der Karte heraus
   an den rechten Bildschirmrand gewandert (showAchievementToasts()). */
.game-over-card {
  background: var(--surface);
  border-radius: var(--radius);
  padding: 22px 26px;
  text-align: center;
  box-shadow: 0 8px 40px rgba(0,0,0,.25);
  max-width: 380px;
  width: 90%;
  /* Untergrenze bleibt als Sicherheitsnetz: bei sehr vielen Legs kann die
     Detailtabelle trotzdem laenger werden als der Schirm. */
  max-height: 92vh;
  overflow-y: auto;
}
.game-over-card h2 { font-size: 1.25rem; margin-bottom: 4px; }
.game-over-card .winner-name { font-size: 1.5rem; font-weight: 800; color: var(--accent); margin-bottom: 12px; }
.game-over-card .btn { width: 100%; margin-top: 20px; }
.game-over-actions { display: flex; gap: 10px; margin-top: 14px; }
.game-over-actions .btn { margin-top: 0; }

.stats-container { display: flex; gap: 16px; flex-wrap: wrap; text-align: left; }
.stats-player-block { flex: 1; min-width: 200px; }
.stats-player-name { font-weight: 700; font-size: 1rem; margin-bottom: 6px; padding-bottom: 4px; border-bottom: 2px solid var(--accent); }
.stats-overall { display: flex; flex-wrap: wrap; gap: 8px; font-size: .82rem; margin-bottom: 6px; }
.stats-overall span { color: var(--text-muted); }
.stats-overall strong { color: var(--text); }
/* Leg-Details stehen zu mehreren nebeneinander im Abschlussbildschirm —
   deshalb als einzige Tabelle enger als der gemeinsame Standard.
   Alles Uebrige (Kopfzeile, Trennlinien, Ausrichtung) kommt von dort. */
.stats-leg-table { font-size: .82rem; }
.stats-leg-table th, .stats-leg-table td { padding: 5px 8px; }

/* ── Abschlussbildschirm X01 (schöneres, lesbareres Design) ── */
.game-over-card--x01 { max-width: 640px; }
.game-over-card--x01 .winner-name { margin-bottom: 6px; }
.game-over-result {
  font-size: .92rem;
  color: var(--text-muted);
  margin-bottom: 20px;
}
.game-over-result strong { color: var(--text); }

.stats-section { flex: 1 1 100%; margin-bottom: 12px; text-align: left; }
.stats-section:last-child { margin-bottom: 0; }
.stats-section-title {
  font-size: .76rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .5px;
  color: var(--text-muted);
  margin-bottom: 10px;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--border);
}

/* Breite Tabellen bekommen einen eigenen Scroll-Container (kein horizontales
   Scrollen der Seite/Karte, siehe Aufgabe 1 Mobiltauglichkeit) */
.stats-table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }

/* Direktvergleich im Abschlussbildschirm — Layout kommt aus dem gemeinsamen
   Datentabellen-Block, hier nur die Beschriftungsspalte, die umbrechen darf. */
.stats-compare-table td.stats-compare-label { white-space: normal; }

.stats-legdetail-grid { display: flex; gap: 16px; flex-wrap: wrap; }
.stats-legdetail-grid .stats-player-block { flex: 1; min-width: 200px; }

/* ── Turnierstatistik „Partien" — eine Duell-Karte je Partie statt einer
   Tabellenzeile (Nutzer-Feedback: die frühere Average-Spalte wiederholte die
   Spielernamen unlesbar direkt neben "Name vs. Name"). Kopf im selben Stil
   wie eine abgeschlossene Partie im Turnierplan (.plan-match-players/
   .plan-match-vs/.plan-score-inline/.plan-match-name werden bewusst
   wiederverwendet, siehe js/app.js _renderTvStatsMatches()). ── */
/* Drei Partien nebeneinander, danach umbrechen. Untereinander wurde die Liste
   bei einem Turnierabend sehr lang. */
.tv-match-list {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 12px;
  align-items: start;
}
@media (max-width: 1200px) { .tv-match-list { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 760px)  { .tv-match-list { grid-template-columns: 1fr; } }
.tv-match-card {
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 14px;
}
.tv-match-meta {
  font-size: .75rem;
  color: var(--text-muted);
  margin-bottom: 8px;
}
.tv-match-head { margin-bottom: 10px; }
.tv-match-name-right { text-align: right; }
.tv-match-name-winner { font-weight: 800; }
/* EIN gemeinsames Raster fuer alle Kennzahlzeilen einer Karte.
   Vorher war jede Zeile ein eigenes Grid — die Spaltenbreiten wurden dadurch
   pro Zeile neu berechnet, und weil die Bezeichnungen in der Mitte
   unterschiedlich lang sind ("180ER" gegen "HOECHSTES CHECKOUT"), sprangen die
   Werte links und rechts von Zeile zu Zeile hin und her.
   Mit display: contents auf der Zeile wandern deren drei Felder direkt in
   dieses Raster, teilen sich also die Spaltenbreiten — die Werte stehen
   dadurch sauber untereinander. Das Markup bleibt unveraendert. */
.tv-match-metrics {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  column-gap: 10px;
  font-size: .85rem;
}
.tv-match-metric { display: contents; }
/* Die Kennzahlen liegen in einem dreispaltigen Raster — das Gruppenband muss
   ueber alle drei Spalten laufen, sonst landet es in der linken Wertespalte. */
.tv-match-metrics > .data-group-band { grid-column: 1 / -1; }
/* Die Trennlinie lag vorher auf der Zeile selbst. Da diese kein eigenes
   Kaestchen mehr hat, tragen sie jetzt die drei Felder. */
.tv-match-metric > * { padding: 6px 0; border-bottom: 1px solid var(--border); }
.tv-match-metric:last-child > * { border-bottom: none; }
.tv-match-metric-value { font-weight: 600; white-space: nowrap; }
.tv-match-metric > .tv-match-metric-value:first-child { text-align: right; }
.tv-match-metric > .tv-match-metric-value:last-child  { text-align: left; }
.tv-match-metric-value--better { color: var(--accent); font-weight: 800; }
.tv-match-metric-label {
  text-align: center;
  color: var(--text-muted);
  font-size: .72rem;
  text-transform: uppercase;
  letter-spacing: .3px;
  /* Umbruch erlaubt: bei drei Karten nebeneinander ist eine Karte nur noch
     etwa ein Drittel breit, lange Bezeichnungen wuerden sonst ueberlaufen. */
  white-space: normal;
  line-height: 1.25;
}
@media (max-width: 420px) {
  /* Umbruch gilt inzwischen generell (siehe oben); hier nur noch etwas
     kleiner, damit die Bezeichnung nicht zu viel Platz zwischen den Werten
     einnimmt. */
  .tv-match-metric-label { font-size: .68rem; }
}

/* Neue Erfolge — fest im Abschlussbildschirm statt als darüberliegender Toast
   (Nutzer-Feedback: Einblendung soll stehen bleiben, bis der Nutzer eine der
   Aktionen der Abschlusskarte wählt). */
.game-over-achievements {
  text-align: left;
  margin-bottom: 20px;
  padding: 12px 14px;
  background: rgba(246,173,85,.08);
  border: 1.5px solid rgba(246,173,85,.4);
  border-radius: 10px;
  max-height: 220px;
  overflow-y: auto;
}
.goa-title {
  font-size: .72rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: .5px;
  color: #f6ad55;
  margin-bottom: 8px;
}
.goa-item { display: flex; gap: 10px; align-items: flex-start; padding: 6px 0; }
.goa-item + .goa-item { border-top: 1px dashed var(--border); }
.goa-icon { font-size: 1.3rem; line-height: 1.2; flex-shrink: 0; }
.goa-name { font-weight: 700; font-size: .84rem; color: var(--text); }
.goa-desc { font-size: .74rem; color: var(--text-muted); }

/* ── Turnier Spielerliste (max. 5 pro Spalte) ── */
.player-list-cols {
  list-style: none;
  display: grid;
  grid-template-rows: repeat(5, auto);
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
  gap: 6px;
}

/* ── Laufende Spiele ── */
.active-games-list { display: flex; flex-direction: column; gap: 14px; }

.active-game-card {
  background: var(--bg);
  border-radius: var(--radius);
  border: 1px solid var(--border);
  padding: 16px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.ag-header {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 12px;
}

.ag-title { font-size: 1rem; font-weight: 700; color: var(--text); }
.ag-meta  { font-size: .8rem; color: var(--text-muted); margin-top: 2px; }
.ag-time  { font-size: .78rem; color: var(--text-muted); white-space: nowrap; flex-shrink: 0; }

.ag-players { display: flex; flex-direction: column; gap: 6px; }

.ag-player {
  display: flex;
  align-items: center;
  gap: 12px;
  background: var(--surface);
  border-radius: 8px;
  padding: 8px 12px;
  border: 1px solid var(--border);
}

.ag-player-name  { flex: 1; font-weight: 600; font-size: .9rem; }
.ag-player-score { font-size: 1.25rem; font-weight: 800; color: var(--text); min-width: 44px; text-align: right; }
.ag-player-legs  { font-size: .78rem; color: var(--text-muted); min-width: 80px; text-align: right; }

.ag-actions { display: flex; gap: 10px; }
.ag-actions .btn { flex: 1; }

/* ── Turnierplan ── */
.plan-grid {
  display: grid;
  gap: 14px;
  align-items: start;
}

.plan-col-header {
  text-align: center;
  font-size: .75rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .5px;
  color: var(--text-muted);
  padding: 6px 0 10px;
  border-bottom: 2px solid var(--accent);
  margin-bottom: 6px;
}

.plan-match {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 10px 12px;
}

.plan-match-players {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: .88rem;
  font-weight: 600;
}

.plan-match-vs {
  font-size: .75rem;
  color: var(--text-muted);
  font-weight: 400;
  flex-shrink: 0;
}

/* Mittelspalte der Match-Karte im Format 'round-robin-scorer': stapelt das
   jeweilige Mittelelement (vs / Ergebnis / Aktions-Buttons) und darunter den
   zugewiesenen Schreiber. */
.plan-match-center {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  flex-shrink: 0;
}

.plan-match-center .plan-match-scorer {
  text-align: center;
  white-space: nowrap;
}

.plan-match-name {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: 600;
}

.plan-player-name {
  cursor: pointer;
  border-radius: 3px;
  transition: opacity .15s;
}
.plan-player-name:hover { opacity: .75; }

.plan-match-highlight {
  outline: 2px solid currentColor;
  outline-offset: 1px;
  background: var(--bg) !important;
  z-index: 1;
  position: relative;
}
.plan-match-dimmed {
  opacity: .22;
  transition: opacity .15s;
}
.plan-match { transition: opacity .15s; }

.plan-match.bye { opacity: .55; }
.plan-match.plan-match-empty {
  background: transparent;
  border: 1px dashed var(--border);
  min-height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: .5;
}

/* Auswählbare Partie im gestarteten Turnier */
.plan-match[data-match-id] {
  cursor: pointer;
  transition: background .15s, border-color .15s;
}
.plan-match[data-match-id]:hover { background: var(--bg-hover); }
.plan-match.plan-match-selected {
  border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 12%, transparent);
}

/* Abgeschlossene / laufende Partie */
.plan-match.plan-match-done {
  opacity: .6;
}
.plan-match.plan-match-inprogress {
  border-color: var(--accent);
}
.plan-match.plan-match-other-device {
  border-color: #e0905c;
  opacity: .75;
}
.plan-match-result-other {
  font-size: .72rem;
  color: #e0905c;
  margin-top: 4px;
  font-weight: 500;
}

/* Turnier Freunde einladen */
.tournament-friend-invite {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  margin-top: 12px;
  flex-wrap: wrap;
}
.tournament-friend-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

/* Einladungsleiste */
.invite-bar {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 12px;
  flex-wrap: wrap;
}
.invite-label { font-size: .82rem; color: var(--text-muted); }
.invite-code {
  font-size: 1.1rem;
  font-weight: 800;
  letter-spacing: .15em;
  color: var(--accent);
  font-family: monospace;
}

/* Teilnehmer-Chips */
.participant-bar {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 8px;
}
.participant-chip {
  font-size: .75rem;
  padding: 3px 8px;
  border-radius: 12px;
  background: var(--bg);
  border: 1px solid var(--border);
  color: var(--text-muted);
}
.participant-chip-me {
  border-color: var(--accent);
  color: var(--accent);
}
.plan-score-inline {
  font-size: .95rem;
  font-weight: 800;
  color: var(--accent);
}
.plan-match-winner {
  font-size: .75rem;
  font-weight: 600;
  color: var(--text-muted);
  text-align: center;
  margin-top: 4px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.plan-match-result-progress {
  font-size: .75rem;
  font-weight: 600;
  color: var(--warning, #e0a030);
  text-align: center;
  margin-top: 4px;
}

/* Aktionsleiste für Partie-Auswahl */
.plan-action-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 14px;
  margin-bottom: 12px;
  background: color-mix(in srgb, var(--accent) 10%, var(--bg-card));
  border: 1px solid var(--accent);
  border-radius: 10px;
}

/* Badge für gestartetes Turnier */
.badge-started {
  background: #4db8c8;
  color: #fff;
}

.plan-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 14px;
  margin-bottom: 12px;
  padding: 10px 12px;
  background: var(--bg-card);
  border-radius: 10px;
}

.plan-legend-item {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: .8rem;
  font-weight: 600;
  cursor: pointer;
  border-radius: 4px;
  padding: 2px 6px;
  transition: background .15s, opacity .15s;
}
.plan-legend-item:hover { opacity: .75; }
.plan-legend-item-active {
  background: color-mix(in srgb, currentColor 15%, transparent);
  outline: 1px solid currentColor;
}

/* ── Turnier-Phasen-Header ── */
.plan-phase-header {
  font-size: .8rem;
  font-weight: 700;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--text-muted);
  padding: 14px 4px 6px;
  border-bottom: 2px solid var(--border);
  margin-bottom: 10px;
}

.plan-grid-scroll {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  margin: 0 calc(-1 * var(--space-card));
  padding: 0 var(--space-card);
}

/* ── Tabelle ── */
.standings-card {
  margin-top: 16px;
}
/* Format 'group-swiss' (js/tournament-formats/group-swiss.js): Swiss-Tabelle
   hat zusätzliche Tiebreak-Spalten (Buchholz, Sonneborn-Berger) und kann auf
   schmalen Bildschirmen breiter als der Viewport werden — eigener horizontal
   scrollbarer Container statt die ganze Seite scrollen zu lassen. */
.standings-scroll {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
.plan-match-bye { opacity: .65; }
/* Gruppenphase (group-swiss.js): seit der Dartscheiben-als-Spalten-Umstellung
   teilen sich ALLE Gruppen EIN gemeinsames Raster (siehe Kopf-Kommentar
   render(), Abschnitt "Gruppenphase" dort) — dieses Badge markiert auf jeder
   Karte, zu welcher Gruppe sie gehört, da das sonst nicht mehr aus einer
   separaten Pro-Gruppen-Tabelle hervorginge. */
.gs-group-badge {
  font-size: .65rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--text-muted);
  text-align: center;
  margin-bottom: 4px;
}
.gs-rematch-badge {
  margin-top: 4px;
  font-size: .72rem;
  color: var(--warn, #d4a63a);
  text-align: center;
}
/* Spalte 1 ist der Platz (#), Spalte 2 der Spielername — der gehoert nach
   links, die Platzziffer mittig. Alles Weitere kommt aus dem gemeinsamen
   Datentabellen-Block. */
.standings-table th:first-child,
.standings-table td:first-child { text-align: center; width: 1%; }
.standings-table td:nth-child(2),
.standings-table th:nth-child(2) { text-align: left; }
.standings-winner td { font-weight: 700; }
.standings-tied td { font-weight: 600; color: var(--accent); }
.standings-legend { font-size: .73rem; color: var(--text-muted); margin-top: 10px; line-height: 1.6; }
.standings-finale-box {
  margin-top: 14px;
  padding: 12px 14px;
  border-radius: var(--radius);
  border: 2px solid var(--accent);
  background: color-mix(in srgb, var(--accent) 8%, transparent);
  font-size: .88rem;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.standings-finale-done { border-color: var(--success, #22c55e); background: color-mix(in srgb, var(--success, #22c55e) 8%, transparent); }

/* Erstellen-Dialog 'group-swiss' (Nutzer-Feedback: Varianten statt 3 Zähler,
   #boards-groupswiss-group in index.html, js/app.js
   updateGroupSwissVariantPreview()): zwei auswählbare Karten + Live-Vorschau. */
.gs-variant-choice {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin: 14px 0;
}
.gs-variant-card {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 12px 14px;
  border: 2px solid var(--border);
  border-radius: var(--radius);
  cursor: pointer;
  transition: border-color var(--transition), background var(--transition);
}
.gs-variant-card:hover { border-color: var(--accent); }
.gs-variant-card input[type="radio"] {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}
.gs-variant-card:has(input:checked),
.gs-variant-card.selected {
  border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 8%, transparent);
}
.gs-variant-title { font-weight: 700; font-size: .92rem; }
.gs-variant-desc { font-size: .8rem; color: var(--text-muted); line-height: 1.4; }
.gs-variant-preview {
  font-size: .82rem;
  color: var(--text-muted);
  text-align: center;
  padding: 8px 10px;
  border-radius: var(--radius);
  background: var(--border);
  line-height: 1.5;
}

/* ── K.o.-Turnierbaum (js/tournament-formats/knockout.js) ── */
.ko-champion-banner {
  margin-bottom: 14px;
  padding: 14px 16px;
  border-radius: var(--radius);
  border: 2px solid var(--accent);
  background: color-mix(in srgb, var(--accent) 10%, transparent);
  font-size: .95rem;
  text-align: center;
}
.ko-champion-banner strong { font-size: 1.05rem; }

.ko-view-toggle {
  display: flex;
  gap: 8px;
  margin-bottom: 12px;
}

/* Listenansicht (Standard, mobil-freundlich) */
.ko-round-list-header {
  font-size: .8rem;
  font-weight: 700;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--text-muted);
  padding: 14px 4px 6px;
  border-bottom: 2px solid var(--border);
  margin-bottom: 10px;
}
/* Block C, Aufgabe 3: Karten-Layout aus renderTournamentPlan() (js/app.js,
   Format 'jeder gegen jeden') übernommen — .plan-match-players/.plan-match-name/
   .plan-match-center werden in matchCardHtml() (knockout.js) für die
   Listenansicht wiederverwendet.
   Dartscheiben-als-Spalten-Umstellung (js/tournament-formats/board-grid-core.js):
   die Listenansicht steckt Match-Karten jetzt in .plan-col-Spalten (analog zum
   Format 'Jeder gegen Jeden'), deren Breite bereits über
   grid-template-columns:minmax(180px,1fr) begrenzt ist — die frühere feste
   max-width:50% (für die vorherige, ungespaltene Vollbreiten-Liste gedacht)
   würde die Karte darin nur unnötig auf die halbe Spaltenbreite stauchen,
   daher hier auf volle Breite der (bereits schmalen) Spalte gesetzt. */
.ko-list-match {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 10px 12px;
  margin-bottom: 8px;
  display: flex;
  flex-direction: column;
  gap: 6px;
  max-width: 100%;
}

/* Baumansicht (horizontal scrollbar, Spalten = Runden) */
.ko-bracket-scroll {
  overflow-x: auto;
  overflow-y: hidden;
  -webkit-overflow-scrolling: touch;
  margin: 0 calc(-1 * var(--space-card));
  padding: 4px var(--space-card) 16px;
}
.ko-bracket {
  display: flex;
  align-items: flex-start;
  width: max-content;
}
/* Block C, Aufgabe 4: Baum-Spalten/Verbinder um 20% vergrößert (200px/28px ->
   240px/34px), passend zu ROW/CARD_H/CONN_W in renderTreeView() (knockout.js). */
.ko-round-col { position: relative; width: 320px; flex-shrink: 0; }
.ko-connector-col { position: relative; width: 34px; flex-shrink: 0; }
.ko-round-col-header {
  height: 24px;
  overflow: hidden;
  text-align: center;
  font-size: .72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--text-muted);
  white-space: nowrap;
}
.ko-connector-line {
  position: absolute;
  background: var(--border);
}

/* Match-Karte (in beiden Ansichten wiederverwendet) */
.ko-match {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 6px 10px;
  font-size: .8rem;
  box-sizing: border-box;
}
.ko-round-col .ko-match { position: absolute; width: 100%; overflow: hidden; }
/* Block C, Aufgabe 4: Baum-Match-Felder um 20% vergrößert (padding/font-size),
   Spielernamen stehen dank text-align in matchCardHtml() (knockout.js,
   nameHtml()-Parameter `align`) links-/rechtsbündig statt aneinandergedrängt. */
.ko-round-col .ko-match {
  padding: 7px 12px;
  font-size: .96rem;
  /* Keine feste Höhe mehr — die Karte wächst mit ihrem Inhalt und wird von
     renderTreeView per translateY(-50%) auf ihrer Soll-Mitte zentriert. */
  display: flex;
  flex-direction: column;
}
.ko-match-body { display: flex; align-items: center; gap: 8px; }
/* Namen bleiben EINZEILIG (kein Umbruch, keine hohen Karten) und passen
   trotzdem immer: matchCardHtml() vergibt je nach Länge des längeren der
   beiden Namen eine Größenklasse (.ko-name-s/-m/-l/-xl), die die Schrift
   herunterskaliert. min-width:0 ist nötig, damit ein Flex-Kind überhaupt
   schmaler werden darf als sein Inhalt — sonst drückt ein langer Name die
   Mittelspalte weg. Die Ellipsis greift erst bei absurd langen Namen. */
.ko-player {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  line-height: 1.3;
  font-weight: 600;
}
.ko-match-body.ko-name-s  .ko-player { font-size: 1em; }
.ko-match-body.ko-name-m  .ko-player { font-size: .88em; }
.ko-match-body.ko-name-l  .ko-player { font-size: .78em; }
.ko-match-body.ko-name-xl .ko-player { font-size: .68em; }
.ko-player-winner { color: var(--accent); }
.ko-vs { font-size: .7rem; color: var(--text-muted); flex-shrink: 0; }
.ko-score { font-size: .72rem; color: var(--text-muted); text-align: center; margin-top: 2px; }
/* Block C, Aufgabe 5: Scheiben-Anzeige pro Match (nur bei >1 Scheibe im
   jeweiligen Board-Pool, siehe boardsTotal in buildCtx()/matchCardHtml()). */
.ko-match-board { font-size: .68rem; color: var(--text-muted); text-align: center; margin-top: 2px; }
.ko-match-future { opacity: .45; }
.ko-match-bye { opacity: .55; }
.ko-match-done { opacity: .75; }
.ko-match-inprogress { border-color: var(--accent); }
.ko-match-selected {
  border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 12%, transparent);
}
.ko-match[data-match-id] { cursor: pointer; }
.ko-live-actions { display: flex; gap: 4px; }
.btn-xs { padding: 2px 6px; font-size: .68rem; }

/* Turnierbaum + Loser-Cup (js/tournament-formats/knockout-loser-cup.js):
   Tab-Umschalter Hauptrunde/Loser-Cup wiederverwendet .ko-view-toggle 1:1;
   .lc-tabs ergänzt nur etwas mehr Abstand zum darunterliegenden Baum/Liste-
   Umschalter. Zweite Champion-Banner-Farbe grenzt den Loser-Cup-Sieger
   optisch vom Turniersieger ab. */
.lc-tabs { margin-bottom: 14px; }
.lc-champion-banner {
  border-color: var(--warning, #e0a030);
  background: color-mix(in srgb, var(--warning, #e0a030) 10%, transparent);
}

/* ── Setzliste-Modal (Aufgabe 2, Nutzer-Feedback: manuelle Setzliste mit
   ELO-Vorschlag für 'knockout'/'knockout-loser-cup', siehe js/app.js
   openSeedingModal()) — .bulloff-card ist standardmäßig zentriert/schmal,
   hier linksbündig und etwas breiter für eine scrollbare Namensliste. */
.seed-card { max-width: 480px; text-align: left; }
.seed-card h2 { text-align: center; }
.seed-list {
  max-height: 50vh;
  overflow-y: auto;
  margin-bottom: 16px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.seed-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 8px;
}
.seed-pos { font-weight: 700; color: var(--text-muted); width: 1.8em; flex-shrink: 0; }
.seed-name { flex: 1; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.seed-rating { font-size: .78rem; color: var(--text-muted); flex-shrink: 0; }
.seed-rating-none { font-style: italic; }
.seed-row-actions { display: flex; gap: 4px; flex-shrink: 0; }

@media (max-width: 640px) {
  .ko-round-col { width: 180px; }
  /* Block C, Aufgabe 3: auf dem Handy volle Breite statt 50% — sonst wären
     Name/vs/Schreiber/Scheibe auf sehr schmalen Screens kaum lesbar. */
  .ko-list-match { max-width: 100%; }
}

/* ── Toggle-Label (Checkbox) ── */
.toggle-label {
  display: flex;
  align-items: center;
  gap: 8px;
  cursor: pointer;
  font-size: .9rem;
}
.toggle-label input[type="checkbox"] {
  width: 16px;
  height: 16px;
  accent-color: var(--primary, #4db8c8);
  cursor: pointer;
}

/* ── Toast ── */
.toast {
  position: fixed;
  bottom: max(28px, calc(env(safe-area-inset-bottom, 0px) + 12px));
  right: max(28px, calc(env(safe-area-inset-right, 0px) + 12px));
  background: #2d3748;
  color: #fff;
  padding: 12px 20px;
  border-radius: 8px;
  font-size: .88rem;
  font-weight: 500;
  box-shadow: 0 4px 20px rgba(0,0,0,.25);
  animation: slideIn .25s ease;
  z-index: 999;
  max-width: calc(100vw - 40px);
}
@keyframes slideIn {
  from { opacity: 0; transform: translateY(12px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* ════════════════════════════════════════════
   RESPONSIVE — Mobile First, Biggest First
   ════════════════════════════════════════════ */

/* ── Tablet Landscape / Small Desktop (≤ 1024px) ── */
@media (max-width: 1024px) {
  .card-grid { grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); }
  .game-score-card { padding: 10px 14px; }
}

/* ── Tablet Portrait (≤ 768px) ── */
@media (max-width: 768px) {
  :root {
    --space-content: 20px;
    --space-card:    20px;
  }
  .topbar { padding: 10px 20px; }
  .card-grid { grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); }
  .game-scores { gap: 10px; }
  .numpad-table { gap: 5px; }
  .num-btn { font-size: clamp(1.1rem, 2.04vh, 1.38rem); }

  /* Dart-Tracker: kompakte Darstellung für Tablet portrait */
  .dart-and-total { gap: 12px; }
  .player-dart-slot { min-width: 52px; padding: 3px 8px; }
  .player-dart-slot .slot-val { font-size: 1.5rem; }
  .turn-total-box { min-width: 60px; padding: 3px 8px; }
  .turn-total-box .slot-val { font-size: 1.5rem; }
}

/* ── Large Phones / Small Tablets (≤ 640px) ── */
@media (max-width: 640px) {
  :root {
    --space-content: 16px;
    --space-card:    16px;
  }

  /* Sidebar: force collapsed */
  .sidebar { width: 38px; }
  .logo-text, .nav-label { display: none; }
  .sidebar-header { justify-content: center; padding: 0 0 16px; }
  .nav-item { justify-content: center; padding: 10px 8px; }
  .nav-icon { font-size: 1.2rem; width: 20px; }
  .sidebar-toggle-btn { justify-content: center; padding: 8px 10px; }

  /* Topbar */
  .topbar { padding: 7px 16px; }
  .page-title { font-size: 1rem; }

  /* Cards */
  .card-grid { grid-template-columns: minmax(0, 1fr); }
  .card-grid > * { min-width: 0; }
  .card-header-row { flex-wrap: wrap; row-gap: 8px; }
  #config-players-row,
  #config-players-row #new-game-players,
  #config-players-row #player-selection-row,
  #tv-info-players-row,
  #tv-info-players-row #tv-player-card,
  #tv-info-players-row #tv-chips-row {
    min-width: 0;
  }
  #config-players-row { flex-direction: column; }
  /* Untereinander darf die Turnierliste die volle Breite nutzen — die
     Obergrenze gilt nur fuer die Zeile neben den Einstellungen. */
  #tournament-active-card { max-width: none; }
  #player-selection-row { flex-direction: column !important; }
  #tv-info-players-row { flex-direction: column; }
  #tv-chips-row { flex-direction: column !important; }
  .card-pair { flex-direction: column; }

  /* Spieler-Chips: nach unten statt zur Seite wachsen lassen */
  .saved-players-chips {
    grid-auto-flow: row !important;
    grid-template-rows: none !important;
    grid-template-columns: repeat(auto-fill, minmax(96px, 1fr));
  }

  /* Turnierplan: Dartscheiben-Spalten untereinander statt seitlich scrollen */
  .plan-grid { grid-template-columns: 1fr !important; }

  /* Game view */
  .content.game-active { padding: 8px; }
  .game-layout { gap: 6px; }
  .numpad-area { gap: 4px; }

  /* Score cards */
  .game-score-card { padding: 4px 8px; }
  .game-score-card .player-name { font-size: clamp(0.73rem, 2.2vw, 0.95rem); }
  .game-score-card .player-score { font-size: clamp(1.35rem, 5.6vw, 2.7rem); }
  .game-score-card .player-meta { font-size: .77rem; }
  .player-live-stats { font-size: .7rem; gap: 6px; }
  .dart-and-total { gap: 10px; }
  .player-dart-slot { min-width: 32px; padding: 2px 3px; }
  .player-dart-slot .slot-val { font-size: .92rem; }
  .turn-total-box { min-width: 52px; padding: 2px 6px; }
  .turn-total-box .slot-val { font-size: .92rem; }
  .dart-tracker-hints { gap: 4px; }
  .dart-tracker-slots { gap: 4px; }

  /* Numpad: switch from 3-column grid to stacked sections (5 buttons per row) */
  .numpad-table {
    display: flex;
    flex-direction: column;
    gap: 4px;
    overflow-y: auto;
    flex: 1;
    min-height: 0;
  }
  .numpad-col {
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    grid-template-rows: repeat(4, 1fr);
    gap: 3px;
  }
  .num-btn {
    min-height: 42px;
    padding: 7px 2px;
    font-size: clamp(1.14rem, 4.32vw, 1.38rem);
  }
  .special-btn {
    min-height: 48px;
    font-size: .9rem;
    padding: 8px 4px;
  }
  .numpad-actions { gap: 6px; }
  #undo-btn { padding: 12px 8px; font-size: .92rem; min-height: 48px; }
  #next-btn { padding: 12px 10px; font-size: .92rem; min-height: 48px; flex-basis: 25%; }

  /* Mode buttons */
  .mode-btn { padding: 10px 8px; font-size: .9rem; }
  .game-options .mode-buttons { flex-wrap: wrap; }

  /* Counter */
  .sets-legs-row { gap: 10px; }

  /* Dart tracker */
  .dart-slots { padding: 8px 12px; gap: 8px; }
  .dart-slot { min-width: 48px; }
  .slot-val { font-size: 1.1rem; }
  .checkout-hint { font-size: .78rem; min-height: 16px; }

  /* Datentabellen: auf schmalen Displays durchgehend enger — gilt fuer alle
     Tabellen gemeinsam, siehe Datentabellen-Block oben. */
  .table, .stats-cmp-table, .stats-compare-table, .stats-leg-table,
  .standings-table, .rl-table, .admin-table { font-size: .82rem; }
  .table th, .table td,
  .stats-cmp-table th, .stats-cmp-table td,
  .stats-compare-table th, .stats-compare-table td,
  .stats-leg-table th, .stats-leg-table td,
  .standings-table th, .standings-table td,
  .rl-table th, .admin-table th, .admin-table td { padding: 7px 8px; }
  .rl-row td { padding: 9px 8px; }
  /* Zwischenueberschriften brauchen weniger Vorlauf, wenn ohnehin wenig Platz ist */
  .data-table-group td, .stats-cmp-group td { border-top-width: 18px; padding: 8px 8px 8px 12px; }

  /* Game bottom */
  .game-bottom { grid-template-columns: 1fr; }

  /* Tournament */
  .plan-grid { gap: 10px; }
  .plan-match { padding: 8px 10px; }
  .plan-match-players { font-size: .82rem; }
  .plan-action-bar { flex-direction: column; align-items: stretch; gap: 8px; }
  .plan-legend { gap: 4px 10px; }
  .invite-bar { gap: 8px; }
  .invite-code { font-size: .95rem; }
  .plan-grid { gap: 8px; }
}

/* ── Standard Phones (≤ 480px) ── */
@media (max-width: 480px) {
  :root {
    --space-content: 12px;
    --space-card:    14px;
  }

  /* Topbar */
  .topbar { padding: 6px 10px; }
  .page-title { font-size: .95rem; }
  .topbar #back-btn { padding: 5px 8px; font-size: .78rem; }

  /* Premium-Preise: PayPal-Buttons brauchen eine Mindestbreite, die auf
     schmalen Handys nicht mehr nebeneinander passt -> untereinander stapeln */
  .premium-price-row { flex-direction: column; }

  /* Numpad buttons */
  .num-btn { min-height: 44px; font-size: clamp(1.056rem, 3.6vw, 1.2rem); }
  .special-btn { min-height: 50px; }
  #undo-btn { min-height: 50px; }
  #next-btn { min-height: 50px; flex-basis: 25%; }

  /* Overlays */
  .bulloff-card,
  .leg-win-card,
  .game-over-card {
    padding: 24px 20px;
    width: calc(100% - 24px);
    max-width: unset;
  }
  .bulloff-card h2 { font-size: 1.2rem; }
  .bulloff-player-btn { padding: 14px 10px; font-size: .9rem; }
  .leg-win-name { font-size: 1.6rem; }
  .game-over-card h2 { font-size: 1.3rem; }
  .game-over-card .winner-name { font-size: 1.6rem; }
  .stats-player-block { min-width: unset; flex: 1 1 100%; }
  /* Abschlussbildschirm: die Vergleichstabelle steht in einer Karte mit
     ohnehin wenig Platz — hier noch etwas enger als der Mobil-Standard. */
  .stats-compare-table th, .stats-compare-table td { padding: 6px 8px; font-size: .78rem; }
  .game-over-achievements { max-height: 180px; }

  /* Auth card */
  .auth-card { padding: 24px 20px; }

  .player-live-stats { margin-bottom: 4px; }

  /* Game active */
  .content.game-active { padding: 8px; }
  .game-layout { gap: 6px; }

  /* Tournament */
  .plan-col-header { font-size: .68rem; padding: 4px 0 8px; }
  .participant-bar { gap: 4px; }

  /* Voice select: wrap on narrow screens */
  .voice-select-inner { flex-wrap: wrap; }

  .player-add-row { flex-wrap: wrap; }
  .player-add-row .btn { width: 100%; }

  /* Toast: full width centered on phones */
  .toast {
    bottom: max(16px, calc(env(safe-area-inset-bottom, 0px) + 8px));
    right: 12px;
    left: 12px;
    text-align: center;
    max-width: unset;
  }
}

/* ── Spieltyp-Auswahl ── */

.gametype-buttons {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 4px;
}

.gametype-btn {
  padding: 9px 16px;
  border-radius: 8px;
  border: 2px solid var(--border);
  background: transparent;
  font-size: .85rem;
  font-weight: 600;
  cursor: pointer;
  color: var(--text-muted);
  transition: all var(--transition);
  white-space: nowrap;
}
.gametype-btn:hover  { border-color: var(--accent); color: var(--accent); }
.gametype-btn.selected { border-color: var(--accent); background: var(--accent); color: #fff; }

.gametype-desc {
  color: var(--text-muted);
  font-size: .88rem;
  line-height: 1.5;
  margin-top: 14px;
}

/* ── Cricket ── */

.cricket-fields { display: flex; flex-direction: column; gap: 2px; margin: 10px 0 8px; }
.cricket-field-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 5px 0;
  border-bottom: 1px solid var(--border);
}
.cricket-field-row:last-child { border-bottom: none; }
.cricket-field-row.closed { opacity: .45; }
.cricket-field-name { font-weight: 700; font-size: .95rem; min-width: 34px; }
.cricket-marks { display: flex; gap: 5px; align-items: center; }
.cricket-mark { font-size: 1.15rem; font-weight: 800; color: var(--border); line-height: 1; }
.cricket-mark.filled { color: var(--accent); }
.cricket-points-badge { font-size: 1.3rem; font-weight: 800; color: var(--accent); }
.cricket-dart-slots {
  display: flex;
  gap: 6px;
  justify-content: center;
  margin: 8px 0 4px;
}

/* ── Around the Clock ── */

.atc-target { text-align: center; margin: 14px 0 8px; }
.atc-target-label { font-size: .7rem; text-transform: uppercase; font-weight: 700; color: var(--text-muted); letter-spacing: .4px; }
.atc-target-number { font-size: clamp(2.5rem, 6vh, 5rem); font-weight: 800; color: var(--accent); line-height: 1.1; }
.atc-progress-bar { height: 6px; background: var(--border); border-radius: 3px; overflow: hidden; margin: 8px 0 4px; }
.atc-progress-fill { height: 100%; background: var(--accent); border-radius: 3px; transition: width .3s ease; }
.atc-progress-text { font-size: .78rem; color: var(--text-muted); text-align: center; margin-bottom: 8px; }

/* ── Checkout-Trainer ── */

.checkout-trainer-card { text-align: center; max-width: 380px; margin: 0 auto; flex: 1; }
.checkout-trainer-score { font-size: clamp(3rem, 8vh, 6rem); font-weight: 800; color: var(--accent); line-height: 1; margin-bottom: 4px; }
.checkout-trainer-hint { font-size: .78rem; color: var(--text-muted); text-transform: uppercase; font-weight: 700; letter-spacing: .4px; margin-bottom: 12px; }
.checkout-trainer-result { padding: 9px 14px; border-radius: 8px; font-weight: 700; font-size: .95rem; margin-bottom: 10px; }
.checkout-result-ok   { background: rgba(56,161,105,.15); color: #38a169; }
.checkout-result-fail { background: rgba(229,62,62,.12); color: var(--danger); }
.checkout-optimal { font-size: .8rem; font-weight: 400; margin-top: 3px; }
.checkout-optimal-show { font-size: .82rem; color: var(--text-muted); margin-bottom: 10px; min-height: 1.2em; }
.checkout-trainer-stats { display: flex; gap: 14px; justify-content: center; font-size: .84rem; margin-top: 12px; flex-wrap: wrap; }

/* ── Statistiken ── */

/* Steuerleiste: links alles, was die Datenmenge einschraenkt (Filter), rechts
   oben nur die Darstellung (Ansicht). Beide Bloecke sind beschriftet — ohne
   Ueberschrift war nicht erkennbar, wozu die Knopfreihen gehoeren. */
.stats-controls {
  width: 100%;
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 24px;
  flex-wrap: wrap;
}

.stats-controls-block {
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-width: 0;
}
/* Rechter Block der Steuerleiste (Zeitraum). Rechtsbuendig ueber das
   space-between an .stats-controls; align-items haelt auch die Beschriftung
   ueber dem Feld rechts. Der Abstand zum Bildschirmrand kommt aus der
   Kartenpolsterung, ist also derselbe wie bei allen anderen Karten. */
.stats-controls-range { align-items: flex-end; }

.stats-controls-label {
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.stats-filter-buttons {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
}
/* Zwei Gruppen: die drei Auswahl-Popups einerseits, der Gegnertyp-Umschalter
   andererseits. Mit demselben 10px-Abstand wie zwischen den Popup-Knoepfen
   sahen sie wie eine einzige lange Reihe aus. */
.stats-filter-buttons > .stats-opponent-tabs {
  margin-left: 22px;
  padding-left: 22px;
  border-left: 1px solid var(--border);
}
@media (max-width: 700px) {
  /* Umgebrochen steht der Umschalter in einer eigenen Zeile — dort waere eine
     senkrechte Trennlinie sinnlos. */
  .stats-filter-buttons > .stats-opponent-tabs {
    margin-left: 0;
    padding-left: 0;
    border-left: none;
  }
}
.stats-filter-btn {
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Auf schmalen Displays rutscht der Ansichtsblock unter die Filter und richtet
   sich dann ebenfalls links aus — rechtsbuendig wirkt dort verloren. */
@media (max-width: 700px) {
  .stats-controls-view { align-items: flex-start; }
}

/* ── Untere Reihe: Kennzahlentabelle + Letzte Spiele/Verlauf ──
   Kartenansicht: die beiden Karten nebeneinander (wie vor der
   Tabellenansicht). Tabellenansicht: die Tabelle links, nur so breit wie ihre
   Spalten es verlangen, die beiden anderen Karten rechts daneben
   untereinander. Passt das nicht mehr, bricht die Seitenspalte darunter. */
.stats-lower-row {
  grid-column: 1 / -1;
  display: flex;
  gap: 20px;
  align-items: flex-start;
  flex-wrap: wrap;
}
.stats-side-column {
  display: flex;
  gap: 20px;
  flex: 1 1 340px;
  min-width: 0;
  align-items: stretch;
}
.stats-side-column > .card { flex: 1; min-width: 0; margin: 0; }

/* Gegner + Letzte Spiele nebeneinander. Bricht auf schmalen Bildschirmen
   untereinander um; ist die Gegner-Karte ausgeblendet, nimmt die Partienliste
   die volle Breite. */
.stats-pair-row {
  grid-column: 1 / -1;
  display: flex;
  gap: 20px;
  align-items: flex-start;
  flex-wrap: wrap;
}
.stats-pair-row > .card { flex: 1 1 380px; min-width: 0; margin: 0; }

/* Zeilen der Gegnerliste sind anklickbar: sie nehmen den Spieler in den
   Filter auf. Dieselbe Optik wie die Auswahlzeilen in den Popups, damit die
   Klickbarkeit ohne Erklaerung erkennbar ist. */
.stats-opponents-table tbody tr { cursor: pointer; }
.stats-opponents-table tbody tr:hover { background: var(--bg); }
.stats-opponents-table tbody tr.selected {
  background: rgba(79,110,247,.10);
  box-shadow: inset 3px 0 0 var(--accent);
}

/* Kartenkopf mit Aktion rechts (Gegner-Karte: "Partien im Detail"). */
.stats-card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
}
.stats-card-head h2 { margin: 0; display: inline-flex; align-items: baseline; gap: 8px; }

/* Spieltyp-Reiter ueber der Kennzahlentabelle. Sitzen zwischen Ueberschrift
   und Tabelle, damit klar ist, dass sie NUR diese Tabelle betreffen — die
   Filter der Seite stehen ganz oben in der Steuerleiste. */
.stats-metric-types {
  flex-wrap: wrap;
  margin: 4px 0 12px;
}

/* Zaehler neben der Ueberschrift ("1/3 ausgewaehlt"). Deutlich leiser als der
   Titel — er informiert, konkurriert aber nicht mit ihm. */
.stats-count-badge {
  font-size: .75rem;
  font-weight: 600;
  color: var(--text-muted);
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 2px 8px;
  white-space: nowrap;
}

/* Auswaehlbare Zeilen in Spiel- und Turnierverlauf — dieselbe Optik wie die
   Gegnerliste, damit ueberall gleich erkennbar ist, was sich anklicken laesst. */
.stats-pick-row { cursor: pointer; }
.stats-pick-row:hover { background: var(--bg); }
.stats-pick-row.selected {
  background: rgba(79,110,247,.10);
  box-shadow: inset 3px 0 0 var(--accent);
}

.stats-detail-head-text { display: flex; flex-direction: column; gap: 2px; }

/* .card.full-width ist ein Flex-Container mit justify-content:center. Ohne
   diese Zeile schrumpft der Inhalt auf seine natuerliche Breite und steht
   mittig — das Kartenraster darin bekam dadurch nur einen Bruchteil der
   Seitenbreite und stapelte die Partien untereinander, statt sie zu verteilen.
   Dieselbe Notwendigkeit wie bei .card.full-width.card-narrow weiter oben. */
#stats-detail-view .card.full-width > * { flex: 1; min-width: 0; }

/* ── Partien im Detail ───────────────────────────────────────────────────────
   Erbt das Raster von .tv-match-list, weicht aber bewusst ab: die Karten hier
   tragen vier Kennzahlengruppen und sind entsprechend hoch. Bei nur 12px
   Abstand und einer duennen Kante war nicht zu erkennen, wo eine Karte endet
   und die naechste beginnt — besonders in der zweiten Reihe.

   Spaltenzahl ueber auto-fill statt fest: so entstehen so viele Spalten, wie
   bei lesbarer Mindestbreite hineinpassen, statt immer drei zu erzwingen. */
.stats-detail-list {
  /* min(240px, 100%) statt nur 240px: auf sehr schmalen Geraeten waere eine
     Spalte sonst breiter als der Bildschirm und die Seite muesste waagerecht
     scrollen. So schrumpft die letzte Spalte stattdessen mit.
     240px ist bewusst knapp — bei 330px kamen auf mittleren Bildschirmen
     weniger Spalten heraus als die frueher fest eingestellten drei. */
  grid-template-columns: repeat(auto-fill, minmax(min(240px, 100%), 1fr));
  /* Zeilenabstand groesser als der Spaltenabstand: senkrecht stossen die
     Karten aufeinander, waagerecht trennt sie ohnehin die Rasterlinie. */
  column-gap: 18px;
  row-gap: 28px;
}
/* Kompakter als die Turnierkarten: bei fuenf Spalten nebeneinander zaehlt
   jeder Pixel Innenabstand. */
.stats-detail-list .tv-match-metric { font-size: .82rem; }
.stats-detail-list .tv-match-metric-label { font-size: .72rem; }
.stats-detail-list .tv-match-card {
  /* Rasterelemente haben von Haus aus min-width:auto und koennen daher nicht
     schmaler werden als ihr Inhalt — eine lange Kennzahlzeile haette die Spalte
     aufgeblaeht und die Seite waagerecht scrollen lassen. */
  min-width: 0;
  /* DER entscheidende Punkt: die Karten lagen auf --surface — derselben Farbe
     wie die Karte, in der die Liste steht. Damit war ihre Kante unsichtbar,
     und die einzigen sichtbaren Linien waren die vier Gruppenbaender JE
     Partie. Man sah also vier Trennlinien pro Karte und keine einzige
     zwischen zwei Karten.
     Auf --bg (dunkler als --surface im Dunkelmodus, heller im Hellmodus)
     liest jede Partie als eigener, eingelassener Block. */
  background: var(--bg);
  border: 1px solid var(--border);
  border-top: 3px solid var(--accent);
  border-radius: 10px;
  padding: 16px 14px 14px;
}
/* Die Gruppenbaender treten zurueck: sie gliedern INNERHALB einer Partie und
   duerfen nicht mit der Kartenkante um Aufmerksamkeit konkurrieren. Ohne
   Vollflaeche und ohne farbige Oberkante bleibt die staerkste waagerechte
   Linie die Grenze zwischen zwei Partien. */
.stats-detail-list .data-group-band {
  background: none;
  border-top: 1px solid var(--border);
  border-bottom: none;
  color: var(--text-muted);
  margin: 14px -14px 4px;
  padding: 8px 14px 0;
}
.stats-detail-list .data-group-band:first-child { margin-top: 0; border-top: none; padding-top: 0; }
/* Die Kopfzeile der Karte bekommt eine Trennlinie zu den Kennzahlen darunter,
   damit Paarung und Werte nicht ineinanderlaufen. */
.stats-detail-list .tv-match-head {
  padding-bottom: 10px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 4px;
}

/* Tabellenansicht: Tabelle waechst mit der Spielerzahl, bleibt aber
   linksbuendig und nimmt nie mehr Platz als noetig. */
.stats-lower-row--table > #stats-table-card {
  flex: 0 1 auto;
  width: max-content;
  /* min: sonst waere die Tabelle bei einem einzigen Spieler fast fadenduenn */
  min-width: 340px;
  max-width: 100%;
  margin: 0;
}
.stats-lower-row--table > .stats-side-column {
  flex-direction: column;
}

@media (max-width: 900px) {
  .stats-side-column { flex-direction: column; flex-basis: 100%; }
}

/* Waechst waagerecht in einem eigenen Scroll-Container, damit die Seite selbst
   nie seitlich scrollt. */
.stats-cmp-wrap { overflow-x: auto; }

/* "Letzte Spiele" im Vergleich: je Spieler eine Spaltengruppe. Die Trennlinie
   zwischen den Gruppen macht sichtbar, welche Werte zusammengehoeren. */
.stats-history-grouped th.stats-history-group {
  text-align: center;
  border-bottom: 2px solid var(--border);
}
/* Zeilenaufbau: Datum | Typ | (Ergebnis, Ø, Best Leg) je Spieler. Die letzte
   Spalte jeder Gruppe ist also 3n+2; am Tabellenrand entfaellt die Linie. */
.stats-history-grouped th.stats-history-group:not(:last-child),
.stats-history-grouped thead tr:last-child th:nth-child(3n):not(:last-child),
.stats-history-grouped tbody td:nth-child(3n + 2):not(:last-child) {
  border-right: 1px solid var(--border);
}
/* "nicht dabei" fasst die drei Wertespalten eines Spielers zusammen, der bei
   dieser Partie nicht mitgespielt hat — als Text mittig statt drei Striche,
   die wie eine Leerzeile aussahen. */
.stats-history-empty {
  color: var(--text-muted);
  font-size: .8rem;
  font-style: italic;
  text-align: center;
}
/* Trainer-Session: Treffer/Versuche in der Ergebnisspalte */
.stats-history-session { font-variant-numeric: tabular-nums; }

/* Legende des Average-Verlaufs (nur bei mehreren Spielern) */
.stats-chart-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-bottom: 8px;
  font-size: .8rem;
  color: var(--text-muted);
}
/* Legendeneintrag ist ein Knopf: ein Klick hebt die zugehoerige Kurve hervor.
   Sieht bewusst nicht nach Knopf aus — er soll sich wie die anklickbaren
   Spielernamen im Turnierplan anfuehlen, nicht wie eine Schaltflaeche. */
.stats-chart-legend-item {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: none;
  border: 1px solid transparent;
  border-radius: 999px;
  padding: 2px 8px;
  font: inherit;
  color: inherit;
  cursor: pointer;
  transition: opacity .15s, border-color .15s, color .15s;
}
.stats-chart-legend-item:hover { opacity: .75; }
.stats-chart-legend-item:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.stats-chart-legend-item--active {
  border-color: var(--accent);
  color: var(--text);
  font-weight: 700;
}
.stats-chart-swatch {
  width: 12px;
  height: 3px;
  border-radius: 2px;
  display: inline-block;
}

/* Hervorhebung im Diagramm — dieselbe Logik wie plan-match-highlight/-dimmed
   im Turnierplan: das Gewaehlte bleibt voll sichtbar, der Rest tritt zurueck.
   Ueber Farbe allein waeren die Kurven bei vielen Spielern nicht mehr
   auseinanderzuhalten, weil sich Farben und Strichmuster wiederholen. */
.stats-chart-serie { transition: opacity .15s; }
.stats-chart-serie--dimmed { opacity: .15; }
.stats-chart-serie--highlight polyline { stroke-width: 3.5; }
.stats-chart-serie--highlight circle { r: 5; }

/* Hinweiszeile ueber den Auswahllisten: erklaert, warum dort nur ein Teil der
   Optionen steht, und traegt den Umschalter auf die lockere Regel.
   Siehe renderStatsFacetHint() in js/app.js. */
.stats-facet-hint {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 4px 8px;
  margin: -4px 0 12px;
  font-size: .8rem;
  color: var(--text-muted);
}
.stats-facet-hint:empty { margin: 0; }
.stats-facet-toggle {
  border: none;
  background: none;
  padding: 0;
  font: inherit;
  color: var(--accent);
  font-weight: 600;
  cursor: pointer;
  text-decoration: underline;
}
/* Der Bereinigen-Knopf ist eine Warnung, kein normaler Filter — er taucht nur
   auf, wenn etwas nicht stimmt, und soll das auch aussehen. */
.stats-filter-clean {
  border-color: var(--danger);
  color: var(--danger);
}

/* Turnierzeile im Auswahl-Popup: Name oben, Metazeile darunter — gleiches
   Muster fuer die Spieltyp-Zeilen (Name + Trefferzahl). */
.stats-facet-row .players-row-main,
.stats-tournament-row .players-row-main {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.stats-tournament-meta {
  font-size: .75rem;
  color: var(--text-muted);
}

.stats-kpi-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
  gap: 10px;
  margin-top: 4px;
}

.stats-kpi {
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 14px 10px;
  text-align: center;
}
.stats-kpi-value {
  font-size: 1.5rem;
  font-weight: 800;
  color: var(--accent);
  line-height: 1.1;
}
.stats-kpi-label {
  font-size: .7rem;
  font-weight: 600;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: .4px;
  margin-top: 5px;
}
/* Turnier-Highlights: feste Spaltenzahl statt auto-fill. Die 8 Kacheln
   fuellen sich zeilenweise von links nach rechts und dann nach unten
   (Nutzer-Vorgabe) — mit auto-fill sprang die Spaltenzahl je nach Breite
   und die Kacheln wurden auf grossen Schirmen zu schmalen Streifen. */
.tv-highlight-grid { grid-template-columns: repeat(4, 1fr); grid-auto-flow: row; }
@media (max-width: 1200px) { .tv-highlight-grid { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 760px)  { .tv-highlight-grid { grid-template-columns: repeat(2, 1fr); } }

/* Namens-Chip in den Turnier-Highlights: eigene Zeile statt "· Name" im
   grauen Label, damit der Rekordhalter auf einen Blick erkennbar ist. */
.stats-kpi-name {
  display: inline-block;
  max-width: 100%;
  margin-top: 7px;
  padding: 3px 9px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--accent) 16%, transparent);
  color: var(--text);
  font-size: .8rem;
  font-weight: 700;
  line-height: 1.25;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.stats-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 9px 0;
  border-bottom: 1px solid var(--border);
  font-size: .9rem;
}
.stats-row:last-child { border-bottom: none; }
.stats-row-label { color: var(--text-muted); }
.stats-row-value { font-weight: 700; color: var(--text); }

.stats-history-table { font-size: .82rem; }
.stats-result-win  { color: #38a169; font-weight: 700; }
.stats-result-loss { color: var(--text-muted); font-weight: 500; }

/* ── Small Phones (≤ 360px) ── */
@media (max-width: 360px) {
  .sidebar { width: 38px; }
  .nav-item { padding: 9px 6px; }
  .sets-legs-row { flex-direction: column; gap: 8px; }
  .mode-btn { padding: 8px 4px; font-size: .82rem; }
}

/* ── Landscape Phones (kurze Viewport-Höhe ≤ 500px) ── */
@media (orientation: landscape) and (max-height: 500px) {
  /* Spacing komprimieren — auch für breite Phones (Breite > 640px) */
  :root {
    --space-content: 10px;
    --space-card:    12px;
  }

  /* Sidebar immer eingeklappt */
  .sidebar { width: 38px; }
  .logo-text, .nav-label { display: none; }
  .sidebar-header { justify-content: center; padding: 0 0 12px; }
  .nav-item { justify-content: center; padding: 9px 6px; }
  .sidebar-toggle-btn { justify-content: center; }

  /* Topbar kompakter */
  .topbar { padding: 6px 12px; }
  .page-title { font-size: 1rem; }
  .topbar #back-btn { padding: 5px 10px; font-size: .8rem; }

  /* Game view */
  .content.game-active { padding: 6px; }
  .game-layout { gap: 4px; }
  .numpad-area { gap: 4px; }

  /* Score cards kompakt */
  .game-score-card { padding: 4px 8px; }
  .game-score-card .player-score { font-size: clamp(1.35rem, 4.5vh, 2.8rem); }
  .game-score-card .player-name  { font-size: clamp(0.73rem, 2.0vh, 1.0rem); }
  .game-scores { gap: 6px; }
  .player-live-stats { font-size: .7rem; gap: 6px; margin-bottom: 3px; }
  .player-history { display: none; }

  /* Checkout-tracker kompakt — auch auf breiten Landscape-Phones */
  .dart-tracker-hints { gap: 3px; }
  .dart-tracker-slots { gap: 3px; }
  .player-dart-slot { min-width: 28px; padding: 2px 3px; }
  .player-dart-slot .slot-val { font-size: .88rem; }

  /* Dart-tracker */
  .dart-slots { padding: 6px 10px; gap: 6px; }
  .dart-slot { min-width: 40px; }
  .slot-val { font-size: 1rem; }
  .checkout-hint { min-height: 14px; font-size: .72rem; }

  /* Landscape vereinfachen */
  .player-dart-slot { display: none; }
  .dart-and-total { justify-content: center; }

  /* Numpad: 3-Spalten Desktop-Layout wiederherstellen */
  .numpad-table {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 4px;
    overflow-y: auto;
  }
  .numpad-col {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    grid-template-rows: repeat(5, 1fr);
    gap: 3px;
  }
  .num-btn {
    min-height: 0;
    padding: clamp(3px, 1vh, 7px) 2px;
    font-size: clamp(0.9rem, 2.04vh, 1.176rem);
    flex: unset;
  }
  .numpad-special {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 4px;
  }
  .special-btn { min-height: 0; padding: clamp(4px, 1.2vh, 8px) 4px; font-size: .8rem; }
  .numpad-actions { gap: 5px; }
  #undo-btn { padding: clamp(4px, 1.2vh, 8px) 8px; font-size: .85rem; }
  #next-btn { padding: clamp(4px, 1.2vh, 8px) 10px; font-size: .85rem; flex-basis: 25%; }
}

/* ── Sidebar-Overlay ── */
.sidebar-overlay {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,.45);
  z-index: 99;
}
.sidebar-overlay.visible { display: block; }
@media (min-width: 641px) { .sidebar-overlay { display: none !important; } }

/* ── Custom Confirm Modal ── */
#confirm-modal {
  display: none;
  position: fixed;
  inset: 0;
  z-index: 3000;
  background: rgba(0,0,0,.6);
  align-items: center;
  justify-content: center;
  padding: 16px;
}
#confirm-modal.open { display: flex; }
.confirm-card {
  background: var(--surface);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 28px 24px 20px;
  max-width: 380px;
  width: 100%;
}
.confirm-card p {
  margin: 0 0 20px;
  color: var(--text);
  font-size: .95rem;
  line-height: 1.5;
}
.confirm-actions {
  display: flex;
  gap: 10px;
  justify-content: flex-end;
}

/* ── Danger Zone ── */
.danger-zone {
  border-top: 1px solid var(--border);
  margin-top: 16px;
  padding-top: 16px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

/* ── Score-Cards viele Spieler (mobile) ── */
@media (max-width: 640px) {
  .game-scores--many .player-dart-slot { display: none; }
  .game-scores--many .dart-and-total { justify-content: center; }
}

/* ════════════════════════════════════════════
   ACHIEVEMENT-SYSTEM
   ════════════════════════════════════════════ */

/* Achievement-Toast Container (stacks multiple toasts) */
#ach-toast-container {
  position: fixed;
  top: 20px;
  right: max(20px, calc(env(safe-area-inset-right, 0px) + 16px));
  z-index: 1100;
  display: flex;
  flex-direction: column;
  gap: 10px;
  pointer-events: none;
  max-width: 300px;
}

/* Achievement-Toast */
.achievement-toast {
  background: linear-gradient(135deg, #2d3748 0%, #1a1f2e 100%);
  border: 2px solid #f6ad55;
  border-radius: 14px;
  padding: 14px 18px;
  display: flex;
  align-items: center;
  gap: 14px;
  box-shadow: 0 8px 32px rgba(0,0,0,.4), 0 0 0 1px rgba(246,173,85,.15);
  opacity: 0;
  transform: translateX(calc(100% + 24px));
  transition: opacity .35s ease, transform .35s ease;
  pointer-events: none;
  cursor: pointer;
}
.achievement-toast--visible {
  opacity: 1;
  transform: translateX(0);
  pointer-events: auto;
}
.achievement-toast-icon {
  font-size: 2rem;
  line-height: 1;
  flex-shrink: 0;
}
.achievement-toast-title {
  font-size: .65rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: .7px;
  color: #f6ad55;
  margin-bottom: 3px;
}
.achievement-toast-name {
  font-size: .92rem;
  font-weight: 700;
  color: #fff;
  margin-bottom: 2px;
}
.achievement-toast-desc {
  font-size: .75rem;
  color: #a0aec0;
  line-height: 1.35;
}

/* Achievement-Karte im Stats-Tab */
.ach-summary {
  text-align: center;
  margin-bottom: 24px;
  padding-bottom: 20px;
  border-bottom: 1px solid var(--border);
}
.ach-summary-count {
  display: block;
  font-size: 2.2rem;
  font-weight: 800;
  color: var(--accent);
  line-height: 1.1;
}
.ach-summary-label {
  display: block;
  font-size: .8rem;
  color: var(--text-muted);
  margin: 4px 0 12px;
}
.ach-overall-bar {
  height: 8px;
  background: var(--border);
  border-radius: 4px;
  overflow: hidden;
  max-width: 220px;
  margin: 0 auto;
}
.ach-overall-fill {
  height: 100%;
  background: linear-gradient(90deg, var(--accent), #7c9fff);
  border-radius: 4px;
  transition: width .6s ease;
}

.ach-category { margin-bottom: 24px; }
.ach-category:last-child { margin-bottom: 0; }
.ach-category-title {
  font-size: .72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .6px;
  color: var(--text-muted);
  margin-bottom: 10px;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--border);
}

.ach-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 10px;
}

.ach-item {
  background: var(--bg);
  border: 1.5px solid var(--border);
  border-radius: 10px;
  padding: 12px 14px;
  display: flex;
  gap: 12px;
  align-items: flex-start;
  opacity: .45;
  cursor: pointer;
  transition: opacity var(--transition), border-color var(--transition), box-shadow var(--transition), background var(--transition);
}
.ach-item:hover, .ach-item:focus-visible {
  box-shadow: 0 0 0 1px var(--accent);
}
.ach-item:focus-visible { outline: none; }
.ach-item--unlocked {
  opacity: 1;
  border-color: var(--accent);
  box-shadow: 0 0 0 1px rgba(79,110,247,.15);
}
.ach-item-icon {
  position: relative; /* über den Schimmer-Overlays der Stufenrahmen bleiben (siehe z-index dort) */
  z-index: 1;
  font-size: 1.5rem;
  line-height: 1;
  flex-shrink: 0;
  margin-top: 1px;
  filter: grayscale(1);
}
.ach-item--unlocked .ach-item-icon { filter: none; }
.ach-item-body { position: relative; z-index: 1; min-width: 0; }
.ach-item-name {
  font-size: .86rem;
  font-weight: 700;
  color: var(--text);
  margin-bottom: 2px;
}
.ach-item-desc {
  font-size: .74rem;
  color: var(--text-muted);
  line-height: 1.4;
}
.ach-item-date {
  font-size: .68rem;
  color: var(--accent);
  font-weight: 600;
  margin-top: 5px;
}
.ach-progress-bar {
  height: 4px;
  background: var(--border);
  border-radius: 2px;
  margin-top: 7px;
  overflow: hidden;
}
.ach-progress-fill {
  height: 100%;
  background: var(--accent);
  border-radius: 2px;
}
.ach-progress-text {
  font-size: .67rem;
  color: var(--text-muted);
  margin-top: 3px;
}

/* Erfolgs-Familien (Stufen zusammengeklappt): eine Karte pro Kennzahl,
   Stufenfarbe als Rahmen/Badge statt sechs Einzelkarten in der Liste. */
.ach-tier-badge {
  display: inline-block;
  font-size: .62rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: .5px;
  padding: 2px 7px;
  border-radius: 20px;
  margin-left: 6px;
  color: #fff;
  vertical-align: middle;
}
.ach-tier-badge--iron     { background: var(--tier-iron); }
.ach-tier-badge--bronze   { background: var(--tier-bronze); }
.ach-tier-badge--silver   { background: var(--tier-silver); color: #1a202c; }
.ach-tier-badge--gold     { background: var(--tier-gold); color: #1a202c; }
.ach-tier-badge--platinum { background: var(--tier-platinum); color: #1a202c; }
.ach-tier-badge--diamond  { background: var(--tier-diamond); }

/* ── Kreative Stufenrahmen (Aufgabe 2) ─────────────────────────────────────────
   Wertigkeit steigt sichtbar von Eisen (schlicht, einfarbig, matt) bis Diamant
   (mehrfarbiger Verlauf + Schimmer). Technik "Gradient-Border": zwei
   Hintergrund-Ebenen — die INNERE (padding-box) füllt die Kachel mit der
   gewohnten, ans Theme angepassten Tönung (color-mix() über --bg, damit Hell-
   /Dunkelmodus automatisch passt), die ÄUSSERE (border-box) trägt den
   mehrfarbigen Verlauf und ist dadurch nur im Rahmen-Ring sichtbar — kein
   border-image, keine Bilddateien, rein deklaratives CSS. Ab Silber wird der
   Rahmen dafür transparent gesetzt (die Farbe kommt komplett aus der
   Verlaufs-Ebene). position:relative + overflow:hidden auf der Basis-Klasse
   weiter oben halten Schimmer-Overlays (::after) sauber innerhalb der Kachel.
   Performance (Karte zeigt >100 Kacheln gleichzeitig): NUR Platin und Diamant
   bekommen eine Dauer-Animation — beides seltene Höchststufen, die realistisch
   nie in großer Zahl gleichzeitig sichtbar sind. Alle anderen Stufen sind
   vollständig statisch (kein Layout-/Repaint-Dauerlauf). */
.ach-item--family.ach-item--unlocked {
  position: relative;
  overflow: hidden;
}

/* Nutzer-Feedback: die Rahmen sollen ein echtes visuelles Feature sein, mit dem
   man sein Profil hervorhebt — deshalb durchgehend kräftiger als zuvor:
   dickere Rahmen, sattere Flächen, ab Bronze ein äußerer Schein und eine
   Lichtkante an der Oberkante (inset), die den Kacheln Plastizität gibt.
   Der Leistungsgrundsatz von oben bleibt: der Schein ist eine statische
   box-shadow, ANIMIERT wird weiterhin nur Platin und Diamant. */

/* Gemeinsame Lichtkante + Hover-Anhebung für alle freigeschalteten Stufen.
   Rein statisch, kostet kein Repaint. */
.ach-item--family.ach-item--unlocked {
  transition: transform .16s ease, box-shadow .16s ease;
}
.ach-item--family.ach-item--unlocked:hover {
  transform: translateY(-2px);
}
/* Farbiger Schein hinter dem Icon — hebt die Stufe hervor, auch wenn die
   Kachel klein ist. Liegt unter dem Inhalt (z-index der Body-Ebene ist 1). */
.ach-item--family.ach-item--unlocked .ach-item-icon {
  position: relative;
  z-index: 1;
  filter: drop-shadow(0 0 6px rgba(0,0,0,.25));
}

/* Eisen: bewusst die schlichteste Stufe — aber jetzt mit klar sichtbarem
   Vollrahmen statt einer nur angedeuteten Kante. */
.ach-item--family.ach-item--unlocked.tier-iron {
  border: 2px solid var(--tier-iron);
  background: color-mix(in srgb, var(--tier-iron) 20%, var(--bg));
  box-shadow: inset 0 1px 0 rgba(255,255,255,.14);
}

/* Bronze: zweifarbiger Verlaufsrahmen, jetzt kräftiger und mit erstem,
   zurückhaltendem Außenschein. */
.ach-item--family.ach-item--unlocked.tier-bronze {
  border: 2px solid transparent;
  background:
    linear-gradient(color-mix(in srgb, var(--tier-bronze) 20%, var(--bg)), color-mix(in srgb, var(--tier-bronze) 20%, var(--bg))) padding-box,
    var(--tier-bronze-grad) border-box;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.16),
    0 0 10px -4px color-mix(in srgb, var(--tier-bronze) 70%, transparent);
}

/* Silber: kühler, dreistufiger Verlauf ("gebürstetes Metall") mit deutlicherer
   Glanzdiagonale und spürbarem Schein. */
.ach-item--family.ach-item--unlocked.tier-silver {
  border: 2.5px solid transparent;
  background:
    linear-gradient(color-mix(in srgb, var(--tier-silver) 20%, var(--bg)), color-mix(in srgb, var(--tier-silver) 20%, var(--bg))) padding-box,
    var(--tier-silver-grad) border-box;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.22),
    0 0 12px -4px color-mix(in srgb, var(--tier-silver) 75%, transparent);
}
.ach-item--family.ach-item--unlocked.tier-silver::after {
  content: '';
  position: absolute;
  z-index: 0;
  inset: 0;
  background: linear-gradient(115deg, transparent 40%, rgba(255,255,255,.32) 50%, transparent 60%);
  pointer-events: none;
}

/* Gold: satter Verlauf, dicker Rahmen, warmer Außenschein — die erste Stufe,
   die auf einen Blick "wertvoll" liest, weiterhin ohne Animation. */
.ach-item--family.ach-item--unlocked.tier-gold {
  border: 3px solid transparent;
  background:
    linear-gradient(color-mix(in srgb, var(--tier-gold) 22%, var(--bg)), color-mix(in srgb, var(--tier-gold) 22%, var(--bg))) padding-box,
    var(--tier-gold-grad) border-box;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.28),
    0 0 16px -4px color-mix(in srgb, var(--tier-gold) 85%, transparent);
}
.ach-item--family.ach-item--unlocked.tier-gold::after {
  content: '';
  position: absolute;
  z-index: 0;
  inset: 0;
  background: linear-gradient(115deg, transparent 36%, rgba(255,255,255,.42) 50%, transparent 64%);
  pointer-events: none;
}

/* Platin: eisiger Verlauf, kräftiger Außenschein + animiertes Glanzband. */
.ach-item--family.ach-item--unlocked.tier-platinum {
  border: 3px solid transparent;
  background:
    linear-gradient(color-mix(in srgb, var(--tier-platinum) 22%, var(--bg)), color-mix(in srgb, var(--tier-platinum) 22%, var(--bg))) padding-box,
    var(--tier-platinum-grad) border-box;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.3),
    0 0 20px -3px color-mix(in srgb, var(--tier-platinum) 80%, transparent);
}
.ach-item--family.ach-item--unlocked.tier-platinum::after {
  content: '';
  position: absolute;
  z-index: 0;
  inset: -20% -60%;
  background: linear-gradient(100deg, transparent 42%, rgba(255,255,255,.5) 50%, transparent 58%);
  pointer-events: none;
  animation: ach-tier-shine 4.5s ease-in-out infinite;
}

/* Diamant: mehrfarbiger, fließender Verlaufsrahmen + eigenes Glanzband +
   pulsierender Schein — die auffälligste Stufe, jetzt mit deutlich größerem
   Abstand nach unten. */
.ach-item--family.ach-item--unlocked.tier-diamond {
  border: 3.5px solid transparent;
  background:
    linear-gradient(color-mix(in srgb, var(--tier-diamond) 24%, var(--bg)), color-mix(in srgb, var(--tier-diamond) 24%, var(--bg))) padding-box,
    var(--tier-diamond-grad) border-box;
  background-size: 100% 100%, 320% 320%;
  animation: ach-tier-diamond-flow 7s ease-in-out infinite, ach-tier-diamond-glow 3.5s ease-in-out infinite;
}
.ach-item--family.ach-item--unlocked.tier-diamond::after {
  content: '';
  position: absolute;
  z-index: 0;
  inset: -20% -60%;
  background: linear-gradient(100deg, transparent 40%, rgba(255,255,255,.55) 50%, transparent 60%);
  pointer-events: none;
  animation: ach-tier-shine 3.2s ease-in-out infinite;
}

@keyframes ach-tier-shine {
  0%   { transform: translateX(-45%); opacity: 0; }
  15%  { opacity: 1; }
  50%  { transform: translateX(45%); opacity: 0; }
  100% { transform: translateX(45%); opacity: 0; }
}
@keyframes ach-tier-diamond-flow {
  0%, 100% { background-position: 0% 0%, 0% 50%; }
  50%      { background-position: 0% 0%, 100% 50%; }
}
@keyframes ach-tier-diamond-glow {
  0%, 100% {
    box-shadow:
      inset 0 1px 0 rgba(255,255,255,.32),
      0 0 14px -2px color-mix(in srgb, var(--tier-diamond) 70%, transparent);
  }
  50% {
    box-shadow:
      inset 0 1px 0 rgba(255,255,255,.32),
      0 0 26px 2px color-mix(in srgb, var(--tier-diamond) 85%, transparent);
  }
}

/* Bewegte Effekte respektieren prefers-reduced-motion: die betroffenen Stufen
   bleiben dadurch nicht unsichtbar, sondern fallen auf ihren (bereits
   deutlich wertigen) statischen Verlaufsrahmen zurück. */
@media (prefers-reduced-motion: reduce) {
  .ach-item--family.ach-item--unlocked.tier-platinum,
  .ach-item--family.ach-item--unlocked.tier-diamond,
  .ach-item--family.ach-item--unlocked.tier-platinum::after,
  .ach-item--family.ach-item--unlocked.tier-diamond::after {
    animation: none;
  }
  .ach-item--family.ach-item--unlocked.tier-platinum::after,
  .ach-item--family.ach-item--unlocked.tier-diamond::after {
    opacity: 0;
  }
  /* Diamants Schein steckt ausschließlich in ach-tier-diamond-glow. Ohne
     Animation wäre die höchste Stufe sonst schwächer als Gold — deshalb hier
     der statische Ersatz auf dem Niveau des Animations-Höhepunkts. */
  .ach-item--family.ach-item--unlocked.tier-diamond {
    box-shadow:
      inset 0 1px 0 rgba(255,255,255,.32),
      0 0 22px 0 color-mix(in srgb, var(--tier-diamond) 80%, transparent);
  }
  .ach-item--family.ach-item--unlocked:hover {
    transform: none;
  }
}

.ach-item-rankedtag {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  font-size: .6rem;
  font-weight: 700;
  color: #fff;
  background: var(--danger, #e53e3e);
  border-radius: 20px;
  padding: 1px 7px;
  margin-left: 6px;
  vertical-align: middle;
  white-space: nowrap;
}

@media (max-width: 640px) {
  .ach-grid { grid-template-columns: 1fr; }
  .achievement-toast { max-width: calc(100vw - 32px); }
}

/* ── Erfolgs-Detail-Popup (Aufgabe 1: Stufen ins Popup statt in die Kachel) ── */
.ach-detail-card {
  max-width: 440px;
  max-height: 85vh;
  display: flex;
  flex-direction: column;
  text-align: left;
  position: relative;
  padding: 34px 26px 26px;
}
.ach-detail-close {
  position: absolute;
  top: 10px;
  right: 10px;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  border: none;
  background: var(--bg);
  color: var(--text-muted);
  font-size: .95rem;
  cursor: pointer;
  line-height: 1;
  transition: color var(--transition), background var(--transition);
}
.ach-detail-close:hover { color: var(--text); background: var(--border); }
.ach-detail-header {
  display: flex;
  align-items: center;
  gap: 12px;
  padding-right: 30px;
}
.ach-detail-icon { font-size: 2rem; line-height: 1; flex-shrink: 0; }
.ach-detail-header h2 { font-size: 1.1rem; margin: 0; }
.ach-detail-ranked-note {
  margin-top: 12px;
  padding: 8px 10px;
  border-radius: 8px;
  background: color-mix(in srgb, var(--danger, #e53e3e) 12%, transparent);
  border: 1px solid color-mix(in srgb, var(--danger, #e53e3e) 40%, transparent);
  color: var(--text);
  font-size: .8rem;
  font-weight: 600;
}
.ach-detail-body {
  margin-top: 14px;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.ach-detail-tier {
  position: relative;
  overflow: hidden;
  display: flex;
  gap: 10px;
  align-items: flex-start;
  padding: 10px 12px;
  border-radius: 8px;
  border: 1.5px solid var(--border);
  background: var(--bg);
  opacity: .55;
}
.ach-detail-tier--reached { opacity: 1; }
.ach-detail-tier--current {
  opacity: 1;
  border-color: var(--accent);
  box-shadow: 0 0 0 1px rgba(79,110,247,.2);
}
/* Dieselben Rahmen wie in der Kachel-Liste (siehe .ach-item--family.ach-item--
   unlocked.tier-* weiter oben) — Aufgabe 2, Vorgabe: "Rahmen soll auch im
   Erfolgs-Popup bei der aktuellen Stufe erkennbar sein". Da die aktuelle
   Stufe (currentTier) immer auch die höchste ERREICHTE ist, deckt
   "--reached" automatisch den Fall "aktuelle Stufe" mit ab. Die animierten
   Effekte (Platin/Diamant) laufen hier bewusst mit, da im Popup nie mehr als
   6 Zeilen gleichzeitig sichtbar sind — kein Performance-Problem wie bei der
   Kachel-Liste mit >100 Kacheln. */
.ach-detail-tier--iron.ach-detail-tier--reached {
  border: 2px solid var(--tier-iron);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.14);
}
.ach-detail-tier--bronze.ach-detail-tier--reached {
  border: 2px solid transparent;
  background: linear-gradient(var(--bg), var(--bg)) padding-box, var(--tier-bronze-grad) border-box;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.16),
    0 0 10px -4px color-mix(in srgb, var(--tier-bronze) 70%, transparent);
}
.ach-detail-tier--silver.ach-detail-tier--reached {
  border: 2.5px solid transparent;
  background: linear-gradient(var(--bg), var(--bg)) padding-box, var(--tier-silver-grad) border-box;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.22),
    0 0 12px -4px color-mix(in srgb, var(--tier-silver) 75%, transparent);
}
.ach-detail-tier--gold.ach-detail-tier--reached {
  border: 3px solid transparent;
  background: linear-gradient(var(--bg), var(--bg)) padding-box, var(--tier-gold-grad) border-box;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.28),
    0 0 16px -4px color-mix(in srgb, var(--tier-gold) 85%, transparent);
}
.ach-detail-tier--platinum.ach-detail-tier--reached {
  border: 3px solid transparent;
  background: linear-gradient(var(--bg), var(--bg)) padding-box, var(--tier-platinum-grad) border-box;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.3),
    0 0 20px -3px color-mix(in srgb, var(--tier-platinum) 80%, transparent);
}
.ach-detail-tier--diamond.ach-detail-tier--reached {
  border: 3.5px solid transparent;
  background: linear-gradient(var(--bg), var(--bg)) padding-box, var(--tier-diamond-grad) border-box;
  background-size: 100% 100%, 320% 320%;
  animation: ach-tier-diamond-flow 7s ease-in-out infinite, ach-tier-diamond-glow 3.5s ease-in-out infinite;
}
/* Aktuelle Stufe zusätzlich mit einem farblich passenden Außenring hervor-
   gehoben (statt nur dem generischen Akzent-Ring oben), damit sie neben den
   übrigen erreichten Stufen klar als "die jetzige" erkennbar bleibt. */
.ach-detail-tier--current.ach-detail-tier--iron     { box-shadow: 0 0 0 2px var(--tier-iron); }
.ach-detail-tier--current.ach-detail-tier--bronze   { box-shadow: 0 0 0 2px var(--tier-bronze); }
.ach-detail-tier--current.ach-detail-tier--silver   { box-shadow: 0 0 0 2px var(--tier-silver); }
.ach-detail-tier--current.ach-detail-tier--gold     { box-shadow: 0 0 0 2px var(--tier-gold); }
.ach-detail-tier--current.ach-detail-tier--platinum { box-shadow: 0 0 0 2px var(--tier-platinum), 0 0 10px -2px color-mix(in srgb, var(--tier-platinum) 55%, transparent); }
.ach-detail-tier--current.ach-detail-tier--diamond  { box-shadow: 0 0 0 2px var(--tier-diamond); }

@media (prefers-reduced-motion: reduce) {
  .ach-detail-tier--diamond.ach-detail-tier--reached { animation: none; }
}
.ach-detail-tier-icon { font-size: 1.2rem; line-height: 1.2; flex-shrink: 0; }
.ach-detail-tier-body { min-width: 0; flex: 1; }
.ach-detail-tier-name { font-size: .84rem; font-weight: 700; color: var(--text); }
.ach-detail-tier-desc { font-size: .76rem; color: var(--text-muted); margin-top: 2px; line-height: 1.4; }
.ach-detail-tier-date { font-size: .7rem; color: var(--accent); font-weight: 600; margin-top: 4px; }
.ach-detail-tier-progress { font-size: .7rem; color: var(--text-muted); margin-top: 4px; }

@media (max-width: 480px) {
  .ach-detail-card { padding: 28px 18px 20px; width: 94%; }
}

/* ════════════════════════════════════════════
   RANGLISTE
   ════════════════════════════════════════════ */

.rl-info {
  font-size: .78rem;
  color: var(--text-muted);
  margin-bottom: 16px;
  padding: 8px 12px;
  background: var(--bg);
  border-radius: 8px;
  border-left: 3px solid var(--accent);
}

.rl-table-wrap {
  overflow-x: auto;
  margin-bottom: 20px;
}

/* Rangliste: Layout aus dem gemeinsamen Datentabellen-Block. Die Zeilen
   enthalten Avatare und Abzeichen und brauchen deshalb etwas mehr Hoehe.
   Abweichend vom Standard ist die erste Spalte der Platz (mittig) und die
   zweite der Name (linksbuendig) — wie in den Turnier-Tabellenstaenden. */
.rl-row td { padding: 12px; }
.rl-table th:first-child,
.rl-table td.rl-rank { text-align: center; }
.rl-table th:nth-child(2),
.rl-table td:nth-child(2) { text-align: left; }

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

.rl-row--me {
  background: rgba(79, 110, 247, .06);
}
.rl-row--me td:first-child {
  border-left: 3px solid var(--accent);
  padding-left: 7px;
}

.rl-rank {
  font-size: 1.1rem;
  width: 52px;
  text-align: center;
  font-weight: 700;
}

/* Die Zelle bleibt eine Tabellenzelle — sonst erzeugt der Browser um sie herum
   eine anonyme Zelle, die Zeile verliert ihr Raster und die untere Trennlinie
   sitzt in dieser Spalte auf einer anderen Hoehe als in den uebrigen.
   Der Flex-Container ist deshalb ein DIV in der Zelle. */
.rl-name { font-weight: 600; }
.rl-name-inner {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

.rl-me-badge {
  font-size: .68rem;
  font-weight: 700;
  background: var(--accent);
  color: #fff;
  border-radius: 10px;
  padding: 1px 7px;
  text-transform: uppercase;
  letter-spacing: .3px;
}

.rl-tier-badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: .72rem;
  font-weight: 700;
  padding: 2px 9px;
  border-radius: 20px;
  border: 1px solid;
  white-space: nowrap;
}

.rl-rating {
  white-space: nowrap;
}

.rl-rating-value {
  font-size: 1.15rem;
  font-weight: 800;
  color: var(--accent);
}

.rl-unranked {
  font-size: .8rem;
  color: var(--text-muted);
  font-style: italic;
}

.rl-wl {
  font-size: .82rem;
  color: var(--text-muted);
  white-space: nowrap;
}

/* Tier-Übersicht */
.rl-tier-overview {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-bottom: 16px;
}

.rl-tier-row {
  display: flex;
  align-items: center;
  gap: 12px;
}

.rl-tier-row .rl-tier-badge {
  min-width: 170px;
}

.rl-info-box {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  background: rgba(79,110,247,.07);
  border-left: 3px solid var(--accent);
  border-radius: 6px;
  padding: 10px 14px;
  margin-bottom: 16px;
  font-size: .83rem;
  color: var(--text-muted);
  line-height: 1.55;
}

.rl-info-icon {
  font-size: 1rem;
  color: var(--accent);
  flex-shrink: 0;
  margin-top: 1px;
}

.rl-info-box strong {
  color: var(--text);
}

.rl-kfactor-hint {
  display: flex;
  gap: 16px;
  flex-wrap: wrap;
  font-size: .78rem;
  color: var(--text-muted);
  padding-top: 12px;
  border-top: 1px solid var(--border);
}

.rl-kfactor-hint strong {
  color: var(--text);
}

@media (max-width: 640px) {
  .rl-table { font-size: .82rem; }
  .rl-tier-row { flex-wrap: wrap; gap: 6px; }
  .rl-tier-row .rl-tier-badge { min-width: 0; }
  .rl-kfactor-hint { gap: 10px; }
}

/* Achievements card – flex-column damit Inhalte stapeln (jetzt im Profil-Tab) */
#profile-achievements-card {
  flex-direction: column;
  align-items: stretch;
}

/* Offline Achievements – Spieler-Auswahl-Leiste */
.ach-player-bar {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 14px;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--border);
}

/* ── Premium Card ────────────────────────────────────────────────────────── */
.premium-card { grid-column: 1 / -1; border-top: 3px solid var(--accent); }
.premium-status-badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 14px;
  border-radius: 20px;
  font-size: .85rem;
  font-weight: 700;
  margin-bottom: 16px;
}
.premium-status-badge.free    { background: var(--border); color: var(--text-muted); }
.premium-status-badge.premium { background: rgba(79,110,247,.12); color: var(--accent); border: 1px solid rgba(79,110,247,.3); }
.premium-status-badge.expired { background: rgba(220,53,69,.1); color: var(--danger); }
.premium-features-list {
  list-style: none;
  padding: 0;
  margin: 0 0 20px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.premium-features-list li {
  font-size: .88rem;
  color: var(--text-muted);
  padding-left: 20px;
  position: relative;
}
.premium-features-list li::before {
  content: '✓';
  position: absolute;
  left: 0;
  color: var(--accent);
  font-weight: 700;
}
.premium-active-info {
  font-size: .88rem;
  color: var(--text-muted);
  margin-bottom: 0;
}
.premium-price-row {
  display: flex;
  gap: 12px;
  margin-bottom: 16px;
}
.premium-price-option {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  padding: 16px 12px;
  border: 1px solid var(--border);
  border-radius: 10px;
  position: relative;
}
.premium-price-option--yearly {
  border-color: var(--accent);
  background: rgba(79,110,247,.04);
}
.premium-price-badge {
  position: absolute;
  top: -11px;
  background: var(--accent);
  color: #fff;
  font-size: .72rem;
  font-weight: 700;
  padding: 2px 10px;
  border-radius: 20px;
  white-space: nowrap;
}
.premium-price-amount {
  font-size: 1.5rem;
  font-weight: 800;
  color: var(--text);
  line-height: 1;
}
.premium-price-period {
  font-size: .78rem;
  color: var(--text-muted);
  margin-bottom: 10px;
}
.premium-paypal-btn { width: 100%; text-align: center; font-size: .85rem; }
.premium-paypal-btn-container { width: 100%; min-height: 35px; }
.premium-paypal-success {
  width: 100%;
  text-align: center;
  font-size: .82rem;
  color: var(--text);
}
.premium-paypal-success code {
  display: block;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 6px 8px;
  font-size: .78rem;
  margin: 4px 0;
}
.premium-hint {
  font-size: .78rem;
  color: var(--text-muted);
  margin: 0;
  line-height: 1.5;
}
.premium-hint a { color: var(--accent); }

/* ── Premium Modal ───────────────────────────────────────────────────────── */
.premium-modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,.55);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 9999;
  padding: 16px;
}
.premium-modal-card {
  background: var(--surface);
  border-radius: 14px;
  padding: 28px 24px 24px;
  max-width: 380px;
  width: 100%;
  box-shadow: 0 8px 32px rgba(0,0,0,.18);
  border-top: 3px solid var(--accent);
}
.premium-modal-card h2 { font-size: 1.1rem; font-weight: 700; margin: 0 0 8px; }
.premium-modal-desc { font-size: .88rem; color: var(--text-muted); margin: 0 0 16px; }
.premium-modal-prices {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  font-size: .88rem;
  color: var(--text-muted);
  margin: 16px 0;
}
.premium-modal-sep { color: var(--border); }

/* ── Stats Paywall Banner ────────────────────────────────────────────────── */
.stats-premium-banner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  padding: 20px 16px;
  background: rgba(79,110,247,.05);
  border: 1px dashed rgba(79,110,247,.35);
  border-radius: 10px;
  text-align: center;
}
.stats-premium-banner p {
  font-size: .85rem;
  color: var(--text-muted);
  margin: 0;
}

/* ── Admin Dashboard ────────────────────────────────────────────────────── */
.admin-root {
  display: flex;
  flex-direction: column;
  gap: 20px;
}
.admin-subtabs {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.admin-subtabs button {
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text-muted);
  border-radius: 20px;
  padding: 6px 16px;
  font-size: .85rem;
  font-weight: 600;
  cursor: pointer;
  transition: background var(--transition), color var(--transition), border-color var(--transition);
}
.admin-subtabs button:hover { color: var(--text); }
.admin-subtabs button.active {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}
.admin-section {
  display: flex;
  flex-direction: column;
  gap: 20px;
}
.admin-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  justify-content: space-between;
}
.admin-toolbar-left,
.admin-toolbar-right {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}
.admin-search {
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
  border-radius: 8px;
  padding: 7px 12px;
  font-size: .85rem;
  min-width: 200px;
}
.admin-filter-btns { display: flex; flex-wrap: wrap; gap: 6px; }
.admin-filter-btns button {
  border: 1px solid var(--border);
  background: var(--bg);
  color: var(--text-muted);
  border-radius: 16px;
  padding: 4px 12px;
  font-size: .78rem;
  font-weight: 600;
  cursor: pointer;
  transition: background var(--transition), color var(--transition);
}
.admin-filter-btns button.active {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}
.admin-timestamp { font-size: .78rem; color: var(--text-muted); }

.kpi-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 12px;
}
.kpi-tile {
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 14px 16px;
  text-align: center;
}
.kpi-value { font-size: 1.6rem; font-weight: 700; color: var(--text); line-height: 1.2; }
.kpi-value.kpi-accent  { color: var(--accent); }
.kpi-value.kpi-danger  { color: var(--danger); }
.kpi-value.kpi-ok      { color: #38a169; }
.kpi-label { font-size: .75rem; color: var(--text-muted); margin-top: 4px; }
.kpi-sub   { font-size: .72rem; color: var(--text-muted); margin-top: 2px; opacity: .8; }

/* Admin-Tabellen enthalten E-Mails, UIDs und Freitext — Layout aus dem
   gemeinsamen Block, aber durchgehend linksbuendig (.data-table--text wird
   in js/admin.js gesetzt) und etwas kompakter. */
.admin-table { font-size: .82rem; }
/* Etwas mehr Luft zwischen den Spalten — bei neun Spalten liefen Tag, Datum
   und Zeitangaben sonst optisch ineinander. */
.admin-table th, .admin-table td { padding: 9px 14px; }
.admin-table-wrap { overflow-x: auto; }

/* Aktionsknoepfe in einer Tabellenzeile duerfen NICHT umbrechen: Jede
   Umbruchzeile verdoppelt die Hoehe der gesamten Tabellenzeile. Die Tabelle
   liegt in .admin-table-wrap und darf stattdessen breiter werden — waagerecht
   scrollen ist deutlich angenehmer als eine Liste aus Bloecken. */
.admin-row-actions { display: flex; gap: 6px; flex-wrap: nowrap; }
.admin-row-actions .btn { white-space: nowrap; }

/* Sortierbarer Tabellenkopf */
.admin-th-sort { cursor: pointer; user-select: none; white-space: nowrap; }
.admin-th-sort:hover { color: var(--accent); }
.admin-th-sort.is-sorted { color: var(--accent); }

/* UID: einheitliche Breite durch Monospace, per Klick kopierbar */
.admin-uid {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: .74rem;
  color: var(--text-muted);
  cursor: pointer;
  white-space: nowrap;
}
.admin-uid:hover { color: var(--accent); text-decoration: underline; }

/* Premium-Dialog im Admin-Bereich */
.admin-premium-label { display: block; margin: 14px 0 6px; font-size: .85rem; color: var(--text-muted); }
.admin-premium-date {
  width: 100%;
  padding: 9px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--bg);
  color: var(--text);
  font-size: .95rem;
}
.admin-premium-quick { display: flex; gap: 8px; flex-wrap: wrap; margin: 10px 0 4px; }

/* Hinweis anstelle einer gesperrten Statistik-Karte. Die Karte bleibt stehen
   und erklaert sich — eine verschwundene Karte wirft keine Frage auf, eine
   gesperrte schon. */
.stats-premium-teaser {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 12px;
  padding: 6px 0;
}
.stats-premium-teaser p {
  margin: 0;
  font-size: .85rem;
  line-height: 1.55;
  color: var(--text-muted);
}

/* Warnleiste in der Uebersicht. Erscheint nur, wenn es wirklich etwas zu
   melden gibt — Kennzahlen, die an 364 von 365 Tagen null sind, gehoeren in
   ihren Fachreiter, nicht auf die Startseite. */
.admin-alert {
  border-left: 3px solid var(--danger);
  font-size: .88rem;
  line-height: 1.5;
}

/* Erklaerender Kleintext unter einer Admin-Karte — sagt, was eine Zahl
   tatsaechlich misst. */
.admin-hint {
  margin-top: 10px;
  font-size: .78rem;
  line-height: 1.5;
  color: var(--text-muted);
}

.badge--ok     { background: #38a169; color: #fff; }
.badge--warn   { background: #dd9c1f; color: #fff; }
.badge--danger { background: var(--danger); color: #fff; }
.badge--muted  { background: var(--text-muted); color: #fff; }

.admin-chart { width: 100%; height: auto; }
.admin-chart-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  font-size: .78rem;
  color: var(--text-muted);
  margin-top: 6px;
}
.admin-chart-legend span { display: inline-flex; align-items: center; gap: 6px; }
.admin-chart-legend i {
  display: inline-block;
  width: 10px;
  height: 10px;
  border-radius: 2px;
}

.hbar-row { margin-bottom: 8px; }
.hbar-row-top {
  display: flex;
  justify-content: space-between;
  font-size: .82rem;
  margin-bottom: 2px;
}
.hbar-track { background: var(--border); border-radius: 4px; height: 8px; }
.hbar-fill  { background: var(--accent); height: 100%; border-radius: 4px; }

.admin-card-title {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin: 0 0 14px;
}
.admin-empty { color: var(--text-muted); font-size: .85rem; }
.admin-muted { color: var(--text-muted); font-size: .8rem; }
/* Dieselbe Obergrenze wie die Einstellungskarten in "Neues Spiel"/"Turnier"
   und die Karten in Spieler/Rangliste (siehe .card-narrow) — aber am ganzen
   Bereich statt je Karte: die Admin-Karten entstehen an ueber zwanzig Stellen
   in js/admin.js, und die Reiterleiste soll dieselbe Breite haben wie die
   Karten darunter.
   Unbedenklich fuer die breiten Tabellen: sie liegen in .admin-table-wrap
   bzw. .table-wrapper und scrollen dort waagerecht. */
#admin-dashboard-content { max-width: 760px; }

/* Ausnahme fuer Reiter, deren Inhalt eine breite Tabelle IST. 760px zwingen
   die Nutzertabelle mit ihren neun Spalten sonst in den waagerechten Scroll,
   obwohl daneben Platz frei ist. Die Kennzahlen-Karten der uebrigen Reiter
   bleiben bei 760px — dort wuerde die Breite den Inhalt nur auseinanderziehen.
   Gesetzt wird die Klasse in renderAdminShell() (js/admin.js). */
#admin-dashboard-content.admin-wide { max-width: min(1600px, 100%); }
/* Betreffzeile der Meldungsliste: linksbuendig wie Fliesstext, aber bewusst
   EINZEILIG mit Auslassungspunkten — der Volltext steht im Ticket, hier zaehlt
   nur das Wiederfinden. Ein umbrechender Block machte die Tabelle vorher
   unnoetig breit. */
.admin-feedback-subject {
  text-align: left !important;
  max-width: 420px;
  overflow: hidden;
  text-overflow: ellipsis;
}

@media (max-width: 640px) {
  .admin-toolbar { flex-direction: column; align-items: stretch; }
  .admin-search { min-width: 0; width: 100%; }
}

/* Freilos-Hinweis unter der Gruppenphase (js/tournament-formats/group-swiss.js):
   Freilose sind Pausen, keine Partien — bewusst als schlichter Hinweis statt
   als Match-Karten dargestellt. */
.gs-bye-note {
  margin: 8px 0 0;
  font-size: .8rem;
  color: var(--text-muted);
}

/* ── Profil (js/profile.js, #tab-profil) ───────────────────────────────── */
.profile-header-card { justify-content: flex-start; }

.profile-header {
  display: flex;
  gap: 20px;
  align-items: flex-start;
  flex-wrap: wrap;
  width: 100%;
}
.profile-avatar {
  width: 72px;
  height: 72px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 2.2rem;
  border: 2px solid var(--accent);
  background: rgba(79,110,247,.13);
  flex-shrink: 0;
}
.profile-identity {
  flex: 1;
  min-width: 200px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.profile-name-row { display: flex; align-items: baseline; gap: 6px; flex-wrap: wrap; }
.profile-username { font-size: 1.3rem; font-weight: 800; color: var(--text); }
.profile-tag       { color: var(--text-muted); font-size: .85rem; }
.profile-nick      { color: var(--text-muted); font-size: .9rem; font-style: italic; }

.profile-badges { display: flex; gap: 8px; flex-wrap: wrap; }
.profile-badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: .75rem;
  font-weight: 700;
  padding: 3px 10px;
  border-radius: 20px;
  border: 1px solid var(--border);
  color: var(--text-muted);
}
.profile-badge--premium { background: rgba(214,158,46,.15); color: #d69e2e; border-color: rgba(214,158,46,.4); }
.profile-badge--elo     { background: rgba(79,110,247,.12); color: var(--accent); border-color: rgba(79,110,247,.35); }
.profile-badge--elo:empty { display: none; }

.profile-meta    { display: flex; gap: 6px; flex-wrap: wrap; font-size: .8rem; color: var(--text-muted); }
.profile-actions { display: flex; gap: 8px; margin-top: 6px; flex-wrap: wrap; }

.profile-record-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 10px;
  padding: 8px 0;
  border-bottom: 1px solid var(--border);
}
.profile-record-row:last-child { border-bottom: none; }
.profile-record-date { display: block; font-size: .7rem; font-weight: 500; color: var(--text-muted); text-align: right; }

.profile-recent-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 10px;
  padding: 8px 0;
  border-bottom: 1px solid var(--border);
  font-size: .85rem;
}
.profile-recent-row:last-child { border-bottom: none; }
.profile-recent-date { color: var(--text-muted); font-size: .8rem; }
.profile-recent-mode { font-weight: 600; }
.profile-recent-avg  { color: var(--text-muted); font-size: .82rem; }

.profile-friend-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 10px;
  padding: 8px 0;
  border-bottom: 1px solid var(--border);
}
.profile-friend-row:last-child { border-bottom: none; }
.profile-friend-name { font-weight: 600; }
.profile-friend-tag  { color: var(--text-muted); font-size: .78rem; margin-left: 3px; }
.profile-friend-nick { color: var(--text-muted); font-size: .82rem; }

/* Seit der Profil-Eintrag aus der Sidebar ausgeblendet ist, ist dieser Knopf
   der EINZIGE sichtbare Weg ins eigene Profil — entsprechend deutlicher
   gestaltet: groesser, farbig abgesetzt und mit Akzentrahmen, damit er nicht
   als beilaeufiges Textelement in der Topbar untergeht. */
.topbar-profile-btn {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: 12px;
  margin-left: auto;
  background: color-mix(in srgb, var(--accent) 12%, var(--bg));
  border: 2px solid color-mix(in srgb, var(--accent) 45%, transparent);
  border-radius: 999px;
  padding: 6px 32px 6px 6px;
  cursor: pointer;
  color: var(--text);
  font-size: .95rem;
  font-weight: 700;
  transition: border-color var(--transition), background var(--transition), transform .14s ease, box-shadow .14s ease;
  box-shadow: 0 2px 8px -3px color-mix(in srgb, var(--accent) 60%, transparent);
  /* Doppelte Grundbreite gegenueber vorher (Nutzerwunsch). min-width setzt die
     Untergrenze, die Breite waechst darueber hinaus automatisch mit dem Namen —
     der Knopf ist ein Flex-Item ohne Breitenbegrenzung. */
  min-width: 250px;
  /* Darf NIE schrumpfen: sonst wuerde bei enger Topbar der Name abgeschnitten.
     Platz gibt stattdessen der Seitentitel her (siehe .page-title). */
  flex-shrink: 0;
}
.topbar-profile-btn:hover {
  border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 20%, var(--bg));
  transform: translateY(-1px);
  box-shadow: 0 4px 14px -4px color-mix(in srgb, var(--accent) 75%, transparent);
}
.topbar-profile-btn:active { transform: translateY(0); }
.topbar-profile-avatar {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: color-mix(in srgb, var(--accent) 28%, var(--bg));
  border: 1px solid color-mix(in srgb, var(--accent) 50%, transparent);
  font-size: 1.25rem;
  flex-shrink: 0;
}
/* Kein overflow/text-overflow: der Name wird nie gekuerzt, der Knopf waechst
   stattdessen mit. */
.topbar-profile-name { white-space: nowrap; overflow: visible; }

/* Auf schmalen Viewports bleibt nur der Avatar — dann als runder Knopf, damit
   er weiterhin als eigenstaendiges Bedienelement lesbar ist. Die min-width
   muss hier zurueckgenommen werden, sonst bliebe eine breite leere Pille. */
@media (max-width: 640px) {
  .topbar-profile-name { display: none; }
  .topbar-profile-btn  { padding: 5px; gap: 0; min-width: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .topbar-profile-btn:hover { transform: none; }
}

/* ── Profil-Kopfbereich: Badge "Lokaler Spieler" (Phase 2) ─────────────── */
.profile-badge--local { background: rgba(113,128,150,.15); color: var(--text-muted); border-color: var(--border); }

/* ── Spielersuche (js/profile.js searchPlayers(), Phase 2) ─────────────── */
.profile-search-row {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
}
.profile-search-results {
  display: flex;
  flex-direction: column;
  margin-top: 12px;
}
.profile-search-results:empty { margin-top: 0; }

.profile-search-result {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 0;
  border-bottom: 1px solid var(--border);
}
.profile-search-result:last-child { border-bottom: none; }
.profile-search-avatar {
  width: 34px;
  height: 34px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(79,110,247,.13);
  font-size: 1.1rem;
  flex-shrink: 0;
}
.profile-search-name {
  flex: 1;
  min-width: 0;
  font-weight: 600;
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
}
.profile-search-meta {
  color: var(--text-muted);
  font-size: .8rem;
  white-space: nowrap;
}
/* Eine Trefferzeile kann zwei Aktionen tragen ("Hinzufuegen" + "Ansehen").
   flex-shrink: 0 haelt sie zusammen, wenn der Name lang wird. */
.profile-search-actions {
  display: flex;
  gap: 8px;
  flex-shrink: 0;
}
.profile-search-badge {
  display: inline-flex;
  align-items: center;
  font-size: .68rem;
  font-weight: 700;
  padding: 1px 8px;
  border-radius: 20px;
  background: var(--accent);
  color: #fff;
  text-transform: uppercase;
  letter-spacing: .3px;
}

/* Zeilenklick öffnet ein Profil (Spieler-Tabelle, Rangliste) — reine
   Hover-Rückmeldung, das cursor:pointer wird inline gesetzt (js/app.js
   renderPlayers() / js/elo.js _renderRanglisteOnline()). */
.players-row-clickable:hover,
.rl-row:hover {
  background: var(--bg);
}

/* ── Einstellungen: Hinweistext unter einer .setting-row (Phase 3) ─────── */
.setting-hint {
  font-size: .78rem;
  color: var(--text-muted);
  line-height: 1.5;
  margin: -4px 0 10px;
}

/* ── Profil-Bearbeiten-Modal (js/profile.js _openProfileEdit(), Phase 3+) ──
   Voller Profil-Dialog: Avatar, Benutzername, Spitzname, Privat-Schalter —
   "Was andere sehen, bearbeitest du im Profil." Ehemals nur der Avatar-
   Picker (.avatar-picker-*), Klassen im Zuge des Umzugs umbenannt. ── */
.profile-edit-card { max-width: 460px; max-height: 88vh; overflow-y: auto; }
.profile-edit-preview {
  display: flex;
  justify-content: center;
  margin-bottom: 18px;
}
.profile-edit-section { margin-bottom: 16px; text-align: left; }
.profile-edit-label {
  font-size: .78rem;
  font-weight: 700;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: .4px;
  margin-bottom: 8px;
}
.profile-edit-emoji-grid {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: 8px;
}
.profile-edit-emoji-btn {
  aspect-ratio: 1;
  border: 2px solid var(--border);
  background: var(--bg);
  border-radius: 10px;
  font-size: 1.3rem;
  cursor: pointer;
  transition: border-color var(--transition), transform var(--transition);
  display: flex;
  align-items: center;
  justify-content: center;
}
.profile-edit-emoji-btn:hover { border-color: var(--accent); transform: scale(1.05); }
.profile-edit-emoji-btn.selected { border-color: var(--accent); background: rgba(79,110,247,.12); }

.profile-edit-color-grid {
  display: grid;
  grid-template-columns: repeat(8, 1fr);
  gap: 8px;
}
.profile-edit-color-btn {
  aspect-ratio: 1;
  border-radius: 50%;
  border: 3px solid transparent;
  cursor: pointer;
  transition: border-color var(--transition), transform var(--transition);
  padding: 0;
}
.profile-edit-color-btn:hover { transform: scale(1.1); }
.profile-edit-color-btn.selected { border-color: var(--text); }

@media (max-width: 480px) {
  .profile-edit-emoji-grid { grid-template-columns: repeat(5, 1fr); }
  .profile-edit-color-grid { grid-template-columns: repeat(4, 1fr); }
}

/* ── Rangliste: Umschalter Global / Freunde ─────────────────────────────────
   Zwei Geltungsbereiche in einer Karte (siehe _renderRanglisteGlobal() /
   _renderRanglisteFreunde() in js/elo.js). Optik bewusst wie die uebrigen
   Chip-/Tab-Leisten der App: Pillenform, aktiver Zustand in der Akzentfarbe. */
/* Gruppiert die Ueberschrift "Rangliste" mit dem Global/Freunde-Umschalter, so
   dass beide links zusammenstehen (Nutzerwunsch) und der Aktualisieren-Knopf
   ueber das space-between der .card-header-row allein rechts bleibt. */
.rl-header-actions {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  min-width: 0;
}
.rl-scope-tabs {
  display: inline-flex;
  background: var(--bg-elevated, rgba(127,127,127,.12));
  border-radius: 999px;
  padding: 3px;
  gap: 2px;
}
.rl-scope-tab {
  border: none;
  background: transparent;
  color: var(--text-muted);
  font: inherit;
  font-size: .84rem;
  font-weight: 600;
  padding: 5px 14px;
  border-radius: 999px;
  cursor: pointer;
  transition: background .15s, color .15s;
  white-space: nowrap;
}
.rl-scope-tab:hover { color: var(--text); }
.rl-scope-tab.active {
  background: var(--primary, #4f6ef7);
  color: #fff;
}

/* Anonymisierter Eintrag (Konto mit aktiviertem "Profil privat") */
.rl-anon {
  color: var(--text-muted);
  font-style: italic;
}
.rl-tag {
  color: var(--text-muted);
  font-size: .82rem;
  margin-left: 3px;
}
.rl-row--clickable { cursor: pointer; }

@media (max-width: 520px) {
  .rl-scope-tab { padding: 5px 10px; font-size: .8rem; }
}

/* ── Ranked: feste Regelanzeige ─────────────────────────────────────────────
   Ersetzt die frueheren Auswahlfelder (Checkout/Sets/Legs) im Ranked-Tab.
   Bewusst als reine ANZEIGE gestaltet — keine Button-Optik, damit nicht der
   Eindruck entsteht, man koenne hier etwas umstellen. */
.ranked-fixed-rules {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  gap: 10px;
  margin-bottom: 12px;
}
.ranked-rule {
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: 10px 12px;
  border: 1px solid var(--border, rgba(127,127,127,.25));
  border-radius: 10px;
  background: var(--bg-elevated, rgba(127,127,127,.08));
}
.ranked-rule-label {
  font-size: .74rem;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: .04em;
}
.ranked-rule-value {
  font-size: .98rem;
  font-weight: 700;
  color: var(--text);
}
.ranked-fixed-hint {
  font-size: .82rem;
  color: var(--text-muted);
  margin: 0 0 4px;
  line-height: 1.45;
}

/* ── Spieler-Tab: zwei Bereiche (Freunde / Lokale Spieler) ──────────────────
   Ersetzt die fruehere gemeinsame Tabelle mit "Typ"-Spalte. Zeilenlayout statt
   Tabelle, weil beide Listen wenige Spalten haben und auf dem Handy sonst
   horizontal scrollen muessten. */
.players-section { margin-bottom: 26px; }
.players-section:last-child { margin-bottom: 0; }
.players-section-title {
  font-size: .95rem;
  font-weight: 700;
  margin: 0 0 12px;
  color: var(--text);
}
.players-section-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 12px;
}
.players-count { color: var(--text-muted); font-weight: 500; font-size: .88rem; }

.players-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 12px;
  border: 1px solid var(--border, rgba(127,127,127,.22));
  border-radius: 10px;
  margin-bottom: 8px;
  background: var(--bg-elevated, rgba(127,127,127,.05));
}
.players-row:last-child { margin-bottom: 0; }
.players-row-main { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
.players-row-name { font-weight: 600; overflow: hidden; text-overflow: ellipsis; }
.players-row-tag { color: var(--text-muted); font-size: .82rem; margin-left: 3px; font-weight: 400; }
/* Spitzname steht hinter dem Namen in derselben Zeile (statt einer zweiten
   Zeile via .players-row-sub) — hält die Zeile flach. */
.players-row-nick { color: var(--text-muted); font-size: .82rem; font-weight: 400; }
.players-row-sub { color: var(--text-muted); font-size: .82rem; }
.players-row-actions { display: flex; align-items: center; gap: 6px; flex-shrink: 0; }

/* Loeschen/Entfernen bewusst abgesetzt: mit demselben 6px-Abstand wie die
   harmlosen Knoepfe daneben wird er zu leicht versehentlich getroffen. Der
   Trennstrich macht zusaetzlich sichtbar, dass hier etwas anderes passiert;
   die Rueckfrage (showConfirm) ist die zweite Absicherung. */
.players-row-sep {
  width: 1px;
  align-self: stretch;
  min-height: 22px;
  background: var(--border);
  margin: 0 8px;
  flex-shrink: 0;
}
.players-row-danger { margin-left: 8px; }

@media (max-width: 520px) {
  .players-row { flex-wrap: wrap; }
  .players-row-actions { width: 100%; justify-content: flex-end; }
  /* Auf dem Handy klebt die Knopfreihe ohnehin am rechten Rand — dort reicht
     ein kleinerer Abstand, sonst bricht die Reihe um. */
  .players-row-sep { margin: 0 4px; }
  .players-row-danger { margin-left: 4px; }
}

/* ── Favoriten-Stern (Spieler-Tab #friends-list/#local-players-list UND
   Popup-Auswahlliste #players-overlay) — ein Klick schaltet `favorite` am
   lokalen Spieler bzw. an der eigenen Freundeskopie um. ── */
.favorite-star-btn {
  border: none;
  background: transparent;
  cursor: pointer;
  font-size: 1.15rem;
  line-height: 1;
  padding: 2px 4px;
  color: var(--text-muted);
}
.favorite-star-btn:hover  { color: #f6ad55; }
.favorite-star-btn.active { color: #f6ad55; }

/* Statistik-Einstieg oberhalb der Turnier-Planansicht. Wird von
   _addPlanStatsButton() (js/app.js) nachtraeglich eingefuegt, weil der Plan von
   vier Formatmodulen erzeugt wird. */
.plan-stats-bar {
  display: flex;
  justify-content: flex-end;
  margin-bottom: 12px;
}

/* ── Update-Hinweis (js/version-check.js) ───────────────────────────────────
   Erscheint OBEN mittig, sobald der Server eine neuere Fassung meldet — in
   jeder Ansicht, unabhaengig davon, was der Nutzer gerade tut.
   Bewusst NICHT modal: ein laufendes Spiel darf nicht unterbrochen werden, der
   Nutzer entscheidet selbst, wann er neu laedt.
   Bewusst OBEN und nicht unten: unten liegt waehrend eines Spiels das
   Nummernfeld (.numpad-area, ohne eigenen z-index). Ein fixierter Balken mit
   z-index 900 haette dessen Tasten verdeckt. */
.update-banner {
  position: fixed;
  left: 50%;
  top: max(14px, calc(env(safe-area-inset-top, 0px) + 10px));
  transform: translate(-50%, -20px);
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 12px 10px 16px;
  border-radius: 999px;
  background: var(--surface);
  border: 2px solid color-mix(in srgb, var(--accent) 45%, transparent);
  box-shadow: 0 6px 24px -6px rgba(0,0,0,.4);
  /* Unter den Erfolgs-Einblendungen (1100), aber ueber dem uebrigen Inhalt. */
  z-index: 900;
  opacity: 0;
  transition: opacity .25s ease, transform .25s ease;
  max-width: min(92vw, 520px);
}
.update-banner--visible { opacity: 1; transform: translate(-50%, 0); }
/* Auf breiten Schirmen nach links ruecken, damit der Balken nicht unter die
   Erfolgs-Einblendungen oben rechts (#ach-toast-container, max. 300px) laeuft. */
@media (min-width: 900px) {
  .update-banner { left: calc(50% - 160px); }
}
.update-banner-text { font-size: .9rem; font-weight: 600; color: var(--text); }
.update-banner-close {
  border: none;
  background: transparent;
  color: var(--text-muted);
  font-size: 1rem;
  line-height: 1;
  cursor: pointer;
  padding: 4px;
}
.update-banner-close:hover { color: var(--text); }

@media (prefers-reduced-motion: reduce) {
  .update-banner { transition: opacity .25s ease; transform: translate(-50%, 0); }
}
@media (max-width: 480px) {
  .update-banner { flex-wrap: wrap; border-radius: 14px; justify-content: center; text-align: center; }
}

/* ── Feedback (docs/PLAN-Feedback.md) ──────────────────────────────────────── */
.feedback-topbar-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  flex-shrink: 0;
  padding: 6px 12px;
  font-size: .85rem;
}
/* Auf schmalen Displays nur das Symbol — in der Topbar draengeln sich sonst
   Profil, Autoscorer und Feedback um denselben Platz. */
@media (max-width: 640px) {
  .feedback-topbar-label { display: none; }
  .feedback-topbar-btn { padding: 6px 9px; }
}

.feedback-card { max-width: 560px; width: 100%; max-height: 88vh; overflow-y: auto; }
.feedback-textarea {
  width: 100%;
  resize: vertical;
  min-height: 44px;
  font-family: inherit;
  line-height: 1.45;
}
.feedback-optional { font-weight: 500; text-transform: none; letter-spacing: 0; opacity: .75; }
.feedback-shot-row { display: flex; gap: 8px; flex-wrap: wrap; }
.feedback-shot-preview {
  margin-top: 10px;
  border: 1px solid var(--border);
  border-radius: 8px;
  overflow: hidden;
  /* Die Vorschau soll zeigen, DASS ein Bild dranhaengt — nicht das halbe
     Popup fuellen. Ohne object-fit ragte das Bild aus dem gedeckelten Rahmen
     heraus statt beschnitten zu werden. */
  max-height: 180px;
}
.feedback-shot-preview img {
  display: block;
  width: 100%;
  max-height: 180px;
  object-fit: cover;
  object-position: top;
}
.feedback-context {
  margin: 14px 0 4px;
  font-size: .8rem;
  color: var(--text-muted);
}
.feedback-context summary { cursor: pointer; }
.feedback-context pre {
  margin: 8px 0 0;
  padding: 10px;
  background: var(--bg);
  border-radius: 8px;
  white-space: pre-wrap;
  word-break: break-word;
  font-size: .74rem;
  line-height: 1.5;
}
.feedback-error {
  display: none;
  color: var(--danger);
  font-size: .85rem;
  margin: 10px 0 0;
}

/* ── Feedback-Ticket (Admin) ───────────────────────────────────────────────── */
.feedback-ticket-card { max-width: 680px; width: 100%; max-height: 90vh; overflow-y: auto; }
.ticket-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
.ticket-head h2 { margin: 0 0 4px; }
.ticket-meta { font-size: .82rem; color: var(--text-muted); }
.ticket-status-row { display: flex; gap: 8px; flex-wrap: wrap; margin: 14px 0 16px; }
.ticket-section { margin-top: 20px; padding-top: 16px; border-top: 1px solid var(--border); }
/* Frage klein und gedaempft, Antwort gross: beim Durchsehen vieler Tickets
   liest man die Antworten, die Fragen sind immer dieselben. */
.ticket-qa { display: flex; flex-direction: column; gap: 4px; }
.ticket-q {
  font-size: .74rem;
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--text-muted);
  margin-top: 10px;
}
.ticket-q:first-child { margin-top: 0; }
.ticket-a { white-space: pre-wrap; line-height: 1.5; }
.ticket-shot { margin-top: 14px; }
.ticket-shot img {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--border);
  border-radius: 8px;
  /* Der Screenshot ist ein Bildschirmausschnitt und oft dunkel — ein heller
     Grund dahinter macht sichtbar, wo das Bild aufhoert. */
  background: #fff;
}
.ticket-shot-actions { display: flex; gap: 8px; margin-top: 8px; }
.ticket-note {
  padding: 8px 10px;
  border-left: 3px solid var(--accent);
  background: var(--bg);
  border-radius: 0 8px 8px 0;
  margin-bottom: 8px;
  white-space: pre-wrap;
  font-size: .88rem;
}
.ticket-note-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 2px;
}
.ticket-note-time { font-size: .72rem; color: var(--text-muted); }
/* Erst beim Ueberfahren der Notiz sichtbar: ein Loeschkreuz an jeder Zeile
   zieht sonst mehr Aufmerksamkeit auf sich als der Text daneben. */
.ticket-note-del {
  border: none;
  background: none;
  color: var(--text-muted);
  cursor: pointer;
  padding: 0 2px;
  font-size: .8rem;
  opacity: 0;
  transition: opacity var(--transition), color var(--transition);
}
.ticket-note:hover .ticket-note-del,
.ticket-note-del:focus-visible { opacity: 1; }
.ticket-note-del:hover { color: var(--danger); }
.ticket-note-add { display: flex; flex-direction: column; gap: 8px; align-items: flex-start; margin-top: 10px; }
.ticket-merge-row { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 8px; }
.ticket-merge-row .input { flex: 1; min-width: 200px; }
/* Zeilen der Meldungsliste sind anklickbar — das muss man ihnen ansehen. */
.feedback-row { cursor: pointer; }
.feedback-row:hover { background: var(--bg); }

/* ── Spielerauswahl als Popup (Neues Spiel) ─────────────────────────────────
   Die frueheren Karten "Spieler hinzufuegen" und "Freunde einladen" stehen
   jetzt in #players-overlay, geoeffnet ueber den Knopf neben dem
   Computer-Gegner. */
/* EINZIGE Regel fuer diesen Container — vorher gab es drei Bloecke aus
   verschiedenen Zwischenstaenden, von denen der letzte align-items: stretch
   setzte. Dadurch wurde der Knopf ueber die volle Breite gezogen und sah
   anders aus als jeder andere Knopf der App.
   flex-start haelt den Knopf auf seiner natuerlichen Breite; die Liste
   darunter holt sich die volle Breite ueber width: 100%. */
.players-open-row {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 10px;
}
/* In der Turnier-Teilnehmerkarte klebte die erste Zeile am Knopf darueber —
   dort folgt direkt eine Liste statt der Auswahl-Zusammenfassung wie im
   normalen Spiel. */
#tv-player-card .players-open-row { margin-bottom: 18px; }
/* Grundeigenschaften; Anordnung (zweispaltiges Raster) und leerer Zustand
   stehen weiter unten beim Listen-Umbau. overflow/text-overflow entfallen
   bewusst: sie stammten aus der Zeit der einzeiligen Komma-Aufzaehlung und
   haetten im Raster ganze Eintraege abgeschnitten. */
.players-open-summary {
  font-size: .88rem;
  color: var(--text);
  min-width: 0;
}

.players-modal-card {
  max-width: 560px;
  width: 100%;
  /* Die Auswahl kann bei vielen Freunden/Spielern lang werden. */
  max-height: 88vh;
  overflow-y: auto;
  text-align: left;
}
.players-modal-subtitle {
  font-size: .95rem;
  font-weight: 700;
  margin: 0 0 10px;
  color: var(--text);
}
.players-modal-footer {
  display: flex;
  justify-content: flex-end;
  margin-top: 18px;
}
/* Im Popup ist Platz — die Chips duerfen frei umbrechen. In der frueheren
   Karte war die Zeilenzahl per --chip-rows begrenzt, weil die Karte neben der
   Spielkonfiguration nur begrenzt hoch werden durfte. */
#players-overlay .saved-players-chips {
  max-height: none;
  flex-wrap: wrap;
}
/* Kein display-!important hier: renderSavedPlayerChips() blendet
   #player-selection-row per style.display aus, wenn es gar keine waehlbaren
   Spieler gibt. Ein !important wuerde das aushebeln und einen leeren Block
   stehen lassen. Stattdessen nur die Ausrichtung anpassen. */
#players-overlay #player-selection-row { flex-direction: column; }

/* ── Popup-Auswahlliste (Aufgabe 3): Favoriten / Lokale Spieler / Freunde ──
   Listenformat wie im Spieler-Tab (.players-row wiederverwendet), aber als
   Auswahl klickbar statt mit Bearbeiten/Löschen-Aktionen. Alle drei
   Abschnitte nutzen bewusst dieselbe Zeilenstruktur — der einzige optische
   Unterschied bei Freunden ist der Online-Punkt und ggf. der
   Einladungsstatus (.invite-status), sonst sieht eine Freundeszeile aus wie
   eine lokale Zeile. ── */
/* Klassen- statt ID-basiert: BEIDE Auswahl-Popups (normales Spiel und
   Turnier) nutzen dieselben Abstaende und Ueberschriften. Vorher hingen die
   Regeln an den IDs des Spiel-Popups, weshalb die Abschnitte im Turnier
   sichtbar enger standen. */
.players-sections { display: flex; flex-direction: column; gap: 4px; }
#player-selection-row { display: flex; flex-direction: column; gap: 4px; }
.players-section { margin-bottom: 22px; }
/* Letzter Abschnitt behaelt seinen Abstand: darunter folgt im Popup direkt das
   Eingabefeld fuer Gaeste, das sonst an der letzten Zeile klebt. */
.players-section:last-child { margin-bottom: 14px; }
/* Die Rollenreiter stehen unmittelbar ueber der ersten Gruppe — ohne eigenen
   Abstand wirkte die Ueberschrift wie ein weiterer Reiter. */
#tv-role-tabs { margin-bottom: 20px; }
/* Deutliche Abschnittstrennung: Überschrift mit Trennlinie statt der
   bisherigen reinen .label-Beschriftung ohne optische Abgrenzung. */
.players-section > .label {
  display: flex;
  align-items: center;
  gap: 7px;
  padding-bottom: 7px;
  margin-bottom: 10px;
  border-bottom: 1px solid var(--border, rgba(127,127,127,.22));
  cursor: grab;
  user-select: none;
}
.players-section > .label:active { cursor: grabbing; }
/* Anfasser: macht ohne Erklaertext sichtbar, dass die Ueberschrift gezogen
   werden kann. Dezent, damit er die Beschriftung nicht ueberlagert. */
.section-grip {
  color: var(--text-muted);
  font-size: .95rem;
  line-height: 1;
  letter-spacing: -1px;
  opacity: .55;
}
.players-section > .label:hover .section-grip { opacity: 1; }
.players-section--dragging { opacity: .45; }
.players-section--over > .label {
  border-bottom-color: var(--accent);
  box-shadow: 0 2px 0 -1px var(--accent);
}
/* Entfernen-Kreuz am Zeilenende — ersetzt den frueheren btn-sm, der in einer
   Listenzeile wie ein eigenstaendiger Knopf wirkte. */
.players-row-remove {
  background: none;
  border: none;
  padding: 2px 4px;
  cursor: pointer;
  color: var(--text-muted);
  font-size: .95rem;
  line-height: 1;
}
.players-row-remove:hover { color: var(--danger, #c53030); }
.players-select-row {
  cursor: pointer;
  transition: border-color .15s ease, background .15s ease;
}
.players-select-row:hover     { border-color: var(--accent); }
.players-select-row.selected  { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 12%, var(--bg-elevated, transparent)); }
/* Online-Punkt vor dem Namen eines Freundes (Praesenzsystem, js/presence.js) */
.players-row-online-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #48bb78;
  margin-right: 7px;
  flex-shrink: 0;
}

/* Ausgewaehlte Spieler als abwaehlbare Chips neben dem Knopf "Spieler
   hinzufuegen". Ersetzt die fruehere Komma-Aufzaehlung, die bei mehreren
   Spielern in die Breite lief und unleserlich wurde. */
/* (Frueherer Chip-Block entfernt — die Auswahl wird seit dem Umbau als Liste
   dargestellt, siehe .players-chosen-row weiter unten.) */

/* ── Spieler-Tab: Abschnitte Favoriten / Weitere ────────────────────────────
   Gleiche Gliederung wie im Popup der Spielerauswahl, damit beide Listen
   gleich gelesen werden. Leere Abschnitte werden gar nicht erst erzeugt. */
.players-subsection { margin-bottom: 22px; }
.players-subsection:last-child { margin-bottom: 0; }
.players-subsection-title {
  font-size: .82rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--text-muted);
  padding-bottom: 6px;
  margin-bottom: 10px;
  border-bottom: 1px solid var(--border);
}

/* ── Gewaehlte Spieler: Liste nach unten statt Chips nach rechts ────────────
   Als Chip-Reihe wuchs die Auswahl seitlich aus dem Blickfeld. */
/* Zwei Spalten, Fuellrichtung von links nach rechts und dann nach unten.
   Bewusst Grid und NICHT die CSS-Mehrspaltigkeit (columns): die fuellt erst
   die linke Spalte komplett von oben nach unten und dann die rechte — genau
   die falsche Reihenfolge. Grid legt die Eintraege zeilenweise ab. */
.players-open-summary {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 6px;
  align-items: start;
  /* Der Container richtet seine Kinder an flex-start aus, damit der Knopf
     seine natuerliche Breite behaelt — die Liste soll die Breite aber voll
     ausnutzen. */
  width: 100%;
}
/* Auf schmalen Viewports bleibt eine Spalte — zwei waeren dort zu schmal fuer
   laengere Namen. */
@media (max-width: 520px) {
  .players-open-summary { grid-template-columns: 1fr; }
}
/* Im leeren Zustand steht dort nur ein Hinweistext, kein Raster. */
.players-open-summary--empty {
  display: block;
  color: var(--text-muted);
  font-style: italic;
}
.players-chosen-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  width: 100%;
  padding: 8px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--bg-elevated, rgba(127,127,127,.06));
  color: var(--text);
  font: inherit;
  font-size: .9rem;
  cursor: pointer;
  text-align: left;
  transition: border-color var(--transition), background var(--transition);
}
.players-chosen-row:hover {
  border-color: var(--danger);
  background: color-mix(in srgb, var(--danger) 8%, var(--bg));
}
.players-chosen-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.players-chosen-x { color: var(--text-muted); flex-shrink: 0; }
.players-chosen-row:hover .players-chosen-x { color: var(--danger); }

/* ── Aktionsfuss einer Karte ────────────────────────────────────────────────
   Schliesst eine Karte mit ihrer Hauptaktion ab (z.B. "Spiel starten" unter
   den Spieleinstellungen). Die Trennlinie setzt die Aktion sichtbar von den
   Eingaben darueber ab, ohne sie in eine eigene Karte auszulagern. */
.card-actions {
  display: flex;
  justify-content: center;
  gap: 12px;
  flex-wrap: wrap;
  margin-top: 22px;
  padding-top: 18px;
  border-top: 1px solid var(--border);
}
@media (max-width: 600px) {
  /* Auf dem Handy ist der Knopf die einzige Aktion — volle Breite trifft man
     mit dem Daumen sicherer als eine 200px-Insel am linken Rand. */
  .card-actions .btn { flex: 1 1 auto; }
}
