@@ -0,0 +1,11 @@
|
||||
services:
|
||||
worldcup-app-local:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
container_name: 2026-worldcup-local
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- NODE_ENV=development
|
||||
ports:
|
||||
- "8080:80"
|
||||
+83
-47
@@ -32,12 +32,48 @@ export const groups = [
|
||||
{ name: 'Czech Republic',flag: '🇨🇿', confederation: 'UEFA', isHost: false },
|
||||
],
|
||||
matches: [
|
||||
{ matchday: 1, home: 'Mexico', away: 'South Africa', date: 'Thu, Jun 11', time: '19:00', venue: 'Mexico City' },
|
||||
{ matchday: 1, home: 'South Korea', away: 'Czech Republic',date: 'Fri, Jun 12', time: '20:00', venue: 'Guadalajara' },
|
||||
{ matchday: 2, home: 'Mexico', away: 'Czech Republic',date: 'Mon, Jun 15', time: '22:00', venue: 'Monterrey' },
|
||||
{ matchday: 2, home: 'South Korea', away: 'South Africa', date: 'Tue, Jun 16', time: '19:00', venue: 'Los Angeles' },
|
||||
{ matchday: 3, home: 'Mexico', away: 'South Korea', date: 'Sat, Jun 21', time: '18:00', venue: 'Dallas' },
|
||||
{ matchday: 3, home: 'Czech Republic',away:'South Africa', date: 'Sat, Jun 21', time: '18:00', venue: 'Atlanta' },
|
||||
{
|
||||
matchday: 1,
|
||||
home: 'Mexico',
|
||||
away: 'South Africa',
|
||||
date: 'Thu, Jun 11',
|
||||
time: '19:00',
|
||||
venue: 'Mexico City',
|
||||
status: 'FT',
|
||||
score: { home: 2, away: 1 },
|
||||
scorers: {
|
||||
home: [
|
||||
{ name: 'Santiago Giménez', min: "24'" },
|
||||
{ name: 'Henry Martín', min: "78'" }
|
||||
],
|
||||
away: [
|
||||
{ name: 'Percy Tau', min: "41' (pen)" }
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
matchday: 1,
|
||||
home: 'South Korea',
|
||||
away: 'Czech Republic',
|
||||
date: 'Thu, Jun 11',
|
||||
time: '21:00',
|
||||
venue: 'Guadalajara',
|
||||
status: 'FT',
|
||||
score: { home: 2, away: 1 },
|
||||
scorers: {
|
||||
home: [
|
||||
{ name: 'Hwang In-beom', min: "67'" },
|
||||
{ name: 'Oh Hyeon-gyu', min: "80'" }
|
||||
],
|
||||
away: [
|
||||
{ name: 'Ladislav Krejčí', min: "59'" }
|
||||
]
|
||||
}
|
||||
},
|
||||
{ matchday: 2, home: 'Czech Republic', away: 'South Africa', date: 'Wed, Jun 18', time: '18:00', venue: 'Atlanta' },
|
||||
{ matchday: 2, home: 'Mexico', away: 'South Korea', date: 'Wed, Jun 18', time: '21:00', venue: 'Guadalajara' },
|
||||
{ matchday: 3, home: 'Czech Republic', away: 'Mexico', date: 'Tue, Jun 24', time: '18:00', venue: 'Monterrey' },
|
||||
{ matchday: 3, home: 'South Africa', away: 'South Korea', date: 'Tue, Jun 24', time: '21:00', venue: 'Monterrey' },
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -51,11 +87,11 @@ export const groups = [
|
||||
],
|
||||
matches: [
|
||||
{ matchday: 1, home: 'Canada', away: 'Bosnia & Herzegovina', date: 'Fri, Jun 12', time: '19:00', venue: 'Toronto' },
|
||||
{ matchday: 1, home: 'Qatar', away: 'Switzerland', date: 'Sat, Jun 13', time: '16:00', venue: 'San Francisco'},
|
||||
{ matchday: 2, home: 'Canada', away: 'Switzerland', date: 'Tue, Jun 16', time: '16:00', venue: 'Vancouver' },
|
||||
{ matchday: 2, home: 'Qatar', away: 'Bosnia & Herzegovina', date: 'Wed, Jun 17', time: '19:00', venue: 'Toronto' },
|
||||
{ matchday: 3, home: 'Canada', away: 'Qatar', date: 'Sun, Jun 22', time: '18:00', venue: 'Vancouver' },
|
||||
{ matchday: 3, home: 'Switzerland', away: 'Bosnia & Herzegovina', date: 'Sun, Jun 22', time: '18:00', venue: 'Kansas City' },
|
||||
{ matchday: 1, home: 'Qatar', away: 'Switzerland', date: 'Sat, Jun 13', time: '19:00', venue: 'San Francisco' },
|
||||
{ matchday: 2, home: 'Switzerland', away: 'Bosnia & Herzegovina', date: 'Wed, Jun 18', time: '19:00', venue: 'Los Angeles' },
|
||||
{ matchday: 2, home: 'Canada', away: 'Qatar', date: 'Wed, Jun 18', time: '22:00', venue: 'Vancouver' },
|
||||
{ matchday: 3, home: 'Bosnia & Herzegovina', away: 'Qatar', date: 'Tue, Jun 24', time: '19:00', venue: 'Seattle' },
|
||||
{ matchday: 3, home: 'Switzerland', away: 'Canada', date: 'Tue, Jun 24', time: '19:00', venue: 'Vancouver' },
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -70,10 +106,10 @@ export const groups = [
|
||||
matches: [
|
||||
{ matchday: 1, home: 'Brazil', away: 'Morocco', date: 'Sat, Jun 13', time: '19:00', venue: 'New York' },
|
||||
{ matchday: 1, home: 'Haiti', away: 'Scotland', date: 'Sat, Jun 13', time: '16:00', venue: 'Boston' },
|
||||
{ matchday: 2, home: 'Brazil', away: 'Scotland', date: 'Wed, Jun 17', time: '16:00', venue: 'Los Angeles' },
|
||||
{ matchday: 2, home: 'Morocco', away: 'Haiti', date: 'Wed, Jun 17', time: '22:00', venue: 'Miami' },
|
||||
{ matchday: 3, home: 'Brazil', away: 'Haiti', date: 'Mon, Jun 22', time: '18:00', venue: 'Dallas' },
|
||||
{ matchday: 3, home: 'Scotland', away: 'Morocco', date: 'Mon, Jun 22', time: '18:00', venue: 'Philadelphia' },
|
||||
{ matchday: 2, home: 'Brazil', away: 'Scotland', date: 'Fri, Jun 19', time: '19:00', venue: 'Los Angeles' },
|
||||
{ matchday: 2, home: 'Morocco', away: 'Haiti', date: 'Fri, Jun 19', time: '22:00', venue: 'Miami' },
|
||||
{ matchday: 3, home: 'Brazil', away: 'Haiti', date: 'Tue, Jun 24', time: '18:00', venue: 'Dallas' },
|
||||
{ matchday: 3, home: 'Scotland', away: 'Morocco', date: 'Tue, Jun 24', time: '18:00', venue: 'Philadelphia' },
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -86,12 +122,12 @@ export const groups = [
|
||||
{ name: 'Türkiye', flag: '🇹🇷', confederation: 'UEFA', isHost: false },
|
||||
],
|
||||
matches: [
|
||||
{ matchday: 1, home: 'United States', away: 'Paraguay', date: 'Fri, Jun 12', time: '22:00', venue: 'Los Angeles' },
|
||||
{ matchday: 1, home: 'Australia', away: 'Türkiye', date: 'Sat, Jun 13', time: '22:00', venue: 'Vancouver' },
|
||||
{ matchday: 2, home: 'United States', away: 'Türkiye', date: 'Wed, Jun 17', time: '22:00', venue: 'Seattle' },
|
||||
{ matchday: 2, home: 'Paraguay', away: 'Australia',date: 'Thu, Jun 18', time: '19:00', venue: 'Atlanta' },
|
||||
{ matchday: 3, home: 'United States', away: 'Australia',date: 'Mon, Jun 22', time: '22:00', venue: 'Dallas' },
|
||||
{ matchday: 3, home: 'Türkiye', away: 'Paraguay', date: 'Mon, Jun 22', time: '22:00', venue: 'Houston' },
|
||||
{ matchday: 1, home: 'United States', away: 'Paraguay', date: 'Fri, Jun 12', time: '21:00', venue: 'Los Angeles' },
|
||||
{ matchday: 1, home: 'Australia', away: 'Türkiye', date: 'Sun, Jun 13', time: '00:00', venue: 'Vancouver' },
|
||||
{ matchday: 2, home: 'United States', away: 'Australia', date: 'Thu, Jun 19', time: '15:00', venue: 'Seattle' },
|
||||
{ matchday: 2, home: 'Türkiye', away: 'Paraguay', date: 'Thu, Jun 19', time: '23:00', venue: 'San Francisco'},
|
||||
{ matchday: 3, home: 'Türkiye', away: 'United States', date: 'Thu, Jun 25', time: '22:00', venue: 'Los Angeles' },
|
||||
{ matchday: 3, home: 'Paraguay', away: 'Australia', date: 'Thu, Jun 25', time: '22:00', venue: 'San Francisco'},
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -106,10 +142,10 @@ export const groups = [
|
||||
matches: [
|
||||
{ matchday: 1, home: 'Germany', away: 'Curaçao', date: 'Sun, Jun 14', time: '16:00', venue: 'Kansas City' },
|
||||
{ matchday: 1, home: "Côte d'Ivoire", away: 'Ecuador', date: 'Sun, Jun 14', time: '19:00', venue: 'Atlanta' },
|
||||
{ matchday: 2, home: 'Germany', away: 'Ecuador', date: 'Thu, Jun 18', time: '16:00', venue: 'Seattle' },
|
||||
{ matchday: 2, home: 'Curaçao', away: "Côte d'Ivoire", date: 'Thu, Jun 18', time: '22:00', venue: 'Houston' },
|
||||
{ matchday: 3, home: 'Germany', away: "Côte d'Ivoire", date: 'Tue, Jun 23', time: '18:00', venue: 'Philadelphia'},
|
||||
{ matchday: 3, home: 'Ecuador', away: 'Curaçao', date: 'Tue, Jun 23', time: '18:00', venue: 'Miami' },
|
||||
{ matchday: 2, home: 'Germany', away: "Côte d'Ivoire", date: 'Fri, Jun 20', time: '18:00', venue: 'Philadelphia'},
|
||||
{ matchday: 2, home: 'Ecuador', away: 'Curaçao', date: 'Fri, Jun 20', time: '18:00', venue: 'Miami' },
|
||||
{ matchday: 3, home: 'Curaçao', away: "Côte d'Ivoire", date: 'Wed, Jun 25', time: '18:00', venue: 'Houston' },
|
||||
{ matchday: 3, home: 'Ecuador', away: 'Germany', date: 'Wed, Jun 25', time: '18:00', venue: 'Seattle' },
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -124,10 +160,10 @@ export const groups = [
|
||||
matches: [
|
||||
{ matchday: 1, home: 'Netherlands', away: 'Japan', date: 'Sun, Jun 14', time: '22:00', venue: 'Los Angeles' },
|
||||
{ matchday: 1, home: 'Sweden', away: 'Tunisia', date: 'Mon, Jun 15', time: '16:00', venue: 'Boston' },
|
||||
{ matchday: 2, home: 'Netherlands', away: 'Tunisia', date: 'Fri, Jun 19', time: '16:00', venue: 'Dallas' },
|
||||
{ matchday: 2, home: 'Japan', away: 'Sweden', date: 'Fri, Jun 19', time: '22:00', venue: 'Seattle' },
|
||||
{ matchday: 3, home: 'Netherlands', away: 'Sweden', date: 'Tue, Jun 23', time: '22:00', venue: 'New York' },
|
||||
{ matchday: 3, home: 'Tunisia', away: 'Japan', date: 'Tue, Jun 23', time: '22:00', venue: 'Kansas City' },
|
||||
{ matchday: 2, home: 'Netherlands', away: 'Sweden', date: 'Sat, Jun 20', time: '19:00', venue: 'New York' },
|
||||
{ matchday: 2, home: 'Japan', away: 'Tunisia', date: 'Sat, Jun 20', time: '22:00', venue: 'Kansas City' },
|
||||
{ matchday: 3, home: 'Netherlands', away: 'Tunisia', date: 'Fri, Jun 26', time: '18:00', venue: 'Dallas' },
|
||||
{ matchday: 3, home: 'Japan', away: 'Sweden', date: 'Fri, Jun 26', time: '18:00', venue: 'Seattle' },
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -142,10 +178,10 @@ export const groups = [
|
||||
matches: [
|
||||
{ matchday: 1, home: 'Belgium', away: 'Egypt', date: 'Mon, Jun 15', time: '19:00', venue: 'Miami' },
|
||||
{ matchday: 1, home: 'Iran', away: 'New Zealand', date: 'Mon, Jun 15', time: '22:00', venue: 'San Francisco'},
|
||||
{ matchday: 2, home: 'Belgium', away: 'New Zealand', date: 'Sat, Jun 19', time: '16:00', venue: 'Philadelphia'},
|
||||
{ matchday: 2, home: 'Egypt', away: 'Iran', date: 'Sat, Jun 19', time: '19:00', venue: 'Houston' },
|
||||
{ matchday: 3, home: 'Belgium', away: 'Iran', date: 'Wed, Jun 24', time: '18:00', venue: 'Atlanta' },
|
||||
{ matchday: 3, home: 'New Zealand', away: 'Egypt', date: 'Wed, Jun 24', time: '18:00', venue: 'Boston' },
|
||||
{ matchday: 2, home: 'Belgium', away: 'New Zealand', date: 'Sun, Jun 21', time: '16:00', venue: 'Philadelphia'},
|
||||
{ matchday: 2, home: 'Egypt', away: 'Iran', date: 'Sun, Jun 21', time: '19:00', venue: 'Houston' },
|
||||
{ matchday: 3, home: 'Belgium', away: 'Iran', date: 'Thu, Jun 26', time: '18:00', venue: 'Atlanta' },
|
||||
{ matchday: 3, home: 'New Zealand', away: 'Egypt', date: 'Thu, Jun 26', time: '18:00', venue: 'Boston' },
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -160,10 +196,10 @@ export const groups = [
|
||||
matches: [
|
||||
{ matchday: 1, home: 'Spain', away: 'Cape Verde', date: 'Mon, Jun 15', time: '16:00', venue: 'Guadalajara' },
|
||||
{ matchday: 1, home: 'Saudi Arabia', away: 'Uruguay', date: 'Tue, Jun 16', time: '16:00', venue: 'Mexico City' },
|
||||
{ matchday: 2, home: 'Spain', away: 'Uruguay', date: 'Sat, Jun 20', time: '16:00', venue: 'Monterrey' },
|
||||
{ matchday: 2, home: 'Cape Verde', away: 'Saudi Arabia', date: 'Sat, Jun 20', time: '22:00', venue: 'Guadalajara' },
|
||||
{ matchday: 3, home: 'Spain', away: 'Saudi Arabia', date: 'Wed, Jun 24', time: '22:00', venue: 'Dallas' },
|
||||
{ matchday: 3, home: 'Uruguay', away: 'Cape Verde', date: 'Wed, Jun 24', time: '22:00', venue: 'Miami' },
|
||||
{ matchday: 2, home: 'Spain', away: 'Uruguay', date: 'Sat, Jun 21', time: '19:00', venue: 'Monterrey' },
|
||||
{ matchday: 2, home: 'Cape Verde', away: 'Saudi Arabia', date: 'Sat, Jun 21', time: '22:00', venue: 'Guadalajara' },
|
||||
{ matchday: 3, home: 'Spain', away: 'Saudi Arabia', date: 'Thu, Jun 26', time: '18:00', venue: 'Dallas' },
|
||||
{ matchday: 3, home: 'Uruguay', away: 'Cape Verde', date: 'Thu, Jun 26', time: '18:00', venue: 'Miami' },
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -178,10 +214,10 @@ export const groups = [
|
||||
matches: [
|
||||
{ matchday: 1, home: 'France', away: 'Senegal', date: 'Tue, Jun 16', time: '22:00', venue: 'Houston' },
|
||||
{ matchday: 1, home: 'Iraq', away: 'Norway', date: 'Tue, Jun 16', time: '19:00', venue: 'Philadelphia'},
|
||||
{ matchday: 2, home: 'France', away: 'Norway', date: 'Sat, Jun 20', time: '19:00', venue: 'New York' },
|
||||
{ matchday: 2, home: 'Senegal', away: 'Iraq', date: 'Sun, Jun 21', time: '16:00', venue: 'Atlanta' },
|
||||
{ matchday: 3, home: 'France', away: 'Iraq', date: 'Thu, Jun 25', time: '18:00', venue: 'Seattle' },
|
||||
{ matchday: 3, home: 'Norway', away: 'Senegal', date: 'Thu, Jun 25', time: '18:00', venue: 'Boston' },
|
||||
{ matchday: 2, home: 'France', away: 'Norway', date: 'Sun, Jun 22', time: '19:00', venue: 'New York' },
|
||||
{ matchday: 2, home: 'Senegal', away: 'Iraq', date: 'Sun, Jun 22', time: '16:00', venue: 'Atlanta' },
|
||||
{ matchday: 3, home: 'France', away: 'Iraq', date: 'Thu, Jun 26', time: '18:00', venue: 'Seattle' },
|
||||
{ matchday: 3, home: 'Norway', away: 'Senegal', date: 'Thu, Jun 26', time: '18:00', venue: 'Boston' },
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -230,12 +266,12 @@ export const groups = [
|
||||
{ name: 'Panama', flag: '🇵🇦', confederation: 'CONCACAF', isHost: false },
|
||||
],
|
||||
matches: [
|
||||
{ matchday: 1, home: 'England', away: 'Panama', date: 'Fri, Jun 19', time: '16:00', venue: 'Houston' },
|
||||
{ matchday: 1, home: 'Croatia', away: 'Ghana', date: 'Fri, Jun 19', time: '19:00', venue: 'New York' },
|
||||
{ matchday: 2, home: 'England', away: 'Ghana', date: 'Tue, Jun 23', time: '16:00', venue: 'Philadelphia'},
|
||||
{ matchday: 2, home: 'Panama', away: 'Croatia', date: 'Tue, Jun 23', time: '19:00', venue: 'Miami' },
|
||||
{ matchday: 3, home: 'England', away: 'Croatia', date: 'Sat, Jun 27', time: '18:00', venue: 'San Francisco'},
|
||||
{ matchday: 3, home: 'Ghana', away: 'Panama', date: 'Sat, Jun 27', time: '18:00', venue: 'Atlanta' },
|
||||
{ matchday: 1, home: 'England', away: 'Croatia', date: 'Tue, Jun 17', time: '15:00', venue: 'Dallas' },
|
||||
{ matchday: 1, home: 'Ghana', away: 'Panama', date: 'Tue, Jun 17', time: '19:00', venue: 'Toronto' },
|
||||
{ matchday: 2, home: 'England', away: 'Ghana', date: 'Mon, Jun 23', time: '16:00', venue: 'Boston' },
|
||||
{ matchday: 2, home: 'Panama', away: 'Croatia', date: 'Mon, Jun 23', time: '19:00', venue: 'Miami' },
|
||||
{ matchday: 3, home: 'Panama', away: 'England', date: 'Fri, Jun 27', time: '18:00', venue: 'New York' },
|
||||
{ matchday: 3, home: 'Croatia', away: 'Ghana', date: 'Fri, Jun 27', time: '18:00', venue: 'Atlanta' },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
+310
-10
@@ -7,6 +7,26 @@ console.log('[WC2026] Loaded groups:', groups.length, '| First group matches:',
|
||||
// ── State ──────────────────────────────────────────────────────────────────
|
||||
let activeFilter = 'all';
|
||||
let searchQuery = '';
|
||||
let appGroups = [];
|
||||
|
||||
function loadState() {
|
||||
const saved = localStorage.getItem('wc2026_groups');
|
||||
if (saved) {
|
||||
try {
|
||||
appGroups = JSON.parse(saved);
|
||||
return;
|
||||
} catch (e) {
|
||||
console.error('[WC2026] Failed to load saved state:', e);
|
||||
}
|
||||
}
|
||||
appGroups = JSON.parse(JSON.stringify(groups));
|
||||
}
|
||||
|
||||
function saveState() {
|
||||
localStorage.setItem('wc2026_groups', JSON.stringify(appGroups));
|
||||
}
|
||||
|
||||
loadState();
|
||||
|
||||
// ── Helpers ────────────────────────────────────────────────────────────────
|
||||
function confBadge(confederation) {
|
||||
@@ -14,21 +34,94 @@ function confBadge(confederation) {
|
||||
return `<span class="conf-badge" style="background:${c.bg};color:${c.accent}">${confederation}</span>`;
|
||||
}
|
||||
|
||||
function teamCard(team) {
|
||||
function calculateStandings(group) {
|
||||
const standings = {};
|
||||
group.teams.forEach(team => {
|
||||
standings[team.name] = {
|
||||
name: team.name,
|
||||
flag: team.flag,
|
||||
confederation: team.confederation,
|
||||
isHost: team.isHost,
|
||||
played: 0,
|
||||
won: 0,
|
||||
drawn: 0,
|
||||
lost: 0,
|
||||
gf: 0,
|
||||
ga: 0,
|
||||
gd: 0,
|
||||
pts: 0
|
||||
};
|
||||
});
|
||||
|
||||
group.matches.forEach(match => {
|
||||
if (match.status === 'FT' && match.score) {
|
||||
const home = match.home;
|
||||
const away = match.away;
|
||||
const homeScore = parseInt(match.score.home, 10);
|
||||
const awayScore = parseInt(match.score.away, 10);
|
||||
|
||||
if (!isNaN(homeScore) && !isNaN(awayScore) && standings[home] && standings[away]) {
|
||||
standings[home].played += 1;
|
||||
standings[away].played += 1;
|
||||
standings[home].gf += homeScore;
|
||||
standings[home].ga += awayScore;
|
||||
standings[away].gf += awayScore;
|
||||
standings[away].ga += homeScore;
|
||||
standings[home].gd = standings[home].gf - standings[home].ga;
|
||||
standings[away].gd = standings[away].gf - standings[away].ga;
|
||||
|
||||
if (homeScore > awayScore) {
|
||||
standings[home].won += 1;
|
||||
standings[home].pts += 3;
|
||||
standings[away].lost += 1;
|
||||
} else if (homeScore < awayScore) {
|
||||
standings[away].won += 1;
|
||||
standings[away].pts += 3;
|
||||
standings[home].lost += 1;
|
||||
} else {
|
||||
standings[home].drawn += 1;
|
||||
standings[home].pts += 1;
|
||||
standings[away].drawn += 1;
|
||||
standings[away].pts += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return Object.values(standings).sort((a, b) => {
|
||||
if (b.pts !== a.pts) return b.pts - a.pts;
|
||||
if (b.gd !== a.gd) return b.gd - a.gd;
|
||||
if (b.gf !== a.gf) return b.gf - a.gf;
|
||||
return a.name.localeCompare(b.name);
|
||||
});
|
||||
}
|
||||
|
||||
function teamCard(team, rank, pts, played) {
|
||||
const hostBadge = team.isHost ? '<span class="host-badge">🏟️ Host</span>' : '';
|
||||
const ptsBadge = played > 0 ? `<span class="team-pts-badge">${pts} PTS</span>` : '';
|
||||
const rankClass = rank <= 2 ? 'rank-adv' : rank === 3 ? 'rank-pot' : 'rank-el';
|
||||
return `
|
||||
<div class="team-card">
|
||||
<span class="team-rank ${rankClass}">${rank}</span>
|
||||
<span class="team-flag">${team.flag}</span>
|
||||
<div class="team-info">
|
||||
<span class="team-name">${team.name}</span>
|
||||
<div class="team-meta">${confBadge(team.confederation)}${hostBadge}</div>
|
||||
</div>
|
||||
${ptsBadge}
|
||||
</div>`;
|
||||
}
|
||||
|
||||
function groupCard(group) {
|
||||
const teamsHTML = group.teams.map(teamCard).join('');
|
||||
const standings = calculateStandings(group);
|
||||
const teamsHTML = standings.map((item, idx) => {
|
||||
return teamCard(item, idx + 1, item.pts, item.played);
|
||||
}).join('');
|
||||
|
||||
const matchCount = group.matches ? group.matches.length : 0;
|
||||
const finishedCount = group.matches ? group.matches.filter(m => m.status === 'FT').length : 0;
|
||||
const matchCountStr = finishedCount > 0 ? `${finishedCount}/${matchCount} played` : `${matchCount} matches`;
|
||||
|
||||
return `
|
||||
<article class="group-card" data-group="${group.id}">
|
||||
<div class="group-header" style="--group-color:${group.color}">
|
||||
@@ -37,13 +130,13 @@ function groupCard(group) {
|
||||
<h2 class="group-id">${group.id}</h2>
|
||||
</div>
|
||||
<div class="group-right">
|
||||
<span class="match-count">${matchCount} matches</span>
|
||||
<span class="match-count">${matchCountStr}</span>
|
||||
<div class="group-dot" style="background:${group.color}"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="team-list">${teamsHTML}</div>
|
||||
<div class="card-footer">
|
||||
<span class="view-schedule-hint">📅 Click to view match schedule</span>
|
||||
<span class="view-schedule-hint">📅 Click to view schedule & standings</span>
|
||||
</div>
|
||||
</article>`;
|
||||
}
|
||||
@@ -82,29 +175,81 @@ function buildMatchdayHTML(group) {
|
||||
const away = group.teams.find(t => t.name === match.away);
|
||||
const cardId = `match-${group.id}-${md}-${idx}`;
|
||||
const userLocalTimeStr = getUserLocalTime(match, venue);
|
||||
|
||||
const isFinished = match.status === 'FT';
|
||||
|
||||
let scoreDisplayHTML = `<span class="mc-vs">VS</span>`;
|
||||
if (isFinished && match.score) {
|
||||
const homeWinnerClass = match.score.home > match.score.away ? 'mc-team-winner' : (match.score.home < match.score.away ? 'mc-team-loser' : 'mc-team-draw');
|
||||
const awayWinnerClass = match.score.away > match.score.home ? 'mc-team-winner' : (match.score.away < match.score.home ? 'mc-team-loser' : 'mc-team-draw');
|
||||
|
||||
scoreDisplayHTML = `
|
||||
<div class="mc-score-wrap">
|
||||
<span class="mc-score ${homeWinnerClass}">${match.score.home}</span>
|
||||
<span class="mc-score-dash">–</span>
|
||||
<span class="mc-score ${awayWinnerClass}">${match.score.away}</span>
|
||||
<span class="mc-status-badge">FT</span>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
let scorersHTML = '';
|
||||
if (isFinished && match.scorers) {
|
||||
const homeScorersList = match.scorers.home ? match.scorers.home.map(s => `${s.name} ${s.min}`).join(', ') : '';
|
||||
const awayScorersList = match.scorers.away ? match.scorers.away.map(s => `${s.name} ${s.min}`).join(', ') : '';
|
||||
|
||||
scorersHTML = `
|
||||
<div class="match-scorers-panel">
|
||||
<div class="scorers-team home-scorers">⚽ ${homeScorersList || '—'}</div>
|
||||
<div class="scorers-divider"></div>
|
||||
<div class="scorers-team away-scorers">⚽ ${awayScorersList || '—'}</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
return `
|
||||
<div class="match-card" style="--match-color:${group.color}" id="${cardId}">
|
||||
<div class="match-card ${isFinished ? 'match-finished' : ''}" style="--match-color:${group.color}" id="${cardId}">
|
||||
<button class="match-summary" onclick="toggleMatch('${cardId}')" aria-expanded="false">
|
||||
<div class="match-team-col">
|
||||
<div class="match-team-col home-col">
|
||||
<span class="mc-flag">${home ? home.flag : '🏴'}</span>
|
||||
<span class="mc-name">${match.home}</span>
|
||||
</div>
|
||||
<div class="match-divider">
|
||||
<span class="mc-vs">VS</span>
|
||||
${scoreDisplayHTML}
|
||||
<span class="mc-chevron">›</span>
|
||||
</div>
|
||||
<div class="match-team-col">
|
||||
<div class="match-team-col away-col">
|
||||
<span class="mc-flag">${away ? away.flag : '🏴'}</span>
|
||||
<span class="mc-name">${match.away}</span>
|
||||
</div>
|
||||
</button>
|
||||
<div class="match-details-panel">
|
||||
<div class="match-details-inner">
|
||||
${scorersHTML}
|
||||
<div class="match-detail-row"><span class="md-icon">📅</span><div class="md-text"><span class="md-label">Date</span><span class="md-value">${match.date}</span></div></div>
|
||||
<div class="match-detail-row"><span class="md-icon">🕐</span><div class="md-text"><span class="md-label">Kick-off</span><span class="md-value">${match.time} local time${userLocalTimeStr ? ' / ' + userLocalTimeStr + ' your time' : ''}</span></div></div>
|
||||
<div class="match-detail-row"><span class="md-icon">📍</span><div class="md-text"><span class="md-label">Venue</span><span class="md-value">${venue ? venue.stadium : match.venue}</span></div></div>
|
||||
<div class="match-detail-row"><span class="md-icon">🏙️</span><div class="md-text"><span class="md-label">City</span><span class="md-value">${match.venue}${venue ? ', ' + venue.country : ''}</span></div></div>
|
||||
<div class="match-detail-row"><span class="md-icon">👥</span><div class="md-text"><span class="md-label">Capacity</span><span class="md-value">${venue ? venue.capacity : '—'}</span></div></div>
|
||||
|
||||
<div class="simulator-section">
|
||||
<div class="simulator-title">🎮 Simulate Match Score</div>
|
||||
<div class="simulator-row">
|
||||
<div class="sim-team">
|
||||
<span class="sim-flag">${home ? home.flag : ''}</span>
|
||||
<input type="number" min="0" placeholder="0" class="sim-input" id="input-${cardId}-home" value="${isFinished ? match.score.home : ''}">
|
||||
</div>
|
||||
<span class="sim-vs">–</span>
|
||||
<div class="sim-team">
|
||||
<input type="number" min="0" placeholder="0" class="sim-input" id="input-${cardId}-away" value="${isFinished ? match.score.away : ''}">
|
||||
<span class="sim-flag">${away ? away.flag : ''}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="simulator-actions">
|
||||
<button class="sim-btn sim-btn-save" onclick="saveMatchScore('${group.id}', ${md}, ${idx}, '${cardId}')">Save Score</button>
|
||||
${isFinished ? `<button class="sim-btn sim-btn-clear" onclick="clearMatchScore('${group.id}', ${md}, ${idx}, '${cardId}')">Clear</button>` : ''}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>`;
|
||||
@@ -154,6 +299,61 @@ function buildSquadHTML(group) {
|
||||
}).join('');
|
||||
}
|
||||
|
||||
function buildStandingsHTML(group) {
|
||||
const standings = calculateStandings(group);
|
||||
const rowsHTML = standings.map((item, idx) => {
|
||||
const rank = idx + 1;
|
||||
const rankClass = rank <= 2 ? 'rank-adv' : rank === 3 ? 'rank-pot' : 'rank-el';
|
||||
const rowClass = rank <= 2 ? 'row-adv' : rank === 3 ? 'row-pot' : 'row-el';
|
||||
return `
|
||||
<tr class="${rowClass}">
|
||||
<td class="col-pos"><span class="table-rank-num ${rankClass}">${rank}</span></td>
|
||||
<td class="col-team">
|
||||
<span class="table-flag">${item.flag}</span>
|
||||
<span class="table-team-name">${item.name}</span>
|
||||
${item.isHost ? '<span class="table-host-badge" title="Host">🏟️</span>' : ''}
|
||||
</td>
|
||||
<td class="col-stat">${item.played}</td>
|
||||
<td class="col-stat font-w-600">${item.won}</td>
|
||||
<td class="col-stat">${item.drawn}</td>
|
||||
<td class="col-stat">${item.lost}</td>
|
||||
<td class="col-stat text-hide-mobile">${item.gf}</td>
|
||||
<td class="col-stat text-hide-mobile">${item.ga}</td>
|
||||
<td class="col-stat font-w-600">${item.gd > 0 ? '+' + item.gd : item.gd}</td>
|
||||
<td class="col-stat col-pts">${item.pts}</td>
|
||||
</tr>
|
||||
`;
|
||||
}).join('');
|
||||
|
||||
return `
|
||||
<div class="standings-wrapper">
|
||||
<table class="standings-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="col-pos">#</th>
|
||||
<th class="col-team">Team</th>
|
||||
<th class="col-stat">P</th>
|
||||
<th class="col-stat">W</th>
|
||||
<th class="col-stat">D</th>
|
||||
<th class="col-stat">L</th>
|
||||
<th class="col-stat text-hide-mobile">GF</th>
|
||||
<th class="col-stat text-hide-mobile">GA</th>
|
||||
<th class="col-stat">GD</th>
|
||||
<th class="col-stat col-pts">Pts</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
${rowsHTML}
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="standings-legend">
|
||||
<div class="legend-item"><span class="legend-dot dot-adv"></span> <span class="legend-text">Top 2 advance to Round of 32</span></div>
|
||||
<div class="legend-item"><span class="legend-dot dot-pot"></span> <span class="legend-text">Best 3rd-place teams advance</span></div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
// ── Modal ──────────────────────────────────────────────────────────────────
|
||||
function openModal(group) {
|
||||
if (!group || !group.matches || group.matches.length === 0) return;
|
||||
@@ -176,12 +376,16 @@ function openModal(group) {
|
||||
</div>
|
||||
<div class="modal-tabs">
|
||||
<button class="modal-tab active" id="tab-schedule" onclick="switchTab('schedule')">📅 Schedule</button>
|
||||
<button class="modal-tab" id="tab-standings" onclick="switchTab('standings')">📈 Standings</button>
|
||||
<button class="modal-tab" id="tab-squad" onclick="switchTab('squad')">👕 Squads</button>
|
||||
</div>
|
||||
<div class="modal-body" id="modal-body">
|
||||
<div id="tab-content-schedule" class="tab-content active">
|
||||
<div class="matchdays">${buildMatchdayHTML(group)}</div>
|
||||
</div>
|
||||
<div id="tab-content-standings" class="tab-content">
|
||||
${buildStandingsHTML(group)}
|
||||
</div>
|
||||
<div id="tab-content-squad" class="tab-content">
|
||||
${buildSquadHTML(group)}
|
||||
</div>
|
||||
@@ -211,6 +415,97 @@ function closeModal() {
|
||||
}
|
||||
}
|
||||
|
||||
// ── Simulation Handlers ────────────────────────────────────────────────────
|
||||
window.saveMatchScore = function(groupId, matchday, matchIdx, cardId) {
|
||||
const homeInput = document.getElementById(`input-${cardId}-home`);
|
||||
const awayInput = document.getElementById(`input-${cardId}-away`);
|
||||
if (!homeInput || !awayInput) return;
|
||||
|
||||
const homeVal = homeInput.value.trim();
|
||||
const awayVal = awayInput.value.trim();
|
||||
|
||||
if (homeVal === '' || awayVal === '') {
|
||||
alert('Please enter scores for both teams.');
|
||||
return;
|
||||
}
|
||||
|
||||
const homeScore = parseInt(homeVal, 10);
|
||||
const awayScore = parseInt(awayVal, 10);
|
||||
|
||||
if (isNaN(homeScore) || isNaN(awayScore) || homeScore < 0 || awayScore < 0) {
|
||||
alert('Scores must be non-negative integers.');
|
||||
return;
|
||||
}
|
||||
|
||||
const group = appGroups.find(g => g.id === groupId);
|
||||
if (group) {
|
||||
const dayMatches = group.matches.filter(m => m.matchday === matchday);
|
||||
const match = dayMatches[matchIdx];
|
||||
if (match) {
|
||||
match.status = 'FT';
|
||||
match.score = { home: homeScore, away: awayScore };
|
||||
|
||||
// Preserve or set scorers for Mexico vs South Africa if restored to 2 - 1
|
||||
if (groupId === 'A' && matchday === 1 && matchIdx === 0 && homeScore === 2 && awayScore === 1) {
|
||||
match.scorers = {
|
||||
home: [
|
||||
{ name: 'Santiago Giménez', min: "24'" },
|
||||
{ name: 'Henry Martín', min: "78'" }
|
||||
],
|
||||
away: [
|
||||
{ name: 'Percy Tau', min: "41' (pen)" }
|
||||
]
|
||||
};
|
||||
} else {
|
||||
delete match.scorers;
|
||||
}
|
||||
|
||||
saveState();
|
||||
render();
|
||||
|
||||
const updatedGroup = appGroups.find(g => g.id === groupId);
|
||||
const activeTab = document.querySelector('.modal-tab.active')?.id || 'tab-schedule';
|
||||
const tabName = activeTab.replace('tab-', '');
|
||||
|
||||
openModal(updatedGroup);
|
||||
switchTab(tabName);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
window.clearMatchScore = function(groupId, matchday, matchIdx, cardId) {
|
||||
const group = appGroups.find(g => g.id === groupId);
|
||||
if (group) {
|
||||
const dayMatches = group.matches.filter(m => m.matchday === matchday);
|
||||
const match = dayMatches[matchIdx];
|
||||
if (match) {
|
||||
delete match.status;
|
||||
delete match.score;
|
||||
delete match.scorers;
|
||||
|
||||
saveState();
|
||||
render();
|
||||
|
||||
const updatedGroup = appGroups.find(g => g.id === groupId);
|
||||
const activeTab = document.querySelector('.modal-tab.active')?.id || 'tab-schedule';
|
||||
const tabName = activeTab.replace('tab-', '');
|
||||
|
||||
openModal(updatedGroup);
|
||||
switchTab(tabName);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
window.resetAllScores = function() {
|
||||
if (confirm('Are you sure you want to reset all simulated scores back to default?')) {
|
||||
localStorage.removeItem('wc2026_groups');
|
||||
loadState();
|
||||
render();
|
||||
closeModal();
|
||||
animateCounters();
|
||||
}
|
||||
};
|
||||
|
||||
// ── Accordion toggle ───────────────────────────────────────────────────────
|
||||
window.toggleMatch = function(cardId) {
|
||||
const card = document.getElementById(cardId);
|
||||
@@ -232,7 +527,7 @@ function render() {
|
||||
const grid = document.getElementById('groups-grid');
|
||||
if (!grid) return;
|
||||
|
||||
const filteredGroups = groups.map(group => {
|
||||
const filteredGroups = appGroups.map(group => {
|
||||
let filteredTeams = group.teams;
|
||||
if (activeFilter !== 'all') {
|
||||
filteredTeams = filteredTeams.filter(t => t.confederation === activeFilter);
|
||||
@@ -264,10 +559,14 @@ function render() {
|
||||
// ── Global click handler (set ONCE on document.body) ──────────────────────
|
||||
function setupGlobalClick() {
|
||||
document.body.addEventListener('click', (e) => {
|
||||
// If click is on simulation controls or buttons inside modal, don't trigger group open
|
||||
if (e.target.closest('.sim-btn') || e.target.closest('.sim-input') || e.target.closest('.modal-tabs') || e.target.closest('.modal-close') || e.target.closest('.theme-toggle-btn') || e.target.closest('.reset-simulation-btn')) {
|
||||
return;
|
||||
}
|
||||
const card = e.target.closest('.group-card');
|
||||
if (card) {
|
||||
const groupId = card.dataset.group;
|
||||
const group = groups.find(g => g.id === groupId);
|
||||
const group = appGroups.find(g => g.id === groupId);
|
||||
console.log('[WC2026] Card clicked, groupId:', groupId, 'found:', !!group);
|
||||
openModal(group);
|
||||
}
|
||||
@@ -366,6 +665,7 @@ function buildShell() {
|
||||
<button class="filter-btn" data-filter="CAF">🌍 CAF</button>
|
||||
<button class="filter-btn" data-filter="CONCACAF">🌎 CONCACAF</button>
|
||||
<button class="filter-btn" data-filter="OFC">🌊 OFC</button>
|
||||
<button class="reset-simulation-btn" onclick="resetAllScores()" title="Reset all custom scores to defaults">🔄 Reset</button>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+360
@@ -808,6 +808,366 @@ body {
|
||||
.modal-group-id { font-size: 36px; }
|
||||
}
|
||||
|
||||
/* ── Reset Button in Header/Filter Bar ── */
|
||||
.reset-simulation-btn {
|
||||
background: var(--bg-element);
|
||||
border: 1px dashed var(--border);
|
||||
border-radius: 20px;
|
||||
color: var(--text-muted);
|
||||
cursor: pointer;
|
||||
font-family: inherit; font-size: 12px; font-weight: 600;
|
||||
padding: 6px 14px;
|
||||
transition: all var(--transition);
|
||||
margin-left: auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
.reset-simulation-btn:hover {
|
||||
background: rgba(239, 68, 68, 0.1);
|
||||
border-color: rgba(239, 68, 68, 0.4);
|
||||
color: #ef4444;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
/* ── Group Card Ranks & Points ── */
|
||||
.team-rank {
|
||||
font-size: 11px;
|
||||
font-weight: 800;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 50%;
|
||||
margin-right: 4px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.team-rank.rank-adv {
|
||||
background: rgba(34, 197, 94, 0.15);
|
||||
color: #22c55e;
|
||||
}
|
||||
.team-rank.rank-pot {
|
||||
background: rgba(245, 158, 11, 0.15);
|
||||
color: #f59e0b;
|
||||
}
|
||||
.team-rank.rank-el {
|
||||
background: rgba(239, 68, 68, 0.15);
|
||||
color: #ef4444;
|
||||
}
|
||||
.team-pts-badge {
|
||||
font-size: 11px;
|
||||
font-weight: 800;
|
||||
color: var(--gold);
|
||||
background: rgba(255, 215, 0, 0.1);
|
||||
padding: 2px 6px;
|
||||
border-radius: 4px;
|
||||
margin-left: auto;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
/* ── Standings Table in Modal ── */
|
||||
.standings-wrapper {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
.standings-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-top: 10px;
|
||||
font-size: 14px;
|
||||
}
|
||||
.standings-table th, .standings-table td {
|
||||
padding: 12px 10px;
|
||||
text-align: center;
|
||||
border-bottom: 1px solid var(--border-light);
|
||||
}
|
||||
.standings-table th {
|
||||
font-weight: 700;
|
||||
color: var(--text-muted);
|
||||
font-size: 11px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 1px;
|
||||
background: var(--bg-element);
|
||||
}
|
||||
.standings-table tbody tr {
|
||||
transition: background var(--transition);
|
||||
}
|
||||
.standings-table tbody tr:hover {
|
||||
background: var(--bg-element);
|
||||
}
|
||||
.standings-table td.col-team {
|
||||
text-align: left;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
.table-flag {
|
||||
font-size: 20px;
|
||||
line-height: 1;
|
||||
}
|
||||
.table-team-name {
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
.table-host-badge {
|
||||
font-size: 12px;
|
||||
cursor: help;
|
||||
}
|
||||
.col-pos {
|
||||
width: 40px;
|
||||
}
|
||||
.table-rank-num {
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 50%;
|
||||
font-weight: 800;
|
||||
font-size: 12px;
|
||||
}
|
||||
.table-rank-num.rank-adv {
|
||||
background: rgba(34, 197, 94, 0.2);
|
||||
color: #4ade80;
|
||||
}
|
||||
.table-rank-num.rank-pot {
|
||||
background: rgba(245, 158, 11, 0.2);
|
||||
color: #facc15;
|
||||
}
|
||||
.table-rank-num.rank-el {
|
||||
background: rgba(239, 68, 68, 0.2);
|
||||
color: #f87171;
|
||||
}
|
||||
.col-pts {
|
||||
font-weight: 800;
|
||||
color: var(--gold);
|
||||
}
|
||||
.font-w-600 {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* Row-based visual indicators */
|
||||
.standings-table tbody tr.row-adv td.col-team {
|
||||
border-left: 3px solid #22c55e;
|
||||
}
|
||||
.standings-table tbody tr.row-pot td.col-team {
|
||||
border-left: 3px solid #f59e0b;
|
||||
}
|
||||
.standings-table tbody tr.row-el td.col-team {
|
||||
border-left: 3px solid #ef4444;
|
||||
}
|
||||
|
||||
.standings-legend {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
margin-top: 18px;
|
||||
padding: 10px 14px;
|
||||
background: var(--bg-element);
|
||||
border-radius: 8px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.legend-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
.legend-dot {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
.legend-dot.dot-adv {
|
||||
background: #22c55e;
|
||||
}
|
||||
.legend-dot.dot-pot {
|
||||
background: #f59e0b;
|
||||
}
|
||||
.legend-text {
|
||||
font-size: 12px;
|
||||
color: var(--text-muted);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* Hide some columns on mobile */
|
||||
@media (max-width: 640px) {
|
||||
.text-hide-mobile {
|
||||
display: none;
|
||||
}
|
||||
.standings-table th, .standings-table td {
|
||||
padding: 10px 6px;
|
||||
font-size: 13px;
|
||||
}
|
||||
.reset-simulation-btn {
|
||||
margin-left: 0;
|
||||
margin-top: 10px;
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
/* ── Match Score Displays ── */
|
||||
.mc-score-wrap {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
background: var(--bg-card);
|
||||
padding: 4px 12px;
|
||||
border-radius: 20px;
|
||||
border: 1px solid var(--border);
|
||||
box-shadow: var(--shadow-md);
|
||||
position: relative;
|
||||
}
|
||||
.mc-score {
|
||||
font-size: 18px;
|
||||
font-weight: 800;
|
||||
line-height: 1;
|
||||
}
|
||||
.mc-score.mc-team-winner {
|
||||
color: var(--gold);
|
||||
}
|
||||
.mc-score.mc-team-loser {
|
||||
color: var(--text-muted);
|
||||
}
|
||||
.mc-score.mc-team-draw {
|
||||
color: var(--text-primary);
|
||||
}
|
||||
.mc-score-dash {
|
||||
font-size: 14px;
|
||||
color: var(--text-faint);
|
||||
font-weight: 700;
|
||||
}
|
||||
.mc-status-badge {
|
||||
font-size: 9px;
|
||||
font-weight: 900;
|
||||
background: var(--border-hover);
|
||||
color: var(--text-primary);
|
||||
padding: 2px 6px;
|
||||
border-radius: 10px;
|
||||
margin-left: 4px;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.match-finished {
|
||||
background: color-mix(in srgb, var(--match-color, var(--gold)) 3%, var(--bg-element));
|
||||
}
|
||||
.match-finished .home-col .mc-name,
|
||||
.match-finished .away-col .mc-name {
|
||||
font-weight: 550;
|
||||
}
|
||||
|
||||
/* Scorers list */
|
||||
.match-scorers-panel {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 10px 22px;
|
||||
font-size: 12px;
|
||||
color: var(--text-muted);
|
||||
background: var(--bg-element);
|
||||
border-bottom: 1px solid var(--border-light);
|
||||
gap: 16px;
|
||||
}
|
||||
.scorers-team {
|
||||
flex: 1;
|
||||
font-weight: 500;
|
||||
}
|
||||
.home-scorers {
|
||||
text-align: right;
|
||||
}
|
||||
.away-scorers {
|
||||
text-align: left;
|
||||
}
|
||||
.scorers-divider {
|
||||
width: 1px;
|
||||
background: var(--border-light);
|
||||
}
|
||||
|
||||
/* ── Score Simulator Panel ── */
|
||||
.simulator-section {
|
||||
padding: 16px 22px;
|
||||
background: linear-gradient(180deg, transparent, color-mix(in srgb, var(--match-color, var(--gold)) 5%, transparent));
|
||||
border-top: 1px dashed var(--border-light);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
.simulator-title {
|
||||
font-size: 11px;
|
||||
font-weight: 800;
|
||||
letter-spacing: 1.5px;
|
||||
text-transform: uppercase;
|
||||
color: var(--match-color, var(--gold));
|
||||
}
|
||||
.simulator-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 14px;
|
||||
}
|
||||
.sim-team {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
.sim-flag {
|
||||
font-size: 24px;
|
||||
}
|
||||
.sim-input {
|
||||
width: 60px;
|
||||
height: 38px;
|
||||
background: var(--bg-card);
|
||||
border: 2px solid var(--border);
|
||||
border-radius: 8px;
|
||||
color: var(--text-primary);
|
||||
text-align: center;
|
||||
font-family: inherit;
|
||||
font-size: 16px;
|
||||
font-weight: 800;
|
||||
outline: none;
|
||||
transition: all var(--transition);
|
||||
}
|
||||
.sim-input:focus {
|
||||
border-color: var(--match-color, var(--gold));
|
||||
box-shadow: 0 0 0 3px color-mix(in srgb, var(--match-color, var(--gold)) 20%, transparent);
|
||||
}
|
||||
.sim-vs {
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
color: var(--text-faint);
|
||||
}
|
||||
.simulator-actions {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
.sim-btn {
|
||||
font-family: inherit;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
padding: 8px 16px;
|
||||
border-radius: 20px;
|
||||
cursor: pointer;
|
||||
border: 1px solid transparent;
|
||||
transition: all var(--transition);
|
||||
}
|
||||
.sim-btn-save {
|
||||
background: var(--match-color, var(--gold));
|
||||
color: #000000;
|
||||
font-weight: 800;
|
||||
}
|
||||
.sim-btn-save:hover {
|
||||
filter: brightness(1.1);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
.sim-btn-clear {
|
||||
background: transparent;
|
||||
border-color: var(--border-hover);
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
.sim-btn-clear:hover {
|
||||
background: rgba(239, 68, 68, 0.1);
|
||||
border-color: rgba(239, 68, 68, 0.3);
|
||||
color: #ef4444;
|
||||
}
|
||||
|
||||
@media (min-width: 1200px) {
|
||||
.groups-grid { grid-template-columns: repeat(4, 1fr); }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user