WM 2026 – Interaktive Spielorte & Gruppen-Spielplan
https://unpkg.com/leaflet@1.9.4/dist/leaflet.js
:root{
–bg: #0b1020;
–panel: #121a33;
–panel-2:#0f1730;
–text: #e7ecf6;
–muted:#97a3c7;
–accent:#6aa7ff;
–accent-2:#9bffcf;
–danger:#ff7b7b;
–ok:#9cff9c;
}
*{box-sizing:border-box;}
body{
margin:0; padding:0;
background: var(–bg);
color: var(–text);
font: 14px/1.4 system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial;
display:grid;
grid-template-columns: 360px 1fr;
height:100vh;
overflow:hidden;
}
#sidebar{
background: linear-gradient(180deg,var(–panel),var(–panel-2));
padding:16px;
border-right:1px solid rgba(255,255,255,0.06);
display:flex;
flex-direction:column;
gap:12px;
overflow:auto;
}
h1{
font-size:18px; margin:0 0 4px 0; font-weight:700;
letter-spacing:0.2px;
}
.sub{
color:var(–muted);
font-size:12px;
}
.group-grid{
display:grid;
grid-template-columns: repeat(4,1fr);
gap:8px;
}
.btn{
background:#0e1530;
color:var(–text);
border:1px solid rgba(255,255,255,0.08);
padding:8px 6px;
border-radius:10px;
cursor:pointer;
font-weight:600;
text-align:center;
user-select:none;
transition:120ms ease;
}
.btn:hover{ transform: translateY(-1px); border-color: rgba(255,255,255,0.18); }
.btn.active{
background: radial-gradient(120% 140% at 0% 0%, #2b61ff 0%, #1431a6 55%, #0e1530 100%);
border-color: rgba(106,167,255,0.9);
box-shadow: 0 6px 18px rgba(34,88,255,0.35);
}
.btn.small{
padding:6px 8px;
font-size:12px;
}
#map{
width:100%; height:100%;
}
.card{
background: rgba(255,255,255,0.03);
border:1px solid rgba(255,255,255,0.06);
border-radius:12px;
padding:12px;
}
.legend{
display:flex; gap:8px; flex-wrap:wrap;
font-size:12px; color:var(–muted);
}
.dot{
width:10px; height:10px; border-radius:999px; display:inline-block; margin-right:6px;
vertical-align:middle;
}
.dot.highlight{background:var(–accent-2);}
.dot.dim{background:#4a577c;}
.dot.host{background:var(–accent);}
#schedule{
display:flex; flex-direction:column; gap:8px;
max-height:45vh; overflow:auto;
padding-right:2px;
}
.match{
display:grid;
grid-template-columns: 52px 1fr;
gap:8px;
padding:8px;
border-radius:10px;
background: rgba(0,0,0,0.25);
border:1px solid rgba(255,255,255,0.05);
}
.match .no{
font-weight:800; color:#cfe0ff;
}
.match .meta{
color:var(–muted);
font-size:12px;
margin-top:2px;
}
.pill{
font-size:11px; font-weight:700; letter-spacing:0.2px;
padding:2px 6px; border-radius:999px;
background: rgba(106,167,255,0.12);
border:1px solid rgba(106,167,255,0.35);
color:#cfe0ff;
margin-left:6px;
}
.footer-note{
color:var(–muted);
font-size:11px;
margin-top:6px;
}
/** ———- Daten ———- **/
// 16 Host Cities / Stadien
const venues = [
{ id:“mexico_city“, name:“Mexico City Stadium (Estadio Azteca)“, city:“Mexico City“, country:“MEX“, lat:19.3029, lng:-99.1505 },
{ id:“guadalajara“, name:“Estadio Guadalajara (Akron)“, city:“Guadalajara“, country:“MEX“, lat:20.6810, lng:-103.4613 },
{ id:“monterrey“, name:“Estadio Monterrey (BBVA)“, city:“Monterrey“, country:“MEX“, lat:25.6690, lng:-100.2440 },
{ id:“toronto“, name:“Toronto Stadium (BMO Field)“, city:“Toronto“, country:“CAN“, lat:43.6332, lng:-79.4186 },
{ id:“vancouver“, name:“BC Place Vancouver“, city:“Vancouver“, country:“CAN“, lat:49.2767, lng:-123.1119 },
{ id:“los_angeles“, name:“Los Angeles Stadium (SoFi)“, city:“Los Angeles“, country:“USA“, lat:33.9535, lng:-118.3392 },
{ id:“seattle“, name:“Seattle Stadium (Lumen Field)“, city:“Seattle“, country:“USA“, lat:47.5952, lng:-122.3316 },
{ id:“san_francisco“, name:“San Francisco Bay Area Stadium (Levi’s)“, city:“Santa Clara“, country:“USA“, lat:37.4030, lng:-121.9700 },
{ id:“dallas“, name:“Dallas Stadium (AT&T)“, city:“Dallas/Arlington“, country:“USA“, lat:32.7473, lng:-97.0945 },
{ id:“houston“, name:“Houston Stadium (NRG)“, city:“Houston“, country:“USA“, lat:29.6847, lng:-95.4107 },
{ id:“kansas_city“, name:“Kansas City Stadium (Arrowhead)“, city:“Kansas City“, country:“USA“, lat:39.0489, lng:-94.4839 },
{ id:“atlanta“, name:“Atlanta Stadium (Mercedes-Benz)“, city:“Atlanta“, country:“USA“, lat:33.7553, lng:-84.4006 },
{ id:“miami“, name:“Miami Stadium (Hard Rock)“, city:“Miami Gardens“, country:“USA“, lat:25.9580, lng:-80.2389 },
{ id:“boston“, name:“Boston Stadium (Gillette)“, city:“Boston/Foxborough“, country:“USA“, lat:42.0909, lng:-71.2643 },
{ id:“philadelphia“, name:“Philadelphia Stadium (Lincoln Financial)“, city:“Philadelphia“, country:“USA“, lat:39.9008, lng:-75.1675 },
{ id:“new_york_nj“, name:“New York New Jersey Stadium (MetLife)“, city:“New York/New Jersey“, country:“USA“, lat:40.8135, lng:-74.0745 },
];
// Gruppenphasen-Matches 1–72 (ohne Teams)
// Quelle: offizieller vorläufiger Spielplan mit Gruppenzuordnung. (siehe Fox Sports Auflistung)
const matches = [
// Matchday 1
{ no:1, group:“A“, date:“2026-06-11″, venue:“mexico_city“ },
{ no:2, group:“A“, date:“2026-06-11″, venue:“guadalajara“ },
{ no:3, group:“B“, date:“2026-06-12″, venue:“toronto“ },
{ no:4, group:“D“, date:“2026-06-12″, venue:“los_angeles“ },
{ no:5, group:“C“, date:“2026-06-13″, venue:“boston“ },
{ no:6, group:“D“, date:“2026-06-13″, venue:“vancouver“ },
{ no:7, group:“C“, date:“2026-06-13″, venue:“new_york_nj“ },
{ no:8, group:“B“, date:“2026-06-13″, venue:“san_francisco“ },
{ no:9, group:“E“, date:“2026-06-14″, venue:“philadelphia“ },
{ no:10, group:“E“, date:“2026-06-14″, venue:“houston“ },
{ no:11, group:“F“, date:“2026-06-14″, venue:“dallas“ },
{ no:12, group:“F“, date:“2026-06-14″, venue:“monterrey“ },
{ no:13, group:“H“, date:“2026-06-15″, venue:“miami“ },
{ no:14, group:“H“, date:“2026-06-15″, venue:“atlanta“ },
{ no:15, group:“G“, date:“2026-06-15″, venue:“los_angeles“ },
{ no:16, group:“G“, date:“2026-06-15″, venue:“seattle“ },
{ no:17, group:“I“, date:“2026-06-16″, venue:“new_york_nj“ },
{ no:18, group:“I“, date:“2026-06-16″, venue:“boston“ },
{ no:19, group:“J“, date:“2026-06-16″, venue:“kansas_city“ },
{ no:20, group:“J“, date:“2026-06-16″, venue:“san_francisco“ },
{ no:21, group:“L“, date:“2026-06-17″, venue:“toronto“ },
{ no:22, group:“L“, date:“2026-06-17″, venue:“dallas“ },
{ no:23, group:“K“, date:“2026-06-17″, venue:“houston“ },
{ no:24, group:“K“, date:“2026-06-17″, venue:“mexico_city“ },
// Matchday 2
{ no:25, group:“A“, date:“2026-06-18″, venue:“atlanta“ },
{ no:26, group:“B“, date:“2026-06-18″, venue:“los_angeles“ },
{ no:27, group:“B“, date:“2026-06-18″, venue:“vancouver“ },
{ no:28, group:“A“, date:“2026-06-18″, venue:“guadalajara“ },
{ no:29, group:“C“, date:“2026-06-19″, venue:“philadelphia“ },
{ no:30, group:“C“, date:“2026-06-19″, venue:“boston“ },
{ no:31, group:“D“, date:“2026-06-19″, venue:“san_francisco“ },
{ no:32, group:“D“, date:“2026-06-19″, venue:“seattle“ },
{ no:33, group:“E“, date:“2026-06-20″, venue:“toronto“ },
{ no:34, group:“E“, date:“2026-06-20″, venue:“kansas_city“ },
{ no:35, group:“F“, date:“2026-06-20″, venue:“houston“ },
{ no:36, group:“F“, date:“2026-06-20″, venue:“monterrey“ },
{ no:37, group:“H“, date:“2026-06-21″, venue:“miami“ },
{ no:38, group:“H“, date:“2026-06-21″, venue:“atlanta“ },
{ no:39, group:“G“, date:“2026-06-21″, venue:“los_angeles“ },
{ no:40, group:“G“, date:“2026-06-21″, venue:“vancouver“ },
{ no:41, group:“I“, date:“2026-06-22″, venue:“new_york_nj“ },
{ no:42, group:“I“, date:“2026-06-22″, venue:“philadelphia“ },
{ no:43, group:“J“, date:“2026-06-22″, venue:“dallas“ },
{ no:44, group:“J“, date:“2026-06-22″, venue:“san_francisco“ },
{ no:45, group:“L“, date:“2026-06-23″, venue:“boston“ },
{ no:46, group:“L“, date:“2026-06-23″, venue:“toronto“ },
{ no:47, group:“K“, date:“2026-06-23″, venue:“houston“ },
{ no:48, group:“K“, date:“2026-06-23″, venue:“guadalajara“ },
// Matchday 3
{ no:49, group:“C“, date:“2026-06-24″, venue:“miami“ },
{ no:50, group:“C“, date:“2026-06-24″, venue:“atlanta“ },
{ no:51, group:“B“, date:“2026-06-24″, venue:“vancouver“ },
{ no:52, group:“B“, date:“2026-06-24″, venue:“seattle“ },
{ no:53, group:“A“, date:“2026-06-24″, venue:“mexico_city“ },
{ no:54, group:“A“, date:“2026-06-24″, venue:“monterrey“ },
{ no:55, group:“E“, date:“2026-06-25″, venue:“philadelphia“ },
{ no:56, group:“E“, date:“2026-06-25″, venue:“new_york_nj“ },
{ no:57, group:“F“, date:“2026-06-25″, venue:“dallas“ },
{ no:58, group:“F“, date:“2026-06-25″, venue:“kansas_city“ },
{ no:59, group:“D“, date:“2026-06-25″, venue:“los_angeles“ },
{ no:60, group:“D“, date:“2026-06-25″, venue:“san_francisco“ },
{ no:61, group:“I“, date:“2026-06-26″, venue:“boston“ },
{ no:62, group:“I“, date:“2026-06-26″, venue:“toronto“ },
{ no:63, group:“G“, date:“2026-06-26″, venue:“seattle“ },
{ no:64, group:“G“, date:“2026-06-26″, venue:“vancouver“ },
{ no:65, group:“H“, date:“2026-06-26″, venue:“houston“ },
{ no:66, group:“H“, date:“2026-06-26″, venue:“guadalajara“ },
{ no:67, group:“L“, date:“2026-06-27″, venue:“new_york_nj“ },
{ no:68, group:“L“, date:“2026-06-27″, venue:“philadelphia“ },
{ no:69, group:“J“, date:“2026-06-27″, venue:“kansas_city“ },
{ no:70, group:“J“, date:“2026-06-27″, venue:“dallas“ },
{ no:71, group:“K“, date:“2026-06-27″, venue:“miami“ },
{ no:72, group:“K“, date:“2026-06-27″, venue:“atlanta“ },
];
// Groups list A–L
const groups = [„A“,“B“,“C“,“D“,“E“,“F“,“G“,“H“,“I“,“J“,“K“,“L“];
/** ———- Map init ———- **/
const map = L.map(„map“, { zoomControl: true }).setView([38.5, -97.5], 4);
// neutral tiles
L.tileLayer(„
https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png“, {
maxZoom: 18,
attribution: „© OpenStreetMap“
}).addTo(map);
// icons (simple circle markers via styles)
function markerStyle(highlight=false){
return {
radius: highlight ? 9 : 6,
weight: 2,
color: highlight ? „#9bffcf“ : „#6a789e“,
fillColor: highlight ? „#9bffcf“ : „#2b3558“,
fillOpacity: highlight ? 0.9 : 0.6,
opacity: highlight ? 1 : 0.5
};
}
const venueIndex = Object.fromEntries(venues.map(v => [v.id, v]));
// create markers
const venueMarkers = {};
venues.forEach(v => {
const m = L.circleMarker([v.lat, v.lng], markerStyle(false))
.addTo(map)
.bindPopup(`
${v.city}${v.name}
${v.country}`);
venueMarkers[v.id] = m;
});
/** ———- UI ———- **/
const groupButtonsEl = document.getElementById(„groupButtons“);
const scheduleEl = document.getElementById(„schedule“);
const groupTitleEl = document.getElementById(„groupTitle“);
let activeGroup = null;
function renderButtons(){
groupButtonsEl.innerHTML = „“;
groups.forEach(g => {
const b = document.createElement(„div“);
b.className = „btn“;
b.textContent = `Gruppe ${g}`;
b.onclick = () => selectGroup(g);
b.dataset.group = g;
groupButtonsEl.appendChild(b);
});
}
renderButtons();
document.getElementById(„btnAll“).onclick = () => selectGroup(null);
document.getElementById(„btnResetView“).onclick = () => map.setView([38.5, -97.5], 4);
function setActiveButton(group){
document.querySelectorAll(„.btn[data-group]“).forEach(b => {
b.classList.toggle(„active“, b.dataset.group === group);
});
}
function venuesForGroup(group){
if(!group) return new Set(venues.map(v => v.id));
const set = new Set(matches.filter(m => m.group===group).map(m => m.venue));
return set;
}
function highlightVenues(group){
const set = venuesForGroup(group);
venues.forEach(v => {
const isHi = set.has(v.id);
venueMarkers[v.id].setStyle(markerStyle(isHi));
});
}
function formatDate(iso){
const d = new Date(iso + „T00:00:00“);
return d.toLocaleDateString(„de-DE“, { weekday:“short“, day:“2-digit“, month:“2-digit“, year:“numeric“ });
}
function renderSchedule(group){
scheduleEl.innerHTML = „“;
groupTitleEl.textContent = group ? `Gruppe ${group}` : „Alle“;
const list = group
? matches.filter(m => m.group===group)
: matches.slice();
list.sort((a,b)=> a.date.localeCompare(b.date) || a.no-b.no);
list.forEach(m => {
const v = venueIndex[m.venue];
const row = document.createElement(„div“);
row.className = „match“;
row.innerHTML = `
M${m.no}
${formatDate(m.date)} Gruppe ${m.group}
${v.city} – ${v.name}
`;
row.onclick = () => {
map.setView([v.lat, v.lng], 6, { animate:true });
venueMarkers[v.id].openPopup();
};
scheduleEl.appendChild(row);
});
if(list.length===0){
scheduleEl.innerHTML = `
Keine Matches gefunden.
`;
}
}
function selectGroup(group){
activeGroup = group;
setActiveButton(group);
highlightVenues(group);
renderSchedule(group);
}
selectGroup(null); // initial
Gefällt mir Wird geladen …