update
@@ -0,0 +1,7 @@
|
|||||||
|
node_modules
|
||||||
|
dist
|
||||||
|
.git
|
||||||
|
.env
|
||||||
|
Dockerfile
|
||||||
|
docker-compose.yml
|
||||||
|
.gemini
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
pnpm-debug.log*
|
||||||
|
lerna-debug.log*
|
||||||
|
|
||||||
|
node_modules
|
||||||
|
dist
|
||||||
|
dist-ssr
|
||||||
|
*.local
|
||||||
|
|
||||||
|
# Editor directories and files
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/extensions.json
|
||||||
|
.idea
|
||||||
|
.DS_Store
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
*.sw?
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
# Stage 1: Build the Vite application
|
||||||
|
FROM node:20-alpine AS builder
|
||||||
|
|
||||||
|
# Set working directory
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy package.json and package-lock.json (if available)
|
||||||
|
COPY package*.json ./
|
||||||
|
|
||||||
|
# Install dependencies
|
||||||
|
RUN npm install
|
||||||
|
|
||||||
|
# Copy the rest of the application code
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# Build the application for production
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
# Stage 2: Serve the application with Nginx
|
||||||
|
FROM nginx:alpine
|
||||||
|
|
||||||
|
# Copy the built assets from the builder stage to Nginx's default public directory
|
||||||
|
COPY --from=builder /app/dist /usr/share/nginx/html
|
||||||
|
|
||||||
|
# Expose port 80
|
||||||
|
EXPOSE 80
|
||||||
|
|
||||||
|
# Start Nginx
|
||||||
|
CMD ["nginx", "-g", "daemon off;"]
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
worldcup-app:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
container_name: 2026-worldcup
|
||||||
|
ports:
|
||||||
|
- "8080:80"
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
- NODE_ENV=production
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<link rel="icon" type="image/svg+xml" href="/trophy.svg" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>FIFA World Cup 2026 – Group Stage</title>
|
||||||
|
<meta name="description" content="Explore all 48 teams and 12 groups of the 2026 FIFA World Cup hosted in Canada, Mexico & United States." />
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700;800;900&display=swap" rel="stylesheet" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="app"></div>
|
||||||
|
<script type="module" src="/src/main.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,902 @@
|
|||||||
|
{
|
||||||
|
"name": "2026-worldcup",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"lockfileVersion": 3,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {
|
||||||
|
"": {
|
||||||
|
"name": "2026-worldcup",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"devDependencies": {
|
||||||
|
"vite": "^8.0.12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@emnapi/core": {
|
||||||
|
"version": "1.10.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz",
|
||||||
|
"integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@emnapi/wasi-threads": "1.2.1",
|
||||||
|
"tslib": "^2.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@emnapi/runtime": {
|
||||||
|
"version": "1.10.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz",
|
||||||
|
"integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"dependencies": {
|
||||||
|
"tslib": "^2.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@emnapi/wasi-threads": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"dependencies": {
|
||||||
|
"tslib": "^2.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@napi-rs/wasm-runtime": {
|
||||||
|
"version": "1.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz",
|
||||||
|
"integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@tybys/wasm-util": "^0.10.1"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/Brooooooklyn"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@emnapi/core": "^1.7.1",
|
||||||
|
"@emnapi/runtime": "^1.7.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@oxc-project/types": {
|
||||||
|
"version": "0.133.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.133.0.tgz",
|
||||||
|
"integrity": "sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/Boshen"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@rolldown/binding-android-arm64": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-454rs7jHngixp/NMxd5srYD57OnzSlZ/eFTETjORQHLwJG1lRtmNOJcBerZlfu4GjKqeq8aCCIQrMdHyhI51Hw==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"android"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "^20.19.0 || >=22.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@rolldown/binding-darwin-arm64": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-PcAhP+ynjURNyy8SKGl5DQP94aGuB/7JrXJb/t7P+hanXvQVMWzUvRRhBAcg/lNRadBhoUPqSoP4xw5tR/KBEA==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "^20.19.0 || >=22.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@rolldown/binding-darwin-x64": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-9YpfeUvSE2RS7wysJ81uOZkXJz7f7Q55H2Gvp3VEw/EsahqDtrphrZ0EwDLK5vvKOzaCrBsjF8JmnMLcUt78Gg==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "^20.19.0 || >=22.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@rolldown/binding-freebsd-x64": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-yB1IlAsSNHncV6SCTL27/MVGR5htvQsoGxIv5KMGXALp+Ll1wYsn+x98M9MW7qa+NdSbvrrY7ANI4wLJ0n1e6g==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"freebsd"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "^20.19.0 || >=22.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@rolldown/binding-linux-arm-gnueabihf": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-Yi30IVAAfLUCy2MseFjbB1jAMDl1VMCAas5StnYp8da9+CKvMd2H2cbEjWcw5NPaPqzvYkVIaF1nNUG+b7u/sw==",
|
||||||
|
"cpu": [
|
||||||
|
"arm"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "^20.19.0 || >=22.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@rolldown/binding-linux-arm64-gnu": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-jsO7R8To+AdlYgUmN5sHSCZbfhtMBkO0WUx8iORQnPcMMdgr7qM2DQmMwgabs3GhNztdmoKkMKQFHD6DTMCIQw==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"libc": [
|
||||||
|
"glibc"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "^20.19.0 || >=22.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@rolldown/binding-linux-arm64-musl": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-VWkUHwWriDciit80wleYwKILoR/KMvxh/IdwS/paX+ZgpuRpCrKLUdadJbc0NpBEiyhpYawsJ73j9aCvOH+f7Q==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"libc": [
|
||||||
|
"musl"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "^20.19.0 || >=22.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@rolldown/binding-linux-ppc64-gnu": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-5f1laC0SlIR0yDbFCd8acUhvJIag6N3zC5P7oUPN6wX0aOma+uKJ0wBDH5aq7I1PVI2ttTlhJwzwRIBnLiSGEg==",
|
||||||
|
"cpu": [
|
||||||
|
"ppc64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"libc": [
|
||||||
|
"glibc"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "^20.19.0 || >=22.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@rolldown/binding-linux-s390x-gnu": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-Iq4ko0r4XsgbrF/LunNgHtAGLRRVE2kXonAXQ/MV0mC6jQpMOhW1SvtZja2EhC/kd05++bP78dsqBeIQyYJ6Yg==",
|
||||||
|
"cpu": [
|
||||||
|
"s390x"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"libc": [
|
||||||
|
"glibc"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "^20.19.0 || >=22.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@rolldown/binding-linux-x64-gnu": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-B8m6tD5+/N5FeNQFbKlLA/2yVq9ycQP1SeedyEYYKWBNR3ZQbkvIUcNnDNM03lO1l5F2roiiFJGgvoLLyZXtSg==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"libc": [
|
||||||
|
"glibc"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "^20.19.0 || >=22.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@rolldown/binding-linux-x64-musl": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-pSdpdUJHkuCxun9LE7jvgUB9qsRgaiyNNCX7m/AvHTcq67AiT/Yhoxvw5zPfhrM8k/BfP8ce/hMOpthKDpEUow==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"libc": [
|
||||||
|
"musl"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "^20.19.0 || >=22.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@rolldown/binding-openharmony-arm64": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-OXXS3RKJgX2uLwM+gYyuH5omcH8fL1LJs96pZGgtetVCahON57+d4SJHzTgZiOjxgGkSnpXpOsWuPDGAKAigEg==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"openharmony"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "^20.19.0 || >=22.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@rolldown/binding-wasm32-wasi": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-JTtb8BWFynicNSoPrehsCzBtOKjZ6jhMiPFEmOiuXg1Fl8dn2KHQob+GuPSGR0dryQa1PQJbzjF3dqO/whhjLg==",
|
||||||
|
"cpu": [
|
||||||
|
"wasm32"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@emnapi/core": "1.10.0",
|
||||||
|
"@emnapi/runtime": "1.10.0",
|
||||||
|
"@napi-rs/wasm-runtime": "^1.1.4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^20.19.0 || >=22.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@rolldown/binding-win32-arm64-msvc": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-gEdFFEN70A/jxb2svrWsN3aDL7OUtmvlOy+6fa2jxG8K0wQ1ZbdeLGnidov6Yu5/733dI5ySfzFlQ/cb0bSz1g==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "^20.19.0 || >=22.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@rolldown/binding-win32-x64-msvc": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-eXB7CHuaQdqmJcc3koCNtNPmT/bj2gc999kUFgBxG8Ac0NdgXc4rkCHhqrgrhN3zddvvvrgzj1e90SuSfmyIXA==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "^20.19.0 || >=22.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@rolldown/pluginutils": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/@tybys/wasm-util": {
|
||||||
|
"version": "0.10.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz",
|
||||||
|
"integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"dependencies": {
|
||||||
|
"tslib": "^2.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/detect-libc": {
|
||||||
|
"version": "2.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
|
||||||
|
"integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/fdir": {
|
||||||
|
"version": "6.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
|
||||||
|
"integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"picomatch": "^3 || ^4"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"picomatch": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/fsevents": {
|
||||||
|
"version": "2.3.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
||||||
|
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
|
||||||
|
"dev": true,
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/lightningcss": {
|
||||||
|
"version": "1.32.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz",
|
||||||
|
"integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MPL-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"detect-libc": "^2.0.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 12.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/parcel"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"lightningcss-android-arm64": "1.32.0",
|
||||||
|
"lightningcss-darwin-arm64": "1.32.0",
|
||||||
|
"lightningcss-darwin-x64": "1.32.0",
|
||||||
|
"lightningcss-freebsd-x64": "1.32.0",
|
||||||
|
"lightningcss-linux-arm-gnueabihf": "1.32.0",
|
||||||
|
"lightningcss-linux-arm64-gnu": "1.32.0",
|
||||||
|
"lightningcss-linux-arm64-musl": "1.32.0",
|
||||||
|
"lightningcss-linux-x64-gnu": "1.32.0",
|
||||||
|
"lightningcss-linux-x64-musl": "1.32.0",
|
||||||
|
"lightningcss-win32-arm64-msvc": "1.32.0",
|
||||||
|
"lightningcss-win32-x64-msvc": "1.32.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/lightningcss-android-arm64": {
|
||||||
|
"version": "1.32.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz",
|
||||||
|
"integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MPL-2.0",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"android"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 12.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/parcel"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/lightningcss-darwin-arm64": {
|
||||||
|
"version": "1.32.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz",
|
||||||
|
"integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MPL-2.0",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 12.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/parcel"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/lightningcss-darwin-x64": {
|
||||||
|
"version": "1.32.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz",
|
||||||
|
"integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MPL-2.0",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 12.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/parcel"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/lightningcss-freebsd-x64": {
|
||||||
|
"version": "1.32.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz",
|
||||||
|
"integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MPL-2.0",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"freebsd"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 12.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/parcel"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/lightningcss-linux-arm-gnueabihf": {
|
||||||
|
"version": "1.32.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz",
|
||||||
|
"integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==",
|
||||||
|
"cpu": [
|
||||||
|
"arm"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MPL-2.0",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 12.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/parcel"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/lightningcss-linux-arm64-gnu": {
|
||||||
|
"version": "1.32.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz",
|
||||||
|
"integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"libc": [
|
||||||
|
"glibc"
|
||||||
|
],
|
||||||
|
"license": "MPL-2.0",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 12.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/parcel"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/lightningcss-linux-arm64-musl": {
|
||||||
|
"version": "1.32.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz",
|
||||||
|
"integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"libc": [
|
||||||
|
"musl"
|
||||||
|
],
|
||||||
|
"license": "MPL-2.0",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 12.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/parcel"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/lightningcss-linux-x64-gnu": {
|
||||||
|
"version": "1.32.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz",
|
||||||
|
"integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"libc": [
|
||||||
|
"glibc"
|
||||||
|
],
|
||||||
|
"license": "MPL-2.0",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 12.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/parcel"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/lightningcss-linux-x64-musl": {
|
||||||
|
"version": "1.32.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz",
|
||||||
|
"integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"libc": [
|
||||||
|
"musl"
|
||||||
|
],
|
||||||
|
"license": "MPL-2.0",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 12.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/parcel"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/lightningcss-win32-arm64-msvc": {
|
||||||
|
"version": "1.32.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz",
|
||||||
|
"integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MPL-2.0",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 12.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/parcel"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/lightningcss-win32-x64-msvc": {
|
||||||
|
"version": "1.32.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz",
|
||||||
|
"integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MPL-2.0",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 12.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/parcel"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/nanoid": {
|
||||||
|
"version": "3.3.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz",
|
||||||
|
"integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==",
|
||||||
|
"dev": true,
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/ai"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"bin": {
|
||||||
|
"nanoid": "bin/nanoid.cjs"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/picocolors": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "ISC"
|
||||||
|
},
|
||||||
|
"node_modules/picomatch": {
|
||||||
|
"version": "4.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
|
||||||
|
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/jonschlinkert"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/postcss": {
|
||||||
|
"version": "8.5.15",
|
||||||
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz",
|
||||||
|
"integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==",
|
||||||
|
"dev": true,
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/postcss/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "tidelift",
|
||||||
|
"url": "https://tidelift.com/funding/github/npm/postcss"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/ai"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"nanoid": "^3.3.12",
|
||||||
|
"picocolors": "^1.1.1",
|
||||||
|
"source-map-js": "^1.2.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^10 || ^12 || >=14"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/rolldown": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@oxc-project/types": "=0.133.0",
|
||||||
|
"@rolldown/pluginutils": "^1.0.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"rolldown": "bin/cli.mjs"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^20.19.0 || >=22.12.0"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@rolldown/binding-android-arm64": "1.0.3",
|
||||||
|
"@rolldown/binding-darwin-arm64": "1.0.3",
|
||||||
|
"@rolldown/binding-darwin-x64": "1.0.3",
|
||||||
|
"@rolldown/binding-freebsd-x64": "1.0.3",
|
||||||
|
"@rolldown/binding-linux-arm-gnueabihf": "1.0.3",
|
||||||
|
"@rolldown/binding-linux-arm64-gnu": "1.0.3",
|
||||||
|
"@rolldown/binding-linux-arm64-musl": "1.0.3",
|
||||||
|
"@rolldown/binding-linux-ppc64-gnu": "1.0.3",
|
||||||
|
"@rolldown/binding-linux-s390x-gnu": "1.0.3",
|
||||||
|
"@rolldown/binding-linux-x64-gnu": "1.0.3",
|
||||||
|
"@rolldown/binding-linux-x64-musl": "1.0.3",
|
||||||
|
"@rolldown/binding-openharmony-arm64": "1.0.3",
|
||||||
|
"@rolldown/binding-wasm32-wasi": "1.0.3",
|
||||||
|
"@rolldown/binding-win32-arm64-msvc": "1.0.3",
|
||||||
|
"@rolldown/binding-win32-x64-msvc": "1.0.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/source-map-js": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tinyglobby": {
|
||||||
|
"version": "0.2.17",
|
||||||
|
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz",
|
||||||
|
"integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"fdir": "^6.5.0",
|
||||||
|
"picomatch": "^4.0.4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/SuperchupuDev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tslib": {
|
||||||
|
"version": "2.8.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||||
|
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "0BSD",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"node_modules/vite": {
|
||||||
|
"version": "8.0.16",
|
||||||
|
"resolved": "https://registry.npmjs.org/vite/-/vite-8.0.16.tgz",
|
||||||
|
"integrity": "sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"lightningcss": "^1.32.0",
|
||||||
|
"picomatch": "^4.0.4",
|
||||||
|
"postcss": "^8.5.15",
|
||||||
|
"rolldown": "1.0.3",
|
||||||
|
"tinyglobby": "^0.2.17"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"vite": "bin/vite.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^20.19.0 || >=22.12.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/vitejs/vite?sponsor=1"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"fsevents": "~2.3.3"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/node": "^20.19.0 || >=22.12.0",
|
||||||
|
"@vitejs/devtools": "^0.1.18",
|
||||||
|
"esbuild": "^0.27.0 || ^0.28.0",
|
||||||
|
"jiti": ">=1.21.0",
|
||||||
|
"less": "^4.0.0",
|
||||||
|
"sass": "^1.70.0",
|
||||||
|
"sass-embedded": "^1.70.0",
|
||||||
|
"stylus": ">=0.54.8",
|
||||||
|
"sugarss": "^5.0.0",
|
||||||
|
"terser": "^5.16.0",
|
||||||
|
"tsx": "^4.8.1",
|
||||||
|
"yaml": "^2.4.2"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/node": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@vitejs/devtools": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"esbuild": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"jiti": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"less": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"sass": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"sass-embedded": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"stylus": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"sugarss": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"terser": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"tsx": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"yaml": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"name": "2026-worldcup",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"private": true,
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite",
|
||||||
|
"build": "vite build",
|
||||||
|
"preview": "vite preview"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"vite": "^8.0.12"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 9.3 KiB |
@@ -0,0 +1,24 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<symbol id="bluesky-icon" viewBox="0 0 16 17">
|
||||||
|
<g clip-path="url(#bluesky-clip)"><path fill="#08060d" d="M7.75 7.735c-.693-1.348-2.58-3.86-4.334-5.097-1.68-1.187-2.32-.981-2.74-.79C.188 2.065.1 2.812.1 3.251s.241 3.602.398 4.13c.52 1.744 2.367 2.333 4.07 2.145-2.495.37-4.71 1.278-1.805 4.512 3.196 3.309 4.38-.71 4.987-2.746.608 2.036 1.307 5.91 4.93 2.746 2.72-2.746.747-4.143-1.747-4.512 1.702.189 3.55-.4 4.07-2.145.156-.528.397-3.691.397-4.13s-.088-1.186-.575-1.406c-.42-.19-1.06-.395-2.741.79-1.755 1.24-3.64 3.752-4.334 5.099"/></g>
|
||||||
|
<defs><clipPath id="bluesky-clip"><path fill="#fff" d="M.1.85h15.3v15.3H.1z"/></clipPath></defs>
|
||||||
|
</symbol>
|
||||||
|
<symbol id="discord-icon" viewBox="0 0 20 19">
|
||||||
|
<path fill="#08060d" d="M16.224 3.768a14.5 14.5 0 0 0-3.67-1.153c-.158.286-.343.67-.47.976a13.5 13.5 0 0 0-4.067 0c-.128-.306-.317-.69-.476-.976A14.4 14.4 0 0 0 3.868 3.77C1.546 7.28.916 10.703 1.231 14.077a14.7 14.7 0 0 0 4.5 2.306q.545-.748.965-1.587a9.5 9.5 0 0 1-1.518-.74q.191-.14.372-.293c2.927 1.369 6.107 1.369 8.999 0q.183.152.372.294-.723.437-1.52.74.418.838.963 1.588a14.6 14.6 0 0 0 4.504-2.308c.37-3.911-.63-7.302-2.644-10.309m-9.13 8.234c-.878 0-1.599-.82-1.599-1.82 0-.998.705-1.82 1.6-1.82.894 0 1.614.82 1.599 1.82.001 1-.705 1.82-1.6 1.82m5.91 0c-.878 0-1.599-.82-1.599-1.82 0-.998.705-1.82 1.6-1.82.893 0 1.614.82 1.599 1.82 0 1-.706 1.82-1.6 1.82"/>
|
||||||
|
</symbol>
|
||||||
|
<symbol id="documentation-icon" viewBox="0 0 21 20">
|
||||||
|
<path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="m15.5 13.333 1.533 1.322c.645.555.967.833.967 1.178s-.322.623-.967 1.179L15.5 18.333m-3.333-5-1.534 1.322c-.644.555-.966.833-.966 1.178s.322.623.966 1.179l1.534 1.321"/>
|
||||||
|
<path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="M17.167 10.836v-4.32c0-1.41 0-2.117-.224-2.68-.359-.906-1.118-1.621-2.08-1.96-.599-.21-1.349-.21-2.848-.21-2.623 0-3.935 0-4.983.369-1.684.591-3.013 1.842-3.641 3.428C3 6.449 3 7.684 3 10.154v2.122c0 2.558 0 3.838.706 4.726q.306.383.713.671c.76.536 1.79.64 3.581.66"/>
|
||||||
|
<path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="M3 10a2.78 2.78 0 0 1 2.778-2.778c.555 0 1.209.097 1.748-.047.48-.129.854-.503.982-.982.145-.54.048-1.194.048-1.749a2.78 2.78 0 0 1 2.777-2.777"/>
|
||||||
|
</symbol>
|
||||||
|
<symbol id="github-icon" viewBox="0 0 19 19">
|
||||||
|
<path fill="#08060d" fill-rule="evenodd" d="M9.356 1.85C5.05 1.85 1.57 5.356 1.57 9.694a7.84 7.84 0 0 0 5.324 7.44c.387.079.528-.168.528-.376 0-.182-.013-.805-.013-1.454-2.165.467-2.616-.935-2.616-.935-.349-.91-.864-1.143-.864-1.143-.71-.48.051-.48.051-.48.787.051 1.2.805 1.2.805.695 1.194 1.817.857 2.268.649.064-.507.27-.857.49-1.052-1.728-.182-3.545-.857-3.545-3.87 0-.857.31-1.558.8-2.104-.078-.195-.349-1 .077-2.078 0 0 .657-.208 2.14.805a7.5 7.5 0 0 1 1.946-.26c.657 0 1.328.092 1.946.26 1.483-1.013 2.14-.805 2.14-.805.426 1.078.155 1.883.078 2.078.502.546.799 1.247.799 2.104 0 3.013-1.818 3.675-3.558 3.87.284.247.528.714.528 1.454 0 1.052-.012 1.896-.012 2.156 0 .208.142.455.528.377a7.84 7.84 0 0 0 5.324-7.441c.013-4.338-3.48-7.844-7.773-7.844" clip-rule="evenodd"/>
|
||||||
|
</symbol>
|
||||||
|
<symbol id="social-icon" viewBox="0 0 20 20">
|
||||||
|
<path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="M12.5 6.667a4.167 4.167 0 1 0-8.334 0 4.167 4.167 0 0 0 8.334 0"/>
|
||||||
|
<path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="M2.5 16.667a5.833 5.833 0 0 1 8.75-5.053m3.837.474.513 1.035c.07.144.257.282.414.309l.93.155c.596.1.736.536.307.965l-.723.73a.64.64 0 0 0-.152.531l.207.903c.164.715-.213.991-.84.618l-.872-.52a.63.63 0 0 0-.577 0l-.872.52c-.624.373-1.003.094-.84-.618l.207-.903a.64.64 0 0 0-.152-.532l-.723-.729c-.426-.43-.289-.864.306-.964l.93-.156a.64.64 0 0 0 .412-.31l.513-1.034c.28-.562.735-.562 1.012 0"/>
|
||||||
|
</symbol>
|
||||||
|
<symbol id="x-icon" viewBox="0 0 19 19">
|
||||||
|
<path fill="#08060d" fill-rule="evenodd" d="M1.893 1.98c.052.072 1.245 1.769 2.653 3.77l2.892 4.114c.183.261.333.48.333.486s-.068.089-.152.183l-.522.593-.765.867-3.597 4.087c-.375.426-.734.834-.798.905a1 1 0 0 0-.118.148c0 .01.236.017.664.017h.663l.729-.83c.4-.457.796-.906.879-.999a692 692 0 0 0 1.794-2.038c.034-.037.301-.34.594-.675l.551-.624.345-.392a7 7 0 0 1 .34-.374c.006 0 .93 1.306 2.052 2.903l2.084 2.965.045.063h2.275c1.87 0 2.273-.003 2.266-.021-.008-.02-1.098-1.572-3.894-5.547-2.013-2.862-2.28-3.246-2.273-3.266.008-.019.282-.332 2.085-2.38l2-2.274 1.567-1.782c.022-.028-.016-.03-.65-.03h-.674l-.3.342a871 871 0 0 1-1.782 2.025c-.067.075-.405.458-.75.852a100 100 0 0 1-.803.91c-.148.172-.299.344-.99 1.127-.304.343-.32.358-.345.327-.015-.019-.904-1.282-1.976-2.808L6.365 1.85H1.8zm1.782.91 8.078 11.294c.772 1.08 1.413 1.973 1.425 1.984.016.017.241.02 1.05.017l1.03-.004-2.694-3.766L7.796 5.75 5.722 2.852l-1.039-.004-1.039-.004z" clip-rule="evenodd"/>
|
||||||
|
</symbol>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 4.9 KiB |
|
After Width: | Height: | Size: 709 KiB |
|
After Width: | Height: | Size: 13 KiB |
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="32" height="32" viewBox="0 0 256 256"><path fill="#F7DF1E" d="M0 0h256v256H0V0Z"/><path d="m67.312 213.932l19.59-11.856c3.78 6.701 7.218 12.371 15.465 12.371c7.905 0 12.89-3.092 12.89-15.12v-81.798h24.057v82.138c0 24.917-14.606 36.259-35.916 36.259c-19.245 0-30.416-9.967-36.087-21.996m85.07-2.576l19.588-11.341c5.157 8.421 11.859 14.607 23.715 14.607c9.969 0 16.325-4.984 16.325-11.858c0-8.248-6.53-11.17-17.528-15.98l-6.013-2.58c-17.357-7.387-28.87-16.667-28.87-36.257c0-18.044 13.747-31.792 35.228-31.792c15.294 0 26.292 5.328 34.196 19.247l-18.732 12.03c-4.125-7.389-8.591-10.31-15.465-10.31c-7.046 0-11.514 4.468-11.514 10.31c0 7.217 4.468 10.14 14.778 14.608l6.014 2.577c20.45 8.765 31.963 17.7 31.963 37.804c0 21.654-17.012 33.51-39.867 33.51c-22.339 0-36.774-10.654-43.819-24.574"/></svg>
|
||||||
|
After Width: | Height: | Size: 863 B |
|
After Width: | Height: | Size: 8.5 KiB |
@@ -0,0 +1,9 @@
|
|||||||
|
export function setupCounter(element) {
|
||||||
|
let counter = 0
|
||||||
|
const setCounter = (count) => {
|
||||||
|
counter = count
|
||||||
|
element.innerHTML = `Count is ${counter}`
|
||||||
|
}
|
||||||
|
element.addEventListener('click', () => setCounter(counter + 1))
|
||||||
|
setCounter(0)
|
||||||
|
}
|
||||||
@@ -0,0 +1,250 @@
|
|||||||
|
// 2026 FIFA World Cup – All 48 teams in 12 groups + Match Schedule
|
||||||
|
// Confederations: UEFA, CONMEBOL, AFC, CAF, CONCACAF, OFC
|
||||||
|
// Group stage: June 11 – June 27, 2026
|
||||||
|
|
||||||
|
export const venues = {
|
||||||
|
'Mexico City': { city: 'Mexico City', country: '🇲🇽 Mexico', stadium: 'Estadio Azteca', capacity: '87,523' },
|
||||||
|
'Guadalajara': { city: 'Guadalajara', country: '🇲🇽 Mexico', stadium: 'Estadio Akron', capacity: '49,850' },
|
||||||
|
'Monterrey': { city: 'Monterrey', country: '🇲🇽 Mexico', stadium: 'Estadio BBVA', capacity: '53,500' },
|
||||||
|
'Toronto': { city: 'Toronto', country: '🇨🇦 Canada', stadium: 'BMO Field', capacity: '45,000' },
|
||||||
|
'Vancouver': { city: 'Vancouver', country: '🇨🇦 Canada', stadium: 'BC Place', capacity: '54,500' },
|
||||||
|
'Kansas City': { city: 'Kansas City', country: '🇺🇸 USA', stadium: 'Arrowhead Stadium', capacity: '76,416' },
|
||||||
|
'Los Angeles': { city: 'Los Angeles', country: '🇺🇸 USA', stadium: 'SoFi Stadium', capacity: '70,240' },
|
||||||
|
'San Francisco': { city: 'San Francisco', country: '🇺🇸 USA', stadium: 'Levi\'s Stadium', capacity: '68,500' },
|
||||||
|
'Seattle': { city: 'Seattle', country: '🇺🇸 USA', stadium: 'Lumen Field', capacity: '69,000' },
|
||||||
|
'Dallas': { city: 'Dallas', country: '🇺🇸 USA', stadium: 'AT&T Stadium', capacity: '80,000' },
|
||||||
|
'Atlanta': { city: 'Atlanta', country: '🇺🇸 USA', stadium: 'Mercedes-Benz Stadium', capacity: '71,000' },
|
||||||
|
'Miami': { city: 'Miami', country: '🇺🇸 USA', stadium: 'Hard Rock Stadium', capacity: '65,326' },
|
||||||
|
'New York': { city: 'New York / New Jersey', country: '🇺🇸 USA', stadium: 'MetLife Stadium', capacity: '82,500' },
|
||||||
|
'Boston': { city: 'Boston', country: '🇺🇸 USA', stadium: 'Gillette Stadium', capacity: '65,878' },
|
||||||
|
'Philadelphia': { city: 'Philadelphia', country: '🇺🇸 USA', stadium: 'Lincoln Financial Field', capacity: '69,796' },
|
||||||
|
'Houston': { city: 'Houston', country: '🇺🇸 USA', stadium: 'NRG Stadium', capacity: '72,220' },
|
||||||
|
};
|
||||||
|
|
||||||
|
export const groups = [
|
||||||
|
{
|
||||||
|
id: 'A',
|
||||||
|
color: '#e74c3c',
|
||||||
|
teams: [
|
||||||
|
{ name: 'Mexico', flag: '🇲🇽', confederation: 'CONCACAF', isHost: true },
|
||||||
|
{ name: 'South Africa', flag: '🇿🇦', confederation: 'CAF', isHost: false },
|
||||||
|
{ name: 'South Korea', flag: '🇰🇷', confederation: 'AFC', isHost: false },
|
||||||
|
{ 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: '16: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' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'B',
|
||||||
|
color: '#e67e22',
|
||||||
|
teams: [
|
||||||
|
{ name: 'Canada', flag: '🇨🇦', confederation: 'CONCACAF', isHost: true },
|
||||||
|
{ name: 'Bosnia & Herzegovina', flag: '🇧🇦', confederation: 'UEFA', isHost: false },
|
||||||
|
{ name: 'Qatar', flag: '🇶🇦', confederation: 'AFC', isHost: false },
|
||||||
|
{ name: 'Switzerland', flag: '🇨🇭', confederation: 'UEFA', isHost: false },
|
||||||
|
],
|
||||||
|
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' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'C',
|
||||||
|
color: '#f1c40f',
|
||||||
|
teams: [
|
||||||
|
{ name: 'Brazil', flag: '🇧🇷', confederation: 'CONMEBOL', isHost: false },
|
||||||
|
{ name: 'Morocco', flag: '🇲🇦', confederation: 'CAF', isHost: false },
|
||||||
|
{ name: 'Haiti', flag: '🇭🇹', confederation: 'CONCACAF', isHost: false },
|
||||||
|
{ name: 'Scotland', flag: '🏴', confederation: 'UEFA', isHost: false },
|
||||||
|
],
|
||||||
|
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' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'D',
|
||||||
|
color: '#2ecc71',
|
||||||
|
teams: [
|
||||||
|
{ name: 'United States', flag: '🇺🇸', confederation: 'CONCACAF', isHost: true },
|
||||||
|
{ name: 'Paraguay', flag: '🇵🇾', confederation: 'CONMEBOL', isHost: false },
|
||||||
|
{ name: 'Australia', flag: '🇦🇺', confederation: 'AFC', isHost: false },
|
||||||
|
{ 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' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'E',
|
||||||
|
color: '#1abc9c',
|
||||||
|
teams: [
|
||||||
|
{ name: 'Germany', flag: '🇩🇪', confederation: 'UEFA', isHost: false },
|
||||||
|
{ name: 'Curaçao', flag: '🇨🇼', confederation: 'CONCACAF', isHost: false },
|
||||||
|
{ name: "Côte d'Ivoire", flag: '🇨🇮', confederation: 'CAF', isHost: false },
|
||||||
|
{ name: 'Ecuador', flag: '🇪🇨', confederation: 'CONMEBOL', isHost: false },
|
||||||
|
],
|
||||||
|
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' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'F',
|
||||||
|
color: '#3498db',
|
||||||
|
teams: [
|
||||||
|
{ name: 'Netherlands', flag: '🇳🇱', confederation: 'UEFA', isHost: false },
|
||||||
|
{ name: 'Japan', flag: '🇯🇵', confederation: 'AFC', isHost: false },
|
||||||
|
{ name: 'Sweden', flag: '🇸🇪', confederation: 'UEFA', isHost: false },
|
||||||
|
{ name: 'Tunisia', flag: '🇹🇳', confederation: 'CAF', isHost: false },
|
||||||
|
],
|
||||||
|
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' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'G',
|
||||||
|
color: '#9b59b6',
|
||||||
|
teams: [
|
||||||
|
{ name: 'Belgium', flag: '🇧🇪', confederation: 'UEFA', isHost: false },
|
||||||
|
{ name: 'Egypt', flag: '🇪🇬', confederation: 'CAF', isHost: false },
|
||||||
|
{ name: 'Iran', flag: '🇮🇷', confederation: 'AFC', isHost: false },
|
||||||
|
{ name: 'New Zealand', flag: '🇳🇿', confederation: 'OFC', isHost: false },
|
||||||
|
],
|
||||||
|
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' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'H',
|
||||||
|
color: '#e91e63',
|
||||||
|
teams: [
|
||||||
|
{ name: 'Spain', flag: '🇪🇸', confederation: 'UEFA', isHost: false },
|
||||||
|
{ name: 'Cape Verde', flag: '🇨🇻', confederation: 'CAF', isHost: false },
|
||||||
|
{ name: 'Saudi Arabia', flag: '🇸🇦', confederation: 'AFC', isHost: false },
|
||||||
|
{ name: 'Uruguay', flag: '🇺🇾', confederation: 'CONMEBOL', isHost: false },
|
||||||
|
],
|
||||||
|
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' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'I',
|
||||||
|
color: '#00bcd4',
|
||||||
|
teams: [
|
||||||
|
{ name: 'France', flag: '🇫🇷', confederation: 'UEFA', isHost: false },
|
||||||
|
{ name: 'Senegal', flag: '🇸🇳', confederation: 'CAF', isHost: false },
|
||||||
|
{ name: 'Iraq', flag: '🇮🇶', confederation: 'AFC', isHost: false },
|
||||||
|
{ name: 'Norway', flag: '🇳🇴', confederation: 'UEFA', isHost: false },
|
||||||
|
],
|
||||||
|
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' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'J',
|
||||||
|
color: '#ff9800',
|
||||||
|
teams: [
|
||||||
|
{ name: 'Argentina', flag: '🇦🇷', confederation: 'CONMEBOL', isHost: false },
|
||||||
|
{ name: 'Algeria', flag: '🇩🇿', confederation: 'CAF', isHost: false },
|
||||||
|
{ name: 'Austria', flag: '🇦🇹', confederation: 'UEFA', isHost: false },
|
||||||
|
{ name: 'Jordan', flag: '🇯🇴', confederation: 'AFC', isHost: false },
|
||||||
|
],
|
||||||
|
matches: [
|
||||||
|
{ matchday: 1, home: 'Argentina', away: 'Algeria', date: 'Wed, Jun 17', time: '16:00', venue: 'Dallas' },
|
||||||
|
{ matchday: 1, home: 'Austria', away: 'Jordan', date: 'Wed, Jun 17', time: '19:00', venue: 'Miami' },
|
||||||
|
{ matchday: 2, home: 'Argentina', away: 'Jordan', date: 'Sun, Jun 21', time: '19:00', venue: 'Houston' },
|
||||||
|
{ matchday: 2, home: 'Algeria', away: 'Austria', date: 'Sun, Jun 21', time: '22:00', venue: 'San Francisco'},
|
||||||
|
{ matchday: 3, home: 'Argentina', away: 'Austria', date: 'Thu, Jun 25', time: '22:00', venue: 'Atlanta' },
|
||||||
|
{ matchday: 3, home: 'Jordan', away: 'Algeria', date: 'Thu, Jun 25', time: '22:00', venue: 'Seattle' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'K',
|
||||||
|
color: '#4caf50',
|
||||||
|
teams: [
|
||||||
|
{ name: 'Portugal', flag: '🇵🇹', confederation: 'UEFA', isHost: false },
|
||||||
|
{ name: 'DR Congo', flag: '🇨🇩', confederation: 'CAF', isHost: false },
|
||||||
|
{ name: 'Uzbekistan', flag: '🇺🇿', confederation: 'AFC', isHost: false },
|
||||||
|
{ name: 'Colombia', flag: '🇨🇴', confederation: 'CONMEBOL', isHost: false },
|
||||||
|
],
|
||||||
|
matches: [
|
||||||
|
{ matchday: 1, home: 'Portugal', away: 'DR Congo', date: 'Thu, Jun 18', time: '16:00', venue: 'Kansas City' },
|
||||||
|
{ matchday: 1, home: 'Colombia', away: 'Uzbekistan', date: 'Thu, Jun 18', time: '22:00', venue: 'Los Angeles' },
|
||||||
|
{ matchday: 2, home: 'Portugal', away: 'Uzbekistan', date: 'Mon, Jun 22', time: '16:00', venue: 'San Francisco'},
|
||||||
|
{ matchday: 2, home: 'DR Congo', away: 'Colombia', date: 'Mon, Jun 22', time: '22:00', venue: 'Boston' },
|
||||||
|
{ matchday: 3, home: 'Portugal', away: 'Colombia', date: 'Fri, Jun 26', time: '18:00', venue: 'Philadelphia'},
|
||||||
|
{ matchday: 3, home: 'Uzbekistan', away: 'DR Congo', date: 'Fri, Jun 26', time: '18:00', venue: 'Dallas' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'L',
|
||||||
|
color: '#795548',
|
||||||
|
teams: [
|
||||||
|
{ name: 'England', flag: '🏴', confederation: 'UEFA', isHost: false },
|
||||||
|
{ name: 'Croatia', flag: '🇭🇷', confederation: 'UEFA', isHost: false },
|
||||||
|
{ name: 'Ghana', flag: '🇬🇭', confederation: 'CAF', isHost: false },
|
||||||
|
{ 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' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export const confederationColors = {
|
||||||
|
UEFA: { bg: '#1a3a6e', label: 'UEFA', accent: '#4a90d9' },
|
||||||
|
CONMEBOL: { bg: '#1a5c2e', label: 'CONMEBOL', accent: '#4caf50' },
|
||||||
|
AFC: { bg: '#1a4a6e', label: 'AFC', accent: '#00bcd4' },
|
||||||
|
CAF: { bg: '#5c3a1a', label: 'CAF', accent: '#ff9800' },
|
||||||
|
CONCACAF: { bg: '#5c1a3a', label: 'CONCACAF', accent: '#e91e63' },
|
||||||
|
OFC: { bg: '#1a3a5c', label: 'OFC', accent: '#9c27b0' },
|
||||||
|
};
|
||||||
@@ -0,0 +1,399 @@
|
|||||||
|
import './style.css';
|
||||||
|
import { groups, confederationColors, venues } from './data.js';
|
||||||
|
import { getSquad } from './squads.js';
|
||||||
|
|
||||||
|
console.log('[WC2026] Loaded groups:', groups.length, '| First group matches:', groups[0]?.matches?.length);
|
||||||
|
|
||||||
|
// ── State ──────────────────────────────────────────────────────────────────
|
||||||
|
let activeFilter = 'all';
|
||||||
|
let searchQuery = '';
|
||||||
|
|
||||||
|
// ── Helpers ────────────────────────────────────────────────────────────────
|
||||||
|
function confBadge(confederation) {
|
||||||
|
const c = confederationColors[confederation];
|
||||||
|
return `<span class="conf-badge" style="background:${c.bg};color:${c.accent}">${confederation}</span>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function teamCard(team) {
|
||||||
|
const hostBadge = team.isHost ? '<span class="host-badge">🏟️ Host</span>' : '';
|
||||||
|
return `
|
||||||
|
<div class="team-card">
|
||||||
|
<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>
|
||||||
|
</div>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function groupCard(group) {
|
||||||
|
const teamsHTML = group.teams.map(teamCard).join('');
|
||||||
|
const matchCount = group.matches ? group.matches.length : 0;
|
||||||
|
return `
|
||||||
|
<article class="group-card" data-group="${group.id}">
|
||||||
|
<div class="group-header" style="--group-color:${group.color}">
|
||||||
|
<div class="group-label-wrapper">
|
||||||
|
<span class="group-letter" style="color:${group.color}">GROUP</span>
|
||||||
|
<h2 class="group-id">${group.id}</h2>
|
||||||
|
</div>
|
||||||
|
<div class="group-right">
|
||||||
|
<span class="match-count">${matchCount} matches</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>
|
||||||
|
</div>
|
||||||
|
</article>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Helpers ────────────────────────────────────────────────────────────────
|
||||||
|
function buildMatchdayHTML(group) {
|
||||||
|
const matchdayNames = { 1: 'Matchday 1', 2: 'Matchday 2', 3: 'Matchday 3' };
|
||||||
|
return [1, 2, 3].map(md => {
|
||||||
|
const dayMatches = group.matches.filter(m => m.matchday === md);
|
||||||
|
const matchesHTML = dayMatches.map((match, idx) => {
|
||||||
|
const venue = venues[match.venue];
|
||||||
|
const home = group.teams.find(t => t.name === match.home);
|
||||||
|
const away = group.teams.find(t => t.name === match.away);
|
||||||
|
const cardId = `match-${group.id}-${md}-${idx}`;
|
||||||
|
return `
|
||||||
|
<div class="match-card" style="--match-color:${group.color}" id="${cardId}">
|
||||||
|
<button class="match-summary" onclick="toggleMatch('${cardId}')" aria-expanded="false">
|
||||||
|
<div class="match-team-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>
|
||||||
|
<span class="mc-chevron">›</span>
|
||||||
|
</div>
|
||||||
|
<div class="match-team-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">
|
||||||
|
<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</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>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
}).join('');
|
||||||
|
return `<div class="matchday-section"><div class="matchday-label">${matchdayNames[md]}</div>${matchesHTML}</div>`;
|
||||||
|
}).join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildSquadHTML(group) {
|
||||||
|
const posOrder = ['GK', 'DF', 'MF', 'FW'];
|
||||||
|
const posLabels = { GK: '🧤 Goalkeepers', DF: '🛡️ Defenders', MF: '⚙️ Midfielders', FW: '⚡ Forwards' };
|
||||||
|
|
||||||
|
return group.teams.map(team => {
|
||||||
|
const squad = getSquad(team.name);
|
||||||
|
if (!squad) {
|
||||||
|
return `
|
||||||
|
<div class="squad-team">
|
||||||
|
<div class="squad-team-header"><span class="squad-flag">${team.flag}</span><span class="squad-team-name">${team.name}</span></div>
|
||||||
|
<p class="squad-unavailable">Squad details coming soon</p>
|
||||||
|
</div>`;
|
||||||
|
}
|
||||||
|
const byPos = {};
|
||||||
|
squad.forEach(p => { if (!byPos[p.pos]) byPos[p.pos] = []; byPos[p.pos].push(p); });
|
||||||
|
const posHTML = posOrder.filter(p => byPos[p]).map(pos => `
|
||||||
|
<div class="squad-pos-group">
|
||||||
|
<div class="squad-pos-label">${posLabels[pos]}</div>
|
||||||
|
<div class="squad-players">
|
||||||
|
${byPos[pos].map(p => `
|
||||||
|
<div class="squad-player">
|
||||||
|
<span class="player-pos-badge player-pos-${p.pos}">${p.pos}</span>
|
||||||
|
<div class="player-info">
|
||||||
|
<span class="player-name">${p.name}</span>
|
||||||
|
<span class="player-club">${p.club}</span>
|
||||||
|
</div>
|
||||||
|
</div>`).join('')}
|
||||||
|
</div>
|
||||||
|
</div>`).join('');
|
||||||
|
return `
|
||||||
|
<div class="squad-team">
|
||||||
|
<div class="squad-team-header">
|
||||||
|
<span class="squad-flag">${team.flag}</span>
|
||||||
|
<span class="squad-team-name">${team.name}</span>
|
||||||
|
<span class="squad-count">${squad.length} players</span>
|
||||||
|
</div>
|
||||||
|
${posHTML}
|
||||||
|
</div>`;
|
||||||
|
}).join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Modal ──────────────────────────────────────────────────────────────────
|
||||||
|
function openModal(group) {
|
||||||
|
if (!group || !group.matches || group.matches.length === 0) return;
|
||||||
|
|
||||||
|
const teamsHTML = group.teams.map(t =>
|
||||||
|
`<div class="modal-team-chip"><span>${t.flag}</span><span>${t.name}</span></div>`
|
||||||
|
).join('');
|
||||||
|
|
||||||
|
const modal = document.getElementById('modal');
|
||||||
|
modal.innerHTML = `
|
||||||
|
<div class="modal-backdrop" id="modal-backdrop"></div>
|
||||||
|
<div class="modal-box">
|
||||||
|
<div class="modal-header" style="--group-color:${group.color}">
|
||||||
|
<div class="modal-title-wrap">
|
||||||
|
<span class="modal-group-label">GROUP</span>
|
||||||
|
<span class="modal-group-id" style="color:${group.color}">${group.id}</span>
|
||||||
|
</div>
|
||||||
|
<div class="modal-teams-row">${teamsHTML}</div>
|
||||||
|
<button class="modal-close" id="modal-close">✕</button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-tabs">
|
||||||
|
<button class="modal-tab active" id="tab-schedule" onclick="switchTab('schedule')">📅 Schedule</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-squad" class="tab-content">
|
||||||
|
${buildSquadHTML(group)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
modal.classList.add('open');
|
||||||
|
document.body.style.overflow = 'hidden';
|
||||||
|
document.getElementById('modal-close').onclick = closeModal;
|
||||||
|
document.getElementById('modal-backdrop').onclick = closeModal;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Tab switch ─────────────────────────────────────────────────────────────
|
||||||
|
window.switchTab = function(tab) {
|
||||||
|
document.querySelectorAll('.modal-tab').forEach(b => b.classList.remove('active'));
|
||||||
|
document.querySelectorAll('.tab-content').forEach(c => c.classList.remove('active'));
|
||||||
|
document.getElementById('tab-' + tab)?.classList.add('active');
|
||||||
|
document.getElementById('tab-content-' + tab)?.classList.add('active');
|
||||||
|
document.getElementById('modal-body')?.scrollTo({ top: 0, behavior: 'smooth' });
|
||||||
|
};
|
||||||
|
|
||||||
|
function closeModal() {
|
||||||
|
const modal = document.getElementById('modal');
|
||||||
|
if (modal) {
|
||||||
|
modal.classList.remove('open');
|
||||||
|
document.body.style.overflow = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Accordion toggle ───────────────────────────────────────────────────────
|
||||||
|
window.toggleMatch = function(cardId) {
|
||||||
|
const card = document.getElementById(cardId);
|
||||||
|
if (!card) return;
|
||||||
|
const isOpen = card.classList.contains('expanded');
|
||||||
|
// Close all others in same group first
|
||||||
|
card.closest('.matchdays')?.querySelectorAll('.match-card.expanded').forEach(c => {
|
||||||
|
c.classList.remove('expanded');
|
||||||
|
c.querySelector('.match-summary')?.setAttribute('aria-expanded', 'false');
|
||||||
|
});
|
||||||
|
if (!isOpen) {
|
||||||
|
card.classList.add('expanded');
|
||||||
|
card.querySelector('.match-summary')?.setAttribute('aria-expanded', 'true');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// ── Render ─────────────────────────────────────────────────────────────────
|
||||||
|
function render() {
|
||||||
|
const grid = document.getElementById('groups-grid');
|
||||||
|
if (!grid) return;
|
||||||
|
|
||||||
|
const filteredGroups = groups.map(group => {
|
||||||
|
let filteredTeams = group.teams;
|
||||||
|
if (activeFilter !== 'all') {
|
||||||
|
filteredTeams = filteredTeams.filter(t => t.confederation === activeFilter);
|
||||||
|
}
|
||||||
|
if (searchQuery) {
|
||||||
|
filteredTeams = filteredTeams.filter(t =>
|
||||||
|
t.name.toLowerCase().includes(searchQuery.toLowerCase())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return { ...group, teams: filteredTeams };
|
||||||
|
}).filter(g => g.teams.length > 0);
|
||||||
|
|
||||||
|
if (filteredGroups.length === 0) {
|
||||||
|
grid.innerHTML = `<div class="no-results"><div class="no-results-icon">🔍</div><p>No teams found.</p></div>`;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
grid.innerHTML = filteredGroups.map(groupCard).join('');
|
||||||
|
|
||||||
|
// Animate cards in
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
document.querySelectorAll('.group-card').forEach((card, i) => {
|
||||||
|
card.style.animationDelay = `${i * 60}ms`;
|
||||||
|
card.classList.add('animate-in');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Global click handler (set ONCE on document.body) ──────────────────────
|
||||||
|
function setupGlobalClick() {
|
||||||
|
document.body.addEventListener('click', (e) => {
|
||||||
|
const card = e.target.closest('.group-card');
|
||||||
|
if (card) {
|
||||||
|
const groupId = card.dataset.group;
|
||||||
|
const group = groups.find(g => g.id === groupId);
|
||||||
|
console.log('[WC2026] Card clicked, groupId:', groupId, 'found:', !!group);
|
||||||
|
openModal(group);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Filter buttons ─────────────────────────────────────────────────────────
|
||||||
|
function setupFilters() {
|
||||||
|
document.querySelectorAll('.filter-btn').forEach(btn => {
|
||||||
|
btn.addEventListener('click', () => {
|
||||||
|
document.querySelectorAll('.filter-btn').forEach(b => b.classList.remove('active'));
|
||||||
|
btn.classList.add('active');
|
||||||
|
activeFilter = btn.dataset.filter;
|
||||||
|
render();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Search ─────────────────────────────────────────────────────────────────
|
||||||
|
function setupSearch() {
|
||||||
|
const input = document.getElementById('search-input');
|
||||||
|
if (!input) return;
|
||||||
|
input.addEventListener('input', (e) => {
|
||||||
|
searchQuery = e.target.value.trim();
|
||||||
|
render();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Sticky header shadow ───────────────────────────────────────────────────
|
||||||
|
function setupScrollBehavior() {
|
||||||
|
const filterBar = document.getElementById('filter-bar');
|
||||||
|
if (!filterBar) return;
|
||||||
|
window.addEventListener('scroll', () => {
|
||||||
|
filterBar.classList.toggle('scrolled', window.scrollY > 80);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── ESC to close modal ─────────────────────────────────────────────────────
|
||||||
|
function setupKeyboard() {
|
||||||
|
document.addEventListener('keydown', (e) => {
|
||||||
|
if (e.key === 'Escape') closeModal();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Count up animation ─────────────────────────────────────────────────────
|
||||||
|
function animateCounters() {
|
||||||
|
document.querySelectorAll('.stat-number[data-target]').forEach(el => {
|
||||||
|
const target = +el.dataset.target;
|
||||||
|
let current = 0;
|
||||||
|
const step = Math.ceil(target / 40);
|
||||||
|
const timer = setInterval(() => {
|
||||||
|
current = Math.min(current + step, target);
|
||||||
|
el.textContent = current;
|
||||||
|
if (current >= target) clearInterval(timer);
|
||||||
|
}, 30);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Build the shell HTML ───────────────────────────────────────────────────
|
||||||
|
function buildShell() {
|
||||||
|
const app = document.getElementById('app');
|
||||||
|
app.innerHTML = `
|
||||||
|
<header class="site-header">
|
||||||
|
<button class="theme-toggle-btn" id="theme-toggle" aria-label="Toggle Theme">🌙</button>
|
||||||
|
<div class="header-content">
|
||||||
|
<div class="trophy-wrap">
|
||||||
|
<span class="trophy-icon">🏆</span>
|
||||||
|
<div class="trophy-glow"></div>
|
||||||
|
</div>
|
||||||
|
<h1 class="site-title">FIFA World Cup <span class="year">2026</span></h1>
|
||||||
|
<p class="site-subtitle">Canada · Mexico · United States</p>
|
||||||
|
<p class="site-dates">June 11 – July 19, 2026</p>
|
||||||
|
<div class="stats-bar">
|
||||||
|
<div class="stat-item"><span class="stat-number" data-target="48">0</span><span class="stat-label">Teams</span></div>
|
||||||
|
<div class="stat-divider"></div>
|
||||||
|
<div class="stat-item"><span class="stat-number" data-target="12">0</span><span class="stat-label">Groups</span></div>
|
||||||
|
<div class="stat-divider"></div>
|
||||||
|
<div class="stat-item"><span class="stat-number" data-target="72">0</span><span class="stat-label">Matches</span></div>
|
||||||
|
<div class="stat-divider"></div>
|
||||||
|
<div class="stat-item"><span class="stat-number" data-target="16">0</span><span class="stat-label">Host Cities</span></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div class="controls-bar" id="filter-bar">
|
||||||
|
<div class="controls-inner">
|
||||||
|
<div class="search-wrap">
|
||||||
|
<span class="search-icon">🔍</span>
|
||||||
|
<input type="text" id="search-input" class="search-input" placeholder="Search team…" autocomplete="off" spellcheck="false" />
|
||||||
|
</div>
|
||||||
|
<nav class="filter-nav">
|
||||||
|
<button class="filter-btn active" data-filter="all">🌍 All</button>
|
||||||
|
<button class="filter-btn" data-filter="UEFA">🇪🇺 UEFA</button>
|
||||||
|
<button class="filter-btn" data-filter="CONMEBOL">🌎 CONMEBOL</button>
|
||||||
|
<button class="filter-btn" data-filter="AFC">🌏 AFC</button>
|
||||||
|
<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>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<main class="main-content">
|
||||||
|
<div class="groups-grid" id="groups-grid"></div>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<div id="modal" class="modal-container"></div>
|
||||||
|
|
||||||
|
<footer class="site-footer">
|
||||||
|
<div class="footer-inner">
|
||||||
|
<p class="footer-main">🏆 FIFA World Cup 2026 · Official Group Stage Draw</p>
|
||||||
|
<p class="footer-sub">December 5, 2025 · Washington D.C. · First World Cup with 48 teams</p>
|
||||||
|
<p class="footer-debut">🌟 Tournament Debuts: Cape Verde · Curaçao · Jordan · Uzbekistan</p>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Theme Logic ────────────────────────────────────────────────────────────
|
||||||
|
function setupTheme() {
|
||||||
|
const btn = document.getElementById('theme-toggle');
|
||||||
|
|
||||||
|
// Default to dark theme if no preference is saved
|
||||||
|
let currentTheme = localStorage.getItem('wc2026-theme') || 'dark';
|
||||||
|
applyTheme(currentTheme);
|
||||||
|
|
||||||
|
btn.addEventListener('click', () => {
|
||||||
|
currentTheme = currentTheme === 'light' ? 'dark' : 'light';
|
||||||
|
applyTheme(currentTheme);
|
||||||
|
localStorage.setItem('wc2026-theme', currentTheme);
|
||||||
|
});
|
||||||
|
|
||||||
|
function applyTheme(theme) {
|
||||||
|
if (theme === 'dark') {
|
||||||
|
document.documentElement.setAttribute('data-theme', 'dark');
|
||||||
|
btn.innerText = '☀️'; // Button shows option to switch to light
|
||||||
|
} else {
|
||||||
|
document.documentElement.removeAttribute('data-theme');
|
||||||
|
btn.innerText = '🌙'; // Button shows option to switch to dark
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Init ───────────────────────────────────────────────────────────────────
|
||||||
|
buildShell();
|
||||||
|
setupTheme();
|
||||||
|
setupGlobalClick(); // ← set ONCE after shell exists, never re-added
|
||||||
|
render();
|
||||||
|
setupFilters();
|
||||||
|
setupSearch();
|
||||||
|
setupScrollBehavior();
|
||||||
|
setupKeyboard();
|
||||||
|
animateCounters();
|
||||||
@@ -0,0 +1,646 @@
|
|||||||
|
// 2026 FIFA World Cup – Squads (official, confirmed June 2, 2026)
|
||||||
|
// Position codes: GK = Goalkeeper, DF = Defender, MF = Midfielder, FW = Forward
|
||||||
|
|
||||||
|
export const squads = {
|
||||||
|
|
||||||
|
// ── GROUP A ────────────────────────────────────────────────────────────────
|
||||||
|
'Mexico': [
|
||||||
|
{ name: 'Guillermo Ochoa', pos: 'GK', club: 'Salernitana' },
|
||||||
|
{ name: 'Luis Malagón', pos: 'GK', club: 'Club América' },
|
||||||
|
{ name: 'Raúl Rangel', pos: 'GK', club: 'Chivas' },
|
||||||
|
{ name: 'Julián Araujo', pos: 'DF', club: 'Bournemouth' },
|
||||||
|
{ name: 'Kevin Álvarez', pos: 'DF', club: 'Club América' },
|
||||||
|
{ name: 'Jesús Gallardo', pos: 'DF', club: 'Monterrey' },
|
||||||
|
{ name: 'Johan Vásquez', pos: 'DF', club: 'Genoa' },
|
||||||
|
{ name: 'Cesar Montes', pos: 'DF', club: 'Espanyol' },
|
||||||
|
{ name: 'Jorge Sánchez', pos: 'DF', club: 'Ajax' },
|
||||||
|
{ name: 'Edson Álvarez', pos: 'MF', club: 'West Ham' },
|
||||||
|
{ name: 'Carlos Rodríguez', pos: 'MF', club: 'Cruz Azul' },
|
||||||
|
{ name: 'Luis Romo', pos: 'MF', club: 'Monterrey' },
|
||||||
|
{ name: 'Orbelín Pineda', pos: 'MF', club: 'AEK Athens' },
|
||||||
|
{ name: 'Héctor Herrera', pos: 'MF', club: 'LA Galaxy' },
|
||||||
|
{ name: 'Roberto Alvarado', pos: 'MF', club: 'Chivas' },
|
||||||
|
{ name: 'Alexis Vega', pos: 'FW', club: 'Chivas' },
|
||||||
|
{ name: 'Hirving Lozano', pos: 'FW', club: 'PSV' },
|
||||||
|
{ name: 'Santiago Giménez', pos: 'FW', club: 'AC Milan' },
|
||||||
|
{ name: 'Henry Martín', pos: 'FW', club: 'Club América' },
|
||||||
|
{ name: 'Raúl Jiménez', pos: 'FW', club: 'Fulham' },
|
||||||
|
{ name: 'Uriel Antuna', pos: 'FW', club: 'Cruz Azul' },
|
||||||
|
{ name: 'Charly Rodríguez', pos: 'MF', club: 'Tigres' },
|
||||||
|
{ name: 'Gerardo Arteaga', pos: 'DF', club: 'Getafe' },
|
||||||
|
{ name: 'Alan Mozo', pos: 'DF', club: 'Pumas UNAM' },
|
||||||
|
{ name: 'Fernando Beltrán', pos: 'MF', club: 'Chivas' },
|
||||||
|
{ name: 'Jonathan Rodríguez', pos: 'FW', club: 'Cruz Azul' },
|
||||||
|
],
|
||||||
|
'South Africa': [
|
||||||
|
{ name: 'Ronwen Williams', pos: 'GK', club: 'Mamelodi Sundowns' },
|
||||||
|
{ name: 'Veli Mothwa', pos: 'GK', club: 'AmaZulu' },
|
||||||
|
{ name: 'Bruce Bvuma', pos: 'GK', club: 'Kaizer Chiefs' },
|
||||||
|
{ name: 'Sifiso Hlanti', pos: 'DF', club: 'Kaizer Chiefs' },
|
||||||
|
{ name: 'Terrence Mashego', pos: 'DF', club: 'Cape Town City' },
|
||||||
|
{ name: 'Reeve Frosler', pos: 'DF', club: 'Kaizer Chiefs' },
|
||||||
|
{ name: 'Mothobi Mvala', pos: 'DF', club: 'Mamelodi Sundowns' },
|
||||||
|
{ name: 'Rushine De Reuck', pos: 'DF', club: 'Mamelodi Sundowns' },
|
||||||
|
{ name: 'Njabulo Ngcobo', pos: 'DF', club: 'Kaizer Chiefs' },
|
||||||
|
{ name: 'Teboho Mokoena', pos: 'MF', club: 'Mamelodi Sundowns' },
|
||||||
|
{ name: 'Themba Zwane', pos: 'MF', club: 'Mamelodi Sundowns' },
|
||||||
|
{ name: 'Ethan Nkosi', pos: 'MF', club: 'Kaizer Chiefs' },
|
||||||
|
{ name: 'Sipho Mbule', pos: 'MF', club: 'Kaizer Chiefs' },
|
||||||
|
{ name: 'Yusuf Maart', pos: 'MF', club: 'Kaizer Chiefs' },
|
||||||
|
{ name: 'Abbubaker Mobara', pos: 'MF', club: 'Cape Town City' },
|
||||||
|
{ name: 'Percy Tau', pos: 'FW', club: 'Al Ahly' },
|
||||||
|
{ name: 'Lyle Foster', pos: 'FW', club: 'Burnley' },
|
||||||
|
{ name: 'Evidence Makgopa', pos: 'FW', club: 'Orlando Pirates' },
|
||||||
|
{ name: 'Bongokuhle Hlongwane', pos: 'FW', club: 'Minnesota United' },
|
||||||
|
{ name: 'Lebo Mothiba', pos: 'FW', club: 'Strasbourg' },
|
||||||
|
{ name: 'Lebohang Maboe', pos: 'MF', club: 'Mamelodi Sundowns' },
|
||||||
|
{ name: 'Sphephelo Sithole', pos: 'DF', club: 'Udinese' },
|
||||||
|
{ name: 'Nkosinathi Sibisi', pos: 'DF', club: 'Orlando Pirates' },
|
||||||
|
{ name: 'Grant Kekana', pos: 'DF', club: 'Mamelodi Sundowns' },
|
||||||
|
{ name: 'Lebo Manyama', pos: 'FW', club: 'Kaizer Chiefs' },
|
||||||
|
{ name: 'Thembinkosi Lorch', pos: 'FW', club: 'Orlando Pirates' },
|
||||||
|
],
|
||||||
|
'South Korea': [
|
||||||
|
{ name: 'Kim Seung-gyu', pos: 'GK', club: 'Vissel Kobe' },
|
||||||
|
{ name: 'Jo Hyeon-woo', pos: 'GK', club: 'Ulsan HD' },
|
||||||
|
{ name: 'Song Bum-keun', pos: 'GK', club: 'Jeonbuk' },
|
||||||
|
{ name: 'Kim Jin-su', pos: 'DF', club: 'Nottm Forest' },
|
||||||
|
{ name: 'Kim Min-jae', pos: 'DF', club: 'Bayern Munich' },
|
||||||
|
{ name: 'Kim Young-gwon', pos: 'DF', club: 'Ulsan HD' },
|
||||||
|
{ name: 'Lee Ki-je', pos: 'DF', club: 'Jeonbuk' },
|
||||||
|
{ name: 'Hong Chul', pos: 'DF', club: 'Suwon FC' },
|
||||||
|
{ name: 'Choi Jun', pos: 'DF', club: 'Jeonbuk' },
|
||||||
|
{ name: 'Hwang In-beom', pos: 'MF', club: 'Feyenoord' },
|
||||||
|
{ name: 'Jung Woo-young', pos: 'MF', club: 'Al-Qadsiah' },
|
||||||
|
{ name: 'Son Heung-min', pos: 'FW', club: 'Tottenham' },
|
||||||
|
{ name: 'Lee Jae-sung', pos: 'MF', club: 'Mainz' },
|
||||||
|
{ name: 'Kwon Chang-hoon', pos: 'MF', club: 'Daejeon Citizen' },
|
||||||
|
{ name: 'Paik Seung-ho', pos: 'MF', club: 'Jeonbuk' },
|
||||||
|
{ name: 'Hwang Hee-chan', pos: 'FW', club: 'Wolves' },
|
||||||
|
{ name: 'Cho Gue-sung', pos: 'FW', club: 'Midtjylland' },
|
||||||
|
{ name: 'Oh Hyeon-gyu', pos: 'FW', club: 'Celtic' },
|
||||||
|
{ name: 'Lee Seung-woo', pos: 'FW', club: 'Jeonbuk' },
|
||||||
|
{ name: 'Na Sang-ho', pos: 'FW', club: 'Jeonbuk' },
|
||||||
|
{ name: 'Yang Hyun-jun', pos: 'FW', club: 'Celtic' },
|
||||||
|
{ name: 'Kim Moon-hwan', pos: 'DF', club: 'Jeonbuk' },
|
||||||
|
{ name: 'Park Yong-woo', pos: 'MF', club: 'Daejeon Citizen' },
|
||||||
|
{ name: 'Jeong Sang-bin', pos: 'FW', club: 'Feyenoord' },
|
||||||
|
{ name: 'Lee Myeong-jae', pos: 'MF', club: 'Gimcheon Sangmu' },
|
||||||
|
{ name: 'Seol Young-woo', pos: 'FW', club: 'Jeonbuk' },
|
||||||
|
],
|
||||||
|
'Czech Republic': [
|
||||||
|
{ name: 'Jiří Staněk', pos: 'GK', club: 'Sevilla' },
|
||||||
|
{ name: 'Matěj Kovář', pos: 'GK', club: 'Bayer Leverkusen' },
|
||||||
|
{ name: 'Tomáš Vaclík', pos: 'GK', club: 'Unattached' },
|
||||||
|
{ name: 'Vladimír Coufal', pos: 'DF', club: 'West Ham' },
|
||||||
|
{ name: 'Pavel Kadeřábek', pos: 'DF', club: 'Hoffenheim' },
|
||||||
|
{ name: 'Tomáš Holeš', pos: 'DF', club: 'Slavia Prague' },
|
||||||
|
{ name: 'Jakub Brabec', pos: 'DF', club: 'Sigma Olomouc' },
|
||||||
|
{ name: 'Lukáš Hrádecký', pos: 'DF', club: 'Bayer Leverkusen' },
|
||||||
|
{ name: 'Tomáš Čvančara', pos: 'FW', club: 'Mönchengladbach' },
|
||||||
|
{ name: 'Tomáš Souček', pos: 'MF', club: 'West Ham' },
|
||||||
|
{ name: 'Patrik Schick', pos: 'FW', club: 'Bayer Leverkusen' },
|
||||||
|
{ name: 'Lukáš Provod', pos: 'MF', club: 'Slavia Prague' },
|
||||||
|
{ name: 'Marek Matějovský', pos: 'MF', club: 'Sparta Prague' },
|
||||||
|
{ name: 'Ondřej Lingr', pos: 'MF', club: 'Feyenoord' },
|
||||||
|
{ name: 'Jan Kuchta', pos: 'FW', club: 'Sparta Prague' },
|
||||||
|
{ name: 'Václav Černý', pos: 'FW', club: 'Wolfsburg' },
|
||||||
|
{ name: 'Adam Hložek', pos: 'FW', club: 'Bayer Leverkusen' },
|
||||||
|
{ name: 'David Jurásek', pos: 'DF', club: 'Benfica' },
|
||||||
|
{ name: 'Aleš Mateju', pos: 'DF', club: 'Brest' },
|
||||||
|
{ name: 'Martin Vitík', pos: 'DF', club: 'Sparta Prague' },
|
||||||
|
{ name: 'Michal Sadílek', pos: 'MF', club: 'Twente' },
|
||||||
|
{ name: 'Jakub Jankto', pos: 'MF', club: 'Sparta Prague' },
|
||||||
|
{ name: 'Mojmír Chytil', pos: 'FW', club: 'Feyenoord' },
|
||||||
|
{ name: 'Antonín Barák', pos: 'MF', club: 'Fiorentina' },
|
||||||
|
{ name: 'Lukáš Kalvach', pos: 'MF', club: 'Plzeň' },
|
||||||
|
{ name: 'David Douděra', pos: 'MF', club: 'Slavia Prague' },
|
||||||
|
],
|
||||||
|
|
||||||
|
// ── GROUP B ────────────────────────────────────────────────────────────────
|
||||||
|
'Canada': [
|
||||||
|
{ name: 'Maxime Crépeau', pos: 'GK', club: 'LAFC' },
|
||||||
|
{ name: 'Milan Borjan', pos: 'GK', club: 'Red Star Belgrade' },
|
||||||
|
{ name: 'Dayne St. Clair', pos: 'GK', club: 'Minnesota United' },
|
||||||
|
{ name: 'Alphonso Davies', pos: 'DF', club: 'Bayern Munich' },
|
||||||
|
{ name: 'Richie Laryea', pos: 'DF', club: 'Nottm Forest' },
|
||||||
|
{ name: 'Alistair Johnston', pos: 'DF', club: 'Celtic' },
|
||||||
|
{ name: 'Kamal Miller', pos: 'DF', club: 'Inter Miami' },
|
||||||
|
{ name: 'Steven Vitória', pos: 'DF', club: 'Unattached' },
|
||||||
|
{ name: 'Derek Cornelius', pos: 'DF', club: 'Panathinaikos' },
|
||||||
|
{ name: 'Jonathan David', pos: 'FW', club: 'Lille' },
|
||||||
|
{ name: 'Cyle Larin', pos: 'FW', club: 'Mallorca' },
|
||||||
|
{ name: 'Tajon Buchanan', pos: 'FW', club: 'Club Brugge' },
|
||||||
|
{ name: 'Atiba Hutchinson', pos: 'MF', club: 'Beşiktaş' },
|
||||||
|
{ name: 'Stephen Eustáquio', pos: 'MF', club: 'Porto' },
|
||||||
|
{ name: 'Mark-Anthony Kaye', pos: 'MF', club: 'Toronto FC' },
|
||||||
|
{ name: 'Samuel Piette', pos: 'MF', club: 'CF Montréal' },
|
||||||
|
{ name: 'Liam Millar', pos: 'FW', club: 'FC Basel' },
|
||||||
|
{ name: 'Junior Hoilett', pos: 'FW', club: 'Vancouver Whitecaps' },
|
||||||
|
{ name: 'Lucas Cavallini', pos: 'FW', club: 'Vancouver Whitecaps' },
|
||||||
|
{ name: 'Ismaël Koné', pos: 'MF', club: 'Watford' },
|
||||||
|
{ name: 'Jacob Shaffelburg', pos: 'FW', club: 'Nashville SC' },
|
||||||
|
{ name: 'Ike Ugbo', pos: 'FW', club: 'Troyes' },
|
||||||
|
{ name: 'Doneil Henry', pos: 'DF', club: 'CF Montréal' },
|
||||||
|
{ name: 'Zorhan Bassong', pos: 'DF', club: 'Nashville SC' },
|
||||||
|
{ name: 'Scott Kennedy', pos: 'DF', club: 'CF Montréal' },
|
||||||
|
{ name: 'Caden Clark', pos: 'MF', club: 'RB Leipzig' },
|
||||||
|
],
|
||||||
|
'Bosnia & Herzegovina': [
|
||||||
|
{ name: 'Ibrahim Šehić', pos: 'GK', club: 'Kasımpaşa' },
|
||||||
|
{ name: 'Nikola Vasilj', pos: 'GK', club: 'St Pauli' },
|
||||||
|
{ name: 'Vedran Kjosevski', pos: 'GK', club: 'Zrinjski' },
|
||||||
|
{ name: 'Sead Kolašinac', pos: 'DF', club: 'Marseille' },
|
||||||
|
{ name: 'Ognjen Stanić', pos: 'DF', club: 'Toulouse' },
|
||||||
|
{ name: 'Amer Gojak', pos: 'MF', club: 'Trabzonspor' },
|
||||||
|
{ name: 'Miralem Pjanić', pos: 'MF', club: 'Unattached' },
|
||||||
|
{ name: 'Edin Džeko', pos: 'FW', club: 'Fenerbahçe' },
|
||||||
|
{ name: 'Ermedin Demirović', pos: 'FW', club: 'Augsburg' },
|
||||||
|
{ name: 'Armin Hodžić', pos: 'FW', club: 'Maribor' },
|
||||||
|
{ name: 'Sanjin Prcić', pos: 'MF', club: 'Panathinaikos' },
|
||||||
|
{ name: 'Amar Dedić', pos: 'DF', club: 'Red Bull Salzburg' },
|
||||||
|
{ name: 'Denis Huseinbašić', pos: 'MF', club: 'Augsburg' },
|
||||||
|
{ name: 'Luka Menalo', pos: 'FW', club: 'Dinamo Zagreb' },
|
||||||
|
{ name: 'Kenan Kodro', pos: 'FW', club: 'Eibar' },
|
||||||
|
{ name: 'Radovan Pankov', pos: 'DF', club: 'Red Star Belgrade' },
|
||||||
|
{ name: 'Dino Hotić', pos: 'MF', club: 'Malmö' },
|
||||||
|
{ name: 'Vedat Muriqi', pos: 'FW', club: 'Mallorca' },
|
||||||
|
{ name: 'Haris Duljevic', pos: 'MF', club: 'Gent' },
|
||||||
|
{ name: 'Neven Đurasek', pos: 'FW', club: 'Gzira United' },
|
||||||
|
{ name: 'Benjamin Tatar', pos: 'FW', club: 'Trabzonspor' },
|
||||||
|
{ name: 'Muhamed Bešić', pos: 'MF', club: 'Trabzonspor' },
|
||||||
|
{ name: 'Sinisa Sanicanin', pos: 'DF', club: 'Lille' },
|
||||||
|
{ name: 'Miro Mustedanagić', pos: 'MF', club: 'Zrinjski' },
|
||||||
|
{ name: 'Alen Halilović', pos: 'MF', club: 'Unattached' },
|
||||||
|
{ name: 'Nikola Vlašić', pos: 'MF', club: 'Torino' },
|
||||||
|
],
|
||||||
|
'Qatar': [
|
||||||
|
{ name: 'Meshaal Barsham', pos: 'GK', club: 'Al Sadd' },
|
||||||
|
{ name: 'Saad Al Sheeb', pos: 'GK', club: 'Al Sadd' },
|
||||||
|
{ name: 'Yousuf Hassan', pos: 'GK', club: 'Al Arabi' },
|
||||||
|
{ name: 'Pedro Miguel', pos: 'DF', club: 'Al Rayyan' },
|
||||||
|
{ name: 'Bassam Al-Rawi', pos: 'DF', club: 'Al Ahli' },
|
||||||
|
{ name: 'Tarek Salman', pos: 'DF', club: 'Al Rayyan' },
|
||||||
|
{ name: 'Mohammed Waad', pos: 'DF', club: 'Al Khor' },
|
||||||
|
{ name: 'Abdelkarim Hassan', pos: 'DF', club: 'Al Rayyan' },
|
||||||
|
{ name: 'Boualem Khoukhi', pos: 'DF', club: 'Al Sadd' },
|
||||||
|
{ name: 'Karim Boudiaf', pos: 'MF', club: 'Al Duhail' },
|
||||||
|
{ name: 'Abdulaziz Hatem', pos: 'MF', club: 'Al Rayyan' },
|
||||||
|
{ name: 'Akram Afif', pos: 'FW', club: 'Al Sadd' },
|
||||||
|
{ name: 'Almoez Ali', pos: 'FW', club: 'Al Duhail' },
|
||||||
|
{ name: 'Hasan Al-Haydos', pos: 'FW', club: 'Al Sadd' },
|
||||||
|
{ name: 'Ismail Mohamad', pos: 'FW', club: 'Al Shahaniya' },
|
||||||
|
{ name: 'Mohammed Muntari', pos: 'FW', club: 'Al Duhail' },
|
||||||
|
{ name: 'Khalid Muneer', pos: 'MF', club: 'Al Sadd' },
|
||||||
|
{ name: 'Ahmed Alaaeldin', pos: 'MF', club: 'Al Arabi' },
|
||||||
|
{ name: 'Assim Omer Madibo', pos: 'MF', club: 'Al Rayyan' },
|
||||||
|
{ name: 'Salem Al-Hajri', pos: 'MF', club: 'Al Gharafa' },
|
||||||
|
{ name: 'Naif Al-Hadhrami', pos: 'DF', club: 'Al Duhail' },
|
||||||
|
{ name: 'Yusuf Abdurisag', pos: 'FW', club: 'Al Arabi' },
|
||||||
|
{ name: 'Hamid Ismail', pos: 'FW', club: 'Al Ahli' },
|
||||||
|
{ name: 'Jassem Gaber', pos: 'MF', club: 'Al Gharafa' },
|
||||||
|
{ name: 'Ahmed Fathi', pos: 'DF', club: 'Al Sadd' },
|
||||||
|
{ name: 'Musab Kheder', pos: 'MF', club: 'Al Wakrah' },
|
||||||
|
],
|
||||||
|
'Switzerland': [
|
||||||
|
{ name: 'Yann Sommer', pos: 'GK', club: 'Inter Milan' },
|
||||||
|
{ name: 'Jonas Omlin', pos: 'GK', club: 'Monaco' },
|
||||||
|
{ name: 'Gregor Kobel', pos: 'GK', club: 'Borussia Dortmund' },
|
||||||
|
{ name: 'Manuel Akanji', pos: 'DF', club: 'Man City' },
|
||||||
|
{ name: 'Nico Elvedi', pos: 'DF', club: 'Mönchengladbach' },
|
||||||
|
{ name: 'Ricardo Rodríguez', pos: 'DF', club: 'Torino' },
|
||||||
|
{ name: 'Silvan Widmer', pos: 'DF', club: 'Mainz' },
|
||||||
|
{ name: 'Loris Benito', pos: 'DF', club: 'Bordeaux' },
|
||||||
|
{ name: 'Kevin Mbabu', pos: 'DF', club: 'Fulham' },
|
||||||
|
{ name: 'Granit Xhaka', pos: 'MF', club: 'Bayer Leverkusen' },
|
||||||
|
{ name: 'Remo Freuler', pos: 'MF', club: 'Nottm Forest' },
|
||||||
|
{ name: 'Denis Zakaria', pos: 'MF', club: 'Monaco' },
|
||||||
|
{ name: 'Xherdan Shaqiri', pos: 'MF', club: 'Chicago Fire' },
|
||||||
|
{ name: 'Ruben Vargas', pos: 'FW', club: 'Augsburg' },
|
||||||
|
{ name: 'Fabian Rieder', pos: 'MF', club: 'Rennes' },
|
||||||
|
{ name: 'Breel Embolo', pos: 'FW', club: 'Monaco' },
|
||||||
|
{ name: 'Noah Okafor', pos: 'FW', club: 'AC Milan' },
|
||||||
|
{ name: 'Haris Seferović', pos: 'FW', club: 'Galatasaray' },
|
||||||
|
{ name: 'Zeki Amdouni', pos: 'FW', club: 'Burnley' },
|
||||||
|
{ name: 'Ardon Jashari', pos: 'MF', club: 'Club Brugge' },
|
||||||
|
{ name: 'Edimilson Fernandes', pos: 'MF', club: 'Mainz' },
|
||||||
|
{ name: 'Becir Omeragic', pos: 'DF', club: 'Montpellier' },
|
||||||
|
{ name: 'Cédric Zesiger', pos: 'DF', club: 'Wolfsburg' },
|
||||||
|
{ name: 'Michel Aebischer', pos: 'MF', club: 'Bologna' },
|
||||||
|
{ name: 'Dan Ndoye', pos: 'FW', club: 'Bologna' },
|
||||||
|
{ name: 'Kwadwo Duah', pos: 'FW', club: 'Ludogorets' },
|
||||||
|
],
|
||||||
|
|
||||||
|
// ── GROUP C ────────────────────────────────────────────────────────────────
|
||||||
|
'Brazil': [
|
||||||
|
{ name: 'Alisson Becker', pos: 'GK', club: 'Liverpool' },
|
||||||
|
{ name: 'Ederson', pos: 'GK', club: 'Fenerbahçe' },
|
||||||
|
{ name: 'Weverton', pos: 'GK', club: 'Grêmio' },
|
||||||
|
{ name: 'Marquinhos', pos: 'DF', club: 'PSG' },
|
||||||
|
{ name: 'Gabriel Magalhães', pos: 'DF', club: 'Arsenal' },
|
||||||
|
{ name: 'Bremer', pos: 'DF', club: 'Juventus' },
|
||||||
|
{ name: 'Danilo', pos: 'DF', club: 'Flamengo' },
|
||||||
|
{ name: 'Alex Sandro', pos: 'DF', club: 'Flamengo' },
|
||||||
|
{ name: 'Wesley', pos: 'DF', club: 'Roma' },
|
||||||
|
{ name: 'Léo Pereira', pos: 'DF', club: 'Flamengo' },
|
||||||
|
{ name: 'Ibanez', pos: 'DF', club: 'Al Ahli' },
|
||||||
|
{ name: 'Douglas Santos', pos: 'DF', club: 'Zenit' },
|
||||||
|
{ name: 'Casemiro', pos: 'MF', club: 'Man United' },
|
||||||
|
{ name: 'Bruno Guimarães', pos: 'MF', club: 'Newcastle' },
|
||||||
|
{ name: 'Lucas Paquetá', pos: 'MF', club: 'West Ham' },
|
||||||
|
{ name: 'Neymar Jr.', pos: 'FW', club: 'Al-Hilal' },
|
||||||
|
{ name: 'Vinícius Júnior', pos: 'FW', club: 'Real Madrid' },
|
||||||
|
{ name: 'Raphinha', pos: 'FW', club: 'Barcelona' },
|
||||||
|
{ name: 'Gabriel Martinelli', pos: 'FW', club: 'Arsenal' },
|
||||||
|
{ name: 'Matheus Cunha', pos: 'FW', club: 'Wolves' },
|
||||||
|
{ name: 'Endrick', pos: 'FW', club: 'Real Madrid' },
|
||||||
|
{ name: 'Gabriel Jesus', pos: 'FW', club: 'Arsenal' },
|
||||||
|
{ name: 'Pedro', pos: 'FW', club: 'Flamengo' },
|
||||||
|
{ name: 'Rodrygo', pos: 'FW', club: 'Real Madrid' },
|
||||||
|
{ name: 'Andreas Pereira', pos: 'MF', club: 'Fulham' },
|
||||||
|
{ name: 'Gerson', pos: 'MF', club: 'Flamengo' },
|
||||||
|
],
|
||||||
|
'Morocco': [
|
||||||
|
{ name: 'Yassine Bounou', pos: 'GK', club: 'Al-Hilal' },
|
||||||
|
{ name: 'Munir Mohamedi', pos: 'GK', club: 'Nottm Forest' },
|
||||||
|
{ name: 'Mehdi Benjdida', pos: 'GK', club: 'Wydad' },
|
||||||
|
{ name: 'Achraf Hakimi', pos: 'DF', club: 'PSG' },
|
||||||
|
{ name: 'Noussair Mazraoui', pos: 'DF', club: 'Man United' },
|
||||||
|
{ name: 'Romain Saïss', pos: 'DF', club: 'Beşiktaş' },
|
||||||
|
{ name: 'Nayef Aguerd', pos: 'DF', club: 'West Ham' },
|
||||||
|
{ name: 'Jawad El Yamiq', pos: 'DF', club: 'Real Valladolid' },
|
||||||
|
{ name: 'Yahia Attiat-Allah', pos: 'DF', club: 'Wydad' },
|
||||||
|
{ name: 'Sofyan Amrabat', pos: 'MF', club: 'Fiorentina' },
|
||||||
|
{ name: 'Azzedine Ounahi', pos: 'MF', club: 'Marseille' },
|
||||||
|
{ name: 'Selim Amallah', pos: 'MF', club: 'Standard Liège' },
|
||||||
|
{ name: 'Bilal El Khannouss', pos: 'MF', club: 'Genk' },
|
||||||
|
{ name: 'Hakim Ziyech', pos: 'FW', club: 'Galatasaray' },
|
||||||
|
{ name: 'Youssef En-Nesyri', pos: 'FW', club: 'Fenerbahçe' },
|
||||||
|
{ name: 'Ayoub El Kaabi', pos: 'FW', club: 'Olympiacos' },
|
||||||
|
{ name: 'Abde Ezzalzouli', pos: 'FW', club: 'Osasuna' },
|
||||||
|
{ name: 'Soufiane Rahimi', pos: 'FW', club: 'Al-Ain' },
|
||||||
|
{ name: 'Zakaria Aboukhlal', pos: 'FW', club: 'Toulouse' },
|
||||||
|
{ name: 'Brahim Díaz', pos: 'FW', club: 'Real Madrid' },
|
||||||
|
{ name: 'Amine Harit', pos: 'FW', club: 'Marseille' },
|
||||||
|
{ name: 'Ibrahim Salah', pos: 'MF', club: 'Wydad' },
|
||||||
|
{ name: 'Badr Benoun', pos: 'DF', club: 'Qatar SC' },
|
||||||
|
{ name: 'Adam Masina', pos: 'DF', club: 'Udinese' },
|
||||||
|
{ name: 'Ilias Chair', pos: 'MF', club: 'Strasbourg' },
|
||||||
|
{ name: 'Walid Cheddira', pos: 'FW', club: 'Parma' },
|
||||||
|
],
|
||||||
|
'Haiti': [
|
||||||
|
{ name: 'Josué Duverger', pos: 'GK', club: 'Violette' },
|
||||||
|
{ name: 'Derrick Etienne Jr.', pos: 'FW', club: 'Columbus Crew' },
|
||||||
|
{ name: 'James Penney', pos: 'DF', club: 'Unattached' },
|
||||||
|
{ name: 'Steeven Saba', pos: 'FW', club: 'Vitória SC' },
|
||||||
|
{ name: 'Frantzdy Pierrot', pos: 'FW', club: 'Charlotte FC' },
|
||||||
|
{ name: 'Mechack Jérôme', pos: 'DF', club: 'New England Revolution' },
|
||||||
|
{ name: 'Kervens Belfort', pos: 'FW', club: 'Toulouse' },
|
||||||
|
{ name: 'Duckens Nazon', pos: 'FW', club: 'Airdrieonians' },
|
||||||
|
{ name: 'Wilde-Donald Guerrier',pos: 'FW', club: 'Ionikos' },
|
||||||
|
{ name: 'Naomie Noel', pos: 'MF', club: 'Unattached' },
|
||||||
|
{ name: 'Léo Faussemagne', pos: 'MF', club: 'Caen' },
|
||||||
|
{ name: 'Kevin Fortune', pos: 'MF', club: 'Violette' },
|
||||||
|
{ name: 'Herve Bazile', pos: 'FW', club: 'Roda JC' },
|
||||||
|
{ name: 'Dominique Badji', pos: 'FW', club: 'Colorado Rapids' },
|
||||||
|
{ name: 'Carlo Marcelin', pos: 'DF', club: 'Celta Vigo' },
|
||||||
|
{ name: 'Samuel Camille', pos: 'GK', club: 'Violette' },
|
||||||
|
{ name: 'Zuriel Adé', pos: 'GK', club: 'Unattached' },
|
||||||
|
{ name: 'Abioye Romain', pos: 'DF', club: 'Unattached' },
|
||||||
|
{ name: 'Hans Descartes', pos: 'DF', club: 'Unattached' },
|
||||||
|
{ name: 'Nikolaou Gerdy', pos: 'DF', club: 'Unattached' },
|
||||||
|
{ name: 'Jean-Willey Pierre', pos: 'MF', club: 'Unattached' },
|
||||||
|
{ name: 'Nesmy Pericles', pos: 'MF', club: 'Unattached' },
|
||||||
|
{ name: 'Vladimyr Jerome', pos: 'MF', club: 'Unattached' },
|
||||||
|
{ name: 'Fabio Celestin', pos: 'DF', club: 'Unattached' },
|
||||||
|
{ name: 'Wednerson Antenor', pos: 'FW', club: 'Unattached' },
|
||||||
|
{ name: 'Peterson Joseph', pos: 'FW', club: 'Unattached' },
|
||||||
|
],
|
||||||
|
'Scotland': [
|
||||||
|
{ name: 'Angus Gunn', pos: 'GK', club: 'Norwich City' },
|
||||||
|
{ name: 'Craig Gordon', pos: 'GK', club: 'Hearts' },
|
||||||
|
{ name: 'Liam Kelly', pos: 'GK', club: 'Motherwell' },
|
||||||
|
{ name: 'Andrew Robertson', pos: 'DF', club: 'Liverpool' },
|
||||||
|
{ name: 'Kieran Tierney', pos: 'DF', club: 'Arsenal' },
|
||||||
|
{ name: 'Grant Hanley', pos: 'DF', club: 'Norwich City' },
|
||||||
|
{ name: 'John Souttar', pos: 'DF', club: 'Rangers' },
|
||||||
|
{ name: 'Scott McKenna', pos: 'DF', club: 'Nottm Forest' },
|
||||||
|
{ name: 'Aaron Hickey', pos: 'DF', club: 'Brentford' },
|
||||||
|
{ name: 'Callum McGregor', pos: 'MF', club: 'Celtic' },
|
||||||
|
{ name: 'Ryan Jack', pos: 'MF', club: 'Rangers' },
|
||||||
|
{ name: 'Stuart Armstrong', pos: 'MF', club: 'Southampton' },
|
||||||
|
{ name: 'John McGinn', pos: 'MF', club: 'Aston Villa' },
|
||||||
|
{ name: 'Billy Gilmour', pos: 'MF', club: 'Brighton' },
|
||||||
|
{ name: 'Ryan Christie', pos: 'MF', club: 'Bournemouth' },
|
||||||
|
{ name: 'Lyndon Dykes', pos: 'FW', club: 'QPR' },
|
||||||
|
{ name: 'Che Adams', pos: 'FW', club: 'Southampton' },
|
||||||
|
{ name: 'Lawrence Shankland', pos: 'FW', club: 'Hearts' },
|
||||||
|
{ name: 'Liel Abada', pos: 'FW', club: 'Celtic' },
|
||||||
|
{ name: 'Scott Wright', pos: 'FW', club: 'Rangers' },
|
||||||
|
{ name: 'Ross Stewart', pos: 'FW', club: 'Sunderland' },
|
||||||
|
{ name: 'Kenny McLean', pos: 'MF', club: 'Norwich City' },
|
||||||
|
{ name: 'Jack Hendry', pos: 'DF', club: 'Al-Ettifaq' },
|
||||||
|
{ name: 'Liam Cooper', pos: 'DF', club: 'Leeds United' },
|
||||||
|
{ name: 'Matt O\'Riley', pos: 'MF', club: 'Celtic' },
|
||||||
|
{ name: 'Ben Doak', pos: 'FW', club: 'Liverpool' },
|
||||||
|
],
|
||||||
|
|
||||||
|
// ── GROUP D ────────────────────────────────────────────────────────────────
|
||||||
|
'United States': [
|
||||||
|
{ name: 'Matt Turner', pos: 'GK', club: 'Nottm Forest' },
|
||||||
|
{ name: 'Ethan Horvath', pos: 'GK', club: 'Luton Town' },
|
||||||
|
{ name: 'Sean Johnson', pos: 'GK', club: 'Toronto FC' },
|
||||||
|
{ name: 'Sergiño Dest', pos: 'DF', club: 'PSV' },
|
||||||
|
{ name: 'Joe Scally', pos: 'DF', club: 'Mönchengladbach' },
|
||||||
|
{ name: 'Miles Robinson', pos: 'DF', club: 'Atlanta United' },
|
||||||
|
{ name: 'Chris Richards', pos: 'DF', club: 'Crystal Palace' },
|
||||||
|
{ name: 'Tim Ream', pos: 'DF', club: 'Fulham' },
|
||||||
|
{ name: 'Antonee Robinson', pos: 'DF', club: 'Fulham' },
|
||||||
|
{ name: 'Christian Pulisic', pos: 'FW', club: 'AC Milan' },
|
||||||
|
{ name: 'Weston McKennie', pos: 'MF', club: 'Juventus' },
|
||||||
|
{ name: 'Tyler Adams', pos: 'MF', club: 'Bournemouth' },
|
||||||
|
{ name: 'Yunus Musah', pos: 'MF', club: 'AC Milan' },
|
||||||
|
{ name: 'Brenden Aaronson', pos: 'MF', club: 'Leeds United' },
|
||||||
|
{ name: 'Gio Reyna', pos: 'MF', club: 'Borussia Dortmund' },
|
||||||
|
{ name: 'Ricardo Pepi', pos: 'FW', club: 'PSV' },
|
||||||
|
{ name: 'Josh Sargent', pos: 'FW', club: 'Norwich City' },
|
||||||
|
{ name: 'Jordan Morris', pos: 'FW', club: 'Seattle Sounders' },
|
||||||
|
{ name: 'Folarin Balogun', pos: 'FW', club: 'Monaco' },
|
||||||
|
{ name: 'Matthew Hoppe', pos: 'FW', club: 'Middlesbrough' },
|
||||||
|
{ name: 'Tim Weah', pos: 'FW', club: 'Juventus' },
|
||||||
|
{ name: 'Luca de la Torre', pos: 'MF', club: 'Celta Vigo' },
|
||||||
|
{ name: 'Malik Tillman', pos: 'MF', club: 'PSV' },
|
||||||
|
{ name: 'DeJuan Jones', pos: 'DF', club: 'New England Revolution' },
|
||||||
|
{ name: 'Cameron Carter-Vickers',pos:'DF', club: 'Celtic' },
|
||||||
|
{ name: 'Paxten Aaronson', pos: 'MF', club: 'Eintracht Frankfurt' },
|
||||||
|
],
|
||||||
|
'Paraguay': [
|
||||||
|
{ name: 'Antony Silva', pos: 'GK', club: 'Olimpia' },
|
||||||
|
{ name: 'Carlos Coronel', pos: 'GK', club: 'New York Red Bulls' },
|
||||||
|
{ name: 'Rodrigo Muñoz', pos: 'GK', club: 'Independiente' },
|
||||||
|
{ name: 'Gustavo Gómez', pos: 'DF', club: 'Palmeiras' },
|
||||||
|
{ name: 'Omar Alderete', pos: 'DF', club: 'Hertha Berlin' },
|
||||||
|
{ name: 'Junior Alonso', pos: 'DF', club: 'Krasnodar' },
|
||||||
|
{ name: 'Santiago Arzamendia', pos: 'DF', club: 'Cádiz' },
|
||||||
|
{ name: 'Robert Rojas', pos: 'DF', club: 'River Plate' },
|
||||||
|
{ name: 'Óscar Romero', pos: 'MF', club: 'San Lorenzo' },
|
||||||
|
{ name: 'Miguel Almirón', pos: 'MF', club: 'Newcastle' },
|
||||||
|
{ name: 'Richard Sánchez', pos: 'MF', club: 'Club América' },
|
||||||
|
{ name: 'Mathías Villasanti', pos: 'MF', club: 'Grêmio' },
|
||||||
|
{ name: 'Andrés Cubas', pos: 'MF', club: 'Nottm Forest' },
|
||||||
|
{ name: 'Sergio Aquino', pos: 'MF', club: 'Olimpia' },
|
||||||
|
{ name: 'Julio Enciso', pos: 'FW', club: 'Brighton' },
|
||||||
|
{ name: 'Antonio Sanabria', pos: 'FW', club: 'Torino' },
|
||||||
|
{ name: 'Braian Ojeda', pos: 'MF', club: 'Olimpia' },
|
||||||
|
{ name: 'Alejandro Romero', pos: 'FW', club: 'Man City' },
|
||||||
|
{ name: 'Blas Riveros', pos: 'DF', club: 'Basel' },
|
||||||
|
{ name: 'Alberto Espínola', pos: 'DF', club: 'Olimpia' },
|
||||||
|
{ name: 'Iván Piris', pos: 'DF', club: 'Mamelodi Sundowns' },
|
||||||
|
{ name: 'Axel Soto', pos: 'MF', club: 'Olimpia' },
|
||||||
|
{ name: 'Diego Gómez', pos: 'MF', club: 'Inter Miami' },
|
||||||
|
{ name: 'Ángel Romero', pos: 'FW', club: 'Corinthians' },
|
||||||
|
{ name: 'Gabriel Avalos', pos: 'FW', club: 'Olimpia' },
|
||||||
|
{ name: 'Iván Torres', pos: 'MF', club: 'Cerro Porteño' },
|
||||||
|
],
|
||||||
|
'Australia': [
|
||||||
|
{ name: 'Mathew Ryan', pos: 'GK', club: 'AZ Alkmaar' },
|
||||||
|
{ name: 'Danny Vukovic', pos: 'GK', club: 'Genk' },
|
||||||
|
{ name: 'Andrew Redmayne', pos: 'GK', club: 'Sydney FC' },
|
||||||
|
{ name: 'Harry Souttar', pos: 'DF', club: 'Leicester City' },
|
||||||
|
{ name: 'Miloš Degenek', pos: 'DF', club: 'Columbus Crew' },
|
||||||
|
{ name: 'Joel King', pos: 'DF', club: 'Odense' },
|
||||||
|
{ name: 'Nathaniel Atkinson', pos: 'DF', club: 'St Mirren' },
|
||||||
|
{ name: 'Kye Rowles', pos: 'DF', club: 'Hearts' },
|
||||||
|
{ name: 'Fran Karacic', pos: 'DF', club: 'Brescia' },
|
||||||
|
{ name: 'Aaron Mooy', pos: 'MF', club: 'Celtic' },
|
||||||
|
{ name: 'Jackson Irvine', pos: 'MF', club: 'St Pauli' },
|
||||||
|
{ name: 'Riley McGree', pos: 'MF', club: 'Middlesbrough' },
|
||||||
|
{ name: 'Ajdin Hrustic', pos: 'MF', club: 'Hellas Verona' },
|
||||||
|
{ name: 'Keanu Baccus', pos: 'MF', club: 'St Mirren' },
|
||||||
|
{ name: 'Denis Genreau', pos: 'MF', club: 'Toulouse' },
|
||||||
|
{ name: 'Mitchell Duke', pos: 'FW', club: 'Fagiano Okayama' },
|
||||||
|
{ name: 'Martin Boyle', pos: 'FW', club: 'Hibernian' },
|
||||||
|
{ name: 'Jason Cummings', pos: 'FW', club: 'Central Coast Mariners' },
|
||||||
|
{ name: 'Mathew Leckie', pos: 'FW', club: 'Melbourne City' },
|
||||||
|
{ name: 'Craig Goodwin', pos: 'FW', club: 'Adelaide United' },
|
||||||
|
{ name: 'Garang Kuol', pos: 'FW', club: 'Hearts' },
|
||||||
|
{ name: 'Marco Tilio', pos: 'FW', club: 'Celtic' },
|
||||||
|
{ name: 'Awer Mabil', pos: 'FW', club: 'Cádiz' },
|
||||||
|
{ name: 'Brandon Borrello', pos: 'FW', club: 'Freiburg' },
|
||||||
|
{ name: 'Nishan Velupillay', pos: 'FW', club: 'Unattached' },
|
||||||
|
{ name: 'Cameron Devlin', pos: 'MF', club: 'Hearts' },
|
||||||
|
],
|
||||||
|
'Türkiye': [
|
||||||
|
{ name: 'Altay Bayındır', pos: 'GK', club: 'Man United' },
|
||||||
|
{ name: 'Uğurcan Çakır', pos: 'GK', club: 'Trabzonspor' },
|
||||||
|
{ name: 'Mert Günok', pos: 'GK', club: 'Beşiktaş' },
|
||||||
|
{ name: 'Zeki Çelik', pos: 'DF', club: 'Roma' },
|
||||||
|
{ name: 'Merih Demiral', pos: 'DF', club: 'Al-Qadsiah' },
|
||||||
|
{ name: 'Çağlar Söyüncü', pos: 'DF', club: 'Fenerbahçe' },
|
||||||
|
{ name: 'Samet Akaydın', pos: 'DF', club: 'Fenerbahçe' },
|
||||||
|
{ name: 'Ferdi Kadıoğlu', pos: 'DF', club: 'Brighton' },
|
||||||
|
{ name: 'Mert Müldür', pos: 'DF', club: 'Sassuolo' },
|
||||||
|
{ name: 'Hakan Çalhanoğlu', pos: 'MF', club: 'Inter Milan' },
|
||||||
|
{ name: 'Salih Özcan', pos: 'MF', club: 'Borussia Dortmund' },
|
||||||
|
{ name: 'Kaan Ayhan', pos: 'MF', club: 'Galatasaray' },
|
||||||
|
{ name: 'Okay Yokuşlu', pos: 'MF', club: 'West Brom' },
|
||||||
|
{ name: 'Yunus Akgün', pos: 'FW', club: 'Leicester City' },
|
||||||
|
{ name: 'Kerem Aktürkoğlu', pos: 'FW', club: 'Galatasaray' },
|
||||||
|
{ name: 'Cenk Tosun', pos: 'FW', club: 'Beşiktaş' },
|
||||||
|
{ name: 'Burak Yılmaz', pos: 'FW', club: 'Unattached' },
|
||||||
|
{ name: 'Berk Celik', pos: 'MF', club: 'Galatasaray' },
|
||||||
|
{ name: 'Halil Dervişoğlu', pos: 'FW', club: 'Galatasaray' },
|
||||||
|
{ name: 'Arda Güler', pos: 'FW', club: 'Real Madrid' },
|
||||||
|
{ name: 'Emirhan İlkhan', pos: 'MF', club: 'Beşiktaş' },
|
||||||
|
{ name: 'Muhammed Şengezer', pos: 'DF', club: 'Antalyaspor' },
|
||||||
|
{ name: 'Muhammed Akçay', pos: 'DF', club: 'Trabzonspor' },
|
||||||
|
{ name: 'Ahmet Kutucu', pos: 'FW', club: 'Hertha Berlin' },
|
||||||
|
{ name: 'Dorukhan Toköz', pos: 'MF', club: 'Beşiktaş' },
|
||||||
|
{ name: 'Efecan Karaca', pos: 'FW', club: 'Antalyaspor' },
|
||||||
|
],
|
||||||
|
|
||||||
|
// ── GROUP I (France) ───────────────────────────────────────────────────────
|
||||||
|
'France': [
|
||||||
|
{ name: 'Mike Maignan', pos: 'GK', club: 'AC Milan' },
|
||||||
|
{ name: 'Robin Risser', pos: 'GK', club: 'RC Lens' },
|
||||||
|
{ name: 'Brice Samba', pos: 'GK', club: 'Stade Rennais' },
|
||||||
|
{ name: 'Lucas Digne', pos: 'DF', club: 'Aston Villa' },
|
||||||
|
{ name: 'Malo Gusto', pos: 'DF', club: 'Chelsea' },
|
||||||
|
{ name: 'Lucas Hernández', pos: 'DF', club: 'PSG' },
|
||||||
|
{ name: 'Théo Hernández', pos: 'DF', club: 'Al-Hilal' },
|
||||||
|
{ name: 'Ibrahima Konaté', pos: 'DF', club: 'Liverpool' },
|
||||||
|
{ name: 'Jules Koundé', pos: 'DF', club: 'Barcelona' },
|
||||||
|
{ name: 'Maxence Lacroix', pos: 'DF', club: 'Crystal Palace' },
|
||||||
|
{ name: 'William Saliba', pos: 'DF', club: 'Arsenal' },
|
||||||
|
{ name: 'Dayot Upamecano', pos: 'DF', club: 'Bayern Munich' },
|
||||||
|
{ name: 'N\'Golo Kanté', pos: 'MF', club: 'Fenerbahçe' },
|
||||||
|
{ name: 'Manu Koné', pos: 'MF', club: 'AS Roma' },
|
||||||
|
{ name: 'Adrien Rabiot', pos: 'MF', club: 'AC Milan' },
|
||||||
|
{ name: 'Aurélien Tchouaméni', pos: 'MF', club: 'Real Madrid' },
|
||||||
|
{ name: 'Warren Zaïre-Emery', pos: 'MF', club: 'PSG' },
|
||||||
|
{ name: 'Maghnes Akliouche', pos: 'FW', club: 'AS Monaco' },
|
||||||
|
{ name: 'Bradley Barcola', pos: 'FW', club: 'PSG' },
|
||||||
|
{ name: 'Rayan Cherki', pos: 'FW', club: 'Man City' },
|
||||||
|
{ name: 'Ousmane Dembélé', pos: 'FW', club: 'PSG' },
|
||||||
|
{ name: 'Désiré Doué', pos: 'FW', club: 'PSG' },
|
||||||
|
{ name: 'Jean-Philippe Mateta', pos: 'FW', club: 'Crystal Palace' },
|
||||||
|
{ name: 'Kylian Mbappé', pos: 'FW', club: 'Real Madrid' },
|
||||||
|
{ name: 'Michael Olise', pos: 'FW', club: 'Bayern Munich' },
|
||||||
|
{ name: 'Marcus Thuram', pos: 'FW', club: 'Inter Milan' },
|
||||||
|
],
|
||||||
|
|
||||||
|
// ── GROUP J (Argentina) ────────────────────────────────────────────────────
|
||||||
|
'Argentina': [
|
||||||
|
{ name: 'Emiliano Martínez', pos: 'GK', club: 'Aston Villa' },
|
||||||
|
{ name: 'Gerónimo Rulli', pos: 'GK', club: 'Marseille' },
|
||||||
|
{ name: 'Juan Musso', pos: 'GK', club: 'Atlético Madrid' },
|
||||||
|
{ name: 'Leonardo Balerdi', pos: 'DF', club: 'Marseille' },
|
||||||
|
{ name: 'Nicolás Tagliafico', pos: 'DF', club: 'Lyon' },
|
||||||
|
{ name: 'Gonzalo Montiel', pos: 'DF', club: 'River Plate' },
|
||||||
|
{ name: 'Lisandro Martínez', pos: 'DF', club: 'Man United' },
|
||||||
|
{ name: 'Cristian Romero', pos: 'DF', club: 'Tottenham' },
|
||||||
|
{ name: 'Nicolás Otamendi', pos: 'DF', club: 'Benfica' },
|
||||||
|
{ name: 'Facundo Medina', pos: 'DF', club: 'Marseille' },
|
||||||
|
{ name: 'Nahuel Molina', pos: 'DF', club: 'Atlético Madrid' },
|
||||||
|
{ name: 'Leandro Paredes', pos: 'MF', club: 'Boca Juniors' },
|
||||||
|
{ name: 'Rodrigo De Paul', pos: 'MF', club: 'Inter Miami' },
|
||||||
|
{ name: 'Valentín Barco', pos: 'MF', club: 'Strasbourg' },
|
||||||
|
{ name: 'Giovani Lo Celso', pos: 'MF', club: 'Real Betis' },
|
||||||
|
{ name: 'Exequiel Palacios', pos: 'MF', club: 'Bayer Leverkusen' },
|
||||||
|
{ name: 'Enzo Fernández', pos: 'MF', club: 'Chelsea' },
|
||||||
|
{ name: 'Alexis Mac Allister', pos: 'MF', club: 'Liverpool' },
|
||||||
|
{ name: 'Julián Álvarez', pos: 'FW', club: 'Atlético Madrid' },
|
||||||
|
{ name: 'Lionel Messi', pos: 'FW', club: 'Inter Miami' },
|
||||||
|
{ name: 'Nicolás González', pos: 'FW', club: 'Juventus' },
|
||||||
|
{ name: 'Lautaro Martínez', pos: 'FW', club: 'Inter Milan' },
|
||||||
|
{ name: 'Paulo Dybala', pos: 'FW', club: 'Roma' },
|
||||||
|
{ name: 'Thiago Almada', pos: 'MF', club: 'Atlanta United' },
|
||||||
|
{ name: 'Valentín Carboni', pos: 'FW', club: 'Inter Milan' },
|
||||||
|
{ name: 'Alejandro Garnacho', pos: 'FW', club: 'Man United' },
|
||||||
|
],
|
||||||
|
|
||||||
|
// ── GROUP L (England) ──────────────────────────────────────────────────────
|
||||||
|
'England': [
|
||||||
|
{ name: 'Jordan Pickford', pos: 'GK', club: 'Everton' },
|
||||||
|
{ name: 'Dean Henderson', pos: 'GK', club: 'Crystal Palace' },
|
||||||
|
{ name: 'James Trafford', pos: 'GK', club: 'Burnley' },
|
||||||
|
{ name: 'Reece James', pos: 'DF', club: 'Chelsea' },
|
||||||
|
{ name: 'John Stones', pos: 'DF', club: 'Man City' },
|
||||||
|
{ name: 'Marc Guéhi', pos: 'DF', club: 'Crystal Palace' },
|
||||||
|
{ name: 'Tino Livramento', pos: 'DF', club: 'Newcastle' },
|
||||||
|
{ name: 'Ezri Konsa', pos: 'DF', club: 'Aston Villa' },
|
||||||
|
{ name: 'Dan Burn', pos: 'DF', club: 'Newcastle' },
|
||||||
|
{ name: 'Nico O\'Reilly', pos: 'DF', club: 'Man City' },
|
||||||
|
{ name: 'Jarell Quansah', pos: 'DF', club: 'Liverpool' },
|
||||||
|
{ name: 'Djed Spence', pos: 'DF', club: 'Genoa' },
|
||||||
|
{ name: 'Jude Bellingham', pos: 'MF', club: 'Real Madrid' },
|
||||||
|
{ name: 'Declan Rice', pos: 'MF', club: 'Arsenal' },
|
||||||
|
{ name: 'Kobbie Mainoo', pos: 'MF', club: 'Man United' },
|
||||||
|
{ name: 'Jordan Henderson', pos: 'MF', club: 'Ajax' },
|
||||||
|
{ name: 'Elliot Anderson', pos: 'MF', club: 'Newcastle' },
|
||||||
|
{ name: 'Eberechi Eze', pos: 'MF', club: 'Crystal Palace' },
|
||||||
|
{ name: 'Morgan Rogers', pos: 'MF', club: 'Aston Villa' },
|
||||||
|
{ name: 'Harry Kane', pos: 'FW', club: 'Bayern Munich' },
|
||||||
|
{ name: 'Bukayo Saka', pos: 'FW', club: 'Arsenal' },
|
||||||
|
{ name: 'Marcus Rashford', pos: 'FW', club: 'Man United' },
|
||||||
|
{ name: 'Anthony Gordon', pos: 'FW', club: 'Newcastle' },
|
||||||
|
{ name: 'Ivan Toney', pos: 'FW', club: 'Al-Ahli' },
|
||||||
|
{ name: 'Ollie Watkins', pos: 'FW', club: 'Aston Villa' },
|
||||||
|
{ name: 'Noni Madueke', pos: 'FW', club: 'Chelsea' },
|
||||||
|
],
|
||||||
|
|
||||||
|
// ── GROUP E (Germany) ──────────────────────────────────────────────────────
|
||||||
|
'Germany': [
|
||||||
|
{ name: 'Manuel Neuer', pos: 'GK', club: 'Bayern Munich' },
|
||||||
|
{ name: 'Marc-André ter Stegen',pos: 'GK', club: 'Barcelona' },
|
||||||
|
{ name: 'Oliver Baumann', pos: 'GK', club: 'Hoffenheim' },
|
||||||
|
{ name: 'Benjamin Henrichs', pos: 'DF', club: 'RB Leipzig' },
|
||||||
|
{ name: 'Matthias Ginter', pos: 'DF', club: 'Freiburg' },
|
||||||
|
{ name: 'Niklas Süle', pos: 'DF', club: 'Borussia Dortmund' },
|
||||||
|
{ name: 'Nico Schlotterbeck', pos: 'DF', club: 'Borussia Dortmund' },
|
||||||
|
{ name: 'Antonio Rüdiger', pos: 'DF', club: 'Real Madrid' },
|
||||||
|
{ name: 'David Raum', pos: 'DF', club: 'RB Leipzig' },
|
||||||
|
{ name: 'Thilo Kehrer', pos: 'DF', club: 'Monaco' },
|
||||||
|
{ name: 'Josua Kimmich', pos: 'MF', club: 'Bayern Munich' },
|
||||||
|
{ name: 'Ilkay Gündoğan', pos: 'MF', club: 'Barcelona' },
|
||||||
|
{ name: 'Leon Goretzka', pos: 'MF', club: 'Bayern Munich' },
|
||||||
|
{ name: 'Florian Wirtz', pos: 'MF', club: 'Bayer Leverkusen' },
|
||||||
|
{ name: 'Jamal Musiala', pos: 'MF', club: 'Bayern Munich' },
|
||||||
|
{ name: 'Kai Havertz', pos: 'FW', club: 'Arsenal' },
|
||||||
|
{ name: 'Leroy Sané', pos: 'FW', club: 'Bayern Munich' },
|
||||||
|
{ name: 'Thomas Müller', pos: 'FW', club: 'Bayern Munich' },
|
||||||
|
{ name: 'Serge Gnabry', pos: 'FW', club: 'Bayern Munich' },
|
||||||
|
{ name: 'Niclas Füllkrug', pos: 'FW', club: 'Borussia Dortmund' },
|
||||||
|
{ name: 'Karim Adeyemi', pos: 'FW', club: 'Borussia Dortmund' },
|
||||||
|
{ name: 'Chris Führich', pos: 'FW', club: 'Stuttgart' },
|
||||||
|
{ name: 'Maximilian Mittelstädt',pos:'DF', club: 'Stuttgart' },
|
||||||
|
{ name: 'Pascal Groß', pos: 'MF', club: 'Brighton' },
|
||||||
|
{ name: 'Robert Andrich', pos: 'MF', club: 'Bayer Leverkusen' },
|
||||||
|
{ name: 'Deniz Undav', pos: 'FW', club: 'Stuttgart' },
|
||||||
|
],
|
||||||
|
|
||||||
|
// ── GROUP H (Spain) ────────────────────────────────────────────────────────
|
||||||
|
'Spain': [
|
||||||
|
{ name: 'Unai Simón', pos: 'GK', club: 'Athletic Bilbao' },
|
||||||
|
{ name: 'David Raya', pos: 'GK', club: 'Arsenal' },
|
||||||
|
{ name: 'Robert Sánchez', pos: 'GK', club: 'Chelsea' },
|
||||||
|
{ name: 'Dani Carvajal', pos: 'DF', club: 'Real Madrid' },
|
||||||
|
{ name: 'Alejandro Balde', pos: 'DF', club: 'Barcelona' },
|
||||||
|
{ name: 'Aymeric Laporte', pos: 'DF', club: 'Al-Nassr' },
|
||||||
|
{ name: 'Iñigo Martínez', pos: 'DF', club: 'Barcelona' },
|
||||||
|
{ name: 'Marc Cucurella', pos: 'DF', club: 'Chelsea' },
|
||||||
|
{ name: 'Dani Vivian', pos: 'DF', club: 'Athletic Bilbao' },
|
||||||
|
{ name: 'Pedri', pos: 'MF', club: 'Barcelona' },
|
||||||
|
{ name: 'Sergio Busquets', pos: 'MF', club: 'Inter Miami' },
|
||||||
|
{ name: 'Fabian Ruiz', pos: 'MF', club: 'PSG' },
|
||||||
|
{ name: 'Rodri', pos: 'MF', club: 'Man City' },
|
||||||
|
{ name: 'Gavi', pos: 'MF', club: 'Barcelona' },
|
||||||
|
{ name: 'Mikel Merino', pos: 'MF', club: 'Arsenal' },
|
||||||
|
{ name: 'Álvaro Morata', pos: 'FW', club: 'AC Milan' },
|
||||||
|
{ name: 'Ferran Torres', pos: 'FW', club: 'Barcelona' },
|
||||||
|
{ name: 'Nico Williams', pos: 'FW', club: 'Athletic Bilbao' },
|
||||||
|
{ name: 'Lamine Yamal', pos: 'FW', club: 'Barcelona' },
|
||||||
|
{ name: 'Dani Olmo', pos: 'FW', club: 'Barcelona' },
|
||||||
|
{ name: 'Mikel Oyarzabal', pos: 'FW', club: 'Real Sociedad' },
|
||||||
|
{ name: 'Joselu', pos: 'FW', club: 'Al-Qadsiah' },
|
||||||
|
{ name: 'Yeremy Pino', pos: 'FW', club: 'Villarreal' },
|
||||||
|
{ name: 'Martín Zubimendi', pos: 'MF', club: 'Arsenal' },
|
||||||
|
{ name: 'Robin Le Normand', pos: 'DF', club: 'Atlético Madrid' },
|
||||||
|
{ name: 'Pau Cubarsí', pos: 'DF', club: 'Barcelona' },
|
||||||
|
],
|
||||||
|
|
||||||
|
// ── GROUP K (Portugal) ─────────────────────────────────────────────────────
|
||||||
|
'Portugal': [
|
||||||
|
{ name: 'Diogo Costa', pos: 'GK', club: 'Porto' },
|
||||||
|
{ name: 'Rui Patrício', pos: 'GK', club: 'Roma' },
|
||||||
|
{ name: 'José Sá', pos: 'GK', club: 'Wolves' },
|
||||||
|
{ name: 'João Cancelo', pos: 'DF', club: 'Barcelona' },
|
||||||
|
{ name: 'Nuno Mendes', pos: 'DF', club: 'PSG' },
|
||||||
|
{ name: 'Rúben Dias', pos: 'DF', club: 'Man City' },
|
||||||
|
{ name: 'Pepe', pos: 'DF', club: 'Unattached' },
|
||||||
|
{ name: 'António Silva', pos: 'DF', club: 'Benfica' },
|
||||||
|
{ name: 'Diogo Dalot', pos: 'DF', club: 'Man United' },
|
||||||
|
{ name: 'Bernardo Silva', pos: 'MF', club: 'Man City' },
|
||||||
|
{ name: 'Vitinha', pos: 'MF', club: 'PSG' },
|
||||||
|
{ name: 'Rúben Neves', pos: 'MF', club: 'Al-Hilal' },
|
||||||
|
{ name: 'João Palhinha', pos: 'MF', club: 'Bayern Munich' },
|
||||||
|
{ name: 'Bruno Fernandes', pos: 'MF', club: 'Man United' },
|
||||||
|
{ name: 'Matheus Nunes', pos: 'MF', club: 'Man City' },
|
||||||
|
{ name: 'Cristiano Ronaldo', pos: 'FW', club: 'Al-Nassr' },
|
||||||
|
{ name: 'Rafael Leão', pos: 'FW', club: 'AC Milan' },
|
||||||
|
{ name: 'João Félix', pos: 'FW', club: 'Barcelona' },
|
||||||
|
{ name: 'Gonçalo Ramos', pos: 'FW', club: 'PSG' },
|
||||||
|
{ name: 'Pedro Neto', pos: 'FW', club: 'Chelsea' },
|
||||||
|
{ name: 'Diogo Jota', pos: 'FW', club: 'Liverpool' },
|
||||||
|
{ name: 'Francisco Conceição', pos: 'FW', club: 'Juventus' },
|
||||||
|
{ name: 'Rúben Semedo', pos: 'DF', club: 'Olympiacos' },
|
||||||
|
{ name: 'Gonçalo Inácio', pos: 'DF', club: 'Sporting CP' },
|
||||||
|
{ name: 'Otávio', pos: 'MF', club: 'Al-Nassr' },
|
||||||
|
{ name: 'Gedson Fernandes', pos: 'MF', club: 'Benfica' },
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
// For teams without detailed squads, generate placeholder
|
||||||
|
export function getSquad(teamName) {
|
||||||
|
return squads[teamName] || null;
|
||||||
|
}
|
||||||
@@ -0,0 +1,797 @@
|
|||||||
|
/* ── Reset & Base ─────────────────────────────────────────────────────────── */
|
||||||
|
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
||||||
|
|
||||||
|
:root {
|
||||||
|
/* LIGHT THEME */
|
||||||
|
--bg-deep: #f0f4f8;
|
||||||
|
--bg-card: #ffffff;
|
||||||
|
--bg-card-hover:#f8fafc;
|
||||||
|
--bg-header: #e2e8f0;
|
||||||
|
--border: rgba(0,0,0,0.08);
|
||||||
|
--border-hover: rgba(0,0,0,0.15);
|
||||||
|
--text-primary: #0f172a;
|
||||||
|
--text-secondary: #334155;
|
||||||
|
--text-muted: rgba(15,23,42,0.6);
|
||||||
|
--gold: #d4af37;
|
||||||
|
--gold-glow: rgba(212,175,55,0.2);
|
||||||
|
--pitch-1: #2e7d32;
|
||||||
|
--pitch-2: #276b2a;
|
||||||
|
--light-beam: rgba(255,255,255,0.15);
|
||||||
|
--radius-card: 16px;
|
||||||
|
--radius-sm: 8px;
|
||||||
|
--transition: 0.25s cubic-bezier(0.4,0,0.2,1);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="dark"] {
|
||||||
|
/* DARK THEME */
|
||||||
|
--bg-deep: #080c14;
|
||||||
|
--bg-card: #0d1424;
|
||||||
|
--bg-card-hover:#111c30;
|
||||||
|
--bg-header: #060a12;
|
||||||
|
--border: rgba(255,255,255,0.07);
|
||||||
|
--border-hover: rgba(255,255,255,0.15);
|
||||||
|
--text-primary: #f0f4ff;
|
||||||
|
--text-secondary: #cbd5e1;
|
||||||
|
--text-muted: rgba(240,244,255,0.5);
|
||||||
|
--gold: #ffd700;
|
||||||
|
--gold-glow: rgba(255,215,0,0.3);
|
||||||
|
--pitch-1: #1a4f21;
|
||||||
|
--pitch-2: #15401b;
|
||||||
|
--light-beam: rgba(255,255,255,0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
html { scroll-behavior: smooth; }
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: 'Outfit', system-ui, sans-serif;
|
||||||
|
background: var(--bg-deep);
|
||||||
|
color: var(--text-primary);
|
||||||
|
min-height: 100vh;
|
||||||
|
overflow-x: hidden;
|
||||||
|
transition: background var(--transition), color var(--transition);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Header & Stadium Animation ───────────────────────────────────────────── */
|
||||||
|
.site-header {
|
||||||
|
position: relative;
|
||||||
|
min-height: 420px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
overflow: hidden;
|
||||||
|
border-bottom: 1px solid var(--border);
|
||||||
|
background: var(--bg-header) url('/stadium_bg.png') no-repeat center bottom / cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.site-header::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
/* Add an overlay so the text remains legible */
|
||||||
|
background: linear-gradient(to bottom, var(--bg-header) 0%, transparent 40%, var(--bg-deep) 100%);
|
||||||
|
opacity: 0.8;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Theme Toggle Button */
|
||||||
|
.theme-toggle-btn {
|
||||||
|
position: absolute;
|
||||||
|
top: 24px;
|
||||||
|
right: 24px;
|
||||||
|
z-index: 10;
|
||||||
|
background: var(--bg-card);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: 50%;
|
||||||
|
width: 44px;
|
||||||
|
height: 44px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
cursor: pointer;
|
||||||
|
color: var(--text-primary);
|
||||||
|
font-size: 20px;
|
||||||
|
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
|
||||||
|
transition: all var(--transition);
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-toggle-btn:hover {
|
||||||
|
transform: scale(1.1);
|
||||||
|
border-color: var(--gold);
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-content {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
text-align: center;
|
||||||
|
padding: 56px 24px 44px;
|
||||||
|
max-width: 800px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.trophy-wrap { position: relative; display: inline-block; margin-bottom: 16px; }
|
||||||
|
.trophy-icon {
|
||||||
|
font-size: clamp(52px, 10vw, 76px);
|
||||||
|
display: block;
|
||||||
|
animation: trophy-bob 3s ease-in-out infinite;
|
||||||
|
filter: drop-shadow(0 0 24px rgba(255,215,0,0.5));
|
||||||
|
}
|
||||||
|
.trophy-glow {
|
||||||
|
position: absolute; inset: -20px;
|
||||||
|
background: radial-gradient(circle, rgba(255,215,0,0.2) 0%, transparent 70%);
|
||||||
|
border-radius: 50%;
|
||||||
|
animation: pulse-glow 3s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
@keyframes trophy-bob {
|
||||||
|
0%, 100% { transform: translateY(0); }
|
||||||
|
50% { transform: translateY(-8px); }
|
||||||
|
}
|
||||||
|
@keyframes pulse-glow {
|
||||||
|
0%, 100% { opacity: 0.6; transform: scale(1); }
|
||||||
|
50% { opacity: 1; transform: scale(1.15); }
|
||||||
|
}
|
||||||
|
|
||||||
|
.site-title {
|
||||||
|
font-size: clamp(26px, 6vw, 50px);
|
||||||
|
font-weight: 900;
|
||||||
|
letter-spacing: -1px;
|
||||||
|
line-height: 1.1;
|
||||||
|
background: linear-gradient(135deg, #ffffff 30%, var(--gold) 100%);
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
-webkit-text-fill-color: transparent;
|
||||||
|
background-clip: text;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
.year {
|
||||||
|
background: linear-gradient(135deg, var(--gold), #ffaa00);
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
background-clip: text;
|
||||||
|
}
|
||||||
|
.site-subtitle {
|
||||||
|
font-size: clamp(13px, 2.5vw, 17px);
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--text-muted);
|
||||||
|
letter-spacing: 2px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
.site-dates {
|
||||||
|
font-size: 13px;
|
||||||
|
color: rgba(240,244,255,0.35);
|
||||||
|
letter-spacing: 1px;
|
||||||
|
margin-bottom: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stats-bar {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
background: rgba(255,255,255,0.04);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: 50px;
|
||||||
|
padding: 12px 24px;
|
||||||
|
backdrop-filter: blur(12px);
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 0;
|
||||||
|
}
|
||||||
|
.stat-item { display: flex; flex-direction: column; align-items: center; padding: 0 18px; }
|
||||||
|
.stat-number { font-size: 26px; font-weight: 800; color: var(--gold); line-height: 1; }
|
||||||
|
.stat-label { font-size: 10px; font-weight: 500; color: var(--text-muted); letter-spacing: 1px; text-transform: uppercase; margin-top: 2px; }
|
||||||
|
.stat-divider { width: 1px; height: 32px; background: var(--border); flex-shrink: 0; }
|
||||||
|
|
||||||
|
/* ── Controls Bar ─────────────────────────────────────────────────────────── */
|
||||||
|
.controls-bar {
|
||||||
|
position: sticky; top: 0; z-index: 100;
|
||||||
|
background: rgba(8,12,20,0.85);
|
||||||
|
backdrop-filter: blur(20px) saturate(180%);
|
||||||
|
border-bottom: 1px solid var(--border);
|
||||||
|
transition: box-shadow var(--transition);
|
||||||
|
}
|
||||||
|
.controls-bar.scrolled { box-shadow: 0 4px 32px rgba(0,0,0,0.5); }
|
||||||
|
.controls-inner {
|
||||||
|
max-width: 1400px; margin: 0 auto; padding: 12px 24px;
|
||||||
|
display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-wrap { position: relative; flex-shrink: 0; }
|
||||||
|
.search-icon { position: absolute; left: 12px; top: 50%; transform: translateY(-50%); font-size: 14px; pointer-events: none; }
|
||||||
|
.search-input {
|
||||||
|
background: rgba(255,255,255,0.06);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: 24px;
|
||||||
|
color: var(--text-primary);
|
||||||
|
font-family: inherit; font-size: 14px;
|
||||||
|
padding: 8px 16px 8px 36px;
|
||||||
|
width: 180px; outline: none;
|
||||||
|
transition: all var(--transition);
|
||||||
|
}
|
||||||
|
.search-input::placeholder { color: var(--text-muted); }
|
||||||
|
.search-input:focus {
|
||||||
|
border-color: rgba(255,215,0,0.4);
|
||||||
|
background: rgba(255,255,255,0.09);
|
||||||
|
box-shadow: 0 0 0 3px rgba(255,215,0,0.1);
|
||||||
|
width: 220px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-nav { display: flex; gap: 6px; flex-wrap: wrap; }
|
||||||
|
.filter-btn {
|
||||||
|
background: rgba(255,255,255,0.05);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: 20px;
|
||||||
|
color: var(--text-muted);
|
||||||
|
cursor: pointer;
|
||||||
|
font-family: inherit; font-size: 13px; font-weight: 500;
|
||||||
|
padding: 6px 14px;
|
||||||
|
transition: all var(--transition);
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.filter-btn:hover {
|
||||||
|
background: rgba(255,255,255,0.09);
|
||||||
|
border-color: var(--border-hover);
|
||||||
|
color: var(--text-primary);
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
|
.filter-btn.active {
|
||||||
|
background: linear-gradient(135deg, rgba(255,215,0,0.2), rgba(255,170,0,0.1));
|
||||||
|
border-color: rgba(255,215,0,0.5);
|
||||||
|
color: var(--gold);
|
||||||
|
font-weight: 600;
|
||||||
|
box-shadow: 0 0 12px rgba(255,215,0,0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Main content ─────────────────────────────────────────────────────────── */
|
||||||
|
.main-content { max-width: 1400px; margin: 0 auto; padding: 36px 24px 80px; }
|
||||||
|
.groups-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Group Card ───────────────────────────────────────────────────────────── */
|
||||||
|
.group-card {
|
||||||
|
background: var(--bg-card);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: var(--radius-card);
|
||||||
|
overflow: hidden;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all var(--transition);
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(20px);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.group-card.animate-in {
|
||||||
|
animation: slide-in 0.45s cubic-bezier(0.34,1.56,0.64,1) forwards;
|
||||||
|
}
|
||||||
|
@keyframes slide-in {
|
||||||
|
to { opacity: 1; transform: translateY(0); }
|
||||||
|
}
|
||||||
|
.group-card:hover {
|
||||||
|
border-color: var(--border-hover);
|
||||||
|
background: var(--bg-card-hover);
|
||||||
|
transform: translateY(-6px);
|
||||||
|
box-shadow: 0 24px 56px rgba(0,0,0,0.5), 0 0 0 1px rgba(255,255,255,0.06);
|
||||||
|
}
|
||||||
|
.group-card:focus { outline: 2px solid var(--gold); outline-offset: 2px; }
|
||||||
|
|
||||||
|
.group-header {
|
||||||
|
display: flex; align-items: center; justify-content: space-between;
|
||||||
|
padding: 16px 20px 14px;
|
||||||
|
border-bottom: 1px solid var(--border);
|
||||||
|
position: relative; overflow: hidden;
|
||||||
|
background: linear-gradient(135deg, color-mix(in srgb, var(--group-color) 10%, transparent), transparent);
|
||||||
|
}
|
||||||
|
.group-label-wrapper { position: relative; z-index: 1; }
|
||||||
|
.group-letter { font-size: 9px; font-weight: 700; letter-spacing: 2.5px; text-transform: uppercase; display: block; opacity: 0.7; }
|
||||||
|
.group-id { font-size: 36px; font-weight: 900; letter-spacing: -2px; line-height: 1; }
|
||||||
|
.group-right { display: flex; align-items: center; gap: 10px; position: relative; z-index: 1; }
|
||||||
|
.match-count { font-size: 11px; color: var(--text-muted); font-weight: 500; }
|
||||||
|
.group-dot { width: 10px; height: 10px; border-radius: 50%; box-shadow: 0 0 12px currentColor; flex-shrink: 0; }
|
||||||
|
|
||||||
|
.team-list { padding: 8px 12px 10px; flex: 1; }
|
||||||
|
.team-card {
|
||||||
|
display: flex; align-items: center; gap: 12px;
|
||||||
|
padding: 9px 10px;
|
||||||
|
border-radius: var(--radius-sm);
|
||||||
|
transition: background var(--transition);
|
||||||
|
}
|
||||||
|
.team-card:hover { background: rgba(255,255,255,0.04); }
|
||||||
|
.team-flag {
|
||||||
|
font-size: 26px; line-height: 1; flex-shrink: 0;
|
||||||
|
filter: drop-shadow(0 2px 4px rgba(0,0,0,0.4));
|
||||||
|
transition: transform var(--transition);
|
||||||
|
}
|
||||||
|
.team-card:hover .team-flag { transform: scale(1.15) rotate(-3deg); }
|
||||||
|
.team-info { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
|
||||||
|
.team-name { font-size: 15px; font-weight: 600; color: var(--text-primary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
||||||
|
.team-meta { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
|
||||||
|
.conf-badge { font-size: 10px; font-weight: 700; letter-spacing: 0.5px; padding: 2px 7px; border-radius: 20px; text-transform: uppercase; }
|
||||||
|
.host-badge { font-size: 10px; font-weight: 600; padding: 2px 7px; border-radius: 20px; background: rgba(255,215,0,0.15); color: var(--gold); border: 1px solid rgba(255,215,0,0.3); }
|
||||||
|
|
||||||
|
.card-footer {
|
||||||
|
padding: 10px 16px;
|
||||||
|
border-top: 1px solid var(--border);
|
||||||
|
display: flex; align-items: center; justify-content: center;
|
||||||
|
}
|
||||||
|
.view-schedule-hint {
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--text-muted);
|
||||||
|
font-weight: 500;
|
||||||
|
letter-spacing: 0.3px;
|
||||||
|
transition: color var(--transition);
|
||||||
|
}
|
||||||
|
.group-card:hover .view-schedule-hint { color: var(--gold); }
|
||||||
|
|
||||||
|
/* ── No results ───────────────────────────────────────────────────────────── */
|
||||||
|
.no-results { grid-column: 1 / -1; text-align: center; padding: 80px 24px; color: var(--text-muted); }
|
||||||
|
.no-results-icon { font-size: 48px; margin-bottom: 16px; }
|
||||||
|
.no-results p { font-size: 18px; }
|
||||||
|
|
||||||
|
/* ── MODAL ────────────────────────────────────────────────────────────────── */
|
||||||
|
.modal-container {
|
||||||
|
display: none;
|
||||||
|
position: fixed; inset: 0; z-index: 1000;
|
||||||
|
align-items: center; justify-content: center;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
.modal-container.open { display: flex; }
|
||||||
|
|
||||||
|
.modal-backdrop {
|
||||||
|
position: absolute; inset: 0;
|
||||||
|
background: rgba(0,0,0,0.75);
|
||||||
|
backdrop-filter: blur(6px);
|
||||||
|
animation: fade-in 0.2s ease;
|
||||||
|
}
|
||||||
|
@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }
|
||||||
|
|
||||||
|
.modal-box {
|
||||||
|
position: relative; z-index: 1;
|
||||||
|
background: #0d1424;
|
||||||
|
border: 1px solid rgba(255,255,255,0.1);
|
||||||
|
border-radius: 20px;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 640px;
|
||||||
|
max-height: 85vh;
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex; flex-direction: column;
|
||||||
|
box-shadow: 0 40px 80px rgba(0,0,0,0.6), 0 0 0 1px rgba(255,255,255,0.05);
|
||||||
|
animation: modal-in 0.3s cubic-bezier(0.34,1.56,0.64,1);
|
||||||
|
}
|
||||||
|
@keyframes modal-in {
|
||||||
|
from { opacity: 0; transform: scale(0.88) translateY(24px); }
|
||||||
|
to { opacity: 1; transform: scale(1) translateY(0); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Modal header */
|
||||||
|
.modal-header {
|
||||||
|
padding: 24px 24px 20px;
|
||||||
|
background: linear-gradient(135deg, color-mix(in srgb, var(--group-color) 18%, transparent), color-mix(in srgb, var(--group-color) 4%, transparent));
|
||||||
|
border-bottom: 1px solid rgba(255,255,255,0.07);
|
||||||
|
position: relative;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
.modal-title-wrap {
|
||||||
|
display: flex; align-items: baseline; gap: 8px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
.modal-group-label { font-size: 11px; font-weight: 700; letter-spacing: 3px; text-transform: uppercase; color: var(--text-muted); }
|
||||||
|
.modal-group-id { font-size: 44px; font-weight: 900; letter-spacing: -3px; line-height: 1; color: var(--text-primary); }
|
||||||
|
|
||||||
|
.modal-teams-row { display: flex; gap: 8px; flex-wrap: wrap; }
|
||||||
|
.modal-team-chip {
|
||||||
|
display: flex; align-items: center; gap: 6px;
|
||||||
|
background: rgba(255,255,255,0.07);
|
||||||
|
border: 1px solid rgba(255,255,255,0.1);
|
||||||
|
border-radius: 24px;
|
||||||
|
padding: 5px 12px;
|
||||||
|
font-size: 13px; font-weight: 600;
|
||||||
|
}
|
||||||
|
.modal-team-chip span:first-child { font-size: 18px; }
|
||||||
|
|
||||||
|
.modal-close {
|
||||||
|
position: absolute; top: 18px; right: 18px;
|
||||||
|
background: rgba(255,255,255,0.08);
|
||||||
|
border: 1px solid rgba(255,255,255,0.12);
|
||||||
|
border-radius: 50%;
|
||||||
|
color: var(--text-muted);
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 16px;
|
||||||
|
width: 34px; height: 34px;
|
||||||
|
display: flex; align-items: center; justify-content: center;
|
||||||
|
transition: all var(--transition);
|
||||||
|
}
|
||||||
|
.modal-close:hover { background: rgba(255,255,255,0.15); color: var(--text-primary); transform: scale(1.1); }
|
||||||
|
|
||||||
|
/* Modal body */
|
||||||
|
.modal-body { overflow-y: auto; padding: 20px 24px 24px; flex: 1; }
|
||||||
|
.modal-body::-webkit-scrollbar { width: 4px; }
|
||||||
|
.modal-body::-webkit-scrollbar-track { background: transparent; }
|
||||||
|
.modal-body::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.15); border-radius: 4px; }
|
||||||
|
|
||||||
|
/* Modal Tabs */
|
||||||
|
.modal-tabs {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
padding: 0 24px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
border-bottom: 1px solid rgba(255,255,255,0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-tab {
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
color: var(--text-muted);
|
||||||
|
font-family: inherit;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
padding: 12px 16px;
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
transition: color var(--transition);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-tab:hover {
|
||||||
|
color: var(--text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-tab.active {
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-tab.active::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
bottom: -1px;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 2px;
|
||||||
|
background: var(--text-primary);
|
||||||
|
border-radius: 2px 2px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tab Content */
|
||||||
|
.tab-content {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-content.active {
|
||||||
|
display: block;
|
||||||
|
animation: fadeIn 0.3s ease-out forwards;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fadeIn {
|
||||||
|
from { opacity: 0; transform: translateY(5px); }
|
||||||
|
to { opacity: 1; transform: translateY(0); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Squads Section ───────────────────────────────────────────────────────── */
|
||||||
|
.squad-team {
|
||||||
|
background: color-mix(in srgb, var(--bg-deep) 40%, transparent);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: 12px;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.squad-team-header {
|
||||||
|
padding: 16px 20px;
|
||||||
|
background: color-mix(in srgb, var(--bg-card-hover) 80%, transparent);
|
||||||
|
border-bottom: 1px solid var(--border);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.squad-flag {
|
||||||
|
font-size: 24px;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.squad-team-name {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--text-primary);
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.squad-count {
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--text-muted);
|
||||||
|
font-weight: 600;
|
||||||
|
background: var(--bg-deep);
|
||||||
|
padding: 4px 8px;
|
||||||
|
border-radius: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.squad-pos-group {
|
||||||
|
padding: 16px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.squad-pos-group + .squad-pos-group {
|
||||||
|
border-top: 1px dashed var(--border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.squad-pos-label {
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
margin-bottom: 12px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.squad-players {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.squad-player {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
padding: 8px;
|
||||||
|
border-radius: 8px;
|
||||||
|
background: var(--bg-card);
|
||||||
|
border: 1px solid transparent;
|
||||||
|
transition: all var(--transition);
|
||||||
|
}
|
||||||
|
|
||||||
|
.squad-player:hover {
|
||||||
|
background: var(--bg-card-hover);
|
||||||
|
border-color: var(--border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.player-pos-badge {
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 800;
|
||||||
|
padding: 4px 6px;
|
||||||
|
border-radius: 4px;
|
||||||
|
min-width: 32px;
|
||||||
|
text-align: center;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.player-pos-GK { background: rgba(234, 179, 8, 0.2); color: #facc15; }
|
||||||
|
.player-pos-DF { background: rgba(59, 130, 246, 0.2); color: #60a5fa; }
|
||||||
|
.player-pos-MF { background: rgba(34, 197, 94, 0.2); color: #4ade80; }
|
||||||
|
.player-pos-FW { background: rgba(239, 68, 68, 0.2); color: #f87171; }
|
||||||
|
|
||||||
|
.player-info {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.player-name {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.player-club {
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--text-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.squad-unavailable {
|
||||||
|
padding: 24px;
|
||||||
|
text-align: center;
|
||||||
|
color: var(--text-muted);
|
||||||
|
font-style: italic;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Matchday section ─────────────────────────────────────────────────────── */
|
||||||
|
.matchdays { display: flex; flex-direction: column; gap: 24px; }
|
||||||
|
.matchday-section {}
|
||||||
|
.matchday-label {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 800;
|
||||||
|
letter-spacing: 2.5px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: var(--gold);
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
.matchday-label::before,
|
||||||
|
.matchday-label::after {
|
||||||
|
content: '';
|
||||||
|
flex: 1;
|
||||||
|
height: 1px;
|
||||||
|
background: linear-gradient(90deg, rgba(255,215,0,0.25), transparent);
|
||||||
|
}
|
||||||
|
.matchday-label::after {
|
||||||
|
background: linear-gradient(90deg, transparent, rgba(255,215,0,0.25));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Match accordion card ─────────────────────────────────────────────────── */
|
||||||
|
.match-card {
|
||||||
|
border: 1px solid rgba(255,255,255,0.07);
|
||||||
|
border-radius: 14px;
|
||||||
|
overflow: hidden;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
transition: border-color var(--transition), box-shadow var(--transition);
|
||||||
|
background: rgba(255,255,255,0.02);
|
||||||
|
}
|
||||||
|
.match-card:last-child { margin-bottom: 0; }
|
||||||
|
.match-card:hover {
|
||||||
|
border-color: rgba(255,255,255,0.14);
|
||||||
|
box-shadow: 0 4px 20px rgba(0,0,0,0.25);
|
||||||
|
}
|
||||||
|
.match-card.expanded {
|
||||||
|
border-color: var(--match-color, rgba(255,215,0,0.4));
|
||||||
|
box-shadow: 0 0 0 1px var(--match-color, rgba(255,215,0,0.15)),
|
||||||
|
0 8px 32px rgba(0,0,0,0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Collapsed header – big flags + names */
|
||||||
|
.match-summary {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr auto 1fr;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 18px 20px;
|
||||||
|
gap: 8px;
|
||||||
|
transition: background var(--transition);
|
||||||
|
}
|
||||||
|
.match-summary:hover { background: rgba(255,255,255,0.03); }
|
||||||
|
|
||||||
|
.match-team-col {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mc-flag {
|
||||||
|
font-size: 42px;
|
||||||
|
line-height: 1;
|
||||||
|
filter: drop-shadow(0 4px 10px rgba(0,0,0,0.5));
|
||||||
|
transition: transform var(--transition);
|
||||||
|
}
|
||||||
|
.match-summary:hover .mc-flag { transform: scale(1.08); }
|
||||||
|
.match-card.expanded .mc-flag { transform: scale(1.05); }
|
||||||
|
|
||||||
|
.mc-name {
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--text-primary);
|
||||||
|
text-align: center;
|
||||||
|
max-width: 110px;
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.match-divider {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
padding: 0 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mc-vs {
|
||||||
|
font-size: 9px;
|
||||||
|
font-weight: 900;
|
||||||
|
letter-spacing: 2px;
|
||||||
|
color: rgba(240,244,255,0.25);
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mc-chevron {
|
||||||
|
font-size: 20px;
|
||||||
|
color: var(--match-color, var(--gold));
|
||||||
|
opacity: 0.6;
|
||||||
|
transition: transform 0.3s cubic-bezier(0.4,0,0.2,1), opacity var(--transition);
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
.match-card.expanded .mc-chevron {
|
||||||
|
transform: rotate(90deg);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Expandable details panel */
|
||||||
|
.match-details-panel {
|
||||||
|
display: grid;
|
||||||
|
grid-template-rows: 0fr;
|
||||||
|
transition: grid-template-rows 0.35s cubic-bezier(0.4,0,0.2,1);
|
||||||
|
}
|
||||||
|
.match-card.expanded .match-details-panel {
|
||||||
|
grid-template-rows: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.match-details-inner {
|
||||||
|
overflow: hidden;
|
||||||
|
border-top: 0px solid transparent;
|
||||||
|
transition: border-color var(--transition), padding var(--transition);
|
||||||
|
}
|
||||||
|
.match-card.expanded .match-details-inner {
|
||||||
|
border-top: 1px solid var(--border);
|
||||||
|
padding: 4px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Detail rows */
|
||||||
|
.match-detail-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 14px;
|
||||||
|
padding: 10px 22px;
|
||||||
|
transition: background var(--transition);
|
||||||
|
}
|
||||||
|
.match-detail-row:hover { background: var(--bg-card-hover); }
|
||||||
|
.match-detail-row + .match-detail-row {
|
||||||
|
border-top: 1px solid var(--border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.md-icon {
|
||||||
|
font-size: 16px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
width: 24px;
|
||||||
|
text-align: center;
|
||||||
|
opacity: 0.85;
|
||||||
|
}
|
||||||
|
|
||||||
|
.md-text {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1px;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.md-label {
|
||||||
|
font-size: 10px;
|
||||||
|
font-weight: 700;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: var(--match-color, var(--gold));
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.md-value {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--text-primary);
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Footer ───────────────────────────────────────────────────────────────── */
|
||||||
|
.site-footer {
|
||||||
|
border-top: 1px solid var(--border);
|
||||||
|
padding: 32px 24px;
|
||||||
|
text-align: center;
|
||||||
|
color: var(--text-muted);
|
||||||
|
font-size: 13px;
|
||||||
|
background: linear-gradient(to top, rgba(255,215,0,0.02), transparent);
|
||||||
|
}
|
||||||
|
.footer-main { font-weight: 600; color: rgba(240,244,255,0.6); margin-bottom: 6px; }
|
||||||
|
.footer-sub { margin-bottom: 6px; }
|
||||||
|
.footer-debut { color: rgba(255,215,0,0.5); font-size: 12px; }
|
||||||
|
|
||||||
|
/* ── Responsive ───────────────────────────────────────────────────────────── */
|
||||||
|
@media (max-width: 640px) {
|
||||||
|
.stats-bar { padding: 10px 12px; }
|
||||||
|
.stat-item { padding: 0 10px; }
|
||||||
|
.stat-number { font-size: 20px; }
|
||||||
|
.stat-divider { height: 26px; }
|
||||||
|
|
||||||
|
.controls-inner { flex-direction: column; align-items: stretch; }
|
||||||
|
.search-input, .search-input:focus { width: 100%; }
|
||||||
|
.search-wrap { width: 100%; }
|
||||||
|
.filter-nav { justify-content: center; }
|
||||||
|
|
||||||
|
.groups-grid { grid-template-columns: 1fr; }
|
||||||
|
|
||||||
|
.modal-box { max-height: 92vh; border-radius: 16px 16px 0 0; align-self: flex-end; margin: 0 -20px -20px; width: calc(100% + 40px); max-width: none; }
|
||||||
|
.match-team-name { font-size: 12px; }
|
||||||
|
.modal-group-id { font-size: 36px; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 1200px) {
|
||||||
|
.groups-grid { grid-template-columns: repeat(4, 1fr); }
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import { defineConfig } from 'vite'
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
server: {
|
||||||
|
watch: {
|
||||||
|
// Required for WSL2 – Windows filesystem doesn't fire inotify events
|
||||||
|
usePolling: true,
|
||||||
|
interval: 300,
|
||||||
|
},
|
||||||
|
host: true,
|
||||||
|
},
|
||||||
|
})
|
||||||