/* ============================================================================
   AMERICANO · REDESIGN  (neues Design: dunkles Navy, Neon-Akzent, Skew-Look)
   ----------------------------------------------------------------------------
   Zentrale Reskin-Schicht. Wird pro Seite NACH den Inline-Styles via
   <link rel="stylesheet" href="redesign.css"> direkt vor </head> eingebunden
   und gewinnt damit über die Quell-Reihenfolge.

   Der Skew-Look (schräge Flächen) entsteht über ::before-Parallelogramme –
   der Text bleibt aufrecht & lesbar, KEIN Markup- und KEIN JS-Umbau nötig,
   funktioniert daher auch bei per-JS nachgeladenen Elementen.

   Komplett reversibel:  git revert <commit>   bzw.   Tag 'pre-redesign'.
   ============================================================================ */

/* ---------- 1 · Design-Tokens (überschreibt die :root jeder Seite) ---------- */
:root {
  --navy:#11142D; --navy-h:#080A1A; --navy-pale:#F1F5F9; --bg:#F8FAFC; --card:#FFFFFF;
  --border:#E2E8F0; --text:#0F172A; --muted:#64748B;
  --green:var(--navy); --green-bg:var(--navy-pale); --green-h:var(--navy-h);
  --red:#EF4444;   --red-bg:#FEE2E2;
  --amber:#F59E0B; --amber-bg:#FEF3C7;
  --sky:#0EA5E9;   --sky-bg:#E0F2FE;
  --neon:#C9E81C;  --neon-h:#BCD916; --neon-glow:rgba(201,232,28,.4);
  --radius:12px;
  --shadow:0 12px 32px rgba(17,20,45,.06), 0 2px 8px rgba(17,20,45,.04);
  --skew:-8deg;
  /* Sport-Akzente (neue Mockup-Werte – überschreiben die Seitenwerte) */
  --padel-accent:#3B82F6; --tennis-accent:#A3E635; --beerpong-accent:#F59E0B;
}

/* ---------- 2 · Basis & Typografie ---------- */
body { background:var(--bg); color:var(--text); }
.section-title h3, .hero h2, .login-card h2, .profile-meta h2,
.card h2, .card > h3, .t-card h4, .mrb-title {
  text-transform:uppercase; font-weight:900; letter-spacing:-.4px;
}

/* ---------- 3 · Header (dunkle App-Leiste) ---------- */
header {
  background:var(--navy) !important; -webkit-backdrop-filter:none; backdrop-filter:none;
  border-bottom:2px solid var(--neon); box-shadow:0 4px 24px rgba(17,20,45,.5);
  /* iOS-Safe-Area: viewport-fit=cover laesst Content unter die Statusbar / Notch
     laufen. Sticky-Header oben kollidieren sonst mit Uhrzeit/Batterie. */
  padding-top: max(12px, env(safe-area-inset-top, 12px)) !important;
}
header h1 { text-transform:uppercase; font-weight:900; letter-spacing:-.3px; font-size:20px; }
header img, header .logo { height:36px; }
@media (max-width:480px) {
  header h1 { font-size:17px; }
  header img, header .logo { height:32px; }
}
header a, header button, header .tbadge, .player-badge {
  border-radius:4px !important; text-transform:uppercase; letter-spacing:.5px; font-weight:800;
}
.player-badge, header .tbadge {
  background:var(--navy-h); color:var(--neon); border:1px solid rgba(201,232,28,.35);
}

/* ---------- 3.B · Inner-App-Header (Variant 01: Skew-Wordmark + Neon-CTA) ---------- */
/* Aktiv per <body class="app">. Landing (index.html, ueber Video-Hero) bleibt vom
   Default-Header oben unberuehrt — neuer Look zieht erst, wenn body die .app-Klasse traegt. */

/* Title als Neon-Skew-Block */
body.app header h1 {
  background:var(--neon); color:var(--navy);
  padding:6px 16px; font-size:16px;
  clip-path:polygon(10px 0, 100% 0, calc(100% - 10px) 100%, 0 100%);
  flex:none; letter-spacing:-.3px;
}

/* Logo-Lockup-Link (erster Header-Anker): Seitenspezifische Pille (bg+border+padding aus
   mitglieder.html-Inline-CSS) entschaerfen + nicht ueber die ganze Zeile stretchen.
   Sonst wirkt der Logo-Wrapper als "heller Kasten" und macht die ganze Header-Zeile
   klickbar zur Landing. */
body.app header > a:first-of-type {
  background:transparent !important;
  border:none !important;
  padding:0 !important;
  flex:none !important;
}

/* Rechte CTA (alle weiteren Header-Anker). Solid-Fill statt Outline, damit clip-path
   nicht die border auf den Schraegseiten frisst. */
body.app header > a:not(:first-of-type) {
  background:rgba(255,255,255,.10) !important; color:#fff;
  border:none !important;
  border-radius:0 !important;
  padding:7px 14px;
  margin-left:auto;
  clip-path:polygon(8px 0, 100% 0, calc(100% - 8px) 100%, 0 100%);
  display:inline-flex; align-items:center; gap:6px;
  transition:background-color .15s;
}
body.app header > a:not(:first-of-type):hover {
  background:rgba(255,255,255,.18) !important;
}
body.app header > a:not(:first-of-type) .ic {
  color:var(--neon); width:12px; height:12px;
}
/* hidden-Attribute respektieren: das obige display:inline-flex hat hoehere
   Spezifitaet als das UA-Default [hidden]{display:none} und liess sonst den
   Login-Link auf /profile sichtbar, obwohl JS .hidden=true gesetzt hat. */
body.app header > a[hidden] { display:none !important; }

/* Burger oben rechts: das margin-left:auto sitzt sonst nur am zweiten Anker
   (line 89). Auf Seiten ohne zweiten Anker (z.B. mein-spiel) oder wenn dieser
   per [hidden] entfernt ist (eigenes /profile), rutscht der Burger sonst neben
   den Logo-Block. Wir pushen ihn dann selbst nach rechts. */
body.app header:not(:has(> a:not(:first-of-type):not([hidden]))) > .menu-btn {
  margin-left: auto;
}

@media (max-width:480px) {
  body.app header h1 { padding:5px 12px; font-size:15px; }
  body.app header > a:not(:first-of-type) { padding:6px 11px; font-size:10.5px; }
}

/* ---------- 4 · Skew-Buttons (Parallelogramm via clip-path) ---------- */
/* clip-path statt ::before  ->  robust in JEDEM Container: kein z-index/Stacking-
   Problem (verschwindet nicht hinter dunklen Karten-Hintergründen), kein Überhang,
   Text bleibt aufrecht & zentriert. Solide Hintergrundfarbe direkt am Button. */
