1651 lines
52 KiB
HTML
1651 lines
52 KiB
HTML
<!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>
|