1124 lines
45 KiB
HTML
1124 lines
45 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="de">
|
||
<head>
|
||
<meta charset="UTF-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||
<title>WM 2026 Tippspiel – GEALAN</title>
|
||
<style>
|
||
/* ── GEALAN Corporate Design ───────────────────────────── */
|
||
:root {
|
||
--dark-blue: #004891;
|
||
--light-blue: #0092D1;
|
||
--red: #CF073F;
|
||
--yellow: #F9AA2E;
|
||
--green: #2E7D32;
|
||
--text: #1B1B1B;
|
||
--gray-mid: #4C4C4C;
|
||
--gray-light: #818181;
|
||
--gray-border:#BEBEBE;
|
||
--gray-bg: #EBEBEB;
|
||
--white: #FFFFFF;
|
||
}
|
||
|
||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||
|
||
body {
|
||
font-family: 'Calibri', 'Roboto', Arial, sans-serif;
|
||
background: var(--gray-bg);
|
||
color: var(--text);
|
||
font-size: 14px;
|
||
}
|
||
|
||
/* ── Header / Topbar ───────────────────────────────────── */
|
||
.app-header {
|
||
background: var(--white);
|
||
border-bottom: 3px solid var(--dark-blue);
|
||
padding: 0 24px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
height: 60px;
|
||
position: sticky;
|
||
top: 0;
|
||
z-index: 100;
|
||
box-shadow: 0 2px 8px rgba(0,0,0,0.08);
|
||
}
|
||
.app-header .logo-area {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 16px;
|
||
}
|
||
.app-header .logo-area .brand {
|
||
font-size: 18px;
|
||
font-weight: 700;
|
||
color: var(--dark-blue);
|
||
letter-spacing: 0.5px;
|
||
}
|
||
.app-header .logo-area .brand span {
|
||
color: var(--light-blue);
|
||
}
|
||
.app-header .logo-area .badge {
|
||
background: var(--yellow);
|
||
color: var(--text);
|
||
font-size: 11px;
|
||
font-weight: 700;
|
||
padding: 2px 8px;
|
||
border-radius: 12px;
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.5px;
|
||
}
|
||
.user-chip {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
background: var(--gray-bg);
|
||
padding: 6px 12px;
|
||
border-radius: 20px;
|
||
font-size: 13px;
|
||
color: var(--gray-mid);
|
||
}
|
||
.user-chip .avatar {
|
||
width: 28px; height: 28px;
|
||
background: var(--dark-blue);
|
||
color: white;
|
||
border-radius: 50%;
|
||
display: flex; align-items: center; justify-content: center;
|
||
font-size: 12px; font-weight: 700;
|
||
}
|
||
|
||
/* ── Navigation ────────────────────────────────────────── */
|
||
.nav {
|
||
background: var(--dark-blue);
|
||
display: flex;
|
||
gap: 0;
|
||
padding: 0 24px;
|
||
}
|
||
.nav-btn {
|
||
padding: 12px 20px;
|
||
color: rgba(255,255,255,0.7);
|
||
cursor: pointer;
|
||
font-size: 14px;
|
||
font-weight: 600;
|
||
border-bottom: 3px solid transparent;
|
||
transition: all 0.2s;
|
||
user-select: none;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
}
|
||
.nav-btn:hover { color: white; background: rgba(255,255,255,0.08); }
|
||
.nav-btn.active {
|
||
color: white;
|
||
border-bottom-color: var(--yellow);
|
||
}
|
||
.nav-btn .icon { font-size: 16px; }
|
||
|
||
/* ── Layout ────────────────────────────────────────────── */
|
||
.container {
|
||
max-width: 1100px;
|
||
margin: 0 auto;
|
||
padding: 24px 16px;
|
||
}
|
||
.page { display: none; }
|
||
.page.active { display: block; }
|
||
|
||
/* ── Cards ─────────────────────────────────────────────── */
|
||
.card {
|
||
background: var(--white);
|
||
border-radius: 8px;
|
||
box-shadow: 0 1px 4px rgba(0,0,0,0.08);
|
||
overflow: hidden;
|
||
}
|
||
.card-header {
|
||
background: var(--dark-blue);
|
||
color: white;
|
||
padding: 14px 20px;
|
||
font-weight: 700;
|
||
font-size: 15px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
}
|
||
.card-body { padding: 16px 20px; }
|
||
|
||
/* ── Dashboard ─────────────────────────────────────────── */
|
||
.stats-row {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||
gap: 16px;
|
||
margin-bottom: 24px;
|
||
}
|
||
.stat-card {
|
||
background: var(--white);
|
||
border-radius: 8px;
|
||
padding: 20px;
|
||
box-shadow: 0 1px 4px rgba(0,0,0,0.08);
|
||
border-top: 4px solid var(--dark-blue);
|
||
}
|
||
.stat-card.blue { border-top-color: var(--dark-blue); }
|
||
.stat-card.light { border-top-color: var(--light-blue); }
|
||
.stat-card.yellow { border-top-color: var(--yellow); }
|
||
.stat-card.green { border-top-color: var(--green); }
|
||
.stat-card .stat-val {
|
||
font-size: 32px;
|
||
font-weight: 900;
|
||
color: var(--dark-blue);
|
||
line-height: 1;
|
||
}
|
||
.stat-card .stat-label {
|
||
font-size: 12px;
|
||
color: var(--gray-mid);
|
||
margin-top: 4px;
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.5px;
|
||
}
|
||
|
||
.dashboard-grid {
|
||
display: grid;
|
||
grid-template-columns: 1fr 1fr;
|
||
gap: 20px;
|
||
}
|
||
@media (max-width: 700px) {
|
||
.dashboard-grid { grid-template-columns: 1fr; }
|
||
}
|
||
|
||
/* ── Spielplan ─────────────────────────────────────────── */
|
||
.filter-bar {
|
||
display: flex;
|
||
gap: 8px;
|
||
flex-wrap: wrap;
|
||
margin-bottom: 16px;
|
||
}
|
||
.filter-btn {
|
||
padding: 6px 14px;
|
||
border: 2px solid var(--gray-border);
|
||
border-radius: 20px;
|
||
background: white;
|
||
color: var(--gray-mid);
|
||
cursor: pointer;
|
||
font-size: 13px;
|
||
font-weight: 600;
|
||
transition: all 0.15s;
|
||
}
|
||
.filter-btn:hover { border-color: var(--light-blue); color: var(--light-blue); }
|
||
.filter-btn.active { background: var(--dark-blue); border-color: var(--dark-blue); color: white; }
|
||
|
||
.match-day-header {
|
||
font-size: 12px;
|
||
font-weight: 700;
|
||
color: var(--gray-light);
|
||
text-transform: uppercase;
|
||
letter-spacing: 1px;
|
||
padding: 16px 0 6px;
|
||
}
|
||
|
||
.match-card {
|
||
background: var(--white);
|
||
border-radius: 8px;
|
||
margin-bottom: 8px;
|
||
box-shadow: 0 1px 3px rgba(0,0,0,0.07);
|
||
border-left: 4px solid transparent;
|
||
transition: all 0.15s;
|
||
overflow: hidden;
|
||
}
|
||
.match-card:hover { box-shadow: 0 2px 8px rgba(0,0,0,0.12); transform: translateY(-1px); }
|
||
.match-card.tipped { border-left-color: var(--light-blue); }
|
||
.match-card.finished { border-left-color: var(--gray-border); }
|
||
.match-card.correct { border-left-color: var(--green); }
|
||
.match-card.wrong { border-left-color: var(--red); }
|
||
|
||
.match-inner {
|
||
padding: 14px 16px;
|
||
display: grid;
|
||
grid-template-columns: 1fr auto 1fr auto;
|
||
align-items: center;
|
||
gap: 12px;
|
||
}
|
||
.match-team {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
}
|
||
.match-team.away { justify-content: flex-end; }
|
||
.match-team .flag {
|
||
width: 28px; height: 20px;
|
||
border-radius: 3px;
|
||
display: flex; align-items: center; justify-content: center;
|
||
font-size: 18px;
|
||
flex-shrink: 0;
|
||
}
|
||
.match-team .team-name {
|
||
font-weight: 700;
|
||
font-size: 14px;
|
||
}
|
||
.match-score-area {
|
||
text-align: center;
|
||
min-width: 90px;
|
||
}
|
||
.match-score {
|
||
font-size: 22px;
|
||
font-weight: 900;
|
||
color: var(--dark-blue);
|
||
letter-spacing: 1px;
|
||
}
|
||
.match-score.tbd { color: var(--gray-border); }
|
||
.match-time {
|
||
font-size: 11px;
|
||
color: var(--gray-light);
|
||
margin-top: 2px;
|
||
}
|
||
.match-group-badge {
|
||
font-size: 10px;
|
||
background: var(--gray-bg);
|
||
color: var(--gray-mid);
|
||
padding: 2px 6px;
|
||
border-radius: 4px;
|
||
font-weight: 700;
|
||
margin-top: 3px;
|
||
display: inline-block;
|
||
}
|
||
.match-tip-btn {
|
||
background: var(--dark-blue);
|
||
color: white;
|
||
border: none;
|
||
padding: 8px 14px;
|
||
border-radius: 6px;
|
||
cursor: pointer;
|
||
font-size: 12px;
|
||
font-weight: 700;
|
||
white-space: nowrap;
|
||
transition: background 0.15s;
|
||
}
|
||
.match-tip-btn:hover { background: var(--light-blue); }
|
||
.match-tip-btn.tipped {
|
||
background: var(--light-blue);
|
||
}
|
||
.match-tip-btn.finished {
|
||
background: var(--gray-border);
|
||
color: var(--gray-mid);
|
||
cursor: default;
|
||
}
|
||
.my-tip-display {
|
||
font-size: 11px;
|
||
color: var(--light-blue);
|
||
font-weight: 700;
|
||
text-align: center;
|
||
margin-top: 2px;
|
||
}
|
||
.status-live {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 4px;
|
||
background: var(--red);
|
||
color: white;
|
||
font-size: 10px;
|
||
font-weight: 700;
|
||
padding: 2px 6px;
|
||
border-radius: 4px;
|
||
text-transform: uppercase;
|
||
}
|
||
.status-live::before {
|
||
content: '';
|
||
width: 6px; height: 6px;
|
||
background: white;
|
||
border-radius: 50%;
|
||
animation: blink 1s infinite;
|
||
}
|
||
@keyframes blink { 0%,100%{opacity:1} 50%{opacity:0.3} }
|
||
|
||
/* ── Tipp-Modal ─────────────────────────────────────────── */
|
||
.modal-overlay {
|
||
display: none;
|
||
position: fixed;
|
||
inset: 0;
|
||
background: rgba(0,0,0,0.5);
|
||
z-index: 200;
|
||
align-items: center;
|
||
justify-content: center;
|
||
padding: 16px;
|
||
}
|
||
.modal-overlay.open { display: flex; }
|
||
.modal {
|
||
background: white;
|
||
border-radius: 12px;
|
||
width: 100%;
|
||
max-width: 420px;
|
||
overflow: hidden;
|
||
box-shadow: 0 20px 60px rgba(0,0,0,0.3);
|
||
animation: slideUp 0.2s ease;
|
||
}
|
||
@keyframes slideUp { from{transform:translateY(20px);opacity:0} to{transform:translateY(0);opacity:1} }
|
||
.modal-header {
|
||
background: var(--dark-blue);
|
||
color: white;
|
||
padding: 16px 20px;
|
||
font-weight: 700;
|
||
font-size: 15px;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
}
|
||
.modal-close { cursor: pointer; font-size: 20px; opacity: 0.7; transition: opacity 0.15s; }
|
||
.modal-close:hover { opacity: 1; }
|
||
.modal-body { padding: 24px 20px; }
|
||
.modal-teams {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
margin-bottom: 24px;
|
||
}
|
||
.modal-team {
|
||
text-align: center;
|
||
flex: 1;
|
||
}
|
||
.modal-team .flag { font-size: 36px; display: block; }
|
||
.modal-team .name { font-weight: 700; font-size: 15px; margin-top: 6px; }
|
||
.modal-vs { font-size: 24px; font-weight: 900; color: var(--gray-border); padding: 0 12px; }
|
||
.modal-input-row {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 16px;
|
||
margin-bottom: 24px;
|
||
}
|
||
.score-input {
|
||
width: 72px; height: 72px;
|
||
border: 3px solid var(--gray-border);
|
||
border-radius: 12px;
|
||
font-size: 32px;
|
||
font-weight: 900;
|
||
text-align: center;
|
||
color: var(--dark-blue);
|
||
outline: none;
|
||
transition: border-color 0.15s;
|
||
}
|
||
.score-input:focus { border-color: var(--light-blue); }
|
||
.score-colon {
|
||
font-size: 32px;
|
||
font-weight: 900;
|
||
color: var(--dark-blue);
|
||
}
|
||
.modal-deadline {
|
||
text-align: center;
|
||
font-size: 12px;
|
||
color: var(--gray-light);
|
||
margin-bottom: 20px;
|
||
}
|
||
.modal-deadline strong { color: var(--yellow); }
|
||
.btn-primary {
|
||
width: 100%;
|
||
background: var(--dark-blue);
|
||
color: white;
|
||
border: none;
|
||
padding: 14px;
|
||
border-radius: 8px;
|
||
font-size: 15px;
|
||
font-weight: 700;
|
||
cursor: pointer;
|
||
transition: background 0.15s;
|
||
}
|
||
.btn-primary:hover { background: var(--light-blue); }
|
||
|
||
/* ── Rangliste ─────────────────────────────────────────── */
|
||
.leaderboard-table {
|
||
width: 100%;
|
||
border-collapse: collapse;
|
||
}
|
||
.leaderboard-table th {
|
||
background: var(--dark-blue);
|
||
color: white;
|
||
padding: 10px 14px;
|
||
text-align: left;
|
||
font-size: 12px;
|
||
font-weight: 700;
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.5px;
|
||
}
|
||
.leaderboard-table td {
|
||
padding: 12px 14px;
|
||
border-bottom: 1px solid var(--gray-bg);
|
||
font-size: 14px;
|
||
}
|
||
.leaderboard-table tr:nth-child(even) td { background: var(--gray-bg); }
|
||
.leaderboard-table tr.me td {
|
||
background: #E8F4FB !important;
|
||
font-weight: 700;
|
||
position: relative;
|
||
}
|
||
.leaderboard-table tr.me td:first-child::before {
|
||
content: '→';
|
||
position: absolute;
|
||
left: 4px;
|
||
color: var(--light-blue);
|
||
}
|
||
.rank-medal { font-size: 18px; }
|
||
.points-badge {
|
||
background: var(--dark-blue);
|
||
color: white;
|
||
padding: 3px 10px;
|
||
border-radius: 12px;
|
||
font-weight: 700;
|
||
font-size: 13px;
|
||
}
|
||
.trend-up { color: var(--green); font-weight: 700; }
|
||
.trend-down { color: var(--red); font-weight: 700; }
|
||
.trend-eq { color: var(--gray-light); }
|
||
|
||
/* ── Gruppen ───────────────────────────────────────────── */
|
||
.groups-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
||
gap: 16px;
|
||
}
|
||
.group-table { width: 100%; border-collapse: collapse; }
|
||
.group-table th {
|
||
text-align: left;
|
||
font-size: 11px;
|
||
color: var(--gray-light);
|
||
padding: 6px 8px;
|
||
border-bottom: 1px solid var(--gray-bg);
|
||
text-transform: uppercase;
|
||
}
|
||
.group-table td {
|
||
padding: 8px;
|
||
font-size: 13px;
|
||
border-bottom: 1px solid var(--gray-bg);
|
||
}
|
||
.group-table tr:last-child td { border-bottom: none; }
|
||
.qualified-1 td:first-child { border-left: 3px solid var(--green); }
|
||
.qualified-2 td:first-child { border-left: 3px solid var(--light-blue); }
|
||
.team-flag-name { display: flex; align-items: center; gap: 6px; }
|
||
.pts-bold { font-weight: 900; color: var(--dark-blue); }
|
||
|
||
/* ── Toast ─────────────────────────────────────────────── */
|
||
.toast {
|
||
position: fixed;
|
||
bottom: 24px;
|
||
right: 24px;
|
||
background: var(--dark-blue);
|
||
color: white;
|
||
padding: 12px 20px;
|
||
border-radius: 8px;
|
||
font-weight: 600;
|
||
font-size: 14px;
|
||
z-index: 999;
|
||
transform: translateY(80px);
|
||
opacity: 0;
|
||
transition: all 0.3s;
|
||
box-shadow: 0 4px 16px rgba(0,0,0,0.2);
|
||
}
|
||
.toast.show { transform: translateY(0); opacity: 1; }
|
||
.toast.success { background: var(--green); }
|
||
|
||
/* ── Info-Box ─────────────────────────────────────────────── */
|
||
.info-box {
|
||
background: #E8F4FB;
|
||
border-left: 4px solid var(--light-blue);
|
||
padding: 12px 16px;
|
||
border-radius: 0 8px 8px 0;
|
||
font-size: 13px;
|
||
color: var(--gray-mid);
|
||
margin-bottom: 20px;
|
||
}
|
||
.info-box strong { color: var(--dark-blue); }
|
||
|
||
.section-title {
|
||
font-size: 20px;
|
||
font-weight: 900;
|
||
color: var(--dark-blue);
|
||
margin-bottom: 16px;
|
||
padding-bottom: 8px;
|
||
border-bottom: 2px solid var(--dark-blue);
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
|
||
<!-- ── Header ──────────────────────────────────────────── -->
|
||
<header class="app-header">
|
||
<div class="logo-area">
|
||
<div class="brand">GEALAN <span>Tippspiel</span></div>
|
||
<span class="badge">⚽ WM 2026</span>
|
||
</div>
|
||
<div class="user-chip">
|
||
<div class="avatar">RK</div>
|
||
<span>Ronny K.</span>
|
||
<strong style="color:var(--dark-blue);margin-left:4px">12 Pkt.</strong>
|
||
</div>
|
||
</header>
|
||
|
||
<!-- ── Navigation ──────────────────────────────────────── -->
|
||
<nav class="nav">
|
||
<div class="nav-btn active" onclick="showPage('dashboard')" data-page="dashboard">
|
||
<span class="icon">🏠</span> Dashboard
|
||
</div>
|
||
<div class="nav-btn" onclick="showPage('spielplan')" data-page="spielplan">
|
||
<span class="icon">📅</span> Spielplan & Tippen
|
||
</div>
|
||
<div class="nav-btn" onclick="showPage('rangliste')" data-page="rangliste">
|
||
<span class="icon">🏆</span> Rangliste
|
||
</div>
|
||
<div class="nav-btn" onclick="showPage('gruppen')" data-page="gruppen">
|
||
<span class="icon">🗂</span> Gruppen
|
||
</div>
|
||
</nav>
|
||
|
||
<!-- ══════════════════════════════════════════════════════ -->
|
||
<!-- PAGE: Dashboard -->
|
||
<!-- ══════════════════════════════════════════════════════ -->
|
||
<div class="page active" id="page-dashboard">
|
||
<div class="container">
|
||
<div class="stats-row">
|
||
<div class="stat-card blue">
|
||
<div class="stat-val">12</div>
|
||
<div class="stat-label">Meine Punkte</div>
|
||
</div>
|
||
<div class="stat-card light">
|
||
<div class="stat-val">7.</div>
|
||
<div class="stat-label">Mein Platz</div>
|
||
</div>
|
||
<div class="stat-card yellow">
|
||
<div class="stat-val">18</div>
|
||
<div class="stat-label">Tipps abgegeben</div>
|
||
</div>
|
||
<div class="stat-card green">
|
||
<div class="stat-val">4</div>
|
||
<div class="stat-label">Exakte Treffer</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="dashboard-grid">
|
||
<!-- Nächste Spiele -->
|
||
<div>
|
||
<div class="card">
|
||
<div class="card-header">
|
||
📅 Nächste Spiele zum Tippen
|
||
<span style="font-size:12px;font-weight:normal;opacity:0.8">3 offen</span>
|
||
</div>
|
||
<div class="card-body" style="padding:0">
|
||
<div id="next-matches-preview"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<!-- Meine letzten Tipps -->
|
||
<div>
|
||
<div class="card">
|
||
<div class="card-header">📊 Meine letzten Auswertungen</div>
|
||
<div class="card-body" style="padding:0">
|
||
<table style="width:100%;border-collapse:collapse">
|
||
<thead>
|
||
<tr style="background:var(--gray-bg)">
|
||
<th style="padding:8px 14px;font-size:12px;text-align:left;color:var(--gray-mid)">Spiel</th>
|
||
<th style="padding:8px 14px;font-size:12px;text-align:center;color:var(--gray-mid)">Tipp</th>
|
||
<th style="padding:8px 14px;font-size:12px;text-align:center;color:var(--gray-mid)">Erg.</th>
|
||
<th style="padding:8px 14px;font-size:12px;text-align:center;color:var(--gray-mid)">Pkt.</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr style="border-bottom:1px solid var(--gray-bg)">
|
||
<td style="padding:10px 14px;font-size:13px">🇩🇪 vs 🇯🇵</td>
|
||
<td style="padding:10px 14px;text-align:center;font-weight:700;color:var(--dark-blue)">2:1</td>
|
||
<td style="padding:10px 14px;text-align:center;font-weight:700">2:1</td>
|
||
<td style="padding:10px 14px;text-align:center"><span style="background:var(--green);color:white;padding:2px 8px;border-radius:10px;font-weight:700;font-size:13px">3</span></td>
|
||
</tr>
|
||
<tr style="background:var(--gray-bg);border-bottom:1px solid var(--white)">
|
||
<td style="padding:10px 14px;font-size:13px">🇧🇷 vs 🇫🇷</td>
|
||
<td style="padding:10px 14px;text-align:center;font-weight:700;color:var(--dark-blue)">1:0</td>
|
||
<td style="padding:10px 14px;text-align:center;font-weight:700">2:0</td>
|
||
<td style="padding:10px 14px;text-align:center"><span style="background:var(--light-blue);color:white;padding:2px 8px;border-radius:10px;font-weight:700;font-size:13px">1</span></td>
|
||
</tr>
|
||
<tr style="border-bottom:1px solid var(--gray-bg)">
|
||
<td style="padding:10px 14px;font-size:13px">🇦🇷 vs 🇲🇽</td>
|
||
<td style="padding:10px 14px;text-align:center;font-weight:700;color:var(--dark-blue)">0:1</td>
|
||
<td style="padding:10px 14px;text-align:center;font-weight:700">2:0</td>
|
||
<td style="padding:10px 14px;text-align:center"><span style="background:var(--red);color:white;padding:2px 8px;border-radius:10px;font-weight:700;font-size:13px">0</span></td>
|
||
</tr>
|
||
<tr style="background:var(--gray-bg)">
|
||
<td style="padding:10px 14px;font-size:13px">🇵🇹 vs 🇺🇸</td>
|
||
<td style="padding:10px 14px;text-align:center;font-weight:700;color:var(--dark-blue)">3:1</td>
|
||
<td style="padding:10px 14px;text-align:center;font-weight:700">3:1</td>
|
||
<td style="padding:10px 14px;text-align:center"><span style="background:var(--green);color:white;padding:2px 8px;border-radius:10px;font-weight:700;font-size:13px">3</span></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Top 5 Rangliste -->
|
||
<div style="margin-top:20px">
|
||
<div class="card">
|
||
<div class="card-header">
|
||
🏆 Aktuelle Rangliste (Top 5)
|
||
<span onclick="showPage('rangliste')" style="font-size:12px;cursor:pointer;opacity:0.8;text-decoration:underline">Alle anzeigen →</span>
|
||
</div>
|
||
<div class="card-body" style="padding:0">
|
||
<table class="leaderboard-table">
|
||
<thead><tr><th>#</th><th>Name</th><th>Tipps</th><th>Exakt</th><th>Punkte</th></tr></thead>
|
||
<tbody>
|
||
<tr><td><span class="rank-medal">🥇</span></td><td>Sandra W.</td><td>22</td><td>6</td><td><span class="points-badge">21</span></td></tr>
|
||
<tr><td><span class="rank-medal">🥈</span></td><td>Markus H.</td><td>20</td><td>5</td><td><span class="points-badge">18</span></td></tr>
|
||
<tr><td><span class="rank-medal">🥉</span></td><td>Julia B.</td><td>21</td><td>4</td><td><span class="points-badge">16</span></td></tr>
|
||
<tr><td style="padding-left:18px;color:var(--gray-mid)">4.</td><td>Thomas K.</td><td>19</td><td>4</td><td><span class="points-badge">15</span></td></tr>
|
||
<tr><td style="padding-left:18px;color:var(--gray-mid)">5.</td><td>Anna S.</td><td>20</td><td>3</td><td><span class="points-badge">13</span></td></tr>
|
||
</tbody>
|
||
</table>
|
||
<div style="padding:10px 16px;background:var(--gray-bg);border-top:1px solid var(--gray-border)">
|
||
<table class="leaderboard-table" style="background:transparent">
|
||
<tbody>
|
||
<tr class="me" style="background:transparent!important">
|
||
<td style="color:var(--light-blue);font-weight:900;padding-left:14px">7.</td>
|
||
<td style="font-weight:700">Ronny K. (ich)</td>
|
||
<td>18</td><td>4</td>
|
||
<td><span class="points-badge" style="background:var(--light-blue)">12</span></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ══════════════════════════════════════════════════════ -->
|
||
<!-- PAGE: Spielplan & Tippen -->
|
||
<!-- ══════════════════════════════════════════════════════ -->
|
||
<div class="page" id="page-spielplan">
|
||
<div class="container">
|
||
<div class="section-title">⚽ Spielplan & Tippen</div>
|
||
<div class="info-box">
|
||
<strong>So funktioniert's:</strong> Klicke auf „Tippen" bei einem Spiel, um dein Ergebnis einzugeben. Tipps sind bis zum Anpfiff möglich. Exakter Tipp = <strong>3 Punkte</strong>, richtige Tendenz = <strong>1 Punkt</strong>.
|
||
</div>
|
||
|
||
<!-- Filter -->
|
||
<div class="filter-bar">
|
||
<button class="filter-btn active" onclick="filterMatches('all', this)">Alle Spiele</button>
|
||
<button class="filter-btn" onclick="filterMatches('open', this)">⏳ Noch offen</button>
|
||
<button class="filter-btn" onclick="filterMatches('tipped', this)">✅ Getippt</button>
|
||
<button class="filter-btn" onclick="filterMatches('finished', this)">✔ Abgeschlossen</button>
|
||
</div>
|
||
|
||
<div id="matches-list"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ══════════════════════════════════════════════════════ -->
|
||
<!-- PAGE: Rangliste -->
|
||
<!-- ══════════════════════════════════════════════════════ -->
|
||
<div class="page" id="page-rangliste">
|
||
<div class="container">
|
||
<div class="section-title">🏆 Gesamtrangliste</div>
|
||
<div class="info-box">
|
||
<strong>Stand nach Spieltag 3 der Gruppenphase.</strong> Rangliste aktualisiert sich automatisch nach Eintrag der Ergebnisse.
|
||
</div>
|
||
<div class="card">
|
||
<div class="card-header">
|
||
Rangliste — 47 Teilnehmer
|
||
<span style="font-size:12px;font-weight:normal">nach 22 Spielen</span>
|
||
</div>
|
||
<table class="leaderboard-table">
|
||
<thead>
|
||
<tr>
|
||
<th style="width:48px">#</th>
|
||
<th>Name</th>
|
||
<th>Abt.</th>
|
||
<th style="text-align:center">Tipps</th>
|
||
<th style="text-align:center">Exakt</th>
|
||
<th style="text-align:center">Tendenz</th>
|
||
<th style="text-align:center">Punkte</th>
|
||
<th style="text-align:center">Trend</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="leaderboard-body"></tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ══════════════════════════════════════════════════════ -->
|
||
<!-- PAGE: Gruppen -->
|
||
<!-- ══════════════════════════════════════════════════════ -->
|
||
<div class="page" id="page-gruppen">
|
||
<div class="container">
|
||
<div class="section-title">🗂 Gruppenphase WM 2026</div>
|
||
<div class="info-box">
|
||
<strong>WM 2026 Format:</strong> 48 Teams in 12 Gruppen à 4 Teams. Die Top 2 jeder Gruppe sowie die 8 besten Dritten ziehen ins Achtelfinale ein.
|
||
</div>
|
||
<div class="groups-grid" id="groups-grid"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ── Tipp-Modal ──────────────────────────────────────── -->
|
||
<div class="modal-overlay" id="tip-modal" onclick="closeModal(event)">
|
||
<div class="modal">
|
||
<div class="modal-header">
|
||
<span id="modal-title">Tipp abgeben</span>
|
||
<span class="modal-close" onclick="closeTipModal()">✕</span>
|
||
</div>
|
||
<div class="modal-body">
|
||
<div class="modal-teams">
|
||
<div class="modal-team">
|
||
<span class="flag" id="modal-home-flag">🏳</span>
|
||
<div class="name" id="modal-home-name">–</div>
|
||
</div>
|
||
<span class="modal-vs">:</span>
|
||
<div class="modal-team">
|
||
<span class="flag" id="modal-away-flag">🏳</span>
|
||
<div class="name" id="modal-away-name">–</div>
|
||
</div>
|
||
</div>
|
||
<div class="modal-input-row">
|
||
<input class="score-input" type="number" id="tip-home" min="0" max="20" value="1" />
|
||
<span class="score-colon">:</span>
|
||
<input class="score-input" type="number" id="tip-away" min="0" max="20" value="1" />
|
||
</div>
|
||
<div class="modal-deadline">⏰ Deadline: <strong id="modal-deadline">–</strong></div>
|
||
<button class="btn-primary" onclick="saveTip()">✅ Tipp speichern</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ── Toast ───────────────────────────────────────────── -->
|
||
<div class="toast" id="toast"></div>
|
||
|
||
<!-- ══════════════════════════════════════════════════════ -->
|
||
<script>
|
||
// ── Mock-Daten (football-data.org Format) ──────────────
|
||
|
||
const GROUPS = {
|
||
'A': ['Kanada', 'Argentinien', 'Peru', 'Neuseeland'],
|
||
'B': ['Mexiko', 'Deutschland', 'Japan', 'Senegal'],
|
||
'C': ['USA', 'Brasilien', 'Kolumbien', 'Marokko'],
|
||
'D': ['Spanien', 'Frankreich', 'Uruguay', 'Ägypten'],
|
||
'E': ['England', 'Portugal', 'Südkorea', 'Kamerun'],
|
||
'F': ['Niederlande', 'Belgien', 'Ecuador', 'Nigeria'],
|
||
'G': ['Italien', 'Kroatien', 'Chile', 'Algerien'],
|
||
'H': ['Schweiz', 'Serbien', 'Tunesien', 'Costa Rica'],
|
||
'I': ['Polen', 'Iran', 'Australien', 'Elfenbeinküste'],
|
||
'J': ['Dänemark', 'Ungarn', 'Katar', 'Jamaika'],
|
||
'K': ['Wales', 'Österreich', 'Saudi-Arabien', 'Panama'],
|
||
'L': ['Türkei', 'Ukraine', 'Albanien', 'Ghana'],
|
||
};
|
||
|
||
const FLAGS = {
|
||
'Kanada':'🇨🇦','Argentinien':'🇦🇷','Peru':'🇵🇪','Neuseeland':'🇳🇿',
|
||
'Mexiko':'🇲🇽','Deutschland':'🇩🇪','Japan':'🇯🇵','Senegal':'🇸🇳',
|
||
'USA':'🇺🇸','Brasilien':'🇧🇷','Kolumbien':'🇨🇴','Marokko':'🇲🇦',
|
||
'Spanien':'🇪🇸','Frankreich':'🇫🇷','Uruguay':'🇺🇾','Ägypten':'🇪🇬',
|
||
'England':'🏴','Portugal':'🇵🇹','Südkorea':'🇰🇷','Kamerun':'🇨🇲',
|
||
'Niederlande':'🇳🇱','Belgien':'🇧🇪','Ecuador':'🇪🇨','Nigeria':'🇳🇬',
|
||
'Italien':'🇮🇹','Kroatien':'🇭🇷','Chile':'🇨🇱','Algerien':'🇩🇿',
|
||
'Schweiz':'🇨🇭','Serbien':'🇷🇸','Tunesien':'🇹🇳','Costa Rica':'🇨🇷',
|
||
'Polen':'🇵🇱','Iran':'🇮🇷','Australien':'🇦🇺','Elfenbeinküste':'🇨🇮',
|
||
'Dänemark':'🇩🇰','Ungarn':'🇭🇺','Katar':'🇶🇦','Jamaika':'🇯🇲',
|
||
'Wales':'🏴','Österreich':'🇦🇹','Saudi-Arabien':'🇸🇦','Panama':'🇵🇦',
|
||
'Türkei':'🇹🇷','Ukraine':'🇺🇦','Albanien':'🇦🇱','Ghana':'🇬🇭',
|
||
};
|
||
|
||
// Spiele generieren (basierend auf football-data.org Struktur)
|
||
const MATCHES = [];
|
||
let matchId = 1;
|
||
const baseDate = new Date('2026-06-11T18:00:00Z');
|
||
|
||
Object.entries(GROUPS).forEach(([group, teams], gi) => {
|
||
const pairs = [
|
||
[0,1],[2,3],[0,2],[1,3],[0,3],[1,2]
|
||
];
|
||
pairs.forEach(([a, b], pi) => {
|
||
const d = new Date(baseDate);
|
||
d.setDate(d.getDate() + gi + pi * 2);
|
||
MATCHES.push({
|
||
id: matchId++,
|
||
utcDate: d.toISOString(),
|
||
status: pi < 2 ? 'FINISHED' : (pi === 2 ? 'SCHEDULED' : 'SCHEDULED'),
|
||
stage: 'GROUP_STAGE',
|
||
group: 'Group ' + group,
|
||
homeTeam: { name: teams[a], flag: FLAGS[teams[a]] || '🏳' },
|
||
awayTeam: { name: teams[b], flag: FLAGS[teams[b]] || '🏳' },
|
||
score: {
|
||
fullTime: pi < 2
|
||
? { homeTeam: Math.floor(Math.random()*4), awayTeam: Math.floor(Math.random()*3) }
|
||
: { homeTeam: null, awayTeam: null }
|
||
}
|
||
});
|
||
});
|
||
});
|
||
|
||
// Nutzer-Tipps (lokal gespeichert)
|
||
const myTips = {};
|
||
// Einige Demo-Tipps
|
||
MATCHES.filter(m => m.status === 'FINISHED').slice(0, 18).forEach(m => {
|
||
myTips[m.id] = {
|
||
home: Math.floor(Math.random() * 4),
|
||
away: Math.floor(Math.random() * 3)
|
||
};
|
||
});
|
||
|
||
// ── Leaderboard-Daten ───────────────────────────────────
|
||
const PLAYERS = [
|
||
{ rank: 1, name: 'Sandra W.', dept: 'Vertrieb', tips: 22, exact: 6, tendency: 8, pts: 21, trend: 'eq' },
|
||
{ rank: 2, name: 'Markus H.', dept: 'Technik', tips: 20, exact: 5, tendency: 7, pts: 18, trend: 'up' },
|
||
{ rank: 3, name: 'Julia B.', dept: 'Marketing', tips: 21, exact: 4, tendency: 8, pts: 16, trend: 'down' },
|
||
{ rank: 4, name: 'Thomas K.', dept: 'Einkauf', tips: 19, exact: 4, tendency: 7, pts: 15, trend: 'up' },
|
||
{ rank: 5, name: 'Anna S.', dept: 'HR', tips: 20, exact: 3, tendency: 8, pts: 13, trend: 'eq' },
|
||
{ rank: 6, name: 'Klaus M.', dept: 'IT', tips: 18, exact: 3, tendency: 7, pts: 13, trend: 'up' },
|
||
{ rank: 7, name: 'Ronny K.', dept: 'IT', tips: 18, exact: 4, tendency: 4, pts: 12, trend: 'up', isMe: true },
|
||
{ rank: 8, name: 'Laura P.', dept: 'Finanzen', tips: 17, exact: 3, tendency: 6, pts: 11, trend: 'down' },
|
||
{ rank: 9, name: 'Stefan R.', dept: 'Technik', tips: 16, exact: 2, tendency: 7, pts: 11, trend: 'eq' },
|
||
{ rank: 10, name: 'Maria L.', dept: 'Vertrieb', tips: 15, exact: 2, tendency: 6, pts: 9, trend: 'down' },
|
||
{ rank: 11, name: 'Felix N.', dept: 'Marketing', tips: 14, exact: 1, tendency: 6, pts: 8, trend: 'eq' },
|
||
{ rank: 12, name: 'Eva H.', dept: 'HR', tips: 13, exact: 1, tendency: 5, pts: 7, trend: 'up' },
|
||
];
|
||
|
||
// ── Helpers ─────────────────────────────────────────────
|
||
function formatDate(isoStr) {
|
||
const d = new Date(isoStr);
|
||
return d.toLocaleDateString('de-DE', { weekday:'short', day:'2-digit', month:'2-digit' })
|
||
+ ', ' + d.toLocaleTimeString('de-DE', { hour:'2-digit', minute:'2-digit' }) + ' Uhr';
|
||
}
|
||
function calcPoints(tip, result) {
|
||
if (!tip || result.homeTeam === null) return null;
|
||
if (tip.home === result.homeTeam && tip.away === result.awayTeam) return 3;
|
||
const tipTend = tip.home > tip.away ? 1 : tip.home < tip.away ? -1 : 0;
|
||
const resTend = result.homeTeam > result.awayTeam ? 1 : result.homeTeam < result.awayTeam ? -1 : 0;
|
||
return tipTend === resTend ? 1 : 0;
|
||
}
|
||
|
||
// ── Page Navigation ─────────────────────────────────────
|
||
function showPage(name) {
|
||
document.querySelectorAll('.page').forEach(p => p.classList.remove('active'));
|
||
document.querySelectorAll('.nav-btn').forEach(b => b.classList.remove('active'));
|
||
document.getElementById('page-' + name).classList.add('active');
|
||
document.querySelector(`[data-page="${name}"]`).classList.add('active');
|
||
}
|
||
|
||
// ── Render: Spielplan ────────────────────────────────────
|
||
let activeFilter = 'all';
|
||
function filterMatches(filter, btn) {
|
||
activeFilter = filter;
|
||
document.querySelectorAll('.filter-btn').forEach(b => b.classList.remove('active'));
|
||
btn.classList.add('active');
|
||
renderMatches();
|
||
}
|
||
function renderMatches() {
|
||
let filtered = MATCHES;
|
||
if (activeFilter === 'open') filtered = MATCHES.filter(m => m.status === 'SCHEDULED' && !myTips[m.id]);
|
||
if (activeFilter === 'tipped') filtered = MATCHES.filter(m => myTips[m.id]);
|
||
if (activeFilter === 'finished') filtered = MATCHES.filter(m => m.status === 'FINISHED');
|
||
|
||
const list = document.getElementById('matches-list');
|
||
if (!filtered.length) {
|
||
list.innerHTML = '<div style="text-align:center;padding:40px;color:var(--gray-light)">Keine Spiele in dieser Kategorie.</div>';
|
||
return;
|
||
}
|
||
|
||
// Nach Datum gruppieren
|
||
const byDate = {};
|
||
filtered.forEach(m => {
|
||
const dateKey = new Date(m.utcDate).toLocaleDateString('de-DE', { weekday:'long', day:'2-digit', month:'long', year:'numeric' });
|
||
if (!byDate[dateKey]) byDate[dateKey] = [];
|
||
byDate[dateKey].push(m);
|
||
});
|
||
|
||
let html = '';
|
||
Object.entries(byDate).forEach(([date, matches]) => {
|
||
html += `<div class="match-day-header">${date}</div>`;
|
||
matches.forEach(m => {
|
||
const tip = myTips[m.id];
|
||
const res = m.score.fullTime;
|
||
const pts = calcPoints(tip, res);
|
||
let cardClass = '';
|
||
if (m.status === 'FINISHED') cardClass = pts === 3 ? 'correct' : pts === 1 ? 'tipped' : pts === 0 ? 'wrong' : 'finished';
|
||
else if (tip) cardClass = 'tipped';
|
||
|
||
const btnText = m.status === 'FINISHED' ? 'Beendet' : (tip ? `✏ ${tip.home}:${tip.away}` : 'Tippen');
|
||
const btnClass = m.status === 'FINISHED' ? 'finished' : (tip ? 'tipped' : '');
|
||
|
||
const scoreHtml = m.status === 'FINISHED'
|
||
? `<div class="match-score">${res.homeTeam}:${res.awayTeam}</div>`
|
||
: `<div class="match-score tbd">-:-</div>`;
|
||
|
||
const ptsHtml = (m.status === 'FINISHED' && tip)
|
||
? `<div style="font-size:11px;margin-top:3px">
|
||
${pts === 3 ? '<span style="color:var(--green);font-weight:700">+3 Pkt. ✓✓</span>'
|
||
: pts === 1 ? '<span style="color:var(--light-blue);font-weight:700">+1 Pkt. ✓</span>'
|
||
: '<span style="color:var(--red);font-weight:700">0 Pkt. ✗</span>'}</div>`
|
||
: '';
|
||
|
||
const tipDisplay = tip && m.status !== 'FINISHED'
|
||
? `<div class="my-tip-display">Mein Tipp: ${tip.home}:${tip.away}</div>` : '';
|
||
|
||
html += `
|
||
<div class="match-card ${cardClass}">
|
||
<div class="match-inner">
|
||
<div class="match-team">
|
||
<span class="flag">${m.homeTeam.flag}</span>
|
||
<span class="team-name">${m.homeTeam.name}</span>
|
||
</div>
|
||
<div class="match-score-area">
|
||
${scoreHtml}
|
||
<div class="match-time">${formatDate(m.utcDate)}</div>
|
||
<div><span class="match-group-badge">${m.group}</span></div>
|
||
${ptsHtml}
|
||
${tipDisplay}
|
||
</div>
|
||
<div class="match-team away">
|
||
<span class="team-name">${m.awayTeam.name}</span>
|
||
<span class="flag">${m.awayTeam.flag}</span>
|
||
</div>
|
||
<div>
|
||
${m.status !== 'FINISHED'
|
||
? `<button class="match-tip-btn ${btnClass}" onclick="openTipModal(${m.id})">${btnText}</button>`
|
||
: `<button class="match-tip-btn finished" disabled>Beendet</button>`}
|
||
</div>
|
||
</div>
|
||
</div>`;
|
||
});
|
||
});
|
||
list.innerHTML = html;
|
||
}
|
||
|
||
// ── Render: Dashboard preview ────────────────────────────
|
||
function renderDashboardPreview() {
|
||
const upcoming = MATCHES.filter(m => m.status === 'SCHEDULED').slice(0, 3);
|
||
const el = document.getElementById('next-matches-preview');
|
||
if (!upcoming.length) { el.innerHTML = '<div style="padding:16px;color:var(--gray-light)">Keine offenen Spiele.</div>'; return; }
|
||
let html = '';
|
||
upcoming.forEach(m => {
|
||
const tip = myTips[m.id];
|
||
html += `
|
||
<div style="display:flex;align-items:center;justify-content:space-between;padding:12px 16px;border-bottom:1px solid var(--gray-bg)">
|
||
<span style="font-size:13px">${m.homeTeam.flag} ${m.homeTeam.name} vs ${m.awayTeam.flag} ${m.awayTeam.name}</span>
|
||
<button class="match-tip-btn ${tip ? 'tipped' : ''}" style="font-size:11px;padding:6px 10px" onclick="showPage('spielplan');openTipModal(${m.id})">
|
||
${tip ? `✏ ${tip.home}:${tip.away}` : 'Tippen'}
|
||
</button>
|
||
</div>`;
|
||
});
|
||
el.innerHTML = html;
|
||
}
|
||
|
||
// ── Render: Rangliste ────────────────────────────────────
|
||
function renderLeaderboard() {
|
||
const tbody = document.getElementById('leaderboard-body');
|
||
tbody.innerHTML = PLAYERS.map(p => `
|
||
<tr ${p.isMe ? 'class="me"' : ''}>
|
||
<td>${p.rank <= 3 ? ['🥇','🥈','🥉'][p.rank-1] : `<span style="padding-left:6px;color:var(--gray-mid)">${p.rank}.</span>`}</td>
|
||
<td>${p.name}${p.isMe ? ' <span style="font-size:11px;color:var(--light-blue)">(ich)</span>' : ''}</td>
|
||
<td style="color:var(--gray-mid)">${p.dept}</td>
|
||
<td style="text-align:center">${p.tips}</td>
|
||
<td style="text-align:center">${p.exact}</td>
|
||
<td style="text-align:center">${p.tendency}</td>
|
||
<td style="text-align:center"><span class="points-badge" ${p.isMe ? 'style="background:var(--light-blue)"' : ''}>${p.pts}</span></td>
|
||
<td style="text-align:center">
|
||
${p.trend === 'up' ? '<span class="trend-up">▲</span>'
|
||
: p.trend === 'down' ? '<span class="trend-down">▼</span>'
|
||
: '<span class="trend-eq">–</span>'}
|
||
</td>
|
||
</tr>`).join('');
|
||
}
|
||
|
||
// ── Render: Gruppen ──────────────────────────────────────
|
||
function renderGroups() {
|
||
const grid = document.getElementById('groups-grid');
|
||
const groupStandings = {};
|
||
MATCHES.filter(m => m.status === 'FINISHED').forEach(m => {
|
||
const g = m.group;
|
||
if (!groupStandings[g]) groupStandings[g] = {};
|
||
[m.homeTeam, m.awayTeam].forEach(t => {
|
||
if (!groupStandings[g][t.name]) groupStandings[g][t.name] = { name: t.name, flag: t.flag, played:0, won:0, draw:0, lost:0, gf:0, ga:0, pts:0 };
|
||
});
|
||
const hs = groupStandings[g][m.homeTeam.name];
|
||
const as = groupStandings[g][m.awayTeam.name];
|
||
const hg = m.score.fullTime.homeTeam, ag = m.score.fullTime.awayTeam;
|
||
hs.played++; as.played++;
|
||
hs.gf += hg; hs.ga += ag;
|
||
as.gf += ag; as.ga += hg;
|
||
if (hg > ag) { hs.won++; hs.pts+=3; as.lost++; }
|
||
else if (hg < ag) { as.won++; as.pts+=3; hs.lost++; }
|
||
else { hs.draw++; hs.pts++; as.draw++; as.pts++; }
|
||
});
|
||
|
||
grid.innerHTML = Object.entries(GROUPS).map(([g, teams]) => {
|
||
const key = 'Group ' + g;
|
||
let standings = teams.map(t => groupStandings[key]?.[t] || { name:t, flag:FLAGS[t]||'🏳', played:0, won:0, draw:0, lost:0, gf:0, ga:0, pts:0 });
|
||
standings.sort((a,b) => b.pts - a.pts || (b.gf-b.ga) - (a.gf-a.ga) || b.gf - a.gf);
|
||
return `
|
||
<div class="card">
|
||
<div class="card-header">Gruppe ${g}</div>
|
||
<div class="card-body" style="padding:8px">
|
||
<table class="group-table">
|
||
<thead><tr><th>Team</th><th>Sp</th><th>S</th><th>U</th><th>N</th><th>Tore</th><th>Pkt</th></tr></thead>
|
||
<tbody>${standings.map((t,i) => `
|
||
<tr class="${i===0?'qualified-1':i===1?'qualified-2':''}">
|
||
<td><div class="team-flag-name">${t.flag} ${t.name}</div></td>
|
||
<td>${t.played}</td><td>${t.won}</td><td>${t.draw}</td><td>${t.lost}</td>
|
||
<td style="color:var(--gray-mid)">${t.gf}:${t.ga}</td>
|
||
<td><span class="pts-bold">${t.pts}</span></td>
|
||
</tr>`).join('')}
|
||
</tbody>
|
||
</table>
|
||
<div style="font-size:10px;color:var(--gray-light);padding:6px 4px 2px">
|
||
<span style="border-left:3px solid var(--green);padding-left:4px;margin-right:8px">Gruppensieger</span>
|
||
<span style="border-left:3px solid var(--light-blue);padding-left:4px">Gruppenzweiter</span>
|
||
</div>
|
||
</div>
|
||
</div>`;
|
||
}).join('');
|
||
}
|
||
|
||
// ── Tipp-Modal ───────────────────────────────────────────
|
||
let activeTipMatchId = null;
|
||
function openTipModal(matchId) {
|
||
const m = MATCHES.find(x => x.id === matchId);
|
||
if (!m || m.status === 'FINISHED') return;
|
||
activeTipMatchId = matchId;
|
||
document.getElementById('modal-home-flag').textContent = m.homeTeam.flag;
|
||
document.getElementById('modal-away-flag').textContent = m.awayTeam.flag;
|
||
document.getElementById('modal-home-name').textContent = m.homeTeam.name;
|
||
document.getElementById('modal-away-name').textContent = m.awayTeam.name;
|
||
document.getElementById('modal-title').textContent = m.group + ' — Tipp abgeben';
|
||
document.getElementById('modal-deadline').textContent = formatDate(m.utcDate);
|
||
const tip = myTips[matchId];
|
||
document.getElementById('tip-home').value = tip ? tip.home : 1;
|
||
document.getElementById('tip-away').value = tip ? tip.away : 1;
|
||
document.getElementById('tip-modal').classList.add('open');
|
||
setTimeout(() => document.getElementById('tip-home').focus(), 100);
|
||
}
|
||
function closeModal(e) {
|
||
if (e.target === document.getElementById('tip-modal')) closeTipModal();
|
||
}
|
||
function closeTipModal() {
|
||
document.getElementById('tip-modal').classList.remove('open');
|
||
}
|
||
function saveTip() {
|
||
const h = parseInt(document.getElementById('tip-home').value);
|
||
const a = parseInt(document.getElementById('tip-away').value);
|
||
if (isNaN(h) || isNaN(a) || h < 0 || a < 0) {
|
||
showToast('Bitte gültige Zahlen eingeben.', false); return;
|
||
}
|
||
myTips[activeTipMatchId] = { home: h, away: a };
|
||
closeTipModal();
|
||
renderMatches();
|
||
renderDashboardPreview();
|
||
showToast(`✅ Tipp gespeichert: ${h}:${a}`, true);
|
||
}
|
||
|
||
// ── Toast ────────────────────────────────────────────────
|
||
function showToast(msg, success=true) {
|
||
const t = document.getElementById('toast');
|
||
t.textContent = msg;
|
||
t.className = 'toast show' + (success ? ' success' : '');
|
||
setTimeout(() => t.classList.remove('show'), 3000);
|
||
}
|
||
|
||
// ── Init ─────────────────────────────────────────────────
|
||
renderMatches();
|
||
renderDashboardPreview();
|
||
renderLeaderboard();
|
||
renderGroups();
|
||
</script>
|
||
</body>
|
||
</html>
|