.btn-primary, .btn-success, .btn-danger, .btn-warn, .btn-sky, .btn-ghost,
.cta, .btn-submit, .btn-reject, .btn.btn-primary, .btn.btn-ghost {
  border:none !important; text-transform:uppercase; letter-spacing:.6px; font-weight:800;
  border-radius:0 !important;
  clip-path:polygon(7px 0, 100% 0, calc(100% - 7px) 100%, 0 100%);
  transition:background .15s, filter .15s, opacity .15s;
}
/* Primär = Neon */
.btn-primary, .cta, .btn-submit {
  background:var(--neon) !important; color:var(--navy) !important;
  filter:drop-shadow(0 4px 10px var(--neon-glow));
}
.btn-primary:hover, .cta:hover, .btn-submit:hover { background:var(--neon-h) !important; }
/* Farb-Varianten (Admin) */
.btn-success { background:var(--neon) !important; color:var(--navy) !important; }
.btn-success:hover { background:var(--neon-h) !important; }
.btn-danger  { background:var(--red) !important; color:#fff !important; }
.btn-danger:hover  { background:#DC2626 !important; }
.btn-warn    { background:var(--amber) !important; color:#fff !important; }
.btn-warn:hover    { background:#D97706 !important; }
.btn-sky     { background:var(--sky) !important; color:#fff !important; }
.btn-sky:hover     { background:#0284C7 !important; }
/* Ghost = helle Fläche (echter Rahmen ginge bei clip-path verloren) */
.btn-ghost, .cta.ghost { background:var(--navy-pale) !important; color:var(--navy) !important; }
.btn-ghost:hover, .cta.ghost:hover { background:#E2E8F0 !important; }
/* Reject (auf dunkel, Spieler-Match) */
.btn-reject { background:rgba(255,255,255,.10) !important; color:#fff !important; }
/* CTA-Sonderzustände (Hub-Cards) */
.cta.enrolled { background:var(--navy) !important; color:var(--neon) !important; filter:none; }
.cta.live     { background:var(--red) !important; color:#fff !important; filter:drop-shadow(0 4px 10px rgba(239,68,68,.35)); }
.cta.urgent   { background:var(--amber) !important; color:#fff !important; animation:ctaUrgentPulse 1.6s ease-in-out infinite; }
.cta.urgent:hover { background:#D97706 !important; }
@keyframes ctaUrgentPulse {
  0%, 100% { filter:drop-shadow(0 4px 10px rgba(245,158,11,.35)); }
  50%      { filter:drop-shadow(0 6px 16px rgba(245,158,11,.65)); }
}
.cta.disabled, .cta[disabled] { background:var(--navy-pale) !important; color:var(--muted) !important; filter:none; }
/* deaktivierte Farb-Buttons sichtbar abschwächen */
.btn-primary:disabled, .btn-success:disabled, .btn-danger:disabled,
.btn-warn:disabled, .btn-sky:disabled, .cta[disabled] { opacity:.5; cursor:not-allowed; }

/* kleine/Icon-Buttons bleiben schlicht & kantig (gut in Tabellen) */
.btn-sm  { border-radius:5px !important; clip-path:none; text-transform:uppercase; letter-spacing:.4px; font-weight:800; }
.btn-icon{ border-radius:6px !important; clip-path:none; }

/* ---------- 5 · Tabs / Segmented (aktiv = skewed Navy mit Neon-Text) ---------- */
.tab, .sport-filter button, .sport-tabs button,
.sport-pill-row > button, .mr-tabs > .mr-tab, .cc-tabs > .cc-tab {
  text-transform:uppercase; letter-spacing:.6px; font-weight:800;
}
.tab { border-radius:6px; }
.tab.active, .sport-filter button.active, .sport-tabs button.active,
.sport-pill-row > button.active, .mr-tabs > .mr-tab.active, .cc-tabs > .cc-tab.active {
  position:relative; z-index:0; background:transparent !important; color:var(--neon) !important;
}
.tab.active .ic, .cc-tabs > .cc-tab.active .ic { color:var(--neon) !important; }
.tab.active::before, .sport-filter button.active::before, .sport-tabs button.active::before,
.sport-pill-row > button.active::before, .mr-tabs > .mr-tab.active::before, .cc-tabs > .cc-tab.active::before {
  content:""; position:absolute; inset:0; z-index:-1; background:var(--navy);
  border-radius:6px; transform:skewX(var(--skew)); box-shadow:0 4px 12px rgba(17,20,45,.18);
}
/* Border-Radius der lokalen Container angleichen, damit ::before/Indicator
   nicht sichtbar aus den Button-Ecken rausguckt. */
.mr-tabs > .mr-tab.active::before { border-radius:8px; }
.cc-tabs > .cc-tab.active::before { border-radius:11px; }
/* Button-Eigenrahmen auf active ausblenden, damit der skewed Indicator
   nicht von einer geraden Border umschlossen wird. */
.mr-tabs > .mr-tab.active,
.cc-tabs > .cc-tab.active { border-color:transparent !important; }
/* Spieler-App: Bottom-Nav-Tab aktiv (Icon neon) */
nav.tabs .tab.active { color:var(--navy) !important; }
nav.tabs .tab.active::before { display:none; }
nav.tabs .tab.active .ic { color:var(--neon) !important; filter:drop-shadow(0 2px 4px var(--neon-glow)); }
/* Admin-Top-Nav: aktiver Tab = schräg-Navy-Block + Neon-Text/Icon (Variante C).
   Greift NUR bei .admin-tabs und hebt damit die obige Spieler-Bottom-Nav-Regel gezielt
   für den Admin wieder auf (Spieler-App bleibt unberührt). */
nav.admin-tabs .tab.active     { color:var(--neon) !important; box-shadow:none; position:relative; z-index:0; }
nav.admin-tabs .tab.active .ic { color:var(--neon) !important; filter:none; }
nav.admin-tabs .tab.active::before {
  content:""; display:block; position:absolute; inset:0; z-index:-1; background:var(--navy);
  border-radius:6px; transform:skewX(var(--skew)); box-shadow:0 4px 12px rgba(17,20,45,.18);
}

/* ── Tab-Slide-Indicator (animierter Trapez-Marker, ersetzt ::before pro Tab) ──
   Wenn tab-slide.js geladen ist, übernimmt ein einzelnes absolute-positioniertes
   Element das Trapez-Highlight und sliced bei Tab-Wechsel zur neuen Position.
   Form/Farben bleiben identisch zum ::before.

   nav.admin-tabs ist absichtlich NICHT in dieser Regel: die Admin-Seite setzt
   bereits `position:sticky` darauf, und sticky etabliert ebenfalls einen
   positioning-Kontext für absolute Kinder. Wenn wir hier zusätzlich
   `position:relative` setzen, würde das das sticky überschreiben - mit der
   Folge, dass `top:62px` einen 62-Pixel-Offset nach unten produziert statt
   den sticky-Anker zu setzen (sichtbar als Lücke zwischen Header und Tabs). */
.sport-filter, .sport-tabs,
.sport-pill-row, .mr-tabs, .cc-tabs { position:relative; }
/* Vollständiger Default-Look für .sport-filter / .sport-tabs als Standalone-
   Komponente. Container-Box bleibt axis-aligned (für tab-slide.js / getBoundingClientRect);
   der Parallelogramm-Hintergrund wird über das skewed ::before darunter gelegt.
   Inaktive Buttons in Muted, aktive übernimmt das System (Navy ::before + Neon-Text).
   Damit funktioniert die Klasse auch ohne lokale CSS-Hilfe (historie, statistik) konsistent. */
.sport-filter, .sport-tabs {
  display:inline-flex; background:transparent; border:none;
  padding:4px; gap:2px; max-width:100%;
  isolation:isolate;
}
/* Skewed Parallelogramm-Hintergrund per ::before, damit der Container selbst
   axis-aligned bleibt (sonst verrutscht der tab-slide-Indicator, der per
   getBoundingClientRect rechnet). */
.sport-filter::before, .sport-tabs::before {
  content:""; position:absolute; inset:0;
  background:var(--card); border:1px solid var(--border);
  border-radius:10px; transform:skewX(var(--skew));
  box-shadow:0 1px 3px rgba(17,20,45,.04);
  z-index:-1;
}
.sport-filter > button, .sport-tabs > button {
  background:transparent; border:none; color:var(--muted);
  padding:9px 16px; font-size:13px;
  border-radius:6px; cursor:pointer; display:inline-flex;
  align-items:center; gap:6px; white-space:nowrap;
}
.sport-filter > button:hover:not(.active),
.sport-tabs > button:hover:not(.active) { color:var(--navy); }
@media (max-width:480px) {
  .sport-filter, .sport-tabs { padding:3px; gap:0; }
  .sport-filter > button, .sport-tabs > button { padding:7px 10px; font-size:12px; gap:4px; flex-shrink:0; }
  .sport-filter > button .ic, .sport-tabs > button .ic { width:14px; height:14px; }
}
/* nav.admin-tabs: Container ist rechteckig, der skewed Indicator am
   ersten/letzten Tab würde sonst über die Container-Kante ragen — leichter Inset
   verhindert das. .sport-filter/.sport-tabs brauchen das nicht mehr, weil
   ihr Container selbst ein Parallelogramm ist (siehe ::before oben). */
nav.admin-tabs > .tab:first-of-type.active::before { inset:0 0 0 4px; }
nav.admin-tabs > .tab:last-of-type.active::before  { inset:0 4px 0 0; }
.tab-slide-indicator {
  position:absolute; pointer-events:none;
  background:var(--navy); border-radius:6px;
  box-shadow:0 4px 12px rgba(17,20,45,.18);
  transform:skewX(var(--skew));
  z-index:0; opacity:0;
  transition:left 360ms cubic-bezier(.16,1,.3,1),
             top  360ms cubic-bezier(.16,1,.3,1),
             width 360ms cubic-bezier(.16,1,.3,1),
             height 360ms cubic-bezier(.16,1,.3,1),
             opacity 200ms;
}
.tab-slide-indicator.ready { opacity:1; }
/* Border-Radius des slidenden Indicators an die jeweilige Container-Form
   angleichen (Default ist 6px, passt zu .tab/.sport-filter/.sport-tabs). */
.mr-tabs > .tab-slide-indicator { border-radius:8px; }
.cc-tabs > .tab-slide-indicator { border-radius:11px; }
/* Wenn JS aktiv: ::before pro Tab ausblenden, der Slide-Indicator macht's */
.has-slide-indicator .tab.active::before,
.has-slide-indicator > button.active::before { display:none !important; }
.has-slide-indicator > .tab, .has-slide-indicator > button { position:relative; z-index:1; }
@media (prefers-reduced-motion:reduce){
  .tab-slide-indicator { transition:opacity 200ms; }
}

/* ── Skeleton-Shimmer (Loading-Placeholder für Listen) ──────────────
   <div class="skel-list">
     <div class="skel-row"><div class="skel-avatar"></div>
       <div class="skel-col"><div class="skel-line w-70"></div><div class="skel-line w-40"></div></div>
     </div>
     ... × N
   </div>
   Card-Variante (ohne Row-Flex): <div class="skel-card"><div class="skel-line ...">…</div></div> */
.skel-list { display:flex; flex-direction:column; gap:8px; }
.skel-row, .skel-card {
  background:var(--card); border:1px solid var(--border);
  border-radius:10px; padding:12px 14px;
  position:relative; overflow:hidden;
}
.skel-row { display:flex; align-items:center; gap:14px; }
.skel-row .skel-avatar {
  width:38px; height:38px; border-radius:50%;
  background:var(--navy-pale); flex-shrink:0;
}
.skel-row .skel-col { flex:1; min-width:0; }
.skel-line {
  height:10px; border-radius:5px;
  background:var(--navy-pale);
  margin-bottom:6px;
}
.skel-line:last-child { margin-bottom:0; }
.skel-line.w-70 { width:70%; }
.skel-line.w-60 { width:60%; }
.skel-line.w-50 { width:50%; }
.skel-line.w-40 { width:40%; }
.skel-line.w-30 { width:30%; }
.skel-card { padding:16px 18px; }
.skel-card .skel-line { margin-bottom:8px; }
.skel-row::after, .skel-card::after {
  content:""; position:absolute; inset:0;
  background:linear-gradient(110deg, transparent 30%, rgba(255,255,255,.6) 50%, transparent 70%);
  transform:translateX(-100%);
  animation:skelShimmer 1.6s ease-in-out infinite;
  pointer-events:none;
}
@keyframes skelShimmer { to { transform:translateX(100%); } }
@media (prefers-reduced-motion:reduce){
  .skel-row::after, .skel-card::after { animation:none; opacity:.25; }
}

/* ---------- 6 · Cards & Container ---------- */
.card, .login-card, .t-card, .qa, .faq-item, .poll, .hist-round, .myrun-banner {
  border-radius:var(--radius); }
.card, .qa, .faq-item { border:1px solid var(--border); }
.card h2, .card > h3 { color:var(--navy); }

/* ---------- 7 · Formulare (2px-Rahmen, Neon-Fokusring) ---------- */
label { text-transform:uppercase; letter-spacing:.5px; font-weight:800; }
/* Label-Kontexte, in denen CAPS unpassend wirkt: Datenschutz-Consent (.check),
   Absage-Gründe (.reasons), Show-Password-Mikro-Toggle (.show-pw),
   Doodle-Termin-Labels (.slot .lbl), horizontale Toggle-Labels (.toggle-field),
   Multi-Line-Push-Trigger-Optionen (label.flex mit align-items:flex-start),
   alle <label> mit display:flex-Inline-Style (Mein-Spiel-Toggles, Custom-Modes). */
.check label, .reasons label, label.show-pw, .slot .lbl, .toggle-field,
label.toggle-row, .opt-row label,
label.flex,
label[style*="display:flex"], label[style*="display: flex"] {
  text-transform:none; letter-spacing:0; font-weight:600;
}
/* Kinder dieser Labels (strong, span, em) erben das uppercase NICHT — wichtig
   für Push-Trigger im Admin, wo der Label-Body aus <strong>Titel</strong><br>
   <span>Beschreibung</span> besteht. */
.check label *, .reasons label *, label.show-pw *, .toggle-field *,
label.toggle-row *, .opt-row label *,
label.flex *,
label[style*="display:flex"] *, label[style*="display: flex"] * {
  text-transform:none; letter-spacing:0;
}
/* Multi-Line-Toggle-Row mit Checkbox links: kein flex-wrap, damit die
   Checkbox bei schmalen Containern nicht in eine eigene Zeile rutscht. */
label.flex[style*="align-items:flex-start"],
label.flex[style*="align-items: flex-start"] {
  flex-wrap:nowrap;
}
input:not([type=checkbox]):not([type=radio]), select, textarea {
  border:2px solid var(--border) !important; border-radius:8px !important; background-color:var(--bg);
}
/* Checkboxen/Radios: nur Akzentfarbe (Navy). KEIN border/background-color — das schaltet
   auf iOS Safari die native :checked-Darstellung ab, der Haken wird dann nie sichtbar
   (sieht aus, als würde der Klick nicht "halten", obwohl serverseitig gespeichert). */
input, select, textarea { accent-color:var(--navy); }
/* Text-Markierung markenkonform (Neon auf Navy) statt Browser-Blau */
::selection { background:var(--neon); color:var(--navy); }
input:not([type=checkbox]):not([type=radio]):focus, select:focus, textarea:focus {
  border-color:var(--neon) !important; box-shadow:0 0 0 4px var(--neon-glow) !important; background-color:#fff;
  outline:none;
}
/* Eigener Aufklapp-Pfeil: nativer macOS-Pfeil legt sich sonst über den Text, sobald
   ein select Rahmen+Hintergrund bekommt. appearance:none + SVG-Chevron rechts daneben. */
select {
  appearance:none; -webkit-appearance:none;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%2311142D' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  background-repeat:no-repeat; background-position:right 8px center; background-size:11px;
  padding-right:26px !important;
}
.switch input:checked + .track { background:var(--navy); }

/* Toggle-Row-Layout: horizontale Checkbox/Switch + Label in einem hellen Container.
   Bisher nur lokal in admin.html — zentral, damit auch mein-spiel/profile/etc. konsistent. */
.toggle-field { display:flex; align-items:center; gap:12px;
                background:var(--bg); border-radius:10px; padding:12px 14px; margin-bottom:12px; }

/* ---------- 8 · Tabellen ---------- */
.tbl-wrap { border-radius:var(--radius); }
th { font-weight:900; letter-spacing:.8px; border-bottom:2px solid var(--border); }
tbody tr:hover td { background:var(--navy-pale); }

/* ---------- 9 · Pills / Tags / Badges ---------- */
.pill, .tag, .b-chip {
  border-radius:4px; text-transform:uppercase; letter-spacing:.5px; font-weight:800;
}
.pill-navy { background:var(--navy); color:var(--neon); }
/* Prominente „Banner"-Badges (Card-Köpfe & Hero): solide Skew-Flächen via clip-path.
   clip-path statt ::before  ->  robust auf dunklen Card-Köpfen, kein z-index-Problem. */
.sport-badge, .state-pill, .mrb-live, .hero-eyebrow {
  background:transparent; border:none !important; border-radius:0 !important;
  text-transform:uppercase; letter-spacing:.8px; font-weight:900;
  clip-path:polygon(6px 0, 100% 0, calc(100% - 6px) 100%, 0 100%);
}
/* State-Pill als kräftiger „ANMELDUNG OFFEN"-Banner */
.state-pill { font-size:11px !important; padding:6px 14px !important; letter-spacing:.6px; }
.hero-eyebrow { background:var(--neon) !important; color:var(--navy) !important;
  font-size:13.5px !important; padding:10px 22px !important; gap:9px !important;
  clip-path:polygon(14px 0, 100% 0, calc(100% - 14px) 100%, 0 100%); }
.hero-eyebrow .ic { width:16px; height:16px; }
.state-pill.open                              { background:var(--neon) !important;  color:var(--navy) !important; }
.state-pill.running, .state-pill.drawn        { background:var(--amber) !important; color:#1A1B3A !important; }
.state-pill.closed                            { background:var(--red) !important;   color:#fff !important; }
.state-pill.upcoming, .state-pill.opens_soon  { background:rgba(255,255,255,.92) !important; color:var(--navy) !important; }
.state-pill.finished                          { background:rgba(255,255,255,.12) !important; color:rgba(255,255,255,.7) !important; }
.sport-badge[data-sport="padel"]    { background:var(--padel-accent) !important;    color:#fff !important; }
.sport-badge[data-sport="tennis"]   { background:var(--tennis-accent) !important;   color:var(--navy) !important; }
.sport-badge[data-sport="beerpong"] { background:var(--beerpong-accent) !important; color:#fff !important; }
.mrb-live { background:rgba(239,68,68,.20) !important; color:#EF4444 !important; }

/* ---------- 10 · Hero ---------- */
.hero {
  background:var(--navy) !important;
  background-image:
    radial-gradient(circle at 100% 0%, #1e2454 0%, transparent 50%),
    radial-gradient(circle at 0% 100%, rgba(201,232,28,.10) 0%, transparent 40%) !important;
}
.hero h2 { letter-spacing:-1.5px; }

/* ---------- 11 · Hub: Turnier-Cards & Quick-Actions ---------- */
.t-card .head { background:var(--navy) !important;
  background-image:radial-gradient(circle at top right,#1e2454 0%,transparent 100%) !important; }
.t-card .month { color:var(--neon); }
.t-stat { background:var(--bg); border-radius:8px; }
.qa-icon, .q-icon { background:var(--navy) !important; color:var(--neon) !important; border-radius:8px; }
.qa:hover { border-color:var(--neon); }

/* ---------- 12 · Spieler-Match „Mein aktuelles Match" (Gemini-Look) ---------- */
.match-hero { background:radial-gradient(circle at top right,#1a1e42 0%,var(--navy) 100%) !important;
  border:1px solid rgba(255,255,255,.07); }
/* Label mit leuchtendem Neon-Punkt */
.match-label { color:var(--neon) !important; opacity:1 !important; font-weight:900; letter-spacing:1.5px;
  display:flex; align-items:center; gap:9px; }
.match-label::before { content:""; width:9px; height:9px; border-radius:50%; background:var(--neon);
  box-shadow:0 0 10px var(--neon); flex-shrink:0; }
/* Teams in Großbuchstaben, kräftig */
.teams-display { gap:16px; margin-bottom:26px; }
.team-names { font-size:clamp(14px,4.2vw,17px); font-weight:900; text-transform:uppercase; letter-spacing:-.3px; }
.team-names .sub { font-size:11px; font-weight:800; text-transform:uppercase; letter-spacing:.5px;
  color:rgba(255,255,255,.45) !important; opacity:1; margin-top:5px; }
/* VS als schräges Neon-umrandetes Quadrat */
.vs-circle { background:transparent !important; border:2px solid rgba(255,255,255,.16) !important;
  border-radius:0 !important; color:var(--neon) !important; font-weight:900; text-transform:uppercase;
  clip-path:polygon(6px 0,100% 0,calc(100% - 6px) 100%,0 100%); }
/* Score-Bereich: dezente Glasfläche */
.score-section { background:rgba(255,255,255,.04) !important; border:1px solid rgba(255,255,255,.07);
  border-radius:var(--radius) !important; }
.score-section .score-label, .score-section p.score-label, p.score-label {
  color:rgba(255,255,255,.45) !important; opacity:1 !important; letter-spacing:1.5px; font-weight:900; text-align:center; }
/* Große dunkle Score-Eingaben mit Neon-Fokus */
.score-inputs input { background:rgba(0,0,0,.28) !important; color:#fff !important;
  border:2px solid rgba(255,255,255,.12) !important; border-radius:10px !important; box-shadow:none !important; }
.score-inputs input:focus { border-color:var(--neon) !important;
  box-shadow:0 0 0 4px var(--neon-glow) !important; background:rgba(201,232,28,.06) !important; }
.score-colon { color:rgba(255,255,255,.22) !important; }
.confirm-score { font-weight:900; }
.confirm-banner { border-radius:8px; }
/* Ergebnis-Anzeige */
.match-result { background:rgba(0,0,0,.25) !important; border:1px solid rgba(255,255,255,.06);
  border-radius:var(--radius) !important; }
.result-score { font-weight:900; letter-spacing:-2px; }
.result-score.win  { color:var(--neon) !important; text-shadow:0 0 30px var(--neon-glow); }
.result-score.lose { color:rgba(255,255,255,.3) !important; }
/* Ergebnis-Banner: schräg + Uppercase */
.result-banner { text-transform:uppercase; letter-spacing:1px; font-weight:900; border-radius:0;
  clip-path:polygon(7px 0,100% 0,calc(100% - 7px) 100%,0 100%); }
.rb-win { background:var(--neon) !important; color:var(--navy) !important; box-shadow:none; }
.rb-loss, .rb-tie, .rb-helper { background:rgba(255,255,255,.06) !important;
  border:1px solid rgba(255,255,255,.12); color:#fff !important; }

/* ---------- 13 · Profil ---------- */
.avatar { border-radius:12px; border:2px solid var(--border); }
.avatar-edit { background:var(--neon); color:var(--navy); border-radius:8px; }
.padel-id { background:var(--navy); color:var(--neon); border-radius:4px; }
.stat { border-radius:8px; border:1px solid var(--border); }

/* ---------- 14 · Toast / Meldungen ---------- */
#toast { border-radius:6px; }
#toast, .toast { text-transform:uppercase; letter-spacing:.5px; font-weight:800; }
.msg-ok  { border-left:4px solid var(--neon); border-radius:8px; }
.msg-err { border-left:4px solid var(--red);   border-radius:8px; }

/* ---------- 15 · Mock-Abgleich: übriggebliebene alte Elemente ---------- */

/* Hub-Turnier-Cards: Ring-Grafik -> saubere Zahlen-Kacheln (wie Mockup).
   Zahlen + Labels bleiben erhalten (keine Info/Funktion verloren), nur der Ring entfällt. */
.t-card .stat-ring { display:none !important; }
.t-card .t-stats { border-top:2px dashed var(--border); gap:10px; }
.t-card .t-stat  { background:var(--bg); border-radius:8px; padding:12px 6px; min-width:0; }
.t-card .t-stat .v { font-size:22px; font-weight:900; color:var(--navy); margin-top:0; }
.t-card .t-stat .l { font-weight:800; letter-spacing:0; white-space:normal; line-height:1.15; padding:0 2px; }
.t-card .day { font-size:40px; letter-spacing:-2px; }

/* State-Pill ragt wie im Mockup leicht aus dem dunklen Kopf heraus */
.t-card .head { overflow:visible; }
.t-card .state-pill { bottom:-13px !important; }
.t-card .body { padding-top:28px !important; }

/* „Dein Turnier läuft"-Banner: Neon-Leiste + CTA als Neon-Skew */
.myrun-banner::before { background:var(--neon) !important; }
.mrb-cta { background:var(--neon) !important; color:var(--navy) !important; border-radius:0 !important;
  clip-path:polygon(7px 0,100% 0,calc(100% - 7px) 100%,0 100%);
  text-transform:uppercase; letter-spacing:.6px; font-weight:900; }

/* Leaderboard: „Du"-Zeile als Navy-Highlight, Avatare als Neon-Quadrate */
.lb-ava { border-radius:6px; }
.me-row td { background:var(--navy) !important; color:#fff !important; }
.me-row td a, .me-row .lb-name, .me-row strong { color:#fff !important; }
.me-row .lb-ava { background:var(--neon) !important; color:var(--navy) !important; }
.rank-gold { color:#F59E0B !important; } .rank-silver { color:#94A3B8 !important; } .rank-bronze { color:#B45309 !important; }

/* Leere Turnierliste: kantiger gestrichelter Rahmen */
.empty-tournaments { border:2px dashed var(--border) !important; border-radius:var(--radius) !important; }

/* ── Stagger-Reveal Util (Word-Stagger · Cards-Cascade · Reveal-On-View) ───
   JS in stagger-reveal.js triggert per data-stagger="words|cards" oder
   .reveal-on-view. Hier nur die CSS-Übergänge + reduced-motion-Fallback. */
[data-stagger="words"].stagger-ready .reveal-word,
[data-stagger="words"].stagger-ready .reveal-block{
  opacity:0; transform:translateY(8px) rotateX(-30deg);
  transform-origin:center bottom;
  transition:opacity 450ms cubic-bezier(.16,1,.3,1),
             transform 450ms cubic-bezier(.34,1.56,.64,1);
  transition-delay:var(--stagger-delay, 0ms);
}
[data-stagger="words"].stagger-ready .reveal-word{ display:inline-block; }
[data-stagger="words"].stagger-revealed .reveal-word,
[data-stagger="words"].stagger-revealed .reveal-block{
  opacity:1; transform:translateY(0) rotateX(0);
}
.reveal-on-view{
  opacity:0; transform:translateY(18px);
  transition:opacity 520ms cubic-bezier(.16,1,.3,1),
             transform 520ms cubic-bezier(.16,1,.3,1);
  transition-delay:var(--stagger-delay, 0ms);
  will-change:opacity, transform;
}
.reveal-on-view.is-visible{
  opacity:1; transform:translateY(0);
}
@media (prefers-reduced-motion:reduce){
  [data-stagger="words"].stagger-ready .reveal-word,
  [data-stagger="words"].stagger-ready .reveal-block,
  .reveal-on-view{
    opacity:1 !important; transform:none !important; transition:none;
  }
}

/* ── Toast v2 (rechts-oben-Stack, Neon-OK + Undo + Countdown) ──────────────
   API: window.toast(msg, kind?, opts?) — siehe toast.js. CSS hier zentral. */
.toast-stack {
  position:fixed; top:18px; right:18px; z-index:9999;
  display:flex; flex-direction:column; gap:10px; align-items:flex-end;
  pointer-events:none;
}
.toast-item {
  pointer-events:auto;
  background:var(--navy); color:#fff;
  padding:11px 16px; border-radius:10px;
  font-size:14px; font-weight:700;
  letter-spacing:.3px;
  box-shadow:0 10px 32px rgba(0,0,0,.22), 0 2px 8px rgba(0,0,0,.08);
  transform:translateX(120%); opacity:0;
  transition:transform 320ms cubic-bezier(.16,1,.3,1), opacity 220ms;
  max-width:360px;
  display:flex; align-items:center; gap:14px;
  position:relative; overflow:hidden;
}
.toast-item.toast-in  { transform:translateX(0); opacity:1; }
.toast-item.toast-out { transform:translateX(120%); opacity:0; }
.toast-item.toast-ok   { background:var(--neon); color:var(--navy);
                         box-shadow:0 10px 32px var(--neon-glow), 0 2px 8px rgba(17,20,45,.08); }
.toast-item.toast-err  { background:var(--red); }
.toast-item.toast-warn { background:var(--amber); }
.toast-text { line-height:1.35; }
.toast-undo {
  background:rgba(255,255,255,.18); color:inherit;
  border:1px solid rgba(255,255,255,.32);
  border-radius:6px; padding:5px 11px;
  font:inherit; font-size:11.5px; font-weight:800;
  text-transform:uppercase; letter-spacing:.6px;
  cursor:pointer; flex-shrink:0;
  transition:background .15s;
}
.toast-undo:hover { background:rgba(255,255,255,.3); }
.toast-item.toast-ok .toast-undo {
  background:rgba(17,20,45,.12); border-color:rgba(17,20,45,.22);
}
.toast-item.toast-ok .toast-undo:hover { background:rgba(17,20,45,.22); }
.toast-countdown {
  position:absolute; left:0; bottom:0; height:3px; width:100%;
  background:rgba(255,255,255,.45);
  transform-origin:left;
  animation:toastCountdown linear forwards;
}
.toast-item.toast-ok .toast-countdown { background:rgba(17,20,45,.4); }
@keyframes toastCountdown { from { transform:scaleX(1); } to { transform:scaleX(0); } }
@media (prefers-reduced-motion:reduce){
  .toast-item { transition:opacity 220ms; transform:none !important; }
  .toast-countdown { animation:none; transform:scaleX(0); }
}
@media (max-width:480px){
  .toast-stack { top:12px; right:10px; left:10px; align-items:stretch; }
  .toast-item { max-width:none; }
}

/* ── Live-Dot (zentrale Komponente · Neon-Puls mit Box-Shadow-Ripple) ──────
   Default = Neon. Für rot: <span class="live-dot live-dot--red"></span>.
   Ersetzt die bisherige rote !important-Overrides in beerpong/player/etc.
   und die per-Seite duplizierten @keyframes pulse. */
.live-dot {
  width:7px; height:7px; border-radius:50%;
  background:var(--neon);
  display:inline-block; flex-shrink:0; vertical-align:middle;
  animation:liveDotPulse 1.8s ease-in-out infinite;
}
.live-dot--red { background:var(--red); animation-name:liveDotPulseRed; }
@keyframes liveDotPulse {
  0%   { box-shadow:0 0 0 0   rgba(201,232,28,.55); }
  70%  { box-shadow:0 0 0 8px rgba(201,232,28,0); }
  100% { box-shadow:0 0 0 0   rgba(201,232,28,0); }
}
@keyframes liveDotPulseRed {
  0%   { box-shadow:0 0 0 0   rgba(239,68,68,.55); }
  70%  { box-shadow:0 0 0 8px rgba(239,68,68,0); }
  100% { box-shadow:0 0 0 0   rgba(239,68,68,0); }
}
@media (prefers-reduced-motion:reduce) {
  .live-dot { animation:none; }
}

/* Section-Titel etwas enger (Mockup) */
.section-title h3 { letter-spacing:-.8px; }

/* Easter Egg (Drag-Throw-Inertia Tennisball): kein CSS nötig — siehe egg.js */


/* ============================================================================
   PHASE 2 · Mikro-Interaktionen
   ----------------------------------------------------------------------------
   Globale, kleine Effekte die überall greifen (Cards, Buttons, Header, Menus).
   ============================================================================ */

/* ── Pressed-Card-Squish (Vol2-01) ──────────────────────────────────────────
   Auf Tap/Click leicht schrumpfen, schnell zurück — physikalisches Feedback.
   Greift app-weit auf alle Karten-/Tile-/Menu-Element-Klassen. */
.t-card, .tile, .hub-tile, .qa, .vb, .mn-item, .oh-panel, .ci-panel,
.aw-pod, .award, .bz-panel, .skel-card, .skel-row,
.faq-item, .poll, .stat, .adm-t {
  transition:transform .15s cubic-bezier(.34,1.56,.64,1),
             border-color .15s, box-shadow .15s;
}
.t-card:active, .tile:active, .hub-tile:active, .qa:active, .vb:active,
.mn-item:active, .oh-panel:active, .aw-pod:active, .award:active,
.stat:active, .adm-t:active, .bz-panel:active {
  transform:scale(.992);
}
@media (prefers-reduced-motion:reduce){
  .t-card, .tile, .hub-tile, .qa, .vb, .mn-item, .oh-panel,
  .aw-pod, .award, .stat, .adm-t { transition:none; }
  .t-card:active, .tile:active, .hub-tile:active, .qa:active, .vb:active,
  .mn-item:active, .oh-panel:active, .aw-pod:active, .award:active,
  .stat:active, .adm-t:active { transform:none; }
}

/* ── Variable-Weight-Hover (Vol3-03) ────────────────────────────────────────
   Menu-Items + Nav-Links werden beim Hover ein Tick fetter — kommt am
   stärksten bei Variable-Fonts wie system-ui (San Francisco, Segoe UI). */
.mn-item, nav.tabs .tab, nav.admin-tabs .tab, .vb, .qa,
.sport-filter button, .sport-tabs button {
  transition:font-weight .18s ease, font-variation-settings .18s ease,
             color .15s, background .15s, transform .15s,
             border-color .15s, box-shadow .15s;
}
.mn-item:hover, nav.tabs .tab:hover:not(.active), nav.admin-tabs .tab:hover:not(.active),
.sport-filter button:hover:not(.active), .sport-tabs button:hover:not(.active) {
  font-variation-settings:'wght' 850;
}
@media (prefers-reduced-motion:reduce){
  .mn-item, nav.tabs .tab, nav.admin-tabs .tab,
  .sport-filter button, .sport-tabs button { transition:color .15s, background .15s; }
}

/* ── Burger-Morph (App-weit-14) ─────────────────────────────────────────────
   Burger ↔ X über aria-expanded. Burger-Icon fade out + rotate, X fadet
   gleichzeitig rein. Greift für #menuToggle (Index) + #adminTabsBurger (Admin).
   Voraussetzung: das Button hat aria-expanded="true|false". */
.menu-btn, #adminTabsBurger { position:relative; }
.menu-btn > .ic, #adminTabsBurger > .ic {
  transition:opacity .22s ease, transform .35s cubic-bezier(.16,1,.3,1);
}
.menu-btn[aria-expanded="true"] > .ic,
#adminTabsBurger[aria-expanded="true"] > .ic {
  opacity:0; transform:rotate(90deg) scale(.7);
}
.menu-btn::after, #adminTabsBurger::after {
  content:""; position:absolute;
  top:50%; left:50%; width:18px; height:18px;
  margin-top:-9px; margin-left:-9px;
  -webkit-mask-image:url(Icons/close.svg);
          mask-image:url(Icons/close.svg);
  -webkit-mask-size:contain; mask-size:contain;
  -webkit-mask-position:center; mask-position:center;
  -webkit-mask-repeat:no-repeat; mask-repeat:no-repeat;
  background-color:currentColor;
  opacity:0; transform:rotate(-90deg) scale(.7);
  transition:opacity .22s ease, transform .35s cubic-bezier(.16,1,.3,1);
  pointer-events:none;
}
.menu-btn[aria-expanded="true"]::after,
#adminTabsBurger[aria-expanded="true"]::after {
  opacity:1; transform:rotate(0) scale(1);
}
@media (prefers-reduced-motion:reduce){
  .menu-btn > .ic, #adminTabsBurger > .ic,
  .menu-btn::after, #adminTabsBurger::after { transition:opacity .15s; }
  .menu-btn[aria-expanded="true"] > .ic,
  #adminTabsBurger[aria-expanded="true"] > .ic { transform:none; }
  .menu-btn[aria-expanded="true"]::after,
  #adminTabsBurger[aria-expanded="true"]::after { transform:none; }
}

/* ── Header-Shrink beim Scrollen (App-weit-15) ──────────────────────────────
   body.scrolled wird per ui-effects.js gesetzt, sobald scrollY > 8.
   Header verliert dann etwas Padding + Logo wird kleiner. Sticky-Container
   darunter (nav.admin-tabs) müssen den neuen Offset mitnehmen, sonst klafft
   eine Lücke zwischen Header-Unterkante und Tab-Strip. */
body.scrolled header {
  padding-top:7px !important; padding-bottom:7px !important;
  box-shadow:0 6px 24px rgba(17,20,45,.45);
}
body.scrolled header img,
body.scrolled header .logo { height:28px; }
body.scrolled header h1 { font-size:17px; letter-spacing:-.25px; }
header, header img, header .logo, header h1 {
  transition:padding .25s ease, height .25s ease, font-size .25s ease, box-shadow .25s ease;
}
/* Sticky-nav.tabs (admin) muss den shrunk-Header-Offset nehmen.
   Shrunk-Header-Höhe: 7 + 28 + 7 + 2 (Neon-Border) = 44px desktop, 48px mobile. */
body.scrolled nav.admin-tabs,
body.scrolled nav.tabs.admin-tabs {
  top:44px !important;
}
nav.admin-tabs, nav.tabs.admin-tabs {
  transition:top .25s ease;
}
@media (max-width:480px){
  body.scrolled nav.admin-tabs,
  body.scrolled nav.tabs.admin-tabs { top:48px !important; }
}
@media (prefers-reduced-motion:reduce){
  header, header img, header .logo, header h1,
  nav.admin-tabs, nav.tabs.admin-tabs { transition:none; }
}

/* ── Success-Checkmark (App-weit-11) ────────────────────────────────────────
   Util: <span class="ok-check"></span> — animiertes Häkchen mit Puls-Ring.
   Trigger durch das Einfügen ins DOM. */
.ok-check {
  display:inline-flex; align-items:center; justify-content:center;
  width:24px; height:24px; border-radius:50%;
  background:var(--neon); color:var(--navy);
  position:relative; vertical-align:middle;
  animation:okCheckPop .55s cubic-bezier(.34,1.56,.64,1) both;
}
.ok-check::before {
  content:""; width:14px; height:14px;
  -webkit-mask-image:url(Icons/check.svg); mask-image:url(Icons/check.svg);
  -webkit-mask-size:contain; mask-size:contain;
  -webkit-mask-position:center; mask-position:center;
  -webkit-mask-repeat:no-repeat; mask-repeat:no-repeat;
  background-color:currentColor;
  transform:scale(0); opacity:0;
  animation:okCheckTick .35s cubic-bezier(.34,1.56,.64,1) .22s forwards;
}
.ok-check::after {
  content:""; position:absolute; inset:-3px; border-radius:50%;
  box-shadow:0 0 0 0 var(--neon-glow);
  animation:okCheckRing 1.2s ease-out .1s both;
}
@keyframes okCheckPop {
  0%   { transform:scale(0) rotate(-90deg); opacity:0; }
  60%  { transform:scale(1.15) rotate(0); opacity:1; }
  100% { transform:scale(1) rotate(0); }
}
@keyframes okCheckTick {
  0% { transform:scale(0); opacity:0; }
  100% { transform:scale(1); opacity:1; }
}
@keyframes okCheckRing {
  0%   { box-shadow:0 0 0 0 var(--neon-glow); opacity:1; }
  100% { box-shadow:0 0 0 14px rgba(201,232,28,0); opacity:0; }
}
@media (prefers-reduced-motion:reduce){
  .ok-check { animation:none; }
  .ok-check::before { animation:none; transform:scale(1); opacity:1; }
  .ok-check::after { animation:none; }
}

/* ── Error-Shake (App-weit-12) ──────────────────────────────────────────────
   Util: target.classList.add('shake') triggert Wackeln. Per Animation-End-
   Handler oder Timeout wieder entfernen, sonst läuft sie nur einmal. */
.shake { animation:errShake .42s cubic-bezier(.36,.07,.19,.97) both; }
@keyframes errShake {
  10%, 90% { transform:translateX(-1px); }
  20%, 80% { transform:translateX(2px); }
  30%, 50%, 70% { transform:translateX(-4px); }
  40%, 60% { transform:translateX(4px); }
}
@media (prefers-reduced-motion:reduce){
  .shake { animation:none; }
}


/* ============================================================================
   PHASE 3 · Formulare (Floating-Label · Inline-Validation · PW-Strength · Empty-State)
   ============================================================================ */

/* ── Floating-Label-Input (Vol2-04) ─────────────────────────────────────────
   Pattern:
     <label class="field--float">
       <input type="email" placeholder=" " required>
       <span class="field-lbl">E-Mail</span>
     </label>
   WICHTIG: placeholder=" " (ein Leerzeichen) — sonst greift :placeholder-shown nicht. */
.field--float {
  display:block; position:relative; margin-bottom:14px;
}
.field--float input,
.field--float select,
.field--float textarea {
  width:100%; padding:20px 14px 6px;
  border:2px solid var(--border); border-radius:10px;
  font-size:15px; font-family:inherit;
  background:var(--card); color:var(--text);
  transition:border-color .15s, box-shadow .15s;
  appearance:none; -webkit-appearance:none;
  text-align:center;
}
.field--float input:focus,
.field--float select:focus,
.field--float textarea:focus {
  outline:none; border-color:var(--navy);
  box-shadow:0 0 0 3px var(--neon-glow);
}
.field--float .field-lbl {
  position:absolute; left:50%; top:50%; transform:translate(-50%,-50%);
  font-size:14px; color:var(--muted); font-weight:600;
  pointer-events:none; background:var(--card); padding:0 6px;
  white-space:nowrap; max-width:calc(100% - 16px);
  overflow:hidden; text-overflow:ellipsis;
  transition:top .18s cubic-bezier(.16,1,.3,1),
             font-size .18s, color .18s, font-weight .18s;
}
/* Label hochfliegen lassen sobald Feld fokussiert oder gefüllt ist. */
.field--float input:focus + .field-lbl,
.field--float input:not(:placeholder-shown) + .field-lbl,
.field--float select:focus + .field-lbl,
.field--float select:not(:placeholder-shown) + .field-lbl,
.field--float textarea:focus + .field-lbl,
.field--float textarea:not(:placeholder-shown) + .field-lbl {
  top:0; font-size:10.5px; color:var(--navy);
  letter-spacing:.5px; text-transform:uppercase; font-weight:800;
}
@media (prefers-reduced-motion:reduce){
  .field--float .field-lbl { transition:color .15s; }
}
/* Selects in field--float: Label dauerhaft im "floated"-Zustand (ein Select hat
   immer einen sichtbaren Wert, :placeholder-shown greift nicht). Chevron wieder
   einsetzen — das background:-Shorthand oben überschreibt sonst den globalen
   select-Chevron auf Navy. */
.field--float:has(select) .field-lbl {
  top:0; font-size:10.5px; color:var(--navy);
  letter-spacing:.5px; text-transform:uppercase; font-weight:800;
}
.field--float select {
  text-align:left;
  background-color:var(--card);
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%2311142D' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  background-repeat:no-repeat;
  background-position:right 14px center;
  background-size:12px;
  padding-right:36px !important;
}

/* ── Inline-Validation Tick/Cross (Vol2-05) ─────────────────────────────────
   Auf bestehende .field--float aufsetzbar: class="field--float field--validate".
   Browser-native :valid / :invalid via type/required/pattern; Tick/Cross-Icon
   wird über das ::after der Wrapper-Label gerendert. */
.field--validate input,
.field--validate select { padding-left:40px; padding-right:40px; }
.field--validate::after {
  content:""; position:absolute; right:12px; top:50%;
  width:18px; height:18px; margin-top:-9px;
  -webkit-mask-size:contain; mask-size:contain;
  -webkit-mask-position:center; mask-position:center;
  -webkit-mask-repeat:no-repeat; mask-repeat:no-repeat;
  opacity:0; transform:scale(.6);
  transition:opacity .22s, transform .28s cubic-bezier(.34,1.56,.64,1);
  pointer-events:none;
}
/* Tick (grün) bei :valid + nicht leer */
.field--validate:has(input:not(:placeholder-shown):valid)::after,
.field--validate:has(select:not(:placeholder-shown):valid)::after {
  -webkit-mask-image:url(Icons/check.svg); mask-image:url(Icons/check.svg);
  background-color:#15803D;
  opacity:1; transform:scale(1);
}
/* Cross (rot) bei :invalid + nicht leer + nicht fokussiert */
.field--validate:has(input:not(:placeholder-shown):invalid:not(:focus))::after,
.field--validate:has(select:not(:placeholder-shown):invalid:not(:focus))::after {
  -webkit-mask-image:url(Icons/close.svg); mask-image:url(Icons/close.svg);
  background-color:var(--red);
  opacity:1; transform:scale(1);
}
.field--validate:has(input:not(:placeholder-shown):invalid:not(:focus)) input,
.field--validate:has(select:not(:placeholder-shown):invalid:not(:focus)) select {
  border-color:var(--red);
}

/* ── Passwort-Stärke-Balken (Vol2-06) ───────────────────────────────────────
   Pattern (per JS-Schritt, siehe forms.js):
     <div class="pw-strength" data-level="0">
       <div class="pw-strength-bar"></div>
       <span class="pw-strength-label">–</span>
     </div>
   data-level: 0 (leer) bis 4 (stark) */
.pw-strength {
  margin:6px 2px 12px; display:flex; align-items:center; gap:10px;
  font-size:11px; font-weight:800; letter-spacing:.5px; text-transform:uppercase;
}
.pw-strength-bar {
  flex:1; height:6px; border-radius:3px;
  background:var(--border); position:relative; overflow:hidden;
}
.pw-strength-bar::after {
  content:""; position:absolute; left:0; top:0; bottom:0;
  width:0%; transition:width .35s cubic-bezier(.34,1.56,.64,1), background .25s;
  background:var(--red); border-radius:3px;
}
.pw-strength[data-level="1"] .pw-strength-bar::after { width:25%;  background:var(--red); }
.pw-strength[data-level="2"] .pw-strength-bar::after { width:50%;  background:var(--amber); }
.pw-strength[data-level="3"] .pw-strength-bar::after { width:75%;  background:#84CC16; }
.pw-strength[data-level="4"] .pw-strength-bar::after { width:100%; background:var(--neon); }
.pw-strength-label { color:var(--muted); min-width:54px; text-align:right; }
.pw-strength[data-level="1"] .pw-strength-label { color:var(--red); }
.pw-strength[data-level="2"] .pw-strength-label { color:var(--amber); }
.pw-strength[data-level="3"] .pw-strength-label { color:#65A30D; }
.pw-strength[data-level="4"] .pw-strength-label { color:var(--navy); }
@media (prefers-reduced-motion:reduce){
  .pw-strength-bar::after { transition:background .25s; }
}

/* ── Empty-State (Vol2-20) ──────────────────────────────────────────────────
   Pattern:
     <div class="empty-state">
       <div class="empty-state-icon"><i class="ic ic-...."></i></div>
       <h3 class="empty-state-title">…</h3>
       <p class="empty-state-msg">…</p>
       <button class="btn-primary">…</button>
     </div>
   Icon schwebt sanft (3.5s ease-in-out), ganzer Block fadet beim Einfügen rein. */
.empty-state {
  display:flex; flex-direction:column; align-items:center; justify-content:center;
  gap:14px; padding:42px 22px; text-align:center;
  border:2px dashed var(--border); border-radius:var(--radius);
  background:var(--card);
  animation:emptyStateIn .55s cubic-bezier(.16,1,.3,1) both;
}
.empty-state-icon {
  width:64px; height:64px; border-radius:50%;
  display:flex; align-items:center; justify-content:center;
  background:var(--navy-pale); color:var(--navy);
  animation:emptyStateFloat 3.5s ease-in-out infinite;
}
.empty-state-icon .ic { width:30px; height:30px; }
.empty-state-title {
  font-size:16px; font-weight:900; color:var(--navy);
  text-transform:uppercase; letter-spacing:.5px; margin:0;
}
.empty-state-msg {
  font-size:14px; color:var(--muted); line-height:1.5;
  margin:0; max-width:380px;
}
.empty-state .btn-primary,
.empty-state > button {
  margin-top:6px; padding:10px 22px; font-size:13px;
}
@keyframes emptyStateIn {
  from { opacity:0; transform:translateY(12px); }
  to   { opacity:1; transform:translateY(0); }
}
@keyframes emptyStateFloat {
  0%, 100% { transform:translateY(0); }
  50%      { transform:translateY(-5px); }
}
@media (prefers-reduced-motion:reduce){
  .empty-state, .empty-state-icon { animation:none; }
}


/* ============================================================================
   PHASE 4 · Zahlen-Animationen
   (Count-Up · Score-Flash · Progress-Donut · Number-Roll-Up)
   ============================================================================ */

/* ── Count-Up (App-weit-07) ─────────────────────────────────────────────────
   Pattern: <span data-countup="42">42</span> — JS animiert von 0 hoch.
   CSS: nur tabular-nums damit Zahlen nicht springen beim Hochzählen. */
[data-countup] {
  font-variant-numeric:tabular-nums;
  font-feature-settings:'tnum' 1;
}

/* ── Score-Flash (App-weit-08) ──────────────────────────────────────────────
   Util: target.classList.add('score-flash') triggert kurzen Neon-Glow.
   Wird via window.scoreFlash(el) auch aus JS getriggert + Klasse selber
   wieder entfernt. */
.score-flash {
  animation:scoreFlash .85s cubic-bezier(.34,1.56,.64,1) both;
}
@keyframes scoreFlash {
  0%   { transform:scale(1);    text-shadow:0 0 0 transparent; color:inherit; }
  25%  { transform:scale(1.18); text-shadow:0 0 18px var(--neon-glow); color:var(--neon); }
  100% { transform:scale(1);    text-shadow:0 0 0 transparent; color:inherit; }
}
@media (prefers-reduced-motion:reduce){
  .score-flash { animation:none; }
}

/* ── Progress-Donut (Vol2-11) ───────────────────────────────────────────────
   Pattern (kein SVG nötig, conic-gradient):
     <div class="progress-donut" style="--progress: 0.62;" data-label="62%">
       <span class="progress-donut-val">23/40</span>
     </div>
   --progress = 0..1. Per CSS animiert beim Wertewechsel. */
.progress-donut {
  --size: 80px;
  --thickness: 9px;
  --progress: 0;
  --color: var(--neon);
  width:var(--size); height:var(--size); border-radius:50%;
  position:relative; flex-shrink:0;
  background:conic-gradient(var(--color) calc(var(--progress) * 360deg),
                            var(--border) 0);
  display:flex; align-items:center; justify-content:center;
  transition:background .6s cubic-bezier(.16,1,.3,1);
}
.progress-donut::before {
  content:""; position:absolute;
  inset:var(--thickness);
  background:var(--card); border-radius:50%;
}
.progress-donut-val {
  position:relative; z-index:1;
  font-size:13px; font-weight:900; color:var(--navy);
  font-variant-numeric:tabular-nums;
}
/* Sport-Akzent-Varianten */
.progress-donut--padel   { --color:var(--padel-accent); }
.progress-donut--tennis  { --color:var(--tennis-accent); }
.progress-donut--warn    { --color:var(--amber); }
.progress-donut--danger  { --color:var(--red); }
@media (prefers-reduced-motion:reduce){
  .progress-donut { transition:none; }
}

/* ── Number-Roll-Up (Vol2-09) ───────────────────────────────────────────────
   Vertikal-Rolling-Digits. CSS-Engine via window.numberRollUp(el, n) — die
   JS-Funktion legt pro Ziffer eine Spalte mit 0–9 an und scrollt sie zur
   Ziel-Position. Hier nur die CSS-Struktur. */
.num-roll {
  display:inline-flex; align-items:center;
  font-variant-numeric:tabular-nums;
  font-feature-settings:'tnum' 1;
  vertical-align:baseline;
}
.num-roll-digit {
  display:inline-block;
  height:1em; line-height:1; overflow:hidden;
  vertical-align:baseline;
}
.num-roll-track {
  display:flex; flex-direction:column; line-height:1;
  transform:translateY(0);
  transition:transform .55s cubic-bezier(.34,1.56,.64,1);
}
.num-roll-track > span { height:1em; }
.num-roll-sign,
.num-roll-sep { display:inline-block; }
@media (prefers-reduced-motion:reduce){
  .num-roll-track { transition:none; }
}


/* ============================================================================
   PHASE 5 · Tab-/Page-Übergänge (Wipe-Transition · Step-Progress global)
   ============================================================================ */

/* ── Wipe-Transition für Panel-Wechsel (Vol3-17) ────────────────────────────
   Standard-Tab-Pattern (.panel.active wird sichtbar) bekommt einen Wipe-In:
   leicht von rechts reinrutschen + fadet ein. Outgoing-Panel verschwindet
   instant (display:none) — Eyeline bleibt aufs neue Panel gerichtet. */
.panel.active,
.tsection.show,
nav.tabs ~ .panel.active {
  animation:panelWipeIn .35s cubic-bezier(.16,1,.3,1);
}
@keyframes panelWipeIn {
  from { opacity:0; transform:translateX(18px); }
  to   { opacity:1; transform:translateX(0); }
}
@media (prefers-reduced-motion:reduce){
  .panel.active, .tsection.show { animation:none; }
}

/* Optional: View-Transitions API für richtig flüssige Out+In, wenn der
   Browser sie kann. Greift bei document.startViewTransition(...) — opt-in. */
@supports (view-transition-name:auto){
  .panel.active { view-transition-name:panel-content; }
}

/* ── Step-Progress global (Vol2-12) ─────────────────────────────────────────
   Stepper-Komponente, die in admin.html (.t-stepper) lebt. Hier nochmal
   neutral als .step-progress aufgebaut, damit Anmelde-Flow, Onboarding etc.
   ihn ohne admin-Markup nutzen können.

   Pattern:
     <ol class="step-progress">
       <li class="step done"><span class="step-dot">1</span><span class="step-lbl">Daten</span></li>
       <li class="step cur"> <span class="step-dot">2</span><span class="step-lbl">Bestätigen</span></li>
       <li class="step">     <span class="step-dot">3</span><span class="step-lbl">Fertig</span></li>
     </ol>
*/
.step-progress {
  display:flex; gap:0; margin:14px 0; padding:0; list-style:none;
  align-items:flex-start;
}
.step-progress .step {
  flex:1; min-width:0; display:flex; flex-direction:column; align-items:center;
  gap:6px; font-size:11px; font-weight:700; color:var(--muted);
  text-transform:uppercase; letter-spacing:.3px; position:relative;
  transition:color 360ms cubic-bezier(.16,1,.3,1);
}
.step-progress .step::after {
  content:''; position:absolute; left:50%; right:-50%; top:9px;
  height:2px; background:var(--border); z-index:0;
  transition:background 480ms cubic-bezier(.16,1,.3,1);
}
.step-progress .step:last-child::after { display:none; }
.step-progress .step.done::after { background:var(--neon); }
.step-progress .step-dot {
  width:20px; height:20px; border-radius:50%;
  background:var(--card); border:2px solid var(--bg);
  display:flex; align-items:center; justify-content:center;
  position:relative; z-index:1; line-height:1; font-size:12px; font-weight:900;
  transition:background 320ms cubic-bezier(.34,1.56,.64,1),
             border-color 320ms cubic-bezier(.34,1.56,.64,1),
             color 280ms, transform 320ms cubic-bezier(.34,1.56,.64,1),
             box-shadow 320ms;
}
.step-progress .step.done { color:var(--navy); }
.step-progress .step.done .step-dot {
  background:var(--neon); border-color:var(--neon); color:var(--navy);
}
.step-progress .step.cur { color:var(--navy); }
.step-progress .step.cur .step-dot {
  background:var(--navy); border-color:var(--navy); color:#fff;
  transform:scale(1.1);
  animation:stepProgressPulse 1.8s ease-in-out infinite;
}
@keyframes stepProgressPulse {
  0%, 100% { box-shadow:0 0 0 4px rgba(43,45,96,.15), 0 0 0 4px rgba(201,232,28,.45); }
  50%      { box-shadow:0 0 0 4px rgba(43,45,96,.15), 0 0 0 12px rgba(201,232,28,0); }
}
.step-progress .step-lbl { font-size:10px; line-height:1.2; text-align:center; padding:0 4px; }
@media (prefers-reduced-motion:reduce){
  .step-progress .step.cur .step-dot { animation:none; }
}
@media (max-width:600px){
  .step-progress .step-lbl { font-size:9px; }
}


/* ============================================================================
   PHASE 6 · Karten-Morph
   (Card-Flip · Expand-to-Detail · Pill-to-Card-Morph · Icon-Morph Padel/Tennis)
   ============================================================================ */

/* ── Card-Flip (Vol2-07) ────────────────────────────────────────────────────
   Pattern:
     <div class="card-flip">
       <div class="card-flip-inner">
         <div class="card-front">…</div>
         <div class="card-back">…</div>
       </div>
     </div>
   Toggle: <div class="card-flip is-flipped">. JS-Helper window.flipCard(el). */
.card-flip {
  perspective:1200px;
  position:relative;
  cursor:pointer;
  -webkit-tap-highlight-color:transparent;
}
.card-flip-inner {
  position:relative;
  width:100%; min-height:100%;
  transform-style:preserve-3d;
  transition:transform .65s cubic-bezier(.16,1,.3,1);
}
.card-flip.is-flipped .card-flip-inner { transform:rotateY(180deg); }
.card-flip .card-front,
.card-flip .card-back {
  backface-visibility:hidden;
  -webkit-backface-visibility:hidden;
}
.card-flip .card-back {
  position:absolute; inset:0;
  transform:rotateY(180deg);
}
@media (prefers-reduced-motion:reduce){
  .card-flip-inner { transition:none; }
  .card-flip.is-flipped .card-flip-inner { transform:none; }
  .card-flip .card-front { display:none; }
  .card-flip:not(.is-flipped) .card-back { display:none; }
  .card-flip .card-back { position:relative; inset:auto; transform:none; }
}

/* ── Expand-to-Detail (Vol2-08) — View-Transitions API ──────────────────────
   Quell-Karte und Ziel-Modal bekommen den gleichen view-transition-name,
   dann macht document.startViewTransition() automatisch das shared-element-
   Morph. Fallback (Browser ohne API): klassische Modal-Animation.

   Pattern:
     <article class="t-card" data-vt="tournament-42">…</article>
     <div class="modal-detail" data-vt="tournament-42">…</div>
   JS:
     openDetail(card) {
       if (document.startViewTransition) {
         document.startViewTransition(() => renderModal(card.dataset.vt));
       } else { renderModal(card.dataset.vt); }
     }

   CSS legt die view-transition-name nur an, wenn das Attribut gesetzt ist. */
[data-vt] { view-transition-name:auto; }
/* Fallback ohne View-Transitions API: smoothes Fade+Scale beim Modal-Open. */
@supports not (view-transition-name:auto){
  .modal-detail.is-open,
  .adm-modal-overlay.is-open .adm-modal-box {
    animation:modalDetailIn .35s cubic-bezier(.16,1,.3,1);
  }
}
@keyframes modalDetailIn {
  from { opacity:0; transform:scale(.92) translateY(8px); }
  to   { opacity:1; transform:scale(1) translateY(0); }
}

/* ── Pill-to-Card-Morph (Vol3-05) ───────────────────────────────────────────
   Pill-Button expandiert zu einer Detail-Karte. Reine CSS-Variante über
   einen Wrapper, der zwischen .as-pill und .as-card umschaltet.

   Pattern:
     <button class="morph-pc as-pill" onclick="this.classList.toggle('as-card')">
       <span class="mpc-label">Anmelden</span>
       <div class="mpc-details" aria-hidden="true">…</div>
     </button>
*/
.morph-pc {
  display:inline-flex; flex-direction:column; align-items:stretch;
  background:var(--neon); color:var(--navy); border:none;
  border-radius:99px; padding:11px 22px;
  font-size:14px; font-weight:800; text-transform:uppercase; letter-spacing:.5px;
  cursor:pointer; overflow:hidden;
  clip-path:polygon(8px 0, 100% 0, calc(100% - 8px) 100%, 0 100%);
  transition:border-radius .45s cubic-bezier(.16,1,.3,1),
             padding .45s cubic-bezier(.16,1,.3,1),
             max-width .45s cubic-bezier(.16,1,.3,1),
             background .25s, clip-path .45s;
  max-width:260px;
}
.morph-pc .mpc-label {
  display:flex; align-items:center; justify-content:center; gap:8px;
  white-space:nowrap; line-height:1;
}
.morph-pc .mpc-details {
  max-height:0; opacity:0; padding-top:0; overflow:hidden;
  text-align:left; font-size:13px; font-weight:600; text-transform:none;
  letter-spacing:normal; line-height:1.5;
  transition:max-height .45s cubic-bezier(.16,1,.3,1),
             opacity .25s, padding-top .25s;
}
.morph-pc.as-card {
  border-radius:14px; padding:18px 22px; max-width:480px;
  clip-path:none;
}
.morph-pc.as-card .mpc-details {
  max-height:320px; opacity:1; padding-top:12px;
}
@media (prefers-reduced-motion:reduce){
  .morph-pc, .morph-pc .mpc-details { transition:none; }
}

/* ── Icon-Morph Padel ↔ Tennis (Vol3-04) ────────────────────────────────────
   Pattern: zwei .ic Icons gestapelt in einem .icon-morph, mit data-sport
   auf dem Container. Wechsel = CSS-Fade + Mini-Drehung.

     <span class="icon-morph" data-sport="padel">
       <i class="ic ic-padel"></i>
       <i class="ic ic-tennis"></i>
     </span>
   JS: container.dataset.sport = 'tennis' (oder andere). */
.icon-morph {
  display:inline-flex; align-items:center; justify-content:center;
  position:relative; width:1.1em; height:1.1em;
  vertical-align:middle;
}
.icon-morph > .ic {
  position:absolute; inset:0;
  opacity:0; transform:scale(.5) rotate(-180deg);
  transition:opacity .35s cubic-bezier(.16,1,.3,1),
             transform .45s cubic-bezier(.34,1.56,.64,1);
}
.icon-morph[data-sport="padel"] > .ic-padel,
.icon-morph[data-sport="tennis"] > .ic-tennis,
.icon-morph[data-sport="beerpong"] > .ic-beer,
.icon-morph[data-sport="mixed"] > .ic-padel {
  opacity:1; transform:scale(1) rotate(0);
}
@media (prefers-reduced-motion:reduce){
  .icon-morph > .ic { transition:opacity .15s; }
  .icon-morph > .ic { transform:none; }
}


/* ============================================================================
   PHASE 7 · Cinematic (Sponsoren-Marquee · Winner-Spotlight · Trophy-Reveal)
   ============================================================================ */

/* ── Sponsoren-Marquee (Vol2-14) ────────────────────────────────────────────
   Endlos-Lauf, pausiert beim Hover. Pattern:
     <div class="marquee" aria-label="Sponsoren">
       <div class="marquee-track">
         <!-- Items 1x, JS dupliziert sie für seamless loop -->
         <span>HTV</span> <span>Tennis-Hannover</span> …
       </div>
     </div>
   Geschwindigkeit über --marquee-duration; aria-label bleibt für Screenreader. */
.marquee {
  overflow:hidden; position:relative;
  --marquee-duration:40s;
  mask-image:linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
  -webkit-mask-image:linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}
.marquee-track {
  display:flex; gap:36px; width:max-content;
  animation:marqueeScroll var(--marquee-duration) linear infinite;
  align-items:center;
}
.marquee:hover .marquee-track,
.marquee.is-paused .marquee-track { animation-play-state:paused; }
.marquee-track > * {
  flex-shrink:0;
  font-weight:800; color:var(--muted);
  text-transform:uppercase; letter-spacing:.8px; font-size:13px;
}
@keyframes marqueeScroll {
  from { transform:translateX(0); }
  to   { transform:translateX(-50%); }
}
@media (prefers-reduced-motion:reduce){
  .marquee-track { animation:none; }
}

/* ── Winner-Spotlight (App-weit-18) ─────────────────────────────────────────
   Pulse-Glow auf Siegerzelle/-Karte/-Pille. Reine Klasse + Sport-Akzent:
     <div class="winner-spot">…</div>
     <div class="winner-spot winner-spot--gold">…</div>
   Goldener Schein für Tournament Champion, neon für „aktuell führend". */
.winner-spot {
  position:relative;
  animation:winnerSpotPulse 2.2s ease-in-out infinite;
}
.winner-spot::after {
  content:""; position:absolute; inset:-6px; border-radius:inherit;
  background:radial-gradient(circle, var(--neon-glow) 0%, transparent 70%);
  z-index:-1; pointer-events:none;
  animation:winnerSpotHalo 2.2s ease-in-out infinite;
}
.winner-spot--gold {
  animation-name:winnerSpotPulseGold;
}
.winner-spot--gold::after {
  background:radial-gradient(circle, rgba(245,158,11,.55) 0%, transparent 70%);
  animation-name:winnerSpotHaloGold;
}
@keyframes winnerSpotPulse {
  0%, 100% { box-shadow:0 0 0 0 var(--neon-glow); }
  50%      { box-shadow:0 0 28px var(--neon-glow); }
}
@keyframes winnerSpotHalo {
  0%, 100% { opacity:.5; transform:scale(1); }
  50%      { opacity:1;  transform:scale(1.06); }
}
@keyframes winnerSpotPulseGold {
  0%, 100% { box-shadow:0 0 0 0 rgba(245,158,11,.45); }
  50%      { box-shadow:0 0 32px rgba(245,158,11,.7); }
}
@keyframes winnerSpotHaloGold {
  0%, 100% { opacity:.55; transform:scale(1); }
  50%      { opacity:1;   transform:scale(1.08); }
}
@media (prefers-reduced-motion:reduce){
  .winner-spot, .winner-spot::after { animation:none; }
}

/* ── Trophy-Reveal (Vol3-18) ────────────────────────────────────────────────
   Cinematic-Reveal für Ceremony/Season-End. Mehrstufige Animation:
     1) Backdrop fadet ein (dunkler Vignette)
     2) Trophäen-Icon schnellt mit Bounce hoch
     3) Konfetti-Strahl von der Mitte (CSS-Strahlen + Rotation)
     4) Spieler-Namen liegen sich beruhigt an

   Pattern:
     <div class="trophy-reveal" data-trophy-reveal>
       <div class="trophy-reveal-back"></div>
       <div class="trophy-reveal-trophy"><i class="ic ic-trophy"></i></div>
       <div class="trophy-reveal-rays"></div>
       <h2 class="trophy-reveal-name">Ruwen S.</h2>
       <p class="trophy-reveal-sub">Champion · Frühlings-Cup 2026</p>
     </div>

   Triggert beim Einfügen ins DOM (animation: both). */
.trophy-reveal {
  position:relative; padding:48px 24px 40px;
  text-align:center;
  display:flex; flex-direction:column; align-items:center; gap:18px;
  overflow:hidden;
  border-radius:var(--radius);
  background:radial-gradient(circle at center, var(--navy) 0%, var(--navy-h) 70%, #050615 100%);
  color:#fff;
  animation:trophyBackdrop .8s ease-out both;
}
.trophy-reveal-back {
  position:absolute; inset:0;
  background:radial-gradient(circle at center, rgba(201,232,28,.18) 0%, transparent 60%);
  animation:trophyBackdropPulse 3.5s ease-in-out infinite;
  pointer-events:none;
}
.trophy-reveal-trophy {
  position:relative; width:96px; height:96px;
  border-radius:50%;
  background:radial-gradient(circle, #FFC906 0%, #E7B400 80%);
  display:flex; align-items:center; justify-content:center;
  box-shadow:0 0 0 6px rgba(255,201,6,.18), 0 20px 60px rgba(255,201,6,.35);
  animation:trophyPop 1.1s cubic-bezier(.34,1.56,.64,1) .35s both;
}
.trophy-reveal-trophy .ic { width:46px; height:46px; color:var(--navy); }
.trophy-reveal-rays {
  position:absolute; top:48%; left:50%; width:600px; height:600px;
  margin:-300px 0 0 -300px; pointer-events:none;
  background:conic-gradient(
    from 0deg,
    transparent 0deg,    rgba(255,201,6,.18) 8deg,  transparent 16deg,
    transparent 32deg,   rgba(255,201,6,.14) 40deg, transparent 48deg,
    transparent 64deg,   rgba(255,201,6,.18) 72deg, transparent 80deg,
    transparent 96deg,   rgba(255,201,6,.14) 104deg, transparent 112deg,
    transparent 128deg,  rgba(255,201,6,.18) 136deg, transparent 144deg,
    transparent 160deg,  rgba(255,201,6,.14) 168deg, transparent 176deg,
    transparent 192deg,  rgba(255,201,6,.18) 200deg, transparent 208deg,
    transparent 224deg,  rgba(255,201,6,.14) 232deg, transparent 240deg,
    transparent 256deg,  rgba(255,201,6,.18) 264deg, transparent 272deg,
    transparent 288deg,  rgba(255,201,6,.14) 296deg, transparent 304deg,
    transparent 320deg,  rgba(255,201,6,.18) 328deg, transparent 336deg,
    transparent 352deg,  rgba(255,201,6,.14) 360deg
  );
  border-radius:50%;
  opacity:0;
  animation:trophyRaysIn .9s ease-out .45s forwards,
            trophyRaysSpin 26s linear .45s infinite;
}
.trophy-reveal-name {
  position:relative;
  font-size:clamp(24px, 6vw, 38px); font-weight:900;
  text-transform:uppercase; letter-spacing:-.5px; margin:0;
  background:linear-gradient(135deg, var(--neon) 0%, #FFC906 100%);
  -webkit-background-clip:text; background-clip:text; color:transparent;
  animation:trophyTextIn .7s cubic-bezier(.16,1,.3,1) .65s both;
}
.trophy-reveal-sub {
  position:relative;
  font-size:14px; color:rgba(255,255,255,.7); font-weight:600;
  text-transform:uppercase; letter-spacing:.8px; margin:0;
  animation:trophyTextIn .7s cubic-bezier(.16,1,.3,1) .85s both;
}
@keyframes trophyBackdrop {
  from { opacity:0; }
  to   { opacity:1; }
}
@keyframes trophyBackdropPulse {
  0%, 100% { opacity:.7; }
  50%      { opacity:1;  }
}
@keyframes trophyPop {
  0%   { opacity:0; transform:scale(0) rotate(-45deg); }
  60%  { opacity:1; transform:scale(1.2) rotate(8deg); }
  100% { opacity:1; transform:scale(1)   rotate(0); }
}
@keyframes trophyRaysIn {
  from { opacity:0; }
  to   { opacity:1; }
}
@keyframes trophyRaysSpin {
  from { transform:rotate(0); }
  to   { transform:rotate(360deg); }
}
@keyframes trophyTextIn {
  from { opacity:0; transform:translateY(14px); }
  to   { opacity:1; transform:translateY(0); }
}
@media (prefers-reduced-motion:reduce){
  .trophy-reveal,
  .trophy-reveal-back,
  .trophy-reveal-trophy,
  .trophy-reveal-rays,
  .trophy-reveal-name,
  .trophy-reveal-sub { animation:none; opacity:1; transform:none; }
  .trophy-reveal-rays { display:none; }
}


/* ============================================================================
   PHASE 8 · Gesten (Pull-to-Refresh · Swipe-to-Action · Drag-Reorder)
   ----------------------------------------------------------------------------
   JS in gestures.js (opt-in: window.Gestures.*). CSS hier zentral.
   ============================================================================ */

/* ── Pull-to-Refresh ────────────────────────────────────────────────────────
   Container kriegt .ptr-indicator als erstes Kind. translateY wird per JS
   gesetzt. Bei .ptr-ready färbt sich der Spinner neon (Schwelle erreicht). */
.ptr-indicator {
  position:relative; display:flex; align-items:center; justify-content:center;
  height:48px; margin-top:-48px; opacity:0;
  color:var(--muted);
  pointer-events:none;
}
.ptr-spinner {
  width:24px; height:24px; border-radius:50%;
  border:2.5px solid var(--border); border-top-color:currentColor;
  animation:none;
}
.ptr-indicator.ptr-pulling .ptr-spinner { color:var(--muted); }
.ptr-indicator.ptr-ready   .ptr-spinner { color:var(--neon); }
.ptr-indicator.ptr-busy    .ptr-spinner {
  animation:ptrSpin .9s linear infinite;
  color:var(--neon);
}
@keyframes ptrSpin { to { transform:rotate(360deg); } }
@media (prefers-reduced-motion:reduce){
  .ptr-indicator.ptr-busy .ptr-spinner { animation:none; }
}

/* ── Swipe-to-Action ────────────────────────────────────────────────────────
   Layered: zwei .swipe-bg darunter (rechts/links), .swipe-front darüber.
   Bei armed-* glüht der Hintergrund neon/rot. */
.swipe-wrap { position:relative; overflow:hidden; }
.swipe-bg {
  position:absolute; inset:0; display:flex; align-items:center;
  padding:0 18px; font-weight:900; text-transform:uppercase; letter-spacing:.6px;
  font-size:13px; color:#fff;
}
.swipe-bg-left  { justify-content:flex-start; background:var(--neon); color:var(--navy); }
.swipe-bg-right { justify-content:flex-end;   background:var(--red); }
.swipe-front {
  position:relative; z-index:1; background:var(--card);
  transition:transform .25s cubic-bezier(.16,1,.3,1);
  touch-action:pan-y;
}
.swipe-armed-right .swipe-bg-left  { box-shadow:inset 0 0 0 3px rgba(17,20,45,.18); }
.swipe-armed-left  .swipe-bg-right { box-shadow:inset 0 0 0 3px rgba(0,0,0,.2); }

/* ── Drag-Reorder ───────────────────────────────────────────────────────────
   .reorder-item bekommt einen Lift bei .is-dragging, Placeholder ist eine
   gestrichelte Box mit gleicher Höhe an der Ziel-Stelle. */
.reorder-list .reorder-item {
  transition:transform .2s cubic-bezier(.16,1,.3,1), box-shadow .2s;
  touch-action:pan-y; user-select:none;
}
.reorder-list .reorder-item.is-dragging {
  box-shadow:0 16px 40px rgba(17,20,45,.22);
  transform:scale(1.02);
  background:var(--card);
}
.reorder-placeholder {
  border:2px dashed var(--neon);
  border-radius:10px;
  background:rgba(201,232,28,.08);
  margin:4px 0;
}
[data-drag-handle] { cursor:grab; touch-action:none; }
[data-drag-handle]:active { cursor:grabbing; }
@media (prefers-reduced-motion:reduce){
  .reorder-list .reorder-item, .swipe-front { transition:none; }
}


/* ============================================================================
   PHASE 9 · Premium-Eye-Candy (Coverflow · Spring-Slider · Number-Path-Morph)
   ============================================================================ */

/* ── Coverflow-Carousel 3D (Vol3-11) ────────────────────────────────────────
   Horizontal-Scroll-Container, Items in der Mitte werden groß, an den Seiten
   gekippt + verkleinert. JS in coverflow.js setzt --pos (Distanz zur Mitte
   in Item-Breiten, signed) auf jedes sichtbare Item.

   Pattern:
     <div class="coverflow" data-coverflow>
       <div class="coverflow-track">
         <article class="coverflow-card">…</article>
         <article class="coverflow-card">…</article>
         …
       </div>
     </div>
*/
.coverflow {
  position:relative; overflow-x:auto; -webkit-overflow-scrolling:touch;
  scroll-snap-type:x mandatory;
  perspective:1400px;
  padding:24px 0;
  scrollbar-width:none;
}
.coverflow::-webkit-scrollbar { display:none; }
.coverflow-track {
  display:flex; gap:24px; padding:0 50%;
  transform-style:preserve-3d;
}
.coverflow-card {
  flex:0 0 auto; width:240px;
  scroll-snap-align:center;
  transform-origin:center center;
  transform:rotateY(calc(var(--pos, 0) * -22deg)) scale(calc(1 - min(.32, abs(var(--pos, 0)) * .18)));
  transition:transform .35s cubic-bezier(.16,1,.3,1);
  opacity:calc(1 - min(.5, abs(var(--pos, 0)) * .25));
  filter:brightness(calc(1 - min(.2, abs(var(--pos, 0)) * .12)));
}
.coverflow-card[data-pos="0"] { z-index:2; }
@media (prefers-reduced-motion:reduce){
  .coverflow-card {
    transform:none !important; opacity:1; filter:none;
    transition:none;
  }
  .coverflow { perspective:none; }
}

/* ── Spring-Slider (Vol3-14) ────────────────────────────────────────────────
   Range-Input mit Spring-Bounce auf dem Thumb beim Loslassen. Über CSS
   reicht: bei :not(:active) bekommt der Thumb eine kurze Bounce-Animation.
   Style ersetzt den nativen Slider rein optisch (Track + Thumb). */
.spring-slider {
  appearance:none; -webkit-appearance:none;
  width:100%; height:36px; background:transparent;
  --val:50; /* per JS oder inline: width-Anteil 0..100 */
  cursor:pointer;
}
.spring-slider::-webkit-slider-runnable-track {
  height:6px; border-radius:3px;
  background:linear-gradient(90deg,
    var(--neon) 0%, var(--neon) calc(var(--val) * 1%),
    var(--border) calc(var(--val) * 1%), var(--border) 100%);
}
.spring-slider::-moz-range-track {
  height:6px; border-radius:3px;
  background:linear-gradient(90deg,
    var(--neon) 0%, var(--neon) calc(var(--val) * 1%),
    var(--border) calc(var(--val) * 1%), var(--border) 100%);
}
.spring-slider::-webkit-slider-thumb {
  -webkit-appearance:none; appearance:none;
  width:22px; height:22px; border-radius:50%;
  background:var(--navy); border:2px solid var(--neon);
  margin-top:-8px;
  box-shadow:0 4px 12px rgba(17,20,45,.25);
  transition:transform .25s cubic-bezier(.16,1,.3,1);
}
.spring-slider::-moz-range-thumb {
  width:22px; height:22px; border-radius:50%;
  background:var(--navy); border:2px solid var(--neon);
  box-shadow:0 4px 12px rgba(17,20,45,.25);
  transition:transform .25s cubic-bezier(.16,1,.3,1);
}
.spring-slider:active::-webkit-slider-thumb { transform:scale(1.25); }
.spring-slider:active::-moz-range-thumb    { transform:scale(1.25); }
/* Bounce nach Loslassen (Klasse .is-released wird per JS gesetzt) */
.spring-slider.is-released::-webkit-slider-thumb {
  animation:springBounce .55s cubic-bezier(.34,1.56,.64,1);
}
.spring-slider.is-released::-moz-range-thumb {
  animation:springBounce .55s cubic-bezier(.34,1.56,.64,1);
}
@keyframes springBounce {
  0%   { transform:scale(1.25); }
  60%  { transform:scale(.85); }
  100% { transform:scale(1); }
}
@media (prefers-reduced-motion:reduce){
  .spring-slider::-webkit-slider-thumb,
  .spring-slider::-moz-range-thumb { transition:none; animation:none; }
}

/* ── Number-Path-Morph (Vol3-06, vereinfacht) ───────────────────────────────
   Notiz: „Ziffern müssen klar bleiben". Daher KEIN echtes Path-Morphing,
   stattdessen vertikales Crossfade zwischen zwei tabular-num-Ziffern, die
   in einem festen Slot übereinanderliegen — die alte Ziffer fadet nach
   oben raus, die neue von unten rein. Klar lesbar, kein Zwischenzustand
   wirkt verschwommen.

   Pattern (per JS aus numbers.js):
     <span class="num-path"><span class="num-path-digit">7</span></span>
   Wechsel via window.setNumPath(span, 8) → fügt neue Ziffer ein, animiert.
   Optional: aufeinanderfolgende Ziffern als Inline-Container für Multi-
   stelligen Score (z.B. 23 → 24).
*/
.num-path {
  display:inline-flex; align-items:baseline;
  position:relative; overflow:hidden;
  font-variant-numeric:tabular-nums;
  line-height:1;
}
.num-path-digit {
  display:inline-block; min-width:.6em; text-align:center;
  position:relative; transition:transform .42s cubic-bezier(.34,1.56,.64,1),
                                 opacity .3s;
}
.num-path-digit.num-path-out {
  position:absolute; inset:0;
  transform:translateY(-100%); opacity:0;
}
.num-path-digit.num-path-in-start {
  transform:translateY(100%); opacity:0;
}
@media (prefers-reduced-motion:reduce){
  .num-path-digit { transition:none; }
  .num-path-digit.num-path-out { display:none; }
}

/* ─── UI-Dialogs (ui-dialogs.js) ─────────────────────────────────────────── */
/* Stil-Disziplin: keine eigenen Farben / Button-Formen.
   - Box nutzt --card / --radius / --shadow (wie .card)
   - Buttons nutzen .btn-primary / .btn-ghost / .btn-danger (App-Klassen,
     inkl. Skew-clip-path) — wir setzen sie im JS, nicht hier nochmal. */
.ui-dlg-overlay {
  position:fixed; inset:0; z-index:10000;
  background:rgba(10,12,30,.55);
  -webkit-backdrop-filter:blur(4px); backdrop-filter:blur(4px);
  display:flex; align-items:center; justify-content:center;
  padding:24px;
  animation:ui-dlg-fade-in .15s ease-out;
}
.ui-dlg-overlay.is-closing { animation:ui-dlg-fade-out .14s ease-in forwards; }
.ui-dlg-box {
  background:var(--card); color:var(--text);
  border-radius:var(--radius);
  border:1px solid var(--border);
  box-shadow:var(--shadow);
  width:100%; max-width:460px;
  padding:22px 22px 18px;
  animation:ui-dlg-pop-in .22s cubic-bezier(.16,1,.3,1);
}
.ui-dlg-overlay.is-closing .ui-dlg-box { animation:ui-dlg-pop-out .14s ease-in forwards; }
.ui-dlg-title {
  font-weight:900; text-transform:uppercase; letter-spacing:-.2px;
  font-size:18px; color:var(--navy);
  margin:0 0 10px;
}
.ui-dlg-body { font-size:15px; line-height:1.5; color:var(--text); }
.ui-dlg-body p { margin:0 0 10px; }
.ui-dlg-body p:last-child { margin-bottom:0; }
.ui-dlg-input-wrap { margin-top:14px; }
.ui-dlg-input {
  width:100%; box-sizing:border-box;
  padding:10px 12px; font-size:15px;
  border:2px solid var(--border); border-radius:8px;
  background:#fff; color:var(--text);
  font-family:inherit;
}
.ui-dlg-input:focus {
  outline:none; border-color:var(--neon);
  box-shadow:0 0 0 4px var(--neon-glow);
}
.ui-dlg-actions {
  display:flex; gap:10px; justify-content:flex-end;
  margin-top:20px; flex-wrap:wrap;
}
/* Die Buttons (.btn-primary / .btn-ghost / .btn-danger) bringen ihren Stil
   selbst mit. Wir geben ihnen nur eine konsistente Mindesthöhe + Padding,
   ohne die App-Farben oder die Skew-Form anzufassen. */
.ui-dlg-actions .btn-primary,
.ui-dlg-actions .btn-ghost,
.ui-dlg-actions .btn-danger {
  padding:10px 22px; min-height:40px;
  font-size:13px; cursor:pointer;
}

html.ui-dlg-open, html.ui-dlg-open body { overflow:hidden; }

@keyframes ui-dlg-fade-in  { from { opacity:0; } to { opacity:1; } }
@keyframes ui-dlg-fade-out { from { opacity:1; } to { opacity:0; } }
@keyframes ui-dlg-pop-in {
  from { transform:translateY(8px) scale(.96); opacity:0; }
  to   { transform:translateY(0)   scale(1);    opacity:1; }
}
@keyframes ui-dlg-pop-out {
  from { transform:translateY(0) scale(1);    opacity:1; }
  to   { transform:translateY(4px) scale(.98); opacity:0; }
}

@media (max-width:480px) {
  .ui-dlg-overlay { padding:14px; align-items:flex-end; }
  .ui-dlg-box { max-width:none; }
  .ui-dlg-actions { flex-direction:column-reverse; }
  .ui-dlg-actions .btn-primary,
  .ui-dlg-actions .btn-ghost,
  .ui-dlg-actions .btn-danger { width:100%; }
}

@media (prefers-reduced-motion:reduce){
  .ui-dlg-overlay, .ui-dlg-box { animation:none !important; }
}

/* ── Auth-Hint: kein Login-Aufblitzer beim Seitenwechsel ──────────
   <html> bekommt im Head-Script .auth-user oder .auth-guest aus dem
   Hint-Cookie padel_uid, lange BEVOR me.php zurueckkommt. Elemente
   mit .auth-only-user / .auth-only-guest werden CSS-seitig vor dem
   ersten Paint korrekt ein-/ausgeblendet. */
html.auth-user  .auth-only-guest,
html.auth-guest .auth-only-user { display:none !important; }
