This repository has been archived on 2026-05-06. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
tippspiel/prototyp_wm2026_mobile.html
2026-04-03 22:02:05 +02:00

1651 lines
52 KiB
HTML
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0"/>
<title>WM 2026 Tippspiel Mobile</title>
<style>
/* ── Design Tokens ─────────────────────────────────────── */
:root {
/* Dark Stadium Palette */
--bg-deep: #0A0E1A; /* tiefstes Dunkelblau Stadion-Nacht */
--bg-card: #131929; /* Karten-Hintergrund */
--bg-elevated: #1C2438; /* leicht erhöhte Flächen */
--bg-input: #222B40; /* Input-Felder */
--border: #2A3550; /* subtile Trennlinien */
/* GEALAN Akzente leuchtend auf Dunkel */
--accent: #0092D1; /* GEALAN Hellblau primärer Akzent */
--accent-glow: rgba(0,146,209,0.18);
--gold: #F9AA2E; /* WM-Gold / Trophäe */
--gold-glow: rgba(249,170,46,0.18);
--green: #00C853; /* Erfolg / Exakt getippt */
--green-glow: rgba(0,200,83,0.15);
--red: #FF3D5A; /* Fehler / Falsch */
--red-glow: rgba(255,61,90,0.15);
/* Text */
--text-primary: #F0F4FF;
--text-secondary: #8A95B0;
--text-muted: #4A5570;
/* Sonstiges */
--radius-sm: 10px;
--radius-md: 16px;
--radius-lg: 24px;
--safe-bottom: 80px; /* Platz für Bottom Nav */
}
* { box-sizing: border-box; margin: 0; padding: 0; -webkit-tap-highlight-color: transparent; }
html, body {
background: var(--bg-deep);
color: var(--text-primary);
font-family: -apple-system, 'SF Pro Display', 'Segoe UI', system-ui, sans-serif;
font-size: 15px;
min-height: 100vh;
overscroll-behavior: none;
}
/* ── Phone Frame (Desktop-Vorschau) ───────────────────── */
.phone-wrapper {
min-height: 100vh;
display: flex;
align-items: flex-start;
justify-content: center;
background: #050810;
padding: 24px 0 40px;
}
.phone-frame {
width: 393px;
min-height: 852px;
background: var(--bg-deep);
border-radius: 54px;
border: 8px solid #1a1a2e;
box-shadow:
0 0 0 1px #2d2d50,
0 40px 120px rgba(0,0,0,0.8),
inset 0 1px 0 rgba(255,255,255,0.06);
overflow: hidden;
position: relative;
display: flex;
flex-direction: column;
}
/* Notch */
.phone-frame::before {
content: '';
position: absolute;
top: 12px; left: 50%;
transform: translateX(-50%);
width: 120px; height: 34px;
background: #1a1a2e;
border-radius: 20px;
z-index: 100;
}
@media (max-width: 450px) {
.phone-wrapper { padding: 0; background: var(--bg-deep); }
.phone-frame { width: 100%; min-height: 100vh; border-radius: 0; border: none; box-shadow: none; }
.phone-frame::before { display: none; }
}
/* ── Status Bar ────────────────────────────────────────── */
.status-bar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 52px 24px 8px;
font-size: 12px;
font-weight: 600;
color: var(--text-secondary);
letter-spacing: 0.3px;
}
/* ── App Header ────────────────────────────────────────── */
.app-header {
padding: 4px 20px 16px;
display: flex;
align-items: center;
justify-content: space-between;
}
.app-title {
display: flex;
flex-direction: column;
}
.app-title .label {
font-size: 11px;
color: var(--text-muted);
text-transform: uppercase;
letter-spacing: 1.5px;
font-weight: 600;
}
.app-title .name {
font-size: 22px;
font-weight: 800;
color: var(--text-primary);
letter-spacing: -0.5px;
line-height: 1.1;
}
.app-title .name span { color: var(--accent); }
.header-avatar {
width: 40px; height: 40px;
background: linear-gradient(135deg, var(--accent), #004891);
border-radius: 50%;
display: flex; align-items: center; justify-content: center;
font-size: 14px; font-weight: 800; color: white;
box-shadow: 0 0 0 3px var(--accent-glow);
}
/* ── Scrollable Content ────────────────────────────────── */
.app-content {
flex: 1;
overflow-y: auto;
overflow-x: hidden;
padding-bottom: var(--safe-bottom);
scroll-behavior: smooth;
-webkit-overflow-scrolling: touch;
}
.app-content::-webkit-scrollbar { display: none; }
/* ── Bottom Navigation ─────────────────────────────────── */
.bottom-nav {
position: absolute;
bottom: 0; left: 0; right: 0;
height: 80px;
background: rgba(13, 18, 35, 0.96);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
border-top: 1px solid var(--border);
display: flex;
align-items: flex-start;
justify-content: space-around;
padding: 10px 0 0;
z-index: 50;
}
.nav-item {
display: flex;
flex-direction: column;
align-items: center;
gap: 4px;
padding: 8px 20px;
cursor: pointer;
border-radius: 12px;
transition: all 0.15s;
min-width: 64px;
}
.nav-item .nav-icon {
font-size: 22px;
transition: transform 0.15s;
}
.nav-item .nav-label {
font-size: 10px;
font-weight: 600;
color: var(--text-muted);
letter-spacing: 0.3px;
}
.nav-item.active .nav-icon { transform: scale(1.1); }
.nav-item.active .nav-label { color: var(--accent); }
.nav-item.active { position: relative; }
.nav-item.active::after {
content: '';
position: absolute;
bottom: -10px;
left: 50%; transform: translateX(-50%);
width: 24px; height: 3px;
background: var(--accent);
border-radius: 2px 2px 0 0;
}
.nav-badge {
position: absolute;
top: 4px; right: 12px;
background: var(--red);
color: white;
font-size: 9px;
font-weight: 800;
width: 16px; height: 16px;
border-radius: 50%;
display: flex; align-items: center; justify-content: center;
}
/* ── Pages ─────────────────────────────────────────────── */
.page { display: none; }
.page.active { display: block; }
/* ── Section titles ────────────────────────────────────── */
.section-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 20px 12px;
}
.section-title {
font-size: 17px;
font-weight: 800;
color: var(--text-primary);
letter-spacing: -0.3px;
}
.section-link {
font-size: 13px;
color: var(--accent);
font-weight: 600;
cursor: pointer;
}
/* ── Hero Stats Strip ──────────────────────────────────── */
.hero-strip {
margin: 0 20px 24px;
background: linear-gradient(135deg, #0D1B35 0%, #0A1526 100%);
border: 1px solid var(--border);
border-radius: var(--radius-lg);
padding: 20px;
position: relative;
overflow: hidden;
}
.hero-strip::before {
content: '⚽';
position: absolute;
right: -10px; top: -10px;
font-size: 80px;
opacity: 0.05;
transform: rotate(-20deg);
}
.hero-strip::after {
content: '';
position: absolute;
top: 0; left: 0; right: 0; height: 2px;
background: linear-gradient(90deg, var(--accent), var(--gold));
border-radius: var(--radius-lg) var(--radius-lg) 0 0;
}
.hero-greeting {
font-size: 13px;
color: var(--text-secondary);
margin-bottom: 4px;
}
.hero-name {
font-size: 20px;
font-weight: 800;
color: var(--text-primary);
margin-bottom: 16px;
letter-spacing: -0.5px;
}
.hero-stats {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 8px;
}
.hero-stat {
display: flex;
flex-direction: column;
align-items: center;
background: var(--bg-input);
border-radius: var(--radius-sm);
padding: 10px 4px;
}
.hero-stat .val {
font-size: 22px;
font-weight: 900;
color: var(--accent);
line-height: 1;
}
.hero-stat .val.gold { color: var(--gold); }
.hero-stat .val.green { color: var(--green); }
.hero-stat .lbl {
font-size: 9px;
color: var(--text-muted);
text-transform: uppercase;
letter-spacing: 0.5px;
margin-top: 4px;
text-align: center;
}
/* ── Match Cards ───────────────────────────────────────── */
.match-scroll {
display: flex;
gap: 12px;
padding: 0 20px 4px;
overflow-x: auto;
scroll-snap-type: x mandatory;
-webkit-overflow-scrolling: touch;
}
.match-scroll::-webkit-scrollbar { display: none; }
.match-card-h {
flex-shrink: 0;
width: 280px;
background: var(--bg-card);
border: 1px solid var(--border);
border-radius: var(--radius-md);
padding: 16px;
scroll-snap-align: start;
cursor: pointer;
transition: transform 0.15s, box-shadow 0.15s;
position: relative;
overflow: hidden;
}
.match-card-h:active { transform: scale(0.97); }
.match-card-h.has-tip {
border-color: var(--accent);
box-shadow: 0 0 0 1px var(--accent), 0 4px 20px var(--accent-glow);
}
.match-card-h.live {
border-color: var(--red);
box-shadow: 0 0 0 1px var(--red), 0 4px 20px var(--red-glow);
}
.match-card-h .group-stage {
font-size: 10px;
color: var(--text-muted);
text-transform: uppercase;
letter-spacing: 1px;
margin-bottom: 12px;
}
.match-card-h .teams {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 12px;
}
.match-card-h .team {
display: flex;
flex-direction: column;
align-items: center;
gap: 6px;
flex: 1;
}
.match-card-h .team .flag { font-size: 32px; }
.match-card-h .team .tname {
font-size: 12px;
font-weight: 700;
color: var(--text-secondary);
text-align: center;
}
.match-card-h .vs {
font-size: 13px;
font-weight: 800;
color: var(--text-muted);
padding: 0 8px;
}
.match-card-h .score-display {
font-size: 28px;
font-weight: 900;
color: var(--text-primary);
letter-spacing: 2px;
text-align: center;
}
.match-card-h .match-time {
font-size: 11px;
color: var(--text-muted);
text-align: center;
margin-top: 4px;
}
.match-card-h .tip-indicator {
font-size: 10px;
color: var(--accent);
font-weight: 700;
text-align: center;
margin-top: 6px;
}
.live-badge {
display: inline-flex;
align-items: center;
gap: 4px;
background: var(--red);
color: white;
font-size: 9px;
font-weight: 800;
padding: 2px 8px;
border-radius: 20px;
text-transform: uppercase;
letter-spacing: 0.5px;
margin-bottom: 10px;
}
.live-badge::before {
content: '';
width: 5px; height: 5px;
background: white;
border-radius: 50%;
animation: blink 1s infinite;
}
@keyframes blink { 0%,100%{opacity:1} 50%{opacity:0.2} }
/* ── Rangliste Mini ────────────────────────────────────── */
.rank-list {
padding: 0 20px;
display: flex;
flex-direction: column;
gap: 8px;
}
.rank-item {
background: var(--bg-card);
border: 1px solid var(--border);
border-radius: var(--radius-sm);
padding: 12px 16px;
display: flex;
align-items: center;
gap: 12px;
cursor: pointer;
transition: background 0.15s;
}
.rank-item:active { background: var(--bg-elevated); }
.rank-item.me {
border-color: var(--accent);
background: linear-gradient(135deg, rgba(0,146,209,0.08), var(--bg-card));
}
.rank-num {
font-size: 14px;
font-weight: 900;
color: var(--text-muted);
width: 24px;
text-align: center;
}
.rank-medal { font-size: 20px; width: 24px; text-align: center; }
.rank-avatar {
width: 36px; height: 36px;
border-radius: 50%;
background: var(--bg-elevated);
display: flex; align-items: center; justify-content: center;
font-size: 13px; font-weight: 800;
color: var(--text-secondary);
flex-shrink: 0;
}
.rank-item.me .rank-avatar {
background: linear-gradient(135deg, var(--accent), #004891);
color: white;
}
.rank-info { flex: 1; }
.rank-name {
font-size: 14px;
font-weight: 700;
color: var(--text-primary);
}
.rank-sub {
font-size: 11px;
color: var(--text-muted);
margin-top: 1px;
}
.rank-pts {
display: flex;
flex-direction: column;
align-items: flex-end;
}
.rank-pts .pts {
font-size: 18px;
font-weight: 900;
color: var(--accent);
}
.rank-pts .pts-label {
font-size: 9px;
color: var(--text-muted);
text-transform: uppercase;
letter-spacing: 0.5px;
}
.rank-trend-up { color: var(--green); font-size: 11px; font-weight: 700; }
.rank-trend-down { color: var(--red); font-size: 11px; font-weight: 700; }
/* ── Spielplan Voll ────────────────────────────────────── */
.filter-chips {
display: flex;
gap: 8px;
padding: 0 20px 16px;
overflow-x: auto;
}
.filter-chips::-webkit-scrollbar { display: none; }
.chip {
flex-shrink: 0;
padding: 6px 14px;
border-radius: 20px;
border: 1.5px solid var(--border);
background: transparent;
color: var(--text-secondary);
font-size: 12px;
font-weight: 700;
cursor: pointer;
transition: all 0.15s;
white-space: nowrap;
}
.chip.active {
background: var(--accent);
border-color: var(--accent);
color: white;
box-shadow: 0 4px 12px var(--accent-glow);
}
.matchday-label {
font-size: 11px;
font-weight: 700;
color: var(--text-muted);
text-transform: uppercase;
letter-spacing: 1px;
padding: 8px 20px 4px;
}
.match-row {
margin: 0 20px 8px;
background: var(--bg-card);
border: 1px solid var(--border);
border-radius: var(--radius-md);
padding: 14px 16px;
display: flex;
align-items: center;
gap: 12px;
cursor: pointer;
transition: all 0.15s;
position: relative;
}
.match-row:active { background: var(--bg-elevated); transform: scale(0.99); }
.match-row.tipped { border-color: rgba(0,146,209,0.4); }
.match-row.correct { border-color: rgba(0,200,83,0.4); }
.match-row.wrong { border-color: rgba(255,61,90,0.3); }
.match-row.finished { opacity: 0.7; }
.match-row .teams-col {
flex: 1;
display: flex;
flex-direction: column;
gap: 6px;
}
.match-row .team-line {
display: flex;
align-items: center;
gap: 8px;
font-size: 14px;
font-weight: 700;
}
.match-row .team-line .flag { font-size: 18px; }
.match-row .score-col {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-width: 48px;
}
.match-row .score-col .score {
font-size: 20px;
font-weight: 900;
color: var(--text-primary);
line-height: 1;
}
.match-row .score-col .score.tbd { color: var(--text-muted); font-size: 16px; }
.match-row .score-col .time-lbl {
font-size: 10px;
color: var(--text-muted);
margin-top: 3px;
text-align: center;
}
.match-row .action-col {
display: flex;
flex-direction: column;
align-items: center;
gap: 4px;
}
.tip-btn {
background: var(--accent);
color: white;
border: none;
padding: 8px 14px;
border-radius: 10px;
font-size: 12px;
font-weight: 800;
cursor: pointer;
transition: all 0.15s;
white-space: nowrap;
box-shadow: 0 2px 8px var(--accent-glow);
}
.tip-btn:active { transform: scale(0.95); }
.tip-btn.done {
background: var(--bg-elevated);
color: var(--accent);
box-shadow: none;
border: 1.5px solid rgba(0,146,209,0.3);
}
.tip-btn.closed {
background: var(--bg-input);
color: var(--text-muted);
box-shadow: none;
cursor: default;
}
.pts-pill {
font-size: 10px;
font-weight: 800;
padding: 2px 8px;
border-radius: 10px;
}
.pts-3 { background: var(--green-glow); color: var(--green); }
.pts-1 { background: var(--accent-glow); color: var(--accent); }
.pts-0 { background: var(--red-glow); color: var(--red); }
/* ── Gruppen Page ──────────────────────────────────────── */
.group-card {
margin: 0 20px 12px;
background: var(--bg-card);
border: 1px solid var(--border);
border-radius: var(--radius-md);
overflow: hidden;
}
.group-card-header {
background: linear-gradient(135deg, #0D1B35, #091426);
padding: 12px 16px;
display: flex;
align-items: center;
justify-content: space-between;
border-bottom: 1px solid var(--border);
}
.group-card-header .gtitle {
font-size: 14px;
font-weight: 800;
color: var(--text-primary);
}
.group-card-header .gcount {
font-size: 11px;
color: var(--text-muted);
}
.group-table-row {
display: flex;
align-items: center;
padding: 10px 16px;
border-bottom: 1px solid rgba(42,53,80,0.5);
gap: 10px;
}
.group-table-row:last-child { border-bottom: none; }
.group-table-row.qualified-1 { border-left: 3px solid var(--green); }
.group-table-row.qualified-2 { border-left: 3px solid var(--accent); }
.gtr-pos {
font-size: 12px;
font-weight: 700;
color: var(--text-muted);
width: 16px;
}
.gtr-team { flex: 1; display: flex; align-items: center; gap: 8px; }
.gtr-flag { font-size: 18px; }
.gtr-name { font-size: 13px; font-weight: 700; color: var(--text-primary); }
.gtr-stats {
display: flex;
gap: 16px;
font-size: 12px;
color: var(--text-muted);
}
.gtr-pts {
font-size: 14px;
font-weight: 900;
color: var(--accent);
min-width: 24px;
text-align: right;
}
/* ── Tipp Sheet (Bottom Sheet Modal) ──────────────────── */
.sheet-overlay {
display: none;
position: absolute;
inset: 0;
background: rgba(0,0,0,0.7);
backdrop-filter: blur(4px);
z-index: 200;
align-items: flex-end;
}
.sheet-overlay.open { display: flex; }
.bottom-sheet {
width: 100%;
background: var(--bg-card);
border-radius: 28px 28px 0 0;
border-top: 1px solid var(--border);
padding: 0 0 40px;
animation: slideUp 0.3s cubic-bezier(0.34,1.56,0.64,1);
position: relative;
}
@keyframes slideUp { from{transform:translateY(100%)} to{transform:translateY(0)} }
.sheet-handle {
width: 40px; height: 4px;
background: var(--border);
border-radius: 2px;
margin: 12px auto 20px;
}
.sheet-match-header {
padding: 0 24px 20px;
text-align: center;
}
.sheet-group-label {
font-size: 11px;
color: var(--text-muted);
text-transform: uppercase;
letter-spacing: 1px;
margin-bottom: 4px;
}
.sheet-match-title {
font-size: 16px;
font-weight: 800;
color: var(--text-primary);
}
.sheet-teams {
display: flex;
align-items: center;
justify-content: space-around;
padding: 0 24px 24px;
}
.sheet-team {
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
flex: 1;
}
.sheet-team .flag { font-size: 48px; }
.sheet-team .tname { font-size: 14px; font-weight: 700; color: var(--text-secondary); }
.sheet-colon {
font-size: 28px;
font-weight: 900;
color: var(--text-muted);
}
.sheet-inputs {
display: flex;
align-items: center;
justify-content: center;
gap: 20px;
padding: 0 24px 20px;
}
.score-picker {
display: flex;
flex-direction: column;
align-items: center;
gap: 0;
}
.score-picker button {
width: 56px; height: 40px;
background: var(--bg-elevated);
border: none;
color: var(--accent);
font-size: 22px;
font-weight: 700;
cursor: pointer;
border-radius: 10px;
transition: background 0.1s;
display: flex; align-items: center; justify-content: center;
}
.score-picker button:active { background: var(--bg-input); }
.score-picker .score-val {
width: 72px; height: 72px;
background: var(--bg-input);
border: 2px solid var(--border);
border-radius: 16px;
display: flex; align-items: center; justify-content: center;
font-size: 36px;
font-weight: 900;
color: var(--text-primary);
margin: 6px 0;
transition: border-color 0.15s, box-shadow 0.15s;
}
.score-picker.active .score-val {
border-color: var(--accent);
box-shadow: 0 0 0 3px var(--accent-glow);
}
.sheet-colon-input {
font-size: 36px;
font-weight: 900;
color: var(--text-muted);
margin-top: 12px;
}
.sheet-deadline {
text-align: center;
font-size: 12px;
color: var(--text-muted);
padding: 0 24px 20px;
}
.sheet-deadline strong { color: var(--gold); }
.sheet-save-btn {
margin: 0 24px;
width: calc(100% - 48px);
background: linear-gradient(135deg, var(--accent), #0074a8);
color: white;
border: none;
padding: 16px;
border-radius: var(--radius-md);
font-size: 16px;
font-weight: 800;
cursor: pointer;
box-shadow: 0 8px 24px var(--accent-glow);
transition: transform 0.1s, box-shadow 0.1s;
letter-spacing: 0.3px;
}
.sheet-save-btn:active { transform: scale(0.98); box-shadow: 0 4px 12px var(--accent-glow); }
/* ── Toast ─────────────────────────────────────────────── */
.toast {
position: absolute;
top: 80px;
left: 50%; transform: translateX(-50%) translateY(-20px);
background: var(--bg-elevated);
color: var(--text-primary);
border: 1px solid var(--border);
border-radius: 20px;
padding: 10px 20px;
font-size: 13px;
font-weight: 700;
white-space: nowrap;
z-index: 300;
opacity: 0;
transition: all 0.3s;
box-shadow: 0 8px 24px rgba(0,0,0,0.4);
}
.toast.show {
opacity: 1;
transform: translateX(-50%) translateY(0);
}
.toast.success { background: #0D2B1A; border-color: var(--green); color: var(--green); }
/* ── WM-Banner ─────────────────────────────────────────── */
.wm-banner {
margin: 0 20px 20px;
background: linear-gradient(135deg, #1a0a00 0%, #2d1500 50%, #1a0a00 100%);
border: 1px solid rgba(249,170,46,0.3);
border-radius: var(--radius-md);
padding: 16px;
display: flex;
align-items: center;
gap: 14px;
overflow: hidden;
position: relative;
}
.wm-banner::after {
content: '';
position: absolute;
top: 0; left: 0; right: 0; height: 2px;
background: linear-gradient(90deg, var(--gold), transparent, var(--gold));
}
.wm-trophy { font-size: 36px; }
.wm-info { flex: 1; }
.wm-title {
font-size: 15px;
font-weight: 800;
color: var(--gold);
letter-spacing: -0.3px;
}
.wm-sub { font-size: 12px; color: rgba(249,170,46,0.6); margin-top: 2px; }
.wm-countdown {
text-align: right;
}
.wm-days {
font-size: 22px;
font-weight: 900;
color: var(--gold);
line-height: 1;
}
.wm-days-label { font-size: 10px; color: rgba(249,170,46,0.6); }
/* ── Letzter Tipp Auswertung ───────────────────────────── */
.result-cards {
display: flex;
gap: 10px;
padding: 0 20px 4px;
overflow-x: auto;
}
.result-cards::-webkit-scrollbar { display: none; }
.result-card {
flex-shrink: 0;
width: 140px;
background: var(--bg-card);
border: 1px solid var(--border);
border-radius: var(--radius-sm);
padding: 12px;
}
.result-card.correct { border-color: rgba(0,200,83,0.4); }
.result-card.tendency { border-color: rgba(0,146,209,0.4); }
.result-card.wrong { border-color: rgba(255,61,90,0.3); }
.result-card .rc-match { font-size: 11px; color: var(--text-muted); margin-bottom: 6px; }
.result-card .rc-scores {
display: flex;
align-items: center;
gap: 6px;
margin-bottom: 8px;
}
.result-card .rc-tip {
font-size: 16px;
font-weight: 900;
color: var(--text-secondary);
}
.result-card .rc-arrow { color: var(--text-muted); font-size: 12px; }
.result-card .rc-result {
font-size: 16px;
font-weight: 900;
color: var(--text-primary);
}
.result-card .rc-pts {
font-size: 12px;
font-weight: 800;
padding: 3px 8px;
border-radius: 8px;
display: inline-block;
}
.correct .rc-pts { background: var(--green-glow); color: var(--green); }
.tendency .rc-pts { background: var(--accent-glow); color: var(--accent); }
.wrong .rc-pts { background: var(--red-glow); color: var(--red); }
/* ── Profil Page ───────────────────────────────────────── */
.profile-hero {
padding: 8px 20px 24px;
text-align: center;
}
.profile-avatar-large {
width: 80px; height: 80px;
background: linear-gradient(135deg, var(--accent), #004891);
border-radius: 50%;
display: flex; align-items: center; justify-content: center;
font-size: 28px; font-weight: 900; color: white;
margin: 0 auto 12px;
box-shadow: 0 0 0 4px var(--accent-glow), 0 8px 24px rgba(0,146,209,0.3);
}
.profile-name {
font-size: 20px;
font-weight: 800;
color: var(--text-primary);
margin-bottom: 2px;
}
.profile-dept { font-size: 13px; color: var(--text-muted); }
.profile-rank-badge {
display: inline-flex;
align-items: center;
gap: 6px;
background: var(--gold-glow);
border: 1px solid rgba(249,170,46,0.3);
color: var(--gold);
font-size: 13px;
font-weight: 800;
padding: 6px 16px;
border-radius: 20px;
margin-top: 12px;
}
.stats-grid-profile {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 10px;
margin: 0 20px 20px;
}
.stat-block {
background: var(--bg-card);
border: 1px solid var(--border);
border-radius: var(--radius-sm);
padding: 14px 10px;
text-align: center;
}
.stat-block .val {
font-size: 24px;
font-weight: 900;
color: var(--accent);
line-height: 1;
}
.stat-block .val.gold { color: var(--gold); }
.stat-block .val.green { color: var(--green); }
.stat-block .lbl {
font-size: 10px;
color: var(--text-muted);
text-transform: uppercase;
letter-spacing: 0.5px;
margin-top: 6px;
}
.accuracy-bar-wrap {
margin: 0 20px 20px;
background: var(--bg-card);
border: 1px solid var(--border);
border-radius: var(--radius-md);
padding: 16px;
}
.ab-title { font-size: 13px; font-weight: 700; color: var(--text-secondary); margin-bottom: 12px; }
.ab-row {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 10px;
}
.ab-label { font-size: 12px; color: var(--text-muted); width: 80px; }
.ab-bar-bg {
flex: 1;
height: 8px;
background: var(--bg-input);
border-radius: 4px;
overflow: hidden;
}
.ab-bar-fill {
height: 100%;
border-radius: 4px;
transition: width 1s ease;
}
.ab-bar-fill.green-fill { background: var(--green); }
.ab-bar-fill.blue-fill { background: var(--accent); }
.ab-bar-fill.red-fill { background: var(--red); }
.ab-pct { font-size: 12px; font-weight: 700; color: var(--text-secondary); width: 32px; text-align: right; }
</style>
</head>
<body>
<div class="phone-wrapper">
<div class="phone-frame">
<!-- Status Bar -->
<div class="status-bar">
<span>9:41</span>
<span>●●●●○ 5G 🔋</span>
</div>
<!-- App Header -->
<div class="app-header">
<div class="app-title">
<span class="label">GEALAN</span>
<span class="name">⚽ WM <span>2026</span></span>
</div>
<div class="header-avatar" onclick="showPage('profil')">RK</div>
</div>
<!-- Content -->
<div class="app-content">
<!-- ════ PAGE: HOME ════════════════════════════════════ -->
<div class="page active" id="page-home">
<!-- WM Countdown Banner -->
<div class="wm-banner">
<div class="wm-trophy">🏆</div>
<div class="wm-info">
<div class="wm-title">FIFA World Cup 2026</div>
<div class="wm-sub">USA · Kanada · Mexiko</div>
</div>
<div class="wm-countdown">
<div class="wm-days" id="days-left"></div>
<div class="wm-days-label">Tage noch</div>
</div>
</div>
<!-- Hero Stats -->
<div class="hero-strip">
<div class="hero-greeting">Willkommen zurück,</div>
<div class="hero-name">Ronny Kramer 👋</div>
<div class="hero-stats">
<div class="hero-stat">
<span class="val">12</span>
<span class="lbl">Punkte</span>
</div>
<div class="hero-stat">
<span class="val gold">7.</span>
<span class="lbl">Platz</span>
</div>
<div class="hero-stat">
<span class="val green">4</span>
<span class="lbl">Exakt</span>
</div>
<div class="hero-stat">
<span class="val">18</span>
<span class="lbl">Tipps</span>
</div>
</div>
</div>
<!-- Nächste Spiele (horizontal scroll) -->
<div style="margin-bottom:24px">
<div class="section-header">
<span class="section-title">Jetzt tippen</span>
<span class="section-link" onclick="showPage('spielplan')">Alle →</span>
</div>
<div class="match-scroll" id="home-matches"></div>
</div>
<!-- Letzte Auswertungen -->
<div style="margin-bottom:24px">
<div class="section-header">
<span class="section-title">Letzte Ergebnisse</span>
</div>
<div class="result-cards">
<div class="result-card correct">
<div class="rc-match">🇩🇪 vs 🇯🇵</div>
<div class="rc-scores">
<span class="rc-tip">2:1</span>
<span class="rc-arrow"></span>
<span class="rc-result">2:1</span>
</div>
<span class="rc-pts">+3 Pkt. ✓✓</span>
</div>
<div class="result-card tendency">
<div class="rc-match">🇧🇷 vs 🇫🇷</div>
<div class="rc-scores">
<span class="rc-tip">1:0</span>
<span class="rc-arrow"></span>
<span class="rc-result">2:0</span>
</div>
<span class="rc-pts">+1 Pkt. ✓</span>
</div>
<div class="result-card wrong">
<div class="rc-match">🇦🇷 vs 🇲🇽</div>
<div class="rc-scores">
<span class="rc-tip">0:1</span>
<span class="rc-arrow"></span>
<span class="rc-result">2:0</span>
</div>
<span class="rc-pts">0 Pkt. ✗</span>
</div>
<div class="result-card correct">
<div class="rc-match">🇵🇹 vs 🇺🇸</div>
<div class="rc-scores">
<span class="rc-tip">3:1</span>
<span class="rc-arrow"></span>
<span class="rc-result">3:1</span>
</div>
<span class="rc-pts">+3 Pkt. ✓✓</span>
</div>
<div class="result-card tendency">
<div class="rc-match">🇪🇸 vs 🇲🇦</div>
<div class="rc-scores">
<span class="rc-tip">2:0</span>
<span class="rc-arrow"></span>
<span class="rc-result">1:0</span>
</div>
<span class="rc-pts">+1 Pkt. ✓</span>
</div>
</div>
</div>
<!-- Rangliste Mini -->
<div style="margin-bottom: 24px">
<div class="section-header">
<span class="section-title">Rangliste</span>
<span class="section-link" onclick="showPage('rangliste')">Alle →</span>
</div>
<div class="rank-list" id="home-ranking"></div>
</div>
</div><!-- /page-home -->
<!-- ════ PAGE: SPIELPLAN ══════════════════════════════ -->
<div class="page" id="page-spielplan">
<div style="padding: 0 20px 16px">
<div class="section-title">Spielplan & Tippen</div>
</div>
<div class="filter-chips">
<button class="chip active" onclick="filterSpieleM('all',this)">Alle</button>
<button class="chip" onclick="filterSpieleM('open',this)">⏳ Offen</button>
<button class="chip" onclick="filterSpieleM('tipped',this)">✅ Getippt</button>
<button class="chip" onclick="filterSpieleM('finished',this)">✔ Gespielt</button>
</div>
<div id="spielplan-list"></div>
</div>
<!-- ════ PAGE: RANGLISTE ══════════════════════════════ -->
<div class="page" id="page-rangliste">
<div style="padding: 0 20px 16px">
<div class="section-title">Gesamtrangliste</div>
</div>
<div class="rank-list" id="full-ranking"></div>
</div>
<!-- ════ PAGE: GRUPPEN ═══════════════════════════════ -->
<div class="page" id="page-gruppen">
<div style="padding: 0 20px 16px">
<div class="section-title">Gruppen WM 2026</div>
</div>
<div id="groups-list"></div>
</div>
<!-- ════ PAGE: PROFIL ════════════════════════════════ -->
<div class="page" id="page-profil">
<div class="profile-hero">
<div class="profile-avatar-large">RK</div>
<div class="profile-name">Ronny Kramer</div>
<div class="profile-dept">IT · GEALAN Fenster-Systeme</div>
<div class="profile-rank-badge">🏆 Platz 7 von 47</div>
</div>
<div class="stats-grid-profile">
<div class="stat-block">
<div class="val">12</div>
<div class="lbl">Punkte</div>
</div>
<div class="stat-block">
<div class="val green">4</div>
<div class="lbl">Exakt</div>
</div>
<div class="stat-block">
<div class="val">18</div>
<div class="lbl">Tipps</div>
</div>
<div class="stat-block">
<div class="val gold">67%</div>
<div class="lbl">Trefferquote</div>
</div>
<div class="stat-block">
<div class="val">7</div>
<div class="lbl">Tendenz</div>
</div>
<div class="stat-block">
<div class="val">0.67</div>
<div class="lbl">Pkt/Tipp</div>
</div>
</div>
<div class="accuracy-bar-wrap">
<div class="ab-title">Tipp-Genauigkeit</div>
<div class="ab-row">
<span class="ab-label">Exakt (3 Pkt.)</span>
<div class="ab-bar-bg"><div class="ab-bar-fill green-fill" style="width:22%"></div></div>
<span class="ab-pct" style="color:var(--green)">22%</span>
</div>
<div class="ab-row">
<span class="ab-label">Tendenz (1 Pkt.)</span>
<div class="ab-bar-bg"><div class="ab-bar-fill blue-fill" style="width:39%"></div></div>
<span class="ab-pct" style="color:var(--accent)">39%</span>
</div>
<div class="ab-row">
<span class="ab-label">Falsch (0 Pkt.)</span>
<div class="ab-bar-bg"><div class="ab-bar-fill red-fill" style="width:39%"></div></div>
<span class="ab-pct" style="color:var(--red)">39%</span>
</div>
</div>
</div>
</div><!-- /app-content -->
<!-- Bottom Navigation -->
<nav class="bottom-nav">
<div class="nav-item active" onclick="showPage('home')" data-page="home">
<span class="nav-icon">🏠</span>
<span class="nav-label">Home</span>
</div>
<div class="nav-item" onclick="showPage('spielplan')" data-page="spielplan" style="position:relative">
<span class="nav-icon">📅</span>
<span class="nav-label">Spielplan</span>
<span class="nav-badge">3</span>
</div>
<div class="nav-item" onclick="showPage('rangliste')" data-page="rangliste">
<span class="nav-icon">🏆</span>
<span class="nav-label">Rangliste</span>
</div>
<div class="nav-item" onclick="showPage('gruppen')" data-page="gruppen">
<span class="nav-icon">🗂</span>
<span class="nav-label">Gruppen</span>
</div>
<div class="nav-item" onclick="showPage('profil')" data-page="profil">
<span class="nav-icon">👤</span>
<span class="nav-label">Profil</span>
</div>
</nav>
<!-- Tipp Bottom Sheet -->
<div class="sheet-overlay" id="tip-sheet" onclick="closeSheet(event)">
<div class="bottom-sheet">
<div class="sheet-handle"></div>
<div class="sheet-match-header">
<div class="sheet-group-label" id="sheet-group">Gruppe A</div>
<div class="sheet-match-title" id="sheet-title"></div>
</div>
<div class="sheet-teams">
<div class="sheet-team">
<span class="flag" id="sheet-home-flag">🏳</span>
<span class="tname" id="sheet-home-name"></span>
</div>
<span class="sheet-colon">:</span>
<div class="sheet-team">
<span class="flag" id="sheet-away-flag">🏳</span>
<span class="tname" id="sheet-away-name"></span>
</div>
</div>
<div class="sheet-inputs">
<div class="score-picker active" id="picker-home">
<button onclick="adjustScore('home',1)"></button>
<div class="score-val" id="val-home">1</div>
<button onclick="adjustScore('home',-1)"></button>
</div>
<div class="sheet-colon-input">:</div>
<div class="score-picker" id="picker-away">
<button onclick="adjustScore('away',1)"></button>
<div class="score-val" id="val-away">1</div>
<button onclick="adjustScore('away',-1)"></button>
</div>
</div>
<div class="sheet-deadline">⏰ Deadline: <strong id="sheet-deadline"></strong></div>
<button class="sheet-save-btn" onclick="saveTip()">✅ Tipp speichern</button>
</div>
</div>
<!-- Toast -->
<div class="toast" id="toast"></div>
</div><!-- /phone-frame -->
</div><!-- /phone-wrapper -->
<script>
// ── Daten ───────────────────────────────────────────────
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':'🇬🇭',
};
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'],
};
const MATCHES = [];
let mid = 1;
const base = new Date('2026-06-11T18:00:00Z');
Object.entries(GROUPS).forEach(([g, teams], gi) => {
[[0,1],[2,3],[0,2],[1,3],[0,3],[1,2]].forEach(([a,b], pi) => {
const d = new Date(base); d.setDate(d.getDate() + gi + pi*2);
MATCHES.push({
id: mid++, utcDate: d.toISOString(),
status: pi < 2 ? 'FINISHED' : 'SCHEDULED',
group: 'Gruppe '+g,
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 }
}
});
});
});
const myTips = {};
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) };
});
const PLAYERS = [
{rank:1,name:'Sandra W.',dept:'Vertrieb',init:'SW',pts:21,exact:6,tips:22,trend:'eq'},
{rank:2,name:'Markus H.',dept:'Technik', init:'MH',pts:18,exact:5,tips:20,trend:'up'},
{rank:3,name:'Julia B.', dept:'Marketing',init:'JB',pts:16,exact:4,tips:21,trend:'down'},
{rank:4,name:'Thomas K.',dept:'Einkauf', init:'TK',pts:15,exact:4,tips:19,trend:'up'},
{rank:5,name:'Anna S.', dept:'HR', init:'AS',pts:13,exact:3,tips:20,trend:'eq'},
{rank:6,name:'Klaus M.', dept:'IT', init:'KM',pts:13,exact:3,tips:18,trend:'up'},
{rank:7,name:'Ronny K.', dept:'IT', init:'RK',pts:12,exact:4,tips:18,trend:'up',isMe:true},
{rank:8,name:'Laura P.', dept:'Finanzen',init:'LP',pts:11,exact:3,tips:17,trend:'down'},
{rank:9,name:'Stefan R.',dept:'Technik', init:'SR',pts:11,exact:2,tips:16,trend:'eq'},
{rank:10,name:'Maria L.',dept:'Vertrieb',init:'ML',pts:9, exact:2,tips:15,trend:'down'},
{rank:11,name:'Felix N.',dept:'Marketing',init:'FN',pts:8,exact:1,tips:14,trend:'eq'},
{rank:12,name:'Eva H.', dept:'HR', init:'EH',pts:7, exact:1,tips:13,trend:'up'},
];
// ── Helpers ─────────────────────────────────────────────
function calcPts(tip, res) {
if (!tip||res.homeTeam===null) return null;
if (tip.home===res.homeTeam&&tip.away===res.awayTeam) return 3;
const tt=tip.home>tip.away?1:tip.home<tip.away?-1:0;
const rt=res.homeTeam>res.awayTeam?1:res.homeTeam<res.awayTeam?-1:0;
return tt===rt?1:0;
}
function fmtTime(iso) {
const d=new Date(iso);
return d.toLocaleDateString('de-DE',{day:'2-digit',month:'2-digit'})+' '+
d.toLocaleTimeString('de-DE',{hour:'2-digit',minute:'2-digit'})+' Uhr';
}
function fmtDeadline(iso) {
const d=new Date(iso);
return d.toLocaleDateString('de-DE',{weekday:'short',day:'2-digit',month:'long'})+', '+
d.toLocaleTimeString('de-DE',{hour:'2-digit',minute:'2-digit'})+' Uhr';
}
// ── WM Countdown ────────────────────────────────────────
function updateCountdown(){
const wm=new Date('2026-06-11');
const now=new Date();
const diff=Math.max(0,Math.floor((wm-now)/(1000*60*60*24)));
const el=document.getElementById('days-left');
if(el) el.textContent = diff>0?diff:'🎉';
}
updateCountdown();
// ── Navigation ───────────────────────────────────────────
function showPage(name){
document.querySelectorAll('.page').forEach(p=>p.classList.remove('active'));
document.querySelectorAll('.nav-item').forEach(b=>b.classList.remove('active'));
document.getElementById('page-'+name).classList.add('active');
const nb=document.querySelector(`[data-page="${name}"]`);
if(nb) nb.classList.add('active');
document.querySelector('.app-content').scrollTop=0;
}
// ── Render: Home Matches (horizontal cards) ──────────────
function renderHomeMatches(){
const upcoming=MATCHES.filter(m=>m.status==='SCHEDULED').slice(0,6);
const wrap=document.getElementById('home-matches');
if(!wrap) return;
wrap.innerHTML=upcoming.map(m=>{
const tip=myTips[m.id];
return `
<div class="match-card-h ${tip?'has-tip':''}" onclick="openSheet(${m.id})">
<div class="group-stage">${m.group}</div>
<div class="teams">
<div class="team">
<span class="flag">${m.homeTeam.flag}</span>
<span class="tname">${m.homeTeam.name}</span>
</div>
<span class="vs">VS</span>
<div class="team">
<span class="flag">${m.awayTeam.flag}</span>
<span class="tname">${m.awayTeam.name}</span>
</div>
</div>
<div class="match-time">${fmtTime(m.utcDate)}</div>
${tip?`<div class="tip-indicator">✅ Mein Tipp: ${tip.home}:${tip.away}</div>`
:`<div class="tip-indicator" style="color:var(--gold)">⚡ Tippe jetzt!</div>`}
</div>`;
}).join('');
}
// ── Render: Home Ranking Mini ────────────────────────────
function renderHomeRanking(){
const wrap=document.getElementById('home-ranking');
if(!wrap) return;
const top=[...PLAYERS].slice(0,3);
const me=PLAYERS.find(p=>p.isMe);
const show=top.some(p=>p.isMe)?top:[...top,me];
wrap.innerHTML=show.map(p=>rankItemHTML(p,true)).join('');
}
function rankItemHTML(p,compact=false){
const medals=['🥇','🥈','🥉'];
return `
<div class="rank-item ${p.isMe?'me':''}" onclick="${p.isMe?'showPage(\'profil\')':''}">
<span class="${p.rank<=3?'rank-medal':'rank-num'}">${p.rank<=3?medals[p.rank-1]:p.rank+'.'}</span>
<div class="rank-avatar">${p.init}</div>
<div class="rank-info">
<div class="rank-name">${p.name}${p.isMe?' <span style="font-size:10px;color:var(--accent)">(ich)</span>':''}</div>
<div class="rank-sub">${p.dept} · ${p.tips} Tipps · ${p.exact} exakt</div>
</div>
<div class="rank-pts">
<span class="pts" style="${p.isMe?'color:var(--gold)':''}">${p.pts}</span>
<span class="pts-label">Punkte</span>
</div>
</div>`;
}
// ── Render: Spielplan ────────────────────────────────────
let spFilter='all';
function filterSpieleM(f,btn){
spFilter=f;
document.querySelectorAll('.chip').forEach(c=>c.classList.remove('active'));
btn.classList.add('active');
renderSpieleM();
}
function renderSpieleM(){
let list=MATCHES;
if(spFilter==='open') list=MATCHES.filter(m=>m.status==='SCHEDULED'&&!myTips[m.id]);
if(spFilter==='tipped') list=MATCHES.filter(m=>!!myTips[m.id]);
if(spFilter==='finished') list=MATCHES.filter(m=>m.status==='FINISHED');
const wrap=document.getElementById('spielplan-list');
if(!list.length){wrap.innerHTML='<div style="padding:32px;text-align:center;color:var(--text-muted)">Keine Spiele.</div>';return;}
const byDate={};
list.forEach(m=>{
const k=new Date(m.utcDate).toLocaleDateString('de-DE',{weekday:'long',day:'2-digit',month:'long'});
if(!byDate[k]) byDate[k]=[];
byDate[k].push(m);
});
let html='';
Object.entries(byDate).forEach(([date,matches])=>{
html+=`<div class="matchday-label">${date}</div>`;
matches.forEach(m=>{
const tip=myTips[m.id];
const res=m.score.fullTime;
const pts=calcPts(tip,res);
let cls='';
if(m.status==='FINISHED') cls=pts===3?'correct':pts===1?'tipped':pts===0?'wrong':'finished';
else if(tip) cls='tipped';
const scoreHTML=m.status==='FINISHED'
?`<div class="score">${res.homeTeam}:${res.awayTeam}</div>`
:`<div class="score tbd">-:-</div>`;
let ptsHTML='';
if(m.status==='FINISHED'&&tip!==undefined){
ptsHTML=pts===3?`<span class="pts-pill pts-3">+3 ✓✓</span>`
:pts===1?`<span class="pts-pill pts-1">+1 ✓</span>`
:`<span class="pts-pill pts-0">0 ✗</span>`;
}
const btnHTML=m.status==='FINISHED'
?`<button class="tip-btn closed" disabled>Beendet</button>`
:tip?`<button class="tip-btn done" onclick="openSheet(${m.id})">✏ ${tip.home}:${tip.away}</button>`
:`<button class="tip-btn" onclick="openSheet(${m.id})">Tippen</button>`;
html+=`
<div class="match-row ${cls}">
<div class="teams-col">
<div class="team-line"><span class="flag">${m.homeTeam.flag}</span>${m.homeTeam.name}</div>
<div class="team-line"><span class="flag">${m.awayTeam.flag}</span>${m.awayTeam.name}</div>
<div style="font-size:10px;color:var(--text-muted);margin-top:4px">${m.group}</div>
</div>
<div class="score-col">
${scoreHTML}
<div class="time-lbl">${fmtTime(m.utcDate)}</div>
${ptsHTML}
</div>
<div class="action-col">${btnHTML}</div>
</div>`;
});
});
wrap.innerHTML=html;
}
// ── Render: Rangliste voll ───────────────────────────────
function renderFullRanking(){
const wrap=document.getElementById('full-ranking');
if(!wrap) return;
wrap.innerHTML=PLAYERS.map(p=>rankItemHTML(p)).join('');
}
// ── Render: Gruppen ──────────────────────────────────────
function renderGroups(){
const wrap=document.getElementById('groups-list');
if(!wrap) return;
const standings={};
MATCHES.filter(m=>m.status==='FINISHED').forEach(m=>{
const g=m.group;
if(!standings[g]) standings[g]={};
[m.homeTeam,m.awayTeam].forEach(t=>{
if(!standings[g][t.name]) standings[g][t.name]={name:t.name,flag:t.flag,p:0,w:0,d:0,l:0,gf:0,ga:0,pts:0};
});
const hs=standings[g][m.homeTeam.name], as=standings[g][m.awayTeam.name];
const hg=m.score.fullTime.homeTeam, ag=m.score.fullTime.awayTeam;
hs.p++;as.p++;hs.gf+=hg;hs.ga+=ag;as.gf+=ag;as.ga+=hg;
if(hg>ag){hs.w++;hs.pts+=3;as.l++;}
else if(hg<ag){as.w++;as.pts+=3;hs.l++;}
else{hs.d++;hs.pts++;as.d++;as.pts++;}
});
wrap.innerHTML=Object.entries(GROUPS).map(([g,teams])=>{
const key='Gruppe '+g;
let rows=teams.map(t=>standings[key]?.[t]||{name:t,flag:FLAGS[t]||'🏳',p:0,w:0,d:0,l:0,gf:0,ga:0,pts:0});
rows.sort((a,b)=>b.pts-a.pts||(b.gf-b.ga)-(a.gf-a.ga)||b.gf-a.gf);
return `
<div class="group-card">
<div class="group-card-header">
<span class="gtitle">Gruppe ${g}</span>
<span class="gcount">4 Teams</span>
</div>
${rows.map((t,i)=>`
<div class="group-table-row ${i===0?'qualified-1':i===1?'qualified-2':''}">
<span class="gtr-pos">${i+1}</span>
<div class="gtr-team">
<span class="gtr-flag">${t.flag}</span>
<span class="gtr-name">${t.name}</span>
</div>
<div class="gtr-stats">
<span>${t.p}Sp</span>
<span>${t.gf}:${t.ga}</span>
</div>
<span class="gtr-pts">${t.pts}</span>
</div>`).join('')}
</div>`;
}).join('');
}
// ── Tipp Sheet ───────────────────────────────────────────
let activeMatch=null;
let tipHome=1, tipAway=1;
function openSheet(id){
activeMatch=MATCHES.find(m=>m.id===id);
if(!activeMatch||activeMatch.status==='FINISHED') return;
const tip=myTips[id];
tipHome=tip?tip.home:1; tipAway=tip?tip.away:1;
document.getElementById('sheet-group').textContent=activeMatch.group;
document.getElementById('sheet-title').textContent=activeMatch.homeTeam.name+' '+activeMatch.awayTeam.name;
document.getElementById('sheet-home-flag').textContent=activeMatch.homeTeam.flag;
document.getElementById('sheet-away-flag').textContent=activeMatch.awayTeam.flag;
document.getElementById('sheet-home-name').textContent=activeMatch.homeTeam.name;
document.getElementById('sheet-away-name').textContent=activeMatch.awayTeam.name;
document.getElementById('sheet-deadline').textContent=fmtDeadline(activeMatch.utcDate);
document.getElementById('val-home').textContent=tipHome;
document.getElementById('val-away').textContent=tipAway;
document.getElementById('tip-sheet').classList.add('open');
}
function closeSheet(e){
if(e.target===document.getElementById('tip-sheet'))
document.getElementById('tip-sheet').classList.remove('open');
}
function adjustScore(side,delta){
if(side==='home'){
tipHome=Math.max(0,tipHome+delta);
document.getElementById('val-home').textContent=tipHome;
document.getElementById('picker-home').classList.add('active');
document.getElementById('picker-away').classList.remove('active');
} else {
tipAway=Math.max(0,tipAway+delta);
document.getElementById('val-away').textContent=tipAway;
document.getElementById('picker-away').classList.add('active');
document.getElementById('picker-home').classList.remove('active');
}
}
function saveTip(){
if(!activeMatch) return;
myTips[activeMatch.id]={home:tipHome,away:tipAway};
document.getElementById('tip-sheet').classList.remove('open');
renderHomeMatches();
renderSpieleM();
showToast(`✅ Tipp gespeichert: ${tipHome}:${tipAway}`,true);
// Badge aktualisieren
const openCount=MATCHES.filter(m=>m.status==='SCHEDULED'&&!myTips[m.id]).length;
const badge=document.querySelector('.nav-badge');
if(badge) badge.textContent=Math.min(openCount,9);
}
// ── Toast ────────────────────────────────────────────────
function showToast(msg,ok=true){
const t=document.getElementById('toast');
t.textContent=msg;
t.className='toast show'+(ok?' success':'');
setTimeout(()=>t.classList.remove('show'),2500);
}
// ── Init ─────────────────────────────────────────────────
renderHomeMatches();
renderHomeRanking();
renderFullRanking();
renderSpieleM();
renderGroups();
</script>
</body>
</html>