refactor: replace hardcoded hex colors with theme tokens, move data/ to root

- Add --color-green-mid token (#4a7a55) to @theme for dimmer stat values
- Replace all text-[#hex]/bg-[#hex] arbitrary values with named tokens:
  text-green, text-green-light, text-green-sec, text-green-muted,
  text-green-dark, text-green-mid, text-text, bg-card, bg-bg, border-border
- Replace rgba(34,197,94,X) inline styles with bg-green/X opacity modifiers
- Convert single-prop style={{ borderColor/background }} to className
- Fix SVG stroke="#dff5e8" → stroke="currentColor"
- Use CSS variables in globals.css base styles (background-color, color)
- Move app/data/wikipedia/ → data/ (project root, not inside Next.js app dir)
- Update Dockerfile, seed.ts, scrape-wikipedia.ts paths accordingly
- Remove unused app/data/world_cup.csv

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-15 18:08:23 +02:00
parent 187ee2e312
commit b141356247
125 changed files with 279 additions and 322 deletions
+1 -1
View File
@@ -22,7 +22,7 @@ COPY --from=builder /app/scripts ./scripts
COPY --from=builder /app/lib ./lib COPY --from=builder /app/lib ./lib
COPY --from=builder /app/package.json ./package.json COPY --from=builder /app/package.json ./package.json
COPY --from=builder /app/tsconfig.json ./tsconfig.json COPY --from=builder /app/tsconfig.json ./tsconfig.json
COPY --from=builder /app/app/data ./app/data COPY --from=builder /app/data ./data
USER nextjs USER nextjs
EXPOSE 3000 EXPOSE 3000
ENV PORT=3000 HOSTNAME="0.0.0.0" ENV PORT=3000 HOSTNAME="0.0.0.0"
-23
View File
@@ -1,23 +0,0 @@
Year,Host,Teams,Champion,Runner-Up,TopScorrer,Attendance,AttendanceAvg,Matches
2022,Qatar,32,Argentina,France,Kylian Mbappé - 8,3404252,53191,64
2018,Russia,32,France,Croatia,Harry Kane - 6,3031768,47371,64
2014,Brazil,32,Germany,Argentina,James Rodríguez - 6,3429873,53592,64
2010,South Africa,32,Spain,Netherlands,"Wesley Sneijder, Thomas Müller... - 5",3178856,49670,64
2006,Germany,32,Italy,France,Miroslav Klose - 5,3352605,52384,64
2002,"Korea Republic, Japan",32,Brazil,Germany,Ronaldo - 8,2705337,42271,64
1998,France,32,France,Brazil,Davor Šuker - 6,2903477,45367,64
1994,United States,24,Brazil,Italy,"Hristo Stoichkov, Oleg Salenko - 6",3587538,68991,52
1990,Italy,24,West Germany,Argentina,Salvatore Schillaci - 6,2516215,48389,52
1986,Mexico,24,Argentina,West Germany,Gary Lineker - 6,2394031,46039,52
1982,Spain,24,Italy,West Germany,Paolo Rossi - 6,2109723,40572,52
1978,Argentina,16,Argentina,Netherlands,Mario Kempes - 6,1545791,40679,38
1974,Germany,16,West Germany,Netherlands,Grzegorz Lato - 7,1865753,49099,38
1970,Mexico,16,Brazil,Italy,Gerd Müller - 10,1603975,50124,32
1966,England,16,England,West Germany,Eusébio - 9,1563135,48848,32
1962,Chile,16,Brazil,Czechoslovakia,"Leonel Sánchez, Flórián Albert... - 4",893172,27912,32
1958,Sweden,16,Brazil,Sweden,Just Fontaine - 13,819810,23423,35
1954,Switzerland,16,Germany,Hungary,Sándor Kocsis - 11,768607,29562,26
1950,Brazil,15,Uruguay,Brazil,Ademir - 8,1045246,47511,22
1938,France,16,Italy,Hungary,Leônidas - 7,375700,20872,18
1934,Italy,16,Italy,Czechoslovakia,Oldřich Nejedlý - 5,363000,21353,17
1930,Uruguay,13,Uruguay,Argentina,Guillermo Stábile - 8,590549,32808,18
1 Year Host Teams Champion Runner-Up TopScorrer Attendance AttendanceAvg Matches
2 2022 Qatar 32 Argentina France Kylian Mbappé - 8 3404252 53191 64
3 2018 Russia 32 France Croatia Harry Kane - 6 3031768 47371 64
4 2014 Brazil 32 Germany Argentina James Rodríguez - 6 3429873 53592 64
5 2010 South Africa 32 Spain Netherlands Wesley Sneijder, Thomas Müller... - 5 3178856 49670 64
6 2006 Germany 32 Italy France Miroslav Klose - 5 3352605 52384 64
7 2002 Korea Republic, Japan 32 Brazil Germany Ronaldo - 8 2705337 42271 64
8 1998 France 32 France Brazil Davor Šuker - 6 2903477 45367 64
9 1994 United States 24 Brazil Italy Hristo Stoichkov, Oleg Salenko - 6 3587538 68991 52
10 1990 Italy 24 West Germany Argentina Salvatore Schillaci - 6 2516215 48389 52
11 1986 Mexico 24 Argentina West Germany Gary Lineker - 6 2394031 46039 52
12 1982 Spain 24 Italy West Germany Paolo Rossi - 6 2109723 40572 52
13 1978 Argentina 16 Argentina Netherlands Mario Kempes - 6 1545791 40679 38
14 1974 Germany 16 West Germany Netherlands Grzegorz Lato - 7 1865753 49099 38
15 1970 Mexico 16 Brazil Italy Gerd Müller - 10 1603975 50124 32
16 1966 England 16 England West Germany Eusébio - 9 1563135 48848 32
17 1962 Chile 16 Brazil Czechoslovakia Leonel Sánchez, Flórián Albert... - 4 893172 27912 32
18 1958 Sweden 16 Brazil Sweden Just Fontaine - 13 819810 23423 35
19 1954 Switzerland 16 Germany Hungary Sándor Kocsis - 11 768607 29562 26
20 1950 Brazil 15 Uruguay Brazil Ademir - 8 1045246 47511 22
21 1938 France 16 Italy Hungary Leônidas - 7 375700 20872 18
22 1934 Italy 16 Italy Czechoslovakia Oldřich Nejedlý - 5 363000 21353 17
23 1930 Uruguay 13 Uruguay Argentina Guillermo Stábile - 8 590549 32808 18
+6 -5
View File
@@ -12,6 +12,7 @@
--color-green-sec: #6abf7a; --color-green-sec: #6abf7a;
--color-green-muted: #2a5c35; --color-green-muted: #2a5c35;
--color-green-dark: #1a3a22; --color-green-dark: #1a3a22;
--color-green-mid: #4a7a55;
--color-text: #dff5e8; --color-text: #dff5e8;
--color-border: rgba(34,197,94,0.15); --color-border: rgba(34,197,94,0.15);
@@ -25,7 +26,7 @@
html { scroll-behavior: smooth; } html { scroll-behavior: smooth; }
body { body {
background-color: #040d08; background-color: var(--color-bg);
/* Diagonal goal-net pattern */ /* Diagonal goal-net pattern */
background-image: background-image:
repeating-linear-gradient( repeating-linear-gradient(
@@ -38,7 +39,7 @@
rgba(34,197,94,0.028) 0, rgba(34,197,94,0.028) 1px, rgba(34,197,94,0.028) 0, rgba(34,197,94,0.028) 1px,
transparent 1px, transparent 28px transparent 1px, transparent 28px
); );
color: #dff5e8; color: var(--color-text);
font-family: "Space Grotesk", system-ui, sans-serif; font-family: "Space Grotesk", system-ui, sans-serif;
min-height: 100vh; min-height: 100vh;
overflow-x: hidden; overflow-x: hidden;
@@ -47,7 +48,7 @@
/* Glass card — semi-transparent over the body net pattern */ /* Glass card — semi-transparent over the body net pattern */
.glass-card { .glass-card {
background: rgba(4, 18, 8, 0.78); background: rgba(4, 18, 8, 0.78);
border: 1px solid rgba(34,197,94,0.15); border: 1px solid var(--color-border);
border-radius: 1rem; border-radius: 1rem;
overflow: hidden; overflow: hidden;
backdrop-filter: blur(10px); backdrop-filter: blur(10px);
@@ -56,7 +57,7 @@
.glass-card-hero { .glass-card-hero {
background: linear-gradient(145deg, rgba(13,32,22,0.82), rgba(16,42,28,0.82)); background: linear-gradient(145deg, rgba(13,32,22,0.82), rgba(16,42,28,0.82));
border: 1px solid rgba(34,197,94,0.28); border: 1px solid color-mix(in srgb, var(--color-green) 28%, transparent);
border-radius: 1rem; border-radius: 1rem;
overflow: hidden; overflow: hidden;
backdrop-filter: blur(10px); backdrop-filter: blur(10px);
@@ -65,7 +66,7 @@
::-webkit-scrollbar { width: 5px; } ::-webkit-scrollbar { width: 5px; }
::-webkit-scrollbar-track { background: #020a04; } ::-webkit-scrollbar-track { background: #020a04; }
::-webkit-scrollbar-thumb { background: rgba(34,197,94,0.25); border-radius: 4px; } ::-webkit-scrollbar-thumb { background: color-mix(in srgb, var(--color-green) 25%, transparent); border-radius: 4px; }
@keyframes livePulse { @keyframes livePulse {
0%, 100% { opacity: 1; transform: scale(1); } 0%, 100% { opacity: 1; transform: scale(1); }
+13 -20
View File
@@ -36,14 +36,14 @@ export default function GroupsPage() {
return ( return (
<div className="max-w-[1200px] mx-auto px-7 py-10 pb-16"> <div className="max-w-[1200px] mx-auto px-7 py-10 pb-16">
<div className="mb-9"> <div className="mb-9">
<h1 className="font-['Bebas_Neue'] text-[52px] tracking-[0.04em] text-[#22c55e] leading-none">2026 Groups</h1> <h1 className="font-['Bebas_Neue'] text-[52px] tracking-[0.04em] text-green leading-none">2026 Groups</h1>
<p className="text-[#2a5c35] text-sm mt-1.5">48 teams · 12 groups · Top 2 + 8 best 3rd-place advance</p> <p className="text-green-muted text-sm mt-1.5">48 teams · 12 groups · Top 2 + 8 best 3rd-place advance</p>
</div> </div>
{loading && !data && ( {loading && !data && (
<div className="grid grid-cols-[repeat(auto-fill,minmax(268px,1fr))] gap-3.5"> <div className="grid grid-cols-[repeat(auto-fill,minmax(268px,1fr))] gap-3.5">
{Array.from({ length: 12 }).map((_, i) => ( {Array.from({ length: 12 }).map((_, i) => (
<div key={i} className="h-56 rounded-2xl animate-pulse" style={{ background: '#0a1810' }} /> <div key={i} className="h-56 rounded-2xl animate-pulse bg-card" />
))} ))}
</div> </div>
)} )}
@@ -58,13 +58,11 @@ export default function GroupsPage() {
const letter = groupName.replace('Group ', '') const letter = groupName.replace('Group ', '')
return ( return (
<div key={groupName} className="glass-card"> <div key={groupName} className="glass-card">
<div className="px-4 py-3 border-b" style={{ <div className="px-4 py-3 border-b border-green/10"
background: 'linear-gradient(90deg,rgba(34,197,94,0.12) 0%,rgba(34,197,94,0.04) 100%)', style={{ background: 'linear-gradient(90deg,color-mix(in srgb,var(--color-green) 12%,transparent) 0%,color-mix(in srgb,var(--color-green) 4%,transparent) 100%)' }}>
borderColor: 'rgba(34,197,94,0.1)', <span className="font-['Bebas_Neue'] text-[28px] text-green tracking-[0.05em]">GROUP {letter}</span>
}}>
<span className="font-['Bebas_Neue'] text-[28px] text-[#22c55e] tracking-[0.05em]">GROUP {letter}</span>
</div> </div>
<div className="grid px-4 py-2 text-[9px] text-[#2a5c35] tracking-[0.1em] uppercase" <div className="grid px-4 py-2 text-[9px] text-green-muted tracking-[0.1em] uppercase"
style={{ gridTemplateColumns: '1fr 22px 22px 22px 22px 22px 30px', gap: '3px' }}> style={{ gridTemplateColumns: '1fr 22px 22px 22px 22px 22px 30px', gap: '3px' }}>
<span>Team</span> <span>Team</span>
<span className="text-center">P</span><span className="text-center">W</span> <span className="text-center">P</span><span className="text-center">W</span>
@@ -73,24 +71,19 @@ export default function GroupsPage() {
</div> </div>
{sorted.map((t, idx) => ( {sorted.map((t, idx) => (
<Link key={t.team.id} href={`/teams/${t.team.slug}`}> <Link key={t.team.id} href={`/teams/${t.team.slug}`}>
<div className="grid px-4 py-2.5 items-center border-t hover:bg-[rgba(34,197,94,0.03)] transition-colors cursor-pointer" <div className={`grid px-4 py-2.5 items-center border-t border-green/[6%] hover:bg-green/[3%] transition-colors cursor-pointer ${idx < 2 ? 'bg-green/[2.5%]' : ''}`}
style={{ style={{ gridTemplateColumns: '1fr 22px 22px 22px 22px 22px 30px', gap: '3px' }}>
gridTemplateColumns: '1fr 22px 22px 22px 22px 22px 30px',
gap: '3px',
borderColor: 'rgba(34,197,94,0.06)',
background: idx < 2 ? 'rgba(34,197,94,0.025)' : undefined,
}}>
<div className="flex items-center gap-2 overflow-hidden"> <div className="flex items-center gap-2 overflow-hidden">
<TeamFlag name={t.team.name} iso2={t.team.iso2} size="sm" /> <TeamFlag name={t.team.name} iso2={t.team.iso2} size="sm" />
<span className={`text-sm truncate font-medium ${idx < 2 ? 'text-[#dff5e8]' : 'text-[#6abf7a]'}`}>{t.team.name}</span> <span className={`text-sm truncate font-medium ${idx < 2 ? 'text-text' : 'text-green-sec'}`}>{t.team.name}</span>
</div> </div>
{[t.played, t.won, t.drawn, t.lost].map((v, i) => ( {[t.played, t.won, t.drawn, t.lost].map((v, i) => (
<span key={i} className="text-center text-[13px] text-[#4a7a55]">{v}</span> <span key={i} className="text-center text-[13px] text-green-mid">{v}</span>
))} ))}
<span className="text-center text-[13px] text-[#4a7a55]"> <span className="text-center text-[13px] text-green-mid">
{t.goalDiff > 0 ? `+${t.goalDiff}` : t.goalDiff} {t.goalDiff > 0 ? `+${t.goalDiff}` : t.goalDiff}
</span> </span>
<span className="text-center text-[13px] font-bold text-[#22c55e]">{t.pts}</span> <span className="text-center text-[13px] font-bold text-green">{t.pts}</span>
</div> </div>
</Link> </Link>
))} ))}
+15 -17
View File
@@ -33,17 +33,17 @@ export default function HistoryPage() {
return ( return (
<div className="max-w-[1200px] mx-auto px-7 py-10 pb-16"> <div className="max-w-[1200px] mx-auto px-7 py-10 pb-16">
<h1 className="font-['Bebas_Neue'] text-[52px] tracking-[0.04em] text-[#22c55e] leading-none mb-2"> <h1 className="font-['Bebas_Neue'] text-[52px] tracking-[0.04em] text-green leading-none mb-2">
World Cup History World Cup History
</h1> </h1>
<p className="text-[#2a5c35] text-sm mb-9"> <p className="text-green-muted text-sm mb-9">
Every edition Uruguay 1930 through 2026 · {tournaments.length} tournaments Every edition Uruguay 1930 through 2026 · {tournaments.length} tournaments
</p> </p>
{loading && !data && ( {loading && !data && (
<div className="grid grid-cols-[repeat(auto-fill,minmax(238px,1fr))] gap-3.5"> <div className="grid grid-cols-[repeat(auto-fill,minmax(238px,1fr))] gap-3.5">
{Array.from({ length: 24 }).map((_, i) => ( {Array.from({ length: 24 }).map((_, i) => (
<div key={i} className="h-52 rounded-2xl animate-pulse" style={{ background: '#0a1810' }} /> <div key={i} className="h-52 rounded-2xl animate-pulse bg-card" />
))} ))}
</div> </div>
)} )}
@@ -54,52 +54,50 @@ export default function HistoryPage() {
const topScorer = t.topScorers?.[0] const topScorer = t.topScorers?.[0]
return ( return (
<Link key={t.year} href={`/tournaments/${t.year}`}> <Link key={t.year} href={`/tournaments/${t.year}`}>
<div className="glass-card p-5 relative cursor-pointer hover:border-[rgba(34,197,94,0.3)] transition-colors"> <div className="glass-card p-5 relative cursor-pointer hover:border-green/30 transition-colors">
{/* Year watermark */} {/* Year watermark */}
<div className="absolute right-[-6px] bottom-[-18px] font-['Bebas_Neue'] text-[88px] leading-none pointer-events-none select-none" <div className="absolute right-[-6px] bottom-[-18px] font-['Bebas_Neue'] text-[88px] leading-none pointer-events-none select-none text-green/[4%]">
style={{ color: 'rgba(34,197,94,0.04)' }}>
{t.year} {t.year}
</div> </div>
<div className="relative"> <div className="relative">
<div className="flex justify-between items-start mb-3.5"> <div className="flex justify-between items-start mb-3.5">
<div> <div>
<div className="font-['Bebas_Neue'] text-[34px] text-[#22c55e] leading-none">{t.year}</div> <div className="font-['Bebas_Neue'] text-[34px] text-green leading-none">{t.year}</div>
<div className="text-xs text-[#2a5c35] mt-0.5"> <div className="text-xs text-green-muted mt-0.5">
{t.host} {t.host}
</div> </div>
</div> </div>
{inProgress {inProgress
? <div className="text-[10px] text-[#22c55e] font-bold tracking-[0.12em] bg-[rgba(34,197,94,0.1)] px-2.5 py-1 rounded-full mt-1"> ? <div className="text-[10px] text-green font-bold tracking-[0.12em] bg-green/10 px-2.5 py-1 rounded-full mt-1">
IN PROGRESS IN PROGRESS
</div> </div>
: t.winner && ( : t.winner && (
<div className="text-right"> <div className="text-right">
<TeamFlag name={t.winner} size="md" /> <TeamFlag name={t.winner} size="md" />
<div className="text-[11px] text-[#6abf7a] mt-0.5">{t.winner}</div> <div className="text-[11px] text-green-sec mt-0.5">{t.winner}</div>
</div> </div>
)} )}
</div> </div>
{!inProgress && t.winner && t.runnerUp && ( {!inProgress && t.winner && t.runnerUp && (
<div className="rounded-lg px-3 py-2 text-xs text-[#6abf7a] mb-3" <div className="rounded-lg px-3 py-2 text-xs text-green-sec mb-3 bg-green/[7%]">
style={{ background: 'rgba(34,197,94,0.07)' }}> <span className="font-semibold text-text">{t.winner}</span>
<span className="font-semibold text-[#dff5e8]">{t.winner}</span> <span className="mx-2 text-green-muted">def.</span>
<span className="mx-2 text-[#2a5c35]">def.</span>
{t.runnerUp} {t.runnerUp}
</div> </div>
)} )}
<div className="flex gap-3.5 text-[11px] text-[#2a5c35] flex-wrap"> <div className="flex gap-3.5 text-[11px] text-green-muted flex-wrap">
{t.totalGoals != null && <span className="inline-flex items-center gap-1"><FireIcon className="w-3 h-3" />{t.totalGoals}</span>} {t.totalGoals != null && <span className="inline-flex items-center gap-1"><FireIcon className="w-3 h-3" />{t.totalGoals}</span>}
{t.matchesCount != null && <span className="inline-flex items-center gap-1"><CalendarDaysIcon className="w-3 h-3" />{t.matchesCount} games</span>} {t.matchesCount != null && <span className="inline-flex items-center gap-1"><CalendarDaysIcon className="w-3 h-3" />{t.matchesCount} games</span>}
{t.teamsCount != null && <span>🏳 {t.teamsCount} teams</span>} {t.teamsCount != null && <span>🏳 {t.teamsCount} teams</span>}
</div> </div>
{topScorer && ( {topScorer && (
<div className="mt-2 text-[10px] text-[#1a3a22]"> <div className="mt-2 text-[10px] text-green-dark">
Golden Boot: <span className="text-[#2a5c35]">{topScorer.playerName} (<span className="inline-flex items-center gap-0.5"><FireIcon className="w-2.5 h-2.5 inline" />{topScorer.goals}</span>)</span> Golden Boot: <span className="text-green-muted">{topScorer.playerName} (<span className="inline-flex items-center gap-0.5"><FireIcon className="w-2.5 h-2.5 inline" />{topScorer.goals}</span>)</span>
</div> </div>
)} )}
</div> </div>
+3 -3
View File
@@ -35,11 +35,11 @@ export default function RootLayout({ children }: { children: React.ReactNode })
<AppApolloProvider> <AppApolloProvider>
<Nav /> <Nav />
<main className="pt-[60px] min-h-screen">{children}</main> <main className="pt-[60px] min-h-screen">{children}</main>
<footer className="border-t mt-8" style={{ borderColor: 'rgba(34,197,94,0.08)' }}> <footer className="border-t border-green/8 mt-8">
<div className="max-w-[1200px] mx-auto px-7 py-6 flex flex-col sm:flex-row items-center justify-between gap-2 text-[11px] text-[#1a3a22]"> <div className="max-w-[1200px] mx-auto px-7 py-6 flex flex-col sm:flex-row items-center justify-between gap-2 text-[11px] text-green-dark">
<span>© {new Date().getFullYear()} World Cup Statistics.</span> <span>© {new Date().getFullYear()} World Cup Statistics.</span>
<a href="https://dev.pivoine.art" target="_blank" rel="noopener noreferrer" <a href="https://dev.pivoine.art" target="_blank" rel="noopener noreferrer"
className="text-[#2a5c35] hover:text-[#22c55e] transition-colors"> className="text-green-muted hover:text-green transition-colors">
dev.pivoine.art dev.pivoine.art
</a> </a>
</div> </div>
+3 -3
View File
@@ -9,15 +9,15 @@ export default function NotFound() {
<div <div
className="pitch-grid glass-card-hero rounded-2xl px-12 py-16 w-full max-w-lg" className="pitch-grid glass-card-hero rounded-2xl px-12 py-16 w-full max-w-lg"
> >
<div className="font-['Bebas_Neue'] text-[120px] text-[#22c55e] leading-none"> <div className="font-['Bebas_Neue'] text-[120px] text-green leading-none">
404 404
</div> </div>
<p className="text-[#6abf7a] text-lg mt-2 mb-8"> <p className="text-green-sec text-lg mt-2 mb-8">
This page doesn&apos;t exist. This page doesn&apos;t exist.
</p> </p>
<Link <Link
href="/" href="/"
className="inline-block font-['Bebas_Neue'] text-xl tracking-[0.1em] text-[#040d08] bg-[#22c55e] px-8 py-3 rounded-xl hover:bg-[#4ade80] transition-colors" className="inline-block font-['Bebas_Neue'] text-xl tracking-[0.1em] text-bg bg-green px-8 py-3 rounded-xl hover:bg-green-light transition-colors"
> >
Back to Home Back to Home
</Link> </Link>
+24 -27
View File
@@ -32,18 +32,17 @@ const HOME_QUERY = gql`
function SectionHeader({ label }: { label: string }) { function SectionHeader({ label }: { label: string }) {
return ( return (
<div className="flex items-center gap-2.5 mb-4"> <div className="flex items-center gap-2.5 mb-4">
<div className="w-[3px] h-[18px] bg-[#22c55e] rounded-sm" /> <div className="w-[3px] h-[18px] bg-green rounded-sm" />
<span className="text-[11px] text-[#2a5c35] font-bold tracking-[0.12em] uppercase">{label}</span> <span className="text-[11px] text-green-muted font-bold tracking-[0.12em] uppercase">{label}</span>
</div> </div>
) )
} }
function StatPill({ label, value }: { label: string; value: string | number }) { function StatPill({ label, value }: { label: string; value: string | number }) {
return ( return (
<div className="flex-1 min-w-[90px] rounded-xl p-3.5 px-5" <div className="flex-1 min-w-[90px] rounded-xl p-3.5 px-5 bg-green/5 border border-green/[12%]">
style={{ background: 'rgba(34,197,94,0.05)', border: '1px solid rgba(34,197,94,0.12)' }}> <div className="text-[9px] text-green-muted tracking-[0.13em] uppercase mb-1.5 whitespace-nowrap">{label}</div>
<div className="text-[9px] text-[#2a5c35] tracking-[0.13em] uppercase mb-1.5 whitespace-nowrap">{label}</div> <div className="font-['Bebas_Neue'] text-[30px] text-green leading-none">{value ?? ''}</div>
<div className="font-['Bebas_Neue'] text-[30px] text-[#22c55e] leading-none">{value ?? ''}</div>
</div> </div>
) )
} }
@@ -58,13 +57,13 @@ function UpcomingFixture({ match }: { match: UpcomingMatch }) {
const time = match.time?.split(' ')[0] ?? '' const time = match.time?.split(' ')[0] ?? ''
return ( return (
<Link href={`/tournaments/${match.year}#match-${match.id}`}> <Link href={`/tournaments/${match.year}#match-${match.id}`}>
<div className="glass-card rounded-[10px] p-3 px-4 flex items-center gap-2.5 hover:border-[rgba(34,197,94,0.2)] transition-colors cursor-pointer"> <div className="glass-card rounded-[10px] p-3 px-4 flex items-center gap-2.5 hover:border-green/20 transition-colors cursor-pointer">
<TeamFlag name={match.team1.name} iso2={match.team1.iso2} size="sm" /> <TeamFlag name={match.team1.name} iso2={match.team1.iso2} size="sm" />
<div className="flex-1 text-[13px] text-[#6abf7a] font-medium truncate"> <div className="flex-1 text-[13px] text-green-sec font-medium truncate">
{match.team1.name} <span className="text-[#2a5c35]">vs</span> {match.team2.name} {match.team1.name} <span className="text-green-muted">vs</span> {match.team2.name}
</div> </div>
<TeamFlag name={match.team2.name} iso2={match.team2.iso2} size="sm" /> <TeamFlag name={match.team2.name} iso2={match.team2.iso2} size="sm" />
{time && <div className="text-[11px] text-[#2a5c35] whitespace-nowrap ml-1">{time}</div>} {time && <div className="text-[11px] text-green-muted whitespace-nowrap ml-1">{time}</div>}
</div> </div>
</Link> </Link>
) )
@@ -100,9 +99,8 @@ export default function HomePage() {
return ( return (
<div> <div>
{/* ── Hero ── */} {/* ── Hero ── */}
<div className="pitch-grid border-b" style={{ <div className="pitch-grid border-b border-border" style={{
background: 'linear-gradient(145deg,rgba(10,26,14,0.9) 0%,rgba(13,36,22,0.9) 55%,rgba(10,26,14,0.9) 100%)', background: 'linear-gradient(145deg,rgba(10,26,14,0.9) 0%,rgba(13,36,22,0.9) 55%,rgba(10,26,14,0.9) 100%)',
borderColor: 'rgba(34,197,94,0.15)',
padding: '52px 0 44px', padding: '52px 0 44px',
}}> }}>
<div className="max-w-[1200px] mx-auto px-7"> <div className="max-w-[1200px] mx-auto px-7">
@@ -110,15 +108,15 @@ export default function HomePage() {
{live.length > 0 {live.length > 0
? <LiveBadge label="Live · Group Stage in Progress" /> ? <LiveBadge label="Live · Group Stage in Progress" />
: <div className="flex items-center gap-2"> : <div className="flex items-center gap-2">
<span className="w-2 h-2 rounded-full bg-[#22c55e] inline-block" /> <span className="w-2 h-2 rounded-full bg-green inline-block" />
<span className="text-[11px] font-bold text-[#22c55e] tracking-[0.14em] uppercase">World Cup 2026 · In Progress</span> <span className="text-[11px] font-bold text-green tracking-[0.14em] uppercase">World Cup 2026 · In Progress</span>
</div> </div>
} }
</div> </div>
<h1 className="font-['Bebas_Neue'] text-[clamp(50px,9vw,100px)] tracking-[0.04em] text-white leading-[0.92] mb-2.5"> <h1 className="font-['Bebas_Neue'] text-[clamp(50px,9vw,100px)] tracking-[0.04em] text-white leading-[0.92] mb-2.5">
World Cup 2026 World Cup 2026
</h1> </h1>
<p className="text-[#2a5c35] text-sm mb-9"> <p className="text-green-muted text-sm mb-9">
USA · Canada · Mexico &nbsp;·&nbsp; 11 June 19 July 2026 · 48 Teams USA · Canada · Mexico &nbsp;·&nbsp; 11 June 19 July 2026 · 48 Teams
</p> </p>
<div className="flex gap-2.5 flex-wrap max-w-[760px]"> <div className="flex gap-2.5 flex-wrap max-w-[760px]">
@@ -132,7 +130,7 @@ export default function HomePage() {
<StatPill label="2026 Avg" value={wc2026.avgGoalsPerGame ? Number(wc2026.avgGoalsPerGame).toFixed(2) : ''} /> <StatPill label="2026 Avg" value={wc2026.avgGoalsPerGame ? Number(wc2026.avgGoalsPerGame).toFixed(2) : ''} />
</>} </>}
</> : [1,2,3,4].map(i => ( </> : [1,2,3,4].map(i => (
<div key={i} className="flex-1 min-w-[90px] h-20 rounded-xl animate-pulse" style={{ background: 'rgba(34,197,94,0.04)' }} /> <div key={i} className="flex-1 min-w-[90px] h-20 rounded-xl animate-pulse bg-green/[4%]" />
))} ))}
</div> </div>
</div> </div>
@@ -184,30 +182,29 @@ export default function HomePage() {
<div className="glass-card"> <div className="glass-card">
{scorers.map((s, i) => ( {scorers.map((s, i) => (
<Link key={s.playerName} href={`/players/${encodeURIComponent(s.playerName)}`}> <Link key={s.playerName} href={`/players/${encodeURIComponent(s.playerName)}`}>
<div className="flex items-center gap-2 sm:gap-3 px-3 sm:px-4 py-3 border-b hover:bg-[rgba(34,197,94,0.03)] transition-colors cursor-pointer" <div className={`flex items-center gap-2 sm:gap-3 px-3 sm:px-4 py-3 border-b border-green/[6%] hover:bg-green/[3%] transition-colors cursor-pointer ${i === 0 ? 'bg-green/[4%]' : ''}`}>
style={{ borderColor: 'rgba(34,197,94,0.06)', background: i === 0 ? 'rgba(34,197,94,0.04)' : undefined }}> <span className="text-[11px] text-green-muted w-5 text-right font-bold flex-shrink-0">{i + 1}</span>
<span className="text-[11px] text-[#2a5c35] w-5 text-right font-bold flex-shrink-0">{i + 1}</span>
{s.team && <TeamFlag name={s.team.name} iso2={s.team.iso2} size="sm" />} {s.team && <TeamFlag name={s.team.name} iso2={s.team.iso2} size="sm" />}
<div className="flex-1 min-w-0"> <div className="flex-1 min-w-0">
<div className={`text-sm font-semibold truncate ${i === 0 ? 'text-[#dff5e8]' : 'text-[#6abf7a]'}`}>{s.playerName}</div> <div className={`text-sm font-semibold truncate ${i === 0 ? 'text-text' : 'text-green-sec'}`}>{s.playerName}</div>
<div className="text-[10px] text-[#2a5c35] truncate">{s.team?.name}{s.penalties > 0 ? ` · ${s.penalties}P` : ''}</div> <div className="text-[10px] text-green-muted truncate">{s.team?.name}{s.penalties > 0 ? ` · ${s.penalties}P` : ''}</div>
</div> </div>
<div className="hidden sm:block w-24 h-1 rounded-full overflow-hidden flex-shrink-0" style={{ background: 'rgba(34,197,94,0.1)' }}> <div className="hidden sm:block w-24 h-1 rounded-full overflow-hidden flex-shrink-0 bg-green/10">
<div className="h-full rounded-full bg-[#22c55e] transition-all" style={{ width: `${(s.goals / maxGoals) * 100}%` }} /> <div className="h-full rounded-full bg-green transition-all" style={{ width: `${(s.goals / maxGoals) * 100}%` }} />
</div> </div>
<span className="font-['Bebas_Neue'] text-[22px] text-[#22c55e] min-w-[24px] text-right flex-shrink-0">{s.goals}</span> <span className="font-['Bebas_Neue'] text-[22px] text-green min-w-[24px] text-right flex-shrink-0">{s.goals}</span>
</div> </div>
</Link> </Link>
))} ))}
</div> </div>
<p className="text-[10px] text-[#1a3a22] mt-3 text-center"> <p className="text-[10px] text-green-dark mt-3 text-center">
<Link href="/stats" className="hover:text-[#2a5c35]">View all-time top scorers </Link> <Link href="/stats" className="hover:text-green-muted">View all-time top scorers </Link>
</p> </p>
</div> </div>
)} )}
{loading && !data && ( {loading && !data && (
<div className="py-16 text-center text-[#2a5c35] text-sm">Loading live World Cup data</div> <div className="py-16 text-center text-green-muted text-sm">Loading live World Cup data</div>
)} )}
</div> </div>
</div> </div>
+13 -13
View File
@@ -47,15 +47,15 @@ export default function PlayerPage({ params }: { params: Promise<{ name: string
`) `)
if (loading && !data) { if (loading && !data) {
return <div className="max-w-[1200px] mx-auto px-7 py-10 text-[#2a5c35]">Loading player</div> return <div className="max-w-[1200px] mx-auto px-7 py-10 text-green-muted">Loading player</div>
} }
if (!player) { if (!player) {
return ( return (
<div className="max-w-[1200px] mx-auto px-7 py-10"> <div className="max-w-[1200px] mx-auto px-7 py-10">
<h1 className="font-['Bebas_Neue'] text-[52px] text-[#22c55e]">{name}</h1> <h1 className="font-['Bebas_Neue'] text-[52px] text-green">{name}</h1>
<p className="text-[#2a5c35] mt-4">No goal data found for this player in World Cup history.</p> <p className="text-green-muted mt-4">No goal data found for this player in World Cup history.</p>
<Link href="/stats" className="text-[#22c55e] text-sm mt-4 inline-block hover:underline"> All-time scorers</Link> <Link href="/stats" className="text-green text-sm mt-4 inline-block hover:underline"> All-time scorers</Link>
</div> </div>
) )
} }
@@ -69,16 +69,16 @@ export default function PlayerPage({ params }: { params: Promise<{ name: string
<div className="flex items-center gap-6 flex-wrap"> <div className="flex items-center gap-6 flex-wrap">
{player.team && <TeamFlag name={player.team.name} iso2={player.team.iso2} size="xl" />} {player.team && <TeamFlag name={player.team.name} iso2={player.team.iso2} size="xl" />}
<div> <div>
<h1 className="font-['Bebas_Neue'] text-[clamp(36px,6vw,64px)] text-[#22c55e] leading-none">{player.playerName}</h1> <h1 className="font-['Bebas_Neue'] text-[clamp(36px,6vw,64px)] text-green leading-none">{player.playerName}</h1>
{player.team && ( {player.team && (
<Link href={`/teams/${player.team.slug}`} className="text-[#6abf7a] text-sm mt-1 hover:text-[#dff5e8] transition-colors inline-block"> <Link href={`/teams/${player.team.slug}`} className="text-green-sec text-sm mt-1 hover:text-text transition-colors inline-block">
{player.team.name} {player.team.name}
</Link> </Link>
)} )}
</div> </div>
<div className="ml-auto text-right"> <div className="ml-auto text-right">
<div className="font-['Bebas_Neue'] text-[80px] text-[#22c55e] leading-none">{player.goals}</div> <div className="font-['Bebas_Neue'] text-[80px] text-green leading-none">{player.goals}</div>
<div className="text-[10px] text-[#2a5c35] tracking-[0.12em] uppercase">World Cup Goals</div> <div className="text-[10px] text-green-muted tracking-[0.12em] uppercase">World Cup Goals</div>
</div> </div>
</div> </div>
</div> </div>
@@ -92,23 +92,23 @@ export default function PlayerPage({ params }: { params: Promise<{ name: string
{ label: 'Tournaments', value: player.tournaments }, { label: 'Tournaments', value: player.tournaments },
].map(item => ( ].map(item => (
<div key={item.label} className="glass-card rounded-xl p-4"> <div key={item.label} className="glass-card rounded-xl p-4">
<div className="text-[9px] text-[#2a5c35] tracking-[0.1em] uppercase mb-1.5">{item.label}</div> <div className="text-[9px] text-green-muted tracking-[0.1em] uppercase mb-1.5">{item.label}</div>
<div className="font-['Bebas_Neue'] text-3xl text-[#22c55e]">{item.value}</div> <div className="font-['Bebas_Neue'] text-3xl text-green">{item.value}</div>
</div> </div>
))} ))}
</div> </div>
{player.ownGoals > 0 && ( {player.ownGoals > 0 && (
<div className="mb-6 glass-card rounded-xl p-3 px-4 text-sm text-[#2a5c35]"> <div className="mb-6 glass-card rounded-xl p-3 px-4 text-sm text-green-muted">
Includes {player.ownGoals} own goal{player.ownGoals !== 1 ? 's' : ''} Includes {player.ownGoals} own goal{player.ownGoals !== 1 ? 's' : ''}
</div> </div>
)} )}
{/* Back links */} {/* Back links */}
<div className="flex gap-4 mt-8"> <div className="flex gap-4 mt-8">
<Link href="/stats" className="text-[#22c55e] text-sm hover:underline"> All-time scorers</Link> <Link href="/stats" className="text-green text-sm hover:underline"> All-time scorers</Link>
{player.team && ( {player.team && (
<Link href={`/teams/${player.team.slug}`} className="text-[#22c55e] text-sm hover:underline"> <Link href={`/teams/${player.team.slug}`} className="text-green text-sm hover:underline">
{player.team.name} team page {player.team.name} team page
</Link> </Link>
)} )}
+29 -30
View File
@@ -62,7 +62,7 @@ function SearchContent() {
return ( return (
<div className="max-w-[1200px] mx-auto px-7 py-10 pb-16"> <div className="max-w-[1200px] mx-auto px-7 py-10 pb-16">
<h1 className="font-['Bebas_Neue'] text-[52px] tracking-[0.04em] text-[#22c55e] leading-none mb-6">Search</h1> <h1 className="font-['Bebas_Neue'] text-[52px] tracking-[0.04em] text-green leading-none mb-6">Search</h1>
{/* Search input */} {/* Search input */}
<div className="relative max-w-lg mb-8"> <div className="relative max-w-lg mb-8">
@@ -70,47 +70,46 @@ function SearchContent() {
type="text" value={q} onChange={e => setQ(e.target.value)} type="text" value={q} onChange={e => setQ(e.target.value)}
placeholder="Search teams, players, tournaments…" placeholder="Search teams, players, tournaments…"
autoFocus autoFocus
className="w-full pl-10 pr-4 py-3 rounded-2xl text-[#dff5e8] text-sm outline-none" className="w-full pl-10 pr-4 py-3 rounded-2xl text-text text-sm outline-none bg-green/[6%] border-green/20"
style={{ background: 'rgba(34,197,94,0.06)', border: '1px solid rgba(34,197,94,0.2)' }}
/> />
<svg className="absolute left-3.5 top-1/2 -translate-y-1/2 opacity-40" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#dff5e8" strokeWidth="2.5"> <svg className="absolute left-3.5 top-1/2 -translate-y-1/2 opacity-40" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5">
<circle cx="11" cy="11" r="8" /><line x1="21" y1="21" x2="16.65" y2="16.65" /> <circle cx="11" cy="11" r="8" /><line x1="21" y1="21" x2="16.65" y2="16.65" />
</svg> </svg>
{loading && <div className="absolute right-3.5 top-1/2 -translate-y-1/2 w-4 h-4 border-2 border-[#22c55e] border-t-transparent rounded-full animate-spin" />} {loading && <div className="absolute right-3.5 top-1/2 -translate-y-1/2 w-4 h-4 border-2 border-green border-t-transparent rounded-full animate-spin" />}
</div> </div>
{/* Prompt */} {/* Prompt */}
{skip && ( {skip && (
<div className="flex flex-col items-center py-20 text-center"> <div className="flex flex-col items-center py-20 text-center">
<div className="text-[56px] mb-5">🔍</div> <div className="text-[56px] mb-5">🔍</div>
<div className="text-[#2a5c35] text-base">Search for nations, players, or tournaments</div> <div className="text-green-muted text-base">Search for nations, players, or tournaments</div>
<div className="text-[#1a3a22] text-sm mt-2">Examples: "Brazil", "Ronaldo", "1966"</div> <div className="text-green-dark text-sm mt-2">Examples: "Brazil", "Ronaldo", "1966"</div>
</div> </div>
)} )}
{/* No results */} {/* No results */}
{!skip && !loading && total === 0 && ( {!skip && !loading && total === 0 && (
<div className="text-center text-[#1a3a22] py-16 text-sm">No results for "{debouncedQ}"</div> <div className="text-center text-green-dark py-16 text-sm">No results for "{debouncedQ}"</div>
)} )}
{/* Results count */} {/* Results count */}
{!skip && total > 0 && ( {!skip && total > 0 && (
<div className="text-[13px] text-[#2a5c35] mb-6">{total} result{total !== 1 ? 's' : ''} for "{debouncedQ}"</div> <div className="text-[13px] text-green-muted mb-6">{total} result{total !== 1 ? 's' : ''} for "{debouncedQ}"</div>
)} )}
<div className="flex flex-col gap-6"> <div className="flex flex-col gap-6">
{/* Teams */} {/* Teams */}
{results?.teams?.length > 0 && ( {results?.teams?.length > 0 && (
<section> <section>
<h3 className="text-[11px] text-[#2a5c35] font-bold tracking-[0.12em] uppercase mb-3">Teams</h3> <h3 className="text-[11px] text-green-muted font-bold tracking-[0.12em] uppercase mb-3">Teams</h3>
<div className="grid grid-cols-[repeat(auto-fill,minmax(200px,1fr))] gap-2.5"> <div className="grid grid-cols-[repeat(auto-fill,minmax(200px,1fr))] gap-2.5">
{results.teams.map((t: { name: string; iso2?: string | null; slug: string; stats?: { appearances: number; titles: number } | null }) => ( {results.teams.map((t: { name: string; iso2?: string | null; slug: string; stats?: { appearances: number; titles: number } | null }) => (
<Link key={t.name} href={`/teams/${t.slug}`}> <Link key={t.name} href={`/teams/${t.slug}`}>
<div className="glass-card flex items-center gap-3 p-3 px-4 rounded-xl hover:border-[rgba(34,197,94,0.25)] transition-colors cursor-pointer"> <div className="glass-card flex items-center gap-3 p-3 px-4 rounded-xl hover:border-green/25 transition-colors cursor-pointer">
<TeamFlag name={t.name} iso2={t.iso2} size="md" /> <TeamFlag name={t.name} iso2={t.iso2} size="md" />
<div> <div>
<div className="text-sm font-semibold text-[#dff5e8]">{t.name}</div> <div className="text-sm font-semibold text-text">{t.name}</div>
<div className="text-[10px] text-[#2a5c35]"> <div className="text-[10px] text-green-muted">
{t.stats?.appearances ?? 0} WCs{t.stats?.titles ? <span className="inline-flex items-center gap-0.5 ml-1">· {t.stats.titles}<TrophyIcon className="w-3 h-3 inline" /></span> : ''} {t.stats?.appearances ?? 0} WCs{t.stats?.titles ? <span className="inline-flex items-center gap-0.5 ml-1">· {t.stats.titles}<TrophyIcon className="w-3 h-3 inline" /></span> : ''}
</div> </div>
</div> </div>
@@ -124,17 +123,17 @@ function SearchContent() {
{/* Players */} {/* Players */}
{results?.players?.length > 0 && ( {results?.players?.length > 0 && (
<section> <section>
<h3 className="text-[11px] text-[#2a5c35] font-bold tracking-[0.12em] uppercase mb-3">Players</h3> <h3 className="text-[11px] text-green-muted font-bold tracking-[0.12em] uppercase mb-3">Players</h3>
<div className="grid grid-cols-[repeat(auto-fill,minmax(220px,1fr))] gap-2.5"> <div className="grid grid-cols-[repeat(auto-fill,minmax(220px,1fr))] gap-2.5">
{results.players.map((p: { playerName: string; goals: number; tournaments: number; team?: { name: string; iso2?: string | null } | null }) => ( {results.players.map((p: { playerName: string; goals: number; tournaments: number; team?: { name: string; iso2?: string | null } | null }) => (
<Link key={p.playerName} href={`/players/${encodeURIComponent(p.playerName)}`}> <Link key={p.playerName} href={`/players/${encodeURIComponent(p.playerName)}`}>
<div className="glass-card flex items-center gap-3 p-3 px-4 rounded-xl hover:border-[rgba(34,197,94,0.25)] transition-colors cursor-pointer"> <div className="glass-card flex items-center gap-3 p-3 px-4 rounded-xl hover:border-green/25 transition-colors cursor-pointer">
{p.team && <TeamFlag name={p.team.name} iso2={p.team.iso2} size="sm" />} {p.team && <TeamFlag name={p.team.name} iso2={p.team.iso2} size="sm" />}
<div className="flex-1 min-w-0"> <div className="flex-1 min-w-0">
<div className="text-sm font-semibold text-[#dff5e8] truncate">{p.playerName}</div> <div className="text-sm font-semibold text-text truncate">{p.playerName}</div>
<div className="text-[10px] text-[#2a5c35]">{p.team?.name} · {p.tournaments} WC{p.tournaments !== 1 ? 's' : ''}</div> <div className="text-[10px] text-green-muted">{p.team?.name} · {p.tournaments} WC{p.tournaments !== 1 ? 's' : ''}</div>
</div> </div>
<span className="font-['Bebas_Neue'] text-xl text-[#22c55e] flex-shrink-0 inline-flex items-center gap-0.5">{p.goals}<FireIcon className="w-3.5 h-3.5" /></span> <span className="font-['Bebas_Neue'] text-xl text-green flex-shrink-0 inline-flex items-center gap-0.5">{p.goals}<FireIcon className="w-3.5 h-3.5" /></span>
</div> </div>
</Link> </Link>
))} ))}
@@ -145,15 +144,15 @@ function SearchContent() {
{/* Tournaments */} {/* Tournaments */}
{results?.tournaments?.length > 0 && ( {results?.tournaments?.length > 0 && (
<section> <section>
<h3 className="text-[11px] text-[#2a5c35] font-bold tracking-[0.12em] uppercase mb-3">Tournaments</h3> <h3 className="text-[11px] text-green-muted font-bold tracking-[0.12em] uppercase mb-3">Tournaments</h3>
<div className="grid grid-cols-[repeat(auto-fill,minmax(180px,1fr))] gap-2.5"> <div className="grid grid-cols-[repeat(auto-fill,minmax(180px,1fr))] gap-2.5">
{results.tournaments.map((t: { year: number; host: string; winner?: string | null; totalGoals?: number | null; matchesCount?: number | null }) => ( {results.tournaments.map((t: { year: number; host: string; winner?: string | null; totalGoals?: number | null; matchesCount?: number | null }) => (
<Link key={t.year} href={`/tournaments/${t.year}`}> <Link key={t.year} href={`/tournaments/${t.year}`}>
<div className="glass-card p-4 rounded-xl hover:border-[rgba(34,197,94,0.25)] transition-colors cursor-pointer"> <div className="glass-card p-4 rounded-xl hover:border-green/25 transition-colors cursor-pointer">
<div className="font-['Bebas_Neue'] text-3xl text-[#22c55e]">{t.year}</div> <div className="font-['Bebas_Neue'] text-3xl text-green">{t.year}</div>
<div className="text-sm text-[#dff5e8]">{t.host}</div> <div className="text-sm text-text">{t.host}</div>
{t.winner && <div className="text-[10px] text-[#2a5c35] mt-1 flex items-center gap-1"><TrophyIcon className="w-3 h-3 flex-shrink-0" />{t.winner}</div>} {t.winner && <div className="text-[10px] text-green-muted mt-1 flex items-center gap-1"><TrophyIcon className="w-3 h-3 flex-shrink-0" />{t.winner}</div>}
{t.totalGoals && <div className="text-[10px] text-[#1a3a22] flex items-center gap-1"><FireIcon className="w-3 h-3 flex-shrink-0" />{t.totalGoals} goals</div>} {t.totalGoals && <div className="text-[10px] text-green-dark flex items-center gap-1"><FireIcon className="w-3 h-3 flex-shrink-0" />{t.totalGoals} goals</div>}
</div> </div>
</Link> </Link>
))} ))}
@@ -164,16 +163,16 @@ function SearchContent() {
{/* Matches */} {/* Matches */}
{results?.matches?.length > 0 && ( {results?.matches?.length > 0 && (
<section> <section>
<h3 className="text-[11px] text-[#2a5c35] font-bold tracking-[0.12em] uppercase mb-3">Matches</h3> <h3 className="text-[11px] text-green-muted font-bold tracking-[0.12em] uppercase mb-3">Matches</h3>
<div className="flex flex-col gap-2"> <div className="flex flex-col gap-2">
{results.matches.map((m: SearchMatch) => ( {results.matches.map((m: SearchMatch) => (
<Link key={m.id} href={`/tournaments/${m.year}#match-${m.id}`}> <Link key={m.id} href={`/tournaments/${m.year}#match-${m.id}`}>
<div className="glass-card flex items-center gap-3 p-3 px-4 rounded-xl hover:border-[rgba(34,197,94,0.25)] transition-colors cursor-pointer"> <div className="glass-card flex items-center gap-3 p-3 px-4 rounded-xl hover:border-green/25 transition-colors cursor-pointer">
<TeamFlag name={m.team1.name} iso2={m.team1.iso2} size="sm" /> <TeamFlag name={m.team1.name} iso2={m.team1.iso2} size="sm" />
<div className="flex-1 text-sm text-[#dff5e8]">{m.team1.name} vs {m.team2.name}</div> <div className="flex-1 text-sm text-text">{m.team1.name} vs {m.team2.name}</div>
{m.scoreFt && <span className="font-['Bebas_Neue'] text-lg text-[#22c55e]">{m.scoreFt[0]}{m.scoreFt[1]}</span>} {m.scoreFt && <span className="font-['Bebas_Neue'] text-lg text-green">{m.scoreFt[0]}{m.scoreFt[1]}</span>}
<TeamFlag name={m.team2.name} iso2={m.team2.iso2} size="sm" /> <TeamFlag name={m.team2.name} iso2={m.team2.iso2} size="sm" />
<div className="text-[10px] text-[#2a5c35] whitespace-nowrap">{m.year} · {m.round}</div> <div className="text-[10px] text-green-muted whitespace-nowrap">{m.year} · {m.round}</div>
</div> </div>
</Link> </Link>
))} ))}
@@ -187,7 +186,7 @@ function SearchContent() {
export default function SearchPage() { export default function SearchPage() {
return ( return (
<Suspense fallback={<div className="p-10 text-[#2a5c35]">Loading</div>}> <Suspense fallback={<div className="p-10 text-green-muted">Loading</div>}>
<SearchContent /> <SearchContent />
</Suspense> </Suspense>
) )
+65 -66
View File
@@ -42,7 +42,7 @@ const STATS_QUERY = gql`
function SectionTitle({ children, icon: Icon }: { children: React.ReactNode; icon: React.ComponentType<{ className?: string }> }) { function SectionTitle({ children, icon: Icon }: { children: React.ReactNode; icon: React.ComponentType<{ className?: string }> }) {
return ( return (
<h2 className="flex items-center gap-1.5 text-[11px] font-bold tracking-[0.14em] uppercase text-[#2a5c35] mb-4"> <h2 className="flex items-center gap-1.5 text-[11px] font-bold tracking-[0.14em] uppercase text-green-muted mb-4">
<Icon className="w-3.5 h-3.5 flex-shrink-0" /> <Icon className="w-3.5 h-3.5 flex-shrink-0" />
{children} {children}
</h2> </h2>
@@ -92,10 +92,10 @@ export default function StatsPage() {
return ( return (
<div className="max-w-[1200px] mx-auto px-7 py-10 pb-16"> <div className="max-w-[1200px] mx-auto px-7 py-10 pb-16">
<h1 className="font-['Bebas_Neue'] text-[52px] tracking-[0.04em] text-[#22c55e] leading-none mb-10">Historical Statistics</h1> <h1 className="font-['Bebas_Neue'] text-[52px] tracking-[0.04em] text-green leading-none mb-10">Historical Statistics</h1>
{loading && !data && ( {loading && !data && (
<div className="text-[#2a5c35] text-sm py-16 text-center">Loading statistics</div> <div className="text-green-muted text-sm py-16 text-center">Loading statistics</div>
)} )}
{/* ── Goals per tournament bar chart ── */} {/* ── Goals per tournament bar chart ── */}
@@ -110,18 +110,18 @@ export default function StatsPage() {
const avg = t.avgGoalsPerGame ? Number(t.avgGoalsPerGame).toFixed(1) : null const avg = t.avgGoalsPerGame ? Number(t.avgGoalsPerGame).toFixed(1) : null
return ( return (
<Link key={t.year} href={`/tournaments/${t.year}`} className="flex flex-col items-center flex-1 min-w-[8px] group"> <Link key={t.year} href={`/tournaments/${t.year}`} className="flex flex-col items-center flex-1 min-w-[8px] group">
<div className="text-[6px] sm:text-[7px] text-[#2a5c35] font-semibold mb-1 leading-none group-hover:text-[#22c55e]">{t.totalGoals}</div> <div className="text-[6px] sm:text-[7px] text-green-muted font-semibold mb-1 leading-none group-hover:text-green">{t.totalGoals}</div>
<div className="w-full rounded-t-sm border-t-2 transition-colors group-hover:bg-[rgba(34,197,94,0.35)]" <div className="w-full rounded-t-sm border-t-2 border-green/45 transition-colors group-hover:bg-green/35 bg-green/[18%]"
style={{ height: `${h}px`, background: 'rgba(34,197,94,0.18)', borderColor: 'rgba(34,197,94,0.45)' }} style={{ height: `${h}px` }}
title={`${t.year}: ${t.totalGoals} goals${avg ? ` · ${avg}/game` : ''}`} title={`${t.year}: ${t.totalGoals} goals${avg ? ` · ${avg}/game` : ''}`}
/> />
</Link> </Link>
) )
})} })}
</div> </div>
<div className="flex gap-[2px] sm:gap-[3px] pt-1.5 pb-3 border-t" style={{ borderColor: 'rgba(34,197,94,0.06)' }}> <div className="flex gap-[2px] sm:gap-[3px] pt-1.5 pb-3 border-t border-green/[6%]">
{tournaments.map(t => ( {tournaments.map(t => (
<div key={t.year} className="flex-1 text-center text-[6px] text-[#1a3a22]" style={{ transform: 'rotate(-45deg)', transformOrigin: 'center top' }}> <div key={t.year} className="flex-1 text-center text-[6px] text-green-dark" style={{ transform: 'rotate(-45deg)', transformOrigin: 'center top' }}>
{t.year} {t.year}
</div> </div>
))} ))}
@@ -138,18 +138,17 @@ export default function StatsPage() {
<Card> <Card>
{scorers.map((s, i) => ( {scorers.map((s, i) => (
<Link key={s.playerName} href={`/players/${encodeURIComponent(s.playerName)}`}> <Link key={s.playerName} href={`/players/${encodeURIComponent(s.playerName)}`}>
<div className="flex items-center gap-2 sm:gap-3 px-3 sm:px-4 py-3 border-b hover:bg-[rgba(34,197,94,0.03)] cursor-pointer" <div className={`flex items-center gap-2 sm:gap-3 px-3 sm:px-4 py-3 border-b hover:bg-green/[3%] cursor-pointer border-green/5 ${i === 0 ? 'bg-green/[4%]' : ''}`}>
style={{ borderColor: 'rgba(34,197,94,0.05)', background: i === 0 ? 'rgba(34,197,94,0.04)' : undefined }}> <span className="text-[11px] text-green-muted w-5 text-right font-bold flex-shrink-0">{i + 1}</span>
<span className="text-[11px] text-[#2a5c35] w-5 text-right font-bold flex-shrink-0">{i + 1}</span>
{s.team && <TeamFlag name={s.team.name} iso2={s.team.iso2} size="sm" />} {s.team && <TeamFlag name={s.team.name} iso2={s.team.iso2} size="sm" />}
<div className="flex-1 min-w-0"> <div className="flex-1 min-w-0">
<div className={`text-sm font-semibold truncate ${i < 3 ? 'text-[#dff5e8]' : 'text-[#6abf7a]'}`}>{s.playerName}</div> <div className={`text-sm font-semibold truncate ${i < 3 ? 'text-text' : 'text-green-sec'}`}>{s.playerName}</div>
<div className="text-[10px] text-[#2a5c35] truncate">{s.team?.name} · {s.tournaments} WC{s.tournaments !== 1 ? 's' : ''}{s.penalties > 0 ? ` · ${s.penalties}P` : ''}</div> <div className="text-[10px] text-green-muted truncate">{s.team?.name} · {s.tournaments} WC{s.tournaments !== 1 ? 's' : ''}{s.penalties > 0 ? ` · ${s.penalties}P` : ''}</div>
</div> </div>
<div className="hidden sm:block w-16 h-1 rounded-full flex-shrink-0" style={{ background: 'rgba(34,197,94,0.1)' }}> <div className="hidden sm:block w-16 h-1 rounded-full flex-shrink-0 bg-green/10">
<div className="h-full rounded-full bg-[#22c55e]" style={{ width: `${(s.goals / maxScorer) * 100}%` }} /> <div className="h-full rounded-full bg-green" style={{ width: `${(s.goals / maxScorer) * 100}%` }} />
</div> </div>
<span className="font-['Bebas_Neue'] text-[22px] text-[#22c55e] min-w-[28px] text-right flex-shrink-0">{s.goals}</span> <span className="font-['Bebas_Neue'] text-[22px] text-green min-w-[28px] text-right flex-shrink-0">{s.goals}</span>
</div> </div>
</Link> </Link>
))} ))}
@@ -162,17 +161,17 @@ export default function StatsPage() {
<Card> <Card>
{titlesByNation.map((t, i) => ( {titlesByNation.map((t, i) => (
<Link key={t.name} href={`/teams/${t.slug}`}> <Link key={t.name} href={`/teams/${t.slug}`}>
<div className="flex items-center gap-2 sm:gap-3 px-3 sm:px-4 py-3.5 border-b hover:bg-[rgba(34,197,94,0.03)] cursor-pointer" <div className="flex items-center gap-2 sm:gap-3 px-3 sm:px-4 py-3.5 border-b border-green/5 hover:bg-green/[3%] cursor-pointer"
style={{ borderColor: 'rgba(34,197,94,0.05)' }}> >
<span className="text-[11px] text-[#2a5c35] w-5 text-right font-bold flex-shrink-0">{i + 1}</span> <span className="text-[11px] text-green-muted w-5 text-right font-bold flex-shrink-0">{i + 1}</span>
<TeamFlag name={t.name} iso2={t.iso2} size="sm" /> <TeamFlag name={t.name} iso2={t.iso2} size="sm" />
<div className="flex-1 min-w-0 text-sm font-semibold text-[#dff5e8] truncate">{t.name}</div> <div className="flex-1 min-w-0 text-sm font-semibold text-text truncate">{t.name}</div>
<div className="hidden sm:flex gap-0.5 flex-shrink-0"> <div className="hidden sm:flex gap-0.5 flex-shrink-0">
{Array.from({ length: t.stats?.titles ?? 0 }).map((_, j) => ( {Array.from({ length: t.stats?.titles ?? 0 }).map((_, j) => (
<TrophyIcon key={j} className="w-4 h-4 text-[#22c55e]" /> <TrophyIcon key={j} className="w-4 h-4 text-green" />
))} ))}
</div> </div>
<span className="font-['Bebas_Neue'] text-[28px] text-[#22c55e] flex-shrink-0">{t.stats?.titles}</span> <span className="font-['Bebas_Neue'] text-[28px] text-green flex-shrink-0">{t.stats?.titles}</span>
</div> </div>
</Link> </Link>
))} ))}
@@ -191,9 +190,9 @@ export default function StatsPage() {
const h = Math.max(8, Math.round((b.count / maxMinute) * 80)) const h = Math.max(8, Math.round((b.count / maxMinute) * 80))
return ( return (
<div key={b.bucket} className="flex-1 flex flex-col items-center gap-1"> <div key={b.bucket} className="flex-1 flex flex-col items-center gap-1">
<span className="text-[7px] sm:text-[9px] text-[#2a5c35] font-bold leading-none">{b.count}</span> <span className="text-[7px] sm:text-[9px] text-green-muted font-bold leading-none">{b.count}</span>
<div className="w-full rounded-t" style={{ height: `${h}px`, background: 'rgba(34,197,94,0.3)', border: '1px solid rgba(34,197,94,0.5)' }} /> <div className="w-full rounded-t bg-green/30 border border-green/50" style={{ height: `${h}px` }} />
<span className="text-[7px] sm:text-[9px] text-[#1a3a22] leading-none">{b.bucket}</span> <span className="text-[7px] sm:text-[9px] text-green-dark leading-none">{b.bucket}</span>
</div> </div>
) )
})} })}
@@ -210,17 +209,17 @@ export default function StatsPage() {
<Card> <Card>
{biggestWins.map(m => ( {biggestWins.map(m => (
<Link key={m.id} href={`/tournaments/${m.year}#match-${m.id}`}> <Link key={m.id} href={`/tournaments/${m.year}#match-${m.id}`}>
<div className="flex items-center gap-3 px-4 py-2.5 border-b hover:bg-[rgba(34,197,94,0.03)] cursor-pointer" <div className="flex items-center gap-3 px-4 py-2.5 border-b border-green/5 hover:bg-green/[3%] cursor-pointer"
style={{ borderColor: 'rgba(34,197,94,0.05)' }}> >
<TeamFlag name={m.team1.name} iso2={m.team1.iso2} size="sm" /> <TeamFlag name={m.team1.name} iso2={m.team1.iso2} size="sm" />
<div className="flex-1 min-w-0"> <div className="flex-1 min-w-0">
<div className="text-sm font-medium text-[#dff5e8] truncate">{m.team1.name} vs {m.team2.name}</div> <div className="text-sm font-medium text-text truncate">{m.team1.name} vs {m.team2.name}</div>
<div className="text-[10px] text-[#2a5c35]">{m.year} · {m.round}</div> <div className="text-[10px] text-green-muted">{m.year} · {m.round}</div>
</div> </div>
<span className="font-['Bebas_Neue'] text-xl text-[#22c55e] flex-shrink-0"> <span className="font-['Bebas_Neue'] text-xl text-green flex-shrink-0">
{m.scoreFt?.[0]}{m.scoreFt?.[1]} {m.scoreFt?.[0]}{m.scoreFt?.[1]}
</span> </span>
<span className="text-[10px] text-[#2a5c35] flex-shrink-0">+{m.margin}</span> <span className="text-[10px] text-green-muted flex-shrink-0">+{m.margin}</span>
</div> </div>
</Link> </Link>
))} ))}
@@ -233,17 +232,17 @@ export default function StatsPage() {
<Card> <Card>
{highScoring.map(m => ( {highScoring.map(m => (
<Link key={m.id} href={`/tournaments/${m.year}#match-${m.id}`}> <Link key={m.id} href={`/tournaments/${m.year}#match-${m.id}`}>
<div className="flex items-center gap-3 px-4 py-2.5 border-b hover:bg-[rgba(34,197,94,0.03)] cursor-pointer" <div className="flex items-center gap-3 px-4 py-2.5 border-b border-green/5 hover:bg-green/[3%] cursor-pointer"
style={{ borderColor: 'rgba(34,197,94,0.05)' }}> >
<TeamFlag name={m.team1.name} iso2={m.team1.iso2} size="sm" /> <TeamFlag name={m.team1.name} iso2={m.team1.iso2} size="sm" />
<div className="flex-1 min-w-0"> <div className="flex-1 min-w-0">
<div className="text-sm font-medium text-[#dff5e8] truncate">{m.team1.name} vs {m.team2.name}</div> <div className="text-sm font-medium text-text truncate">{m.team1.name} vs {m.team2.name}</div>
<div className="text-[10px] text-[#2a5c35]">{m.year} · {m.round}</div> <div className="text-[10px] text-green-muted">{m.year} · {m.round}</div>
</div> </div>
<span className="font-['Bebas_Neue'] text-xl text-[#22c55e] flex-shrink-0"> <span className="font-['Bebas_Neue'] text-xl text-green flex-shrink-0">
{m.scoreFt?.[0]}{m.scoreFt?.[1]} {m.scoreFt?.[0]}{m.scoreFt?.[1]}
</span> </span>
<span className="text-[10px] text-[#4ade80] flex-shrink-0">{m.totalGoals} goals</span> <span className="text-[10px] text-green-light flex-shrink-0">{m.totalGoals} goals</span>
</div> </div>
</Link> </Link>
))} ))}
@@ -261,12 +260,12 @@ export default function StatsPage() {
<div className="flex items-center gap-2 mb-2"> <div className="flex items-center gap-2 mb-2">
{h.team && <TeamFlag name={h.team.name} iso2={h.team.iso2} size="sm" />} {h.team && <TeamFlag name={h.team.name} iso2={h.team.iso2} size="sm" />}
<div> <div>
<div className="text-sm font-semibold text-[#dff5e8]">{h.playerName}</div> <div className="text-sm font-semibold text-text">{h.playerName}</div>
<div className="text-[10px] text-[#2a5c35]">{h.team?.name}</div> <div className="text-[10px] text-green-muted">{h.team?.name}</div>
</div> </div>
<span className="ml-auto font-['Bebas_Neue'] text-2xl text-[#22c55e]">{h.goals}</span> <span className="ml-auto font-['Bebas_Neue'] text-2xl text-green">{h.goals}</span>
</div> </div>
<div className="text-[10px] text-[#2a5c35]"> <div className="text-[10px] text-green-muted">
{h.year} · {h.round} {h.year} · {h.round}
{h.opponent && <span> vs {h.opponent.name}</span>} {h.opponent && <span> vs {h.opponent.name}</span>}
</div> </div>
@@ -288,8 +287,8 @@ export default function StatsPage() {
{ label: 'Decided in 90min', value: etStats.totalKnockoutMatches - etStats.wentToExtraTime }, { label: 'Decided in 90min', value: etStats.totalKnockoutMatches - etStats.wentToExtraTime },
].map(s => ( ].map(s => (
<div key={s.label} className="glass-card rounded-xl p-4"> <div key={s.label} className="glass-card rounded-xl p-4">
<div className="text-[9px] text-[#2a5c35] tracking-[0.1em] uppercase mb-2">{s.label}</div> <div className="text-[9px] text-green-muted tracking-[0.1em] uppercase mb-2">{s.label}</div>
<div className="font-['Bebas_Neue'] text-2xl text-[#22c55e]">{s.value}</div> <div className="font-['Bebas_Neue'] text-2xl text-green">{s.value}</div>
</div> </div>
))} ))}
</div> </div>
@@ -303,20 +302,20 @@ export default function StatsPage() {
<Card> <Card>
<table className="w-full"> <table className="w-full">
<thead> <thead>
<tr className="border-b" style={{ borderColor: 'rgba(34,197,94,0.08)' }}> <tr className="border-b border-green/8">
<th className="text-left px-4 py-2 text-[9px] font-bold tracking-[0.1em] uppercase text-[#2a5c35]">Confederation</th> <th className="text-left px-4 py-2 text-[9px] font-bold tracking-[0.1em] uppercase text-green-muted">Confederation</th>
<th className="text-right px-4 py-2 text-[9px] font-bold tracking-[0.1em] uppercase text-[#2a5c35]">Appearances</th> <th className="text-right px-4 py-2 text-[9px] font-bold tracking-[0.1em] uppercase text-green-muted">Appearances</th>
<th className="text-right px-4 py-2 text-[9px] font-bold tracking-[0.1em] uppercase text-[#2a5c35]">Titles</th> <th className="text-right px-4 py-2 text-[9px] font-bold tracking-[0.1em] uppercase text-green-muted">Titles</th>
<th className="text-right px-4 py-2 text-[9px] font-bold tracking-[0.1em] uppercase text-[#2a5c35]">Goals</th> <th className="text-right px-4 py-2 text-[9px] font-bold tracking-[0.1em] uppercase text-green-muted">Goals</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{confStats.map(c => ( {confStats.map(c => (
<tr key={c.confederation} className="border-t" style={{ borderColor: 'rgba(34,197,94,0.06)' }}> <tr key={c.confederation} className="border-t border-green/[6%]">
<td className="px-4 py-3 text-sm font-medium text-[#dff5e8]">{c.confederation}</td> <td className="px-4 py-3 text-sm font-medium text-text">{c.confederation}</td>
<td className="px-4 py-3 text-right text-sm text-[#6abf7a]">{c.appearances}</td> <td className="px-4 py-3 text-right text-sm text-green-sec">{c.appearances}</td>
<td className="px-4 py-3 text-right font-['Bebas_Neue'] text-xl text-[#22c55e]">{c.titles}</td> <td className="px-4 py-3 text-right font-['Bebas_Neue'] text-xl text-green">{c.titles}</td>
<td className="px-4 py-3 text-right text-sm text-[#6abf7a]">{c.totalGoals}</td> <td className="px-4 py-3 text-right text-sm text-green-sec">{c.totalGoals}</td>
</tr> </tr>
))} ))}
</tbody> </tbody>
@@ -333,34 +332,34 @@ export default function StatsPage() {
<div className="overflow-x-auto"> <div className="overflow-x-auto">
<table className="w-full" style={{ minWidth: '560px' }}> <table className="w-full" style={{ minWidth: '560px' }}>
<thead> <thead>
<tr className="border-b" style={{ borderColor: 'rgba(34,197,94,0.08)' }}> <tr className="border-b border-green/8">
{['#', 'Team', 'WC', 'W', 'D', 'L', 'GF', 'GA', 'GD', 'Win%'].map((h, i) => ( {['#', 'Team', 'WC', 'W', 'D', 'L', 'GF', 'GA', 'GD', 'Win%'].map((h, i) => (
<th key={h} className={`py-2 text-[9px] font-bold tracking-[0.1em] uppercase text-[#2a5c35] ${i === 0 ? 'pl-4 pr-2 text-left w-8' : i === 1 ? 'px-2 text-left' : 'px-2 text-right'}`}>{h}</th> <th key={h} className={`py-2 text-[9px] font-bold tracking-[0.1em] uppercase text-green-muted ${i === 0 ? 'pl-4 pr-2 text-left w-8' : i === 1 ? 'px-2 text-left' : 'px-2 text-right'}`}>{h}</th>
))} ))}
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{teams.slice(0, 40).map((t, i) => ( {teams.slice(0, 40).map((t, i) => (
<tr key={t.id} className="border-t hover:bg-[rgba(34,197,94,0.03)]" style={{ borderColor: 'rgba(34,197,94,0.05)' }}> <tr key={t.id} className="border-t border-green/5 hover:bg-green/[3%]">
<td className="pl-4 pr-2 py-2.5 text-[11px] text-[#2a5c35] font-bold">{i + 1}</td> <td className="pl-4 pr-2 py-2.5 text-[11px] text-green-muted font-bold">{i + 1}</td>
<td className="px-2 py-2.5"> <td className="px-2 py-2.5">
<Link href={`/teams/${t.slug}`} className="flex items-center gap-2"> <Link href={`/teams/${t.slug}`} className="flex items-center gap-2">
<TeamFlag name={t.name} iso2={t.iso2} size="sm" /> <TeamFlag name={t.name} iso2={t.iso2} size="sm" />
<span className="text-sm text-[#dff5e8] whitespace-nowrap">{t.name}</span> <span className="text-sm text-text whitespace-nowrap">{t.name}</span>
</Link> </Link>
</td> </td>
<td className="px-2 py-2.5 text-right text-sm text-[#4a7a55]">{t.stats?.appearances}</td> <td className="px-2 py-2.5 text-right text-sm text-green-mid">{t.stats?.appearances}</td>
<td className="px-2 py-2.5 text-right text-sm text-[#4a7a55]">{t.stats?.wins}</td> <td className="px-2 py-2.5 text-right text-sm text-green-mid">{t.stats?.wins}</td>
<td className="px-2 py-2.5 text-right text-sm text-[#4a7a55]">{t.stats?.draws}</td> <td className="px-2 py-2.5 text-right text-sm text-green-mid">{t.stats?.draws}</td>
<td className="px-2 py-2.5 text-right text-sm text-[#4a7a55]">{t.stats?.losses}</td> <td className="px-2 py-2.5 text-right text-sm text-green-mid">{t.stats?.losses}</td>
<td className="px-2 py-2.5 text-right text-sm text-[#4a7a55]">{t.stats?.goalsFor}</td> <td className="px-2 py-2.5 text-right text-sm text-green-mid">{t.stats?.goalsFor}</td>
<td className="px-2 py-2.5 text-right text-sm text-[#4a7a55]">{t.stats?.goalsAgainst}</td> <td className="px-2 py-2.5 text-right text-sm text-green-mid">{t.stats?.goalsAgainst}</td>
<td className="px-2 py-2.5 text-right text-sm text-[#4a7a55]"> <td className="px-2 py-2.5 text-right text-sm text-green-mid">
{(t.stats?.goalsFor ?? 0) - (t.stats?.goalsAgainst ?? 0) >= 0 {(t.stats?.goalsFor ?? 0) - (t.stats?.goalsAgainst ?? 0) >= 0
? `+${(t.stats?.goalsFor ?? 0) - (t.stats?.goalsAgainst ?? 0)}` ? `+${(t.stats?.goalsFor ?? 0) - (t.stats?.goalsAgainst ?? 0)}`
: (t.stats?.goalsFor ?? 0) - (t.stats?.goalsAgainst ?? 0)} : (t.stats?.goalsFor ?? 0) - (t.stats?.goalsAgainst ?? 0)}
</td> </td>
<td className="px-2 pr-4 py-2.5 text-right text-[13px] font-bold text-[#22c55e]">{t.stats?.winPct}%</td> <td className="px-2 pr-4 py-2.5 text-right text-[13px] font-bold text-green">{t.stats?.winPct}%</td>
</tr> </tr>
))} ))}
</tbody> </tbody>
+35 -37
View File
@@ -77,11 +77,11 @@ export default function TeamPage({ params }: { params: Promise<{ slug: string }>
const years = Object.keys(matchesByYear).map(Number).sort((a, b) => b - a) const years = Object.keys(matchesByYear).map(Number).sort((a, b) => b - a)
if (loading && !teamData) { if (loading && !teamData) {
return <div className="max-w-[1200px] mx-auto px-7 py-10 text-[#2a5c35]">Loading team</div> return <div className="max-w-[1200px] mx-auto px-7 py-10 text-green-muted">Loading team</div>
} }
if (!team) { if (!team) {
return <div className="max-w-[1200px] mx-auto px-7 py-10 text-[#2a5c35]">Team not found.</div> return <div className="max-w-[1200px] mx-auto px-7 py-10 text-green-muted">Team not found.</div>
} }
const s = team.stats const s = team.stats
@@ -95,13 +95,13 @@ export default function TeamPage({ params }: { params: Promise<{ slug: string }>
<div className="flex items-center gap-6 flex-wrap"> <div className="flex items-center gap-6 flex-wrap">
<TeamFlag name={team.name} iso2={team.iso2} size="xl" /> <TeamFlag name={team.name} iso2={team.iso2} size="xl" />
<div> <div>
<h1 className="font-['Bebas_Neue'] text-[56px] text-[#22c55e] leading-none">{team.name}</h1> <h1 className="font-['Bebas_Neue'] text-[56px] text-green leading-none">{team.name}</h1>
<div className="flex gap-3 mt-2 flex-wrap"> <div className="flex gap-3 mt-2 flex-wrap">
{team.fifaCode && <span className="text-[11px] text-[#2a5c35] font-bold tracking-wider">{team.fifaCode}</span>} {team.fifaCode && <span className="text-[11px] text-green-muted font-bold tracking-wider">{team.fifaCode}</span>}
{team.confederation && <span className="text-[11px] text-[#2a5c35]">{team.confederation}</span>} {team.confederation && <span className="text-[11px] text-green-muted">{team.confederation}</span>}
{team.continent && <span className="text-[11px] text-[#2a5c35]">{team.continent}</span>} {team.continent && <span className="text-[11px] text-green-muted">{team.continent}</span>}
{(s?.titles ?? 0) > 0 && ( {(s?.titles ?? 0) > 0 && (
<span className="inline-flex items-center gap-1 text-[11px] text-[#22c55e] font-bold"> <span className="inline-flex items-center gap-1 text-[11px] text-green font-bold">
{Array.from({ length: s?.titles ?? 0 }).map((_, i) => <TrophyIcon key={i} className="w-3.5 h-3.5" />)} {Array.from({ length: s?.titles ?? 0 }).map((_, i) => <TrophyIcon key={i} className="w-3.5 h-3.5" />)}
{s?.titles} title{(s?.titles ?? 0) !== 1 ? 's' : ''} {s?.titles} title{(s?.titles ?? 0) !== 1 ? 's' : ''}
</span> </span>
@@ -116,7 +116,7 @@ export default function TeamPage({ params }: { params: Promise<{ slug: string }>
{/* Stats grid */} {/* Stats grid */}
{s && ( {s && (
<div className="mb-8"> <div className="mb-8">
<h2 className="text-[11px] text-[#2a5c35] font-bold tracking-[0.14em] uppercase mb-4">World Cup Record</h2> <h2 className="text-[11px] text-green-muted font-bold tracking-[0.14em] uppercase mb-4">World Cup Record</h2>
<div className="grid grid-cols-2 sm:grid-cols-4 gap-3 mb-3"> <div className="grid grid-cols-2 sm:grid-cols-4 gap-3 mb-3">
{[ {[
{ label: 'Appearances', value: s.appearances }, { label: 'Appearances', value: s.appearances },
@@ -125,28 +125,28 @@ export default function TeamPage({ params }: { params: Promise<{ slug: string }>
{ label: 'Goals For', value: s.goalsFor }, { label: 'Goals For', value: s.goalsFor },
].map(item => ( ].map(item => (
<div key={item.label} className="glass-card rounded-xl p-4"> <div key={item.label} className="glass-card rounded-xl p-4">
<div className="text-[9px] text-[#2a5c35] tracking-[0.1em] uppercase mb-1.5">{item.label}</div> <div className="text-[9px] text-green-muted tracking-[0.1em] uppercase mb-1.5">{item.label}</div>
<div className="font-['Bebas_Neue'] text-3xl text-[#22c55e]">{item.value}</div> <div className="font-['Bebas_Neue'] text-3xl text-green">{item.value}</div>
</div> </div>
))} ))}
</div> </div>
<div className="glass-card rounded-xl"> <div className="glass-card rounded-xl">
<div className="grid px-4 py-2.5 text-[9px] text-[#2a5c35] tracking-[0.1em] uppercase" <div className="grid px-4 py-2.5 text-[9px] text-green-muted tracking-[0.1em] uppercase"
style={{ gridTemplateColumns: '1fr 44px 44px 44px 60px 60px 60px' }}> style={{ gridTemplateColumns: '1fr 44px 44px 44px 60px 60px 60px' }}>
<span>Team</span><span className="text-center">W</span><span className="text-center">D</span> <span>Team</span><span className="text-center">W</span><span className="text-center">D</span>
<span className="text-center">L</span><span className="text-center">GF</span> <span className="text-center">L</span><span className="text-center">GF</span>
<span className="text-center">GA</span><span className="text-center">GD</span> <span className="text-center">GA</span><span className="text-center">GD</span>
</div> </div>
<div className="grid px-4 py-3 border-t items-center" <div className="grid px-4 py-3 border-t border-green/[6%] items-center"
style={{ gridTemplateColumns: '1fr 44px 44px 44px 60px 60px 60px', borderColor: 'rgba(34,197,94,0.06)' }}> style={{ gridTemplateColumns: '1fr 44px 44px 44px 60px 60px 60px' }}>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<TeamFlag name={team.name} iso2={team.iso2} size="sm" /> <TeamFlag name={team.name} iso2={team.iso2} size="sm" />
<span className="text-sm text-[#dff5e8]">{team.name}</span> <span className="text-sm text-text">{team.name}</span>
</div> </div>
{[s.wins, s.draws, s.losses, s.goalsFor, s.goalsAgainst].map((v, i) => ( {[s.wins, s.draws, s.losses, s.goalsFor, s.goalsAgainst].map((v, i) => (
<span key={i} className="text-center text-sm text-[#4a7a55]">{v}</span> <span key={i} className="text-center text-sm text-green-mid">{v}</span>
))} ))}
<span className="text-center text-sm text-[#4a7a55]">{s.goalDiff >= 0 ? `+${s.goalDiff}` : s.goalDiff}</span> <span className="text-center text-sm text-green-mid">{s.goalDiff >= 0 ? `+${s.goalDiff}` : s.goalDiff}</span>
</div> </div>
</div> </div>
</div> </div>
@@ -155,11 +155,11 @@ export default function TeamPage({ params }: { params: Promise<{ slug: string }>
{/* Tournament participations */} {/* Tournament participations */}
{years.length > 0 && ( {years.length > 0 && (
<div className="mb-8"> <div className="mb-8">
<h2 className="text-[11px] text-[#2a5c35] font-bold tracking-[0.14em] uppercase mb-4">Tournament Participations</h2> <h2 className="text-[11px] text-green-muted font-bold tracking-[0.14em] uppercase mb-4">Tournament Participations</h2>
<div className="flex flex-wrap gap-2"> <div className="flex flex-wrap gap-2">
{years.map(year => ( {years.map(year => (
<Link key={year} href={`/tournaments/${year}`} <Link key={year} href={`/tournaments/${year}`}
className="font-['Bebas_Neue'] text-lg px-3 py-1 rounded-lg transition-colors text-[#6abf7a] bg-[rgba(4,18,8,0.78)] border border-[rgba(34,197,94,0.15)] hover:text-[#22c55e] hover:border-[rgba(34,197,94,0.4)] backdrop-blur-sm"> className="font-['Bebas_Neue'] text-lg px-3 py-1 rounded-lg transition-colors text-green-sec bg-bg/[78%] border border-border hover:text-green hover:border-green/40 backdrop-blur-sm">
{year} {year}
</Link> </Link>
))} ))}
@@ -170,14 +170,14 @@ export default function TeamPage({ params }: { params: Promise<{ slug: string }>
{/* Match history by year */} {/* Match history by year */}
{years.length > 0 && ( {years.length > 0 && (
<div> <div>
<h2 className="text-[11px] text-[#2a5c35] font-bold tracking-[0.14em] uppercase mb-4">Match History</h2> <h2 className="text-[11px] text-green-muted font-bold tracking-[0.14em] uppercase mb-4">Match History</h2>
<div className="space-y-6"> <div className="space-y-6">
{years.map(year => { {years.map(year => {
const yMatches = matchesByYear[year] const yMatches = matchesByYear[year]
return ( return (
<div key={year}> <div key={year}>
<Link href={`/tournaments/${year}`} <Link href={`/tournaments/${year}`}
className="inline-block font-['Bebas_Neue'] text-[22px] text-[#22c55e] mb-2 hover:opacity-70 transition-opacity"> className="inline-block font-['Bebas_Neue'] text-[22px] text-green mb-2 hover:opacity-70 transition-opacity">
{year} {year}
</Link> </Link>
<div className="glass-card rounded-xl"> <div className="glass-card rounded-xl">
@@ -194,23 +194,22 @@ export default function TeamPage({ params }: { params: Promise<{ slug: string }>
const result = myScore != null && theirScore != null const result = myScore != null && theirScore != null
? myScore > theirScore ? 'W' : myScore < theirScore ? 'L' : 'D' ? myScore > theirScore ? 'W' : myScore < theirScore ? 'L' : 'D'
: null : null
const resultColor = result === 'W' ? 'text-[#22c55e]' : result === 'L' ? 'text-[#ef4444]' : 'text-[#6abf7a]' const resultColor = result === 'W' ? 'text-green' : result === 'L' ? 'text-red-500' : 'text-green-sec'
// Display the decisive score (ET score for AET matches, FT for normal, PSO for shootouts) // Display the decisive score (ET score for AET matches, FT for normal, PSO for shootouts)
const displayScore = scoreP ? null : (scoreEt ?? ft) const displayScore = scoreP ? null : (scoreEt ?? ft)
return ( return (
<Link key={m.id} href={`/tournaments/${m.year}#match-${m.id}`}> <Link key={m.id} href={`/tournaments/${m.year}#match-${m.id}`}>
<div className="flex items-center gap-3 px-3 sm:px-4 py-2.5 border-b hover:bg-[rgba(34,197,94,0.03)] transition-colors" <div className={`flex items-center gap-3 px-3 sm:px-4 py-2.5 border-b hover:bg-green/[3%] transition-colors border-green/[6%] ${i % 2 !== 0 ? 'bg-green/[1%]' : ''}`}>
style={{ borderColor: 'rgba(34,197,94,0.06)', background: i % 2 === 0 ? undefined : 'rgba(34,197,94,0.01)' }}>
<span className={`text-[11px] font-bold w-4 flex-shrink-0 ${resultColor}`}>{result ?? ''}</span> <span className={`text-[11px] font-bold w-4 flex-shrink-0 ${resultColor}`}>{result ?? ''}</span>
<TeamFlag name={opponent.name} iso2={opponent.iso2} size="sm" /> <TeamFlag name={opponent.name} iso2={opponent.iso2} size="sm" />
<div className="flex-1 min-w-0"> <div className="flex-1 min-w-0">
<div className="text-sm text-[#dff5e8] truncate">{opponent.name}</div> <div className="text-sm text-text truncate">{opponent.name}</div>
<div className="text-[10px] text-[#2a5c35]"> <div className="text-[10px] text-green-muted">
{m.round}{m.group ? ` · ${m.group}` : ''}{m.date ? ` · ${formatDate(m.date)}` : ''} {m.round}{m.group ? ` · ${m.group}` : ''}{m.date ? ` · ${formatDate(m.date)}` : ''}
</div> </div>
</div> </div>
<div className="text-right flex-shrink-0"> <div className="text-right flex-shrink-0">
<div className="font-['Bebas_Neue'] text-lg text-[#22c55e] leading-none"> <div className="font-['Bebas_Neue'] text-lg text-green leading-none">
{scoreP {scoreP
? `${isHome ? scoreP[0] : scoreP[1]}${isHome ? scoreP[1] : scoreP[0]}` ? `${isHome ? scoreP[0] : scoreP[1]}${isHome ? scoreP[1] : scoreP[0]}`
: displayScore : displayScore
@@ -218,12 +217,12 @@ export default function TeamPage({ params }: { params: Promise<{ slug: string }>
: ''} : ''}
</div> </div>
{scoreP && ft && ( {scoreP && ft && (
<div className="text-[9px] text-[#2a5c35] leading-none"> <div className="text-[9px] text-green-muted leading-none">
{`${isHome ? ft[0] : ft[1]}${isHome ? ft[1] : ft[0]}`} a.e.t. {`${isHome ? ft[0] : ft[1]}${isHome ? ft[1] : ft[0]}`} a.e.t.
</div> </div>
)} )}
{scoreEt && !scoreP && ( {scoreEt && !scoreP && (
<div className="text-[9px] text-[#2a5c35] leading-none">a.e.t.</div> <div className="text-[9px] text-green-muted leading-none">a.e.t.</div>
)} )}
</div> </div>
</div> </div>
@@ -243,23 +242,22 @@ export default function TeamPage({ params }: { params: Promise<{ slug: string }>
<div> <div>
{teamScorers.length > 0 && ( {teamScorers.length > 0 && (
<div> <div>
<h2 className="text-[11px] text-[#2a5c35] font-bold tracking-[0.14em] uppercase mb-4">Top Scorers</h2> <h2 className="text-[11px] text-green-muted font-bold tracking-[0.14em] uppercase mb-4">Top Scorers</h2>
<div className="glass-card"> <div className="glass-card">
{teamScorers.map((sc: { playerName: string; goals: number; penalties: number; tournaments: number }, i: number) => ( {teamScorers.map((sc: { playerName: string; goals: number; penalties: number; tournaments: number }, i: number) => (
<Link key={sc.playerName} href={`/players/${encodeURIComponent(sc.playerName)}`}> <Link key={sc.playerName} href={`/players/${encodeURIComponent(sc.playerName)}`}>
<div className="flex items-center gap-2.5 px-3.5 py-2.5 border-b hover:bg-[rgba(34,197,94,0.03)] cursor-pointer" <div className={`flex items-center gap-2.5 px-3.5 py-2.5 border-b hover:bg-green/[3%] cursor-pointer border-green/[6%] ${i === 0 ? 'bg-green/[4%]' : ''}`}>
style={{ borderColor: 'rgba(34,197,94,0.06)', background: i === 0 ? 'rgba(34,197,94,0.04)' : undefined }}> <span className="text-[10px] text-green-muted w-4 text-right font-bold flex-shrink-0">{i + 1}</span>
<span className="text-[10px] text-[#2a5c35] w-4 text-right font-bold flex-shrink-0">{i + 1}</span>
<div className="flex-1 min-w-0"> <div className="flex-1 min-w-0">
<div className="text-[13px] font-semibold text-[#dff5e8] truncate">{sc.playerName}</div> <div className="text-[13px] font-semibold text-text truncate">{sc.playerName}</div>
<div className="text-[10px] text-[#2a5c35]"> <div className="text-[10px] text-green-muted">
{sc.tournaments} WC{sc.tournaments !== 1 ? 's' : ''}{sc.penalties > 0 ? ` · ${sc.penalties}P` : ''} {sc.tournaments} WC{sc.tournaments !== 1 ? 's' : ''}{sc.penalties > 0 ? ` · ${sc.penalties}P` : ''}
</div> </div>
</div> </div>
<div className="w-10 h-1 rounded-full flex-shrink-0" style={{ background: 'rgba(34,197,94,0.1)' }}> <div className="w-10 h-1 rounded-full flex-shrink-0 bg-green/10">
<div className="h-full rounded-full bg-[#22c55e]" style={{ width: `${(sc.goals / maxScorer) * 100}%` }} /> <div className="h-full rounded-full bg-green" style={{ width: `${(sc.goals / maxScorer) * 100}%` }} />
</div> </div>
<span className="font-['Bebas_Neue'] text-xl text-[#22c55e] flex-shrink-0">{sc.goals}</span> <span className="font-['Bebas_Neue'] text-xl text-green flex-shrink-0">{sc.goals}</span>
</div> </div>
</Link> </Link>
))} ))}
+34 -36
View File
@@ -53,14 +53,14 @@ function GoalList({ match }: { match: MatchData }) {
<span key={i}> <span key={i}>
{i > 0 && <span className="mx-0.5">,</span>} {i > 0 && <span className="mx-0.5">,</span>}
<Link href={`/players/${encodeURIComponent(g.playerName)}`} <Link href={`/players/${encodeURIComponent(g.playerName)}`}
className="underline decoration-dotted underline-offset-2 hover:text-[#22c55e] hover:decoration-solid transition-colors"> className="underline decoration-dotted underline-offset-2 hover:text-green hover:decoration-solid transition-colors">
{g.playerName} {g.playerName}
</Link> </Link>
{' '}{g.minute ?? ''}{g.minuteOffset ? `+${g.minuteOffset}` : ''}'{g.isPenalty ? ' (P)' : g.isOwnGoal ? ' (OG)' : ''} {' '}{g.minute ?? ''}{g.minuteOffset ? `+${g.minuteOffset}` : ''}'{g.isPenalty ? ' (P)' : g.isOwnGoal ? ' (OG)' : ''}
</span> </span>
) )
return ( return (
<div className="flex justify-between gap-4 px-4 pb-2 text-[10px] text-[#2a5c35]"> <div className="flex justify-between gap-4 px-4 pb-2 text-[10px] text-green-muted">
<div className="text-left">{t1Goals.map(renderGoal)}</div> <div className="text-left">{t1Goals.map(renderGoal)}</div>
<div className="text-right">{t2Goals.map(renderGoal)}</div> <div className="text-right">{t2Goals.map(renderGoal)}</div>
</div> </div>
@@ -113,13 +113,13 @@ export default function TournamentPage({ params }: { params: Promise<{ year: str
if (loading && !data) { if (loading && !data) {
return ( return (
<div className="max-w-[1200px] mx-auto px-7 py-10"> <div className="max-w-[1200px] mx-auto px-7 py-10">
<div className="h-24 w-48 rounded-xl animate-pulse mb-6" style={{ background: '#0a1810' }} /> <div className="h-24 w-48 rounded-xl animate-pulse mb-6 bg-card" />
<div className="text-[#2a5c35] text-sm">Loading {year} World Cup…</div> <div className="text-green-muted text-sm">Loading {year} World Cup…</div>
</div> </div>
) )
} }
if (!t) return <div className="max-w-[1200px] mx-auto px-7 py-10 text-[#2a5c35]">Tournament {year} not found.</div> if (!t) return <div className="max-w-[1200px] mx-auto px-7 py-10 text-green-muted">Tournament {year} not found.</div>
return ( return (
<div className="max-w-[1200px] mx-auto px-7 py-10 pb-16"> <div className="max-w-[1200px] mx-auto px-7 py-10 pb-16">
@@ -128,14 +128,14 @@ export default function TournamentPage({ params }: { params: Promise<{ year: str
{liveMatches.length > 0 && <div className="mb-3"><LiveBadge label="Live Now" /></div>} {liveMatches.length > 0 && <div className="mb-3"><LiveBadge label="Live Now" /></div>}
<div className="flex items-start justify-between flex-wrap gap-4"> <div className="flex items-start justify-between flex-wrap gap-4">
<div> <div>
<h1 className="font-['Bebas_Neue'] text-[64px] text-[#22c55e] leading-none">{year}</h1> <h1 className="font-['Bebas_Neue'] text-[64px] text-green leading-none">{year}</h1>
<p className="text-[#6abf7a] text-lg mt-1">{t.host}</p> <p className="text-green-sec text-lg mt-1">{t.host}</p>
</div> </div>
{t.winner && ( {t.winner && (
<div className="text-center"> <div className="text-center">
<TeamFlag name={t.winner} size="xl" className="mb-2" /> <TeamFlag name={t.winner} size="xl" className="mb-2" />
<div className="font-['Bebas_Neue'] text-2xl text-[#dff5e8]">{t.winner}</div> <div className="font-['Bebas_Neue'] text-2xl text-text">{t.winner}</div>
{t.runnerUp && <div className="text-xs text-[#2a5c35] mt-1">def. {t.runnerUp}</div>} {t.runnerUp && <div className="text-xs text-green-muted mt-1">def. {t.runnerUp}</div>}
</div> </div>
)} )}
</div> </div>
@@ -147,8 +147,8 @@ export default function TournamentPage({ params }: { params: Promise<{ year: str
{ label: 'Goals/Game', value: t.avgGoalsPerGame ? Number(t.avgGoalsPerGame).toFixed(2) : null }, { label: 'Goals/Game', value: t.avgGoalsPerGame ? Number(t.avgGoalsPerGame).toFixed(2) : null },
].filter(s => s.value != null).map(s => ( ].filter(s => s.value != null).map(s => (
<div key={s.label}> <div key={s.label}>
<div className="text-[9px] text-[#2a5c35] tracking-[0.12em] uppercase">{s.label}</div> <div className="text-[9px] text-green-muted tracking-[0.12em] uppercase">{s.label}</div>
<div className="font-['Bebas_Neue'] text-3xl text-[#22c55e]">{s.value}</div> <div className="font-['Bebas_Neue'] text-3xl text-green">{s.value}</div>
</div> </div>
))} ))}
</div> </div>
@@ -159,7 +159,7 @@ export default function TournamentPage({ params }: { params: Promise<{ year: str
{/* Live matches first */} {/* Live matches first */}
{liveMatches.length > 0 && ( {liveMatches.length > 0 && (
<div className="mb-8"> <div className="mb-8">
<h2 className="font-['Bebas_Neue'] text-2xl text-[#4ade80] mb-4">LIVE</h2> <h2 className="font-['Bebas_Neue'] text-2xl text-green-light mb-4">LIVE</h2>
<div className="flex flex-col gap-4"> <div className="flex flex-col gap-4">
{liveMatches.map(m => ( {liveMatches.map(m => (
<div key={m.id} id={`match-${m.id}`}> <div key={m.id} id={`match-${m.id}`}>
@@ -174,26 +174,25 @@ export default function TournamentPage({ params }: { params: Promise<{ year: str
{/* Group stage */} {/* Group stage */}
{groupRounds.length > 0 && ( {groupRounds.length > 0 && (
<div className="mb-8"> <div className="mb-8">
<h2 className="font-['Bebas_Neue'] text-2xl text-[#22c55e] mb-5">Group Stage</h2> <h2 className="font-['Bebas_Neue'] text-2xl text-green mb-5">Group Stage</h2>
{groupRounds.map(([groupName, rows]) => { {groupRounds.map(([groupName, rows]) => {
const sorted = [...rows].sort((a, b) => b.pts - a.pts || b.goalDiff - a.goalDiff) const sorted = [...rows].sort((a, b) => b.pts - a.pts || b.goalDiff - a.goalDiff)
const groupMatches = (byRound[groupName] ?? []).sort((a, b) => (a.date ?? '') < (b.date ?? '') ? -1 : 1) const groupMatches = (byRound[groupName] ?? []).sort((a, b) => (a.date ?? '') < (b.date ?? '') ? -1 : 1)
return ( return (
<div key={groupName} className="mb-8"> <div key={groupName} className="mb-8">
<h3 className="text-[13px] font-bold text-[#22c55e] tracking-wide uppercase mb-3">{groupName}</h3> <h3 className="text-[13px] font-bold text-green tracking-wide uppercase mb-3">{groupName}</h3>
{/* Standings mini */} {/* Standings mini */}
<div className="glass-card rounded-xl mb-3"> <div className="glass-card rounded-xl mb-3">
{sorted.map((s, i) => ( {sorted.map((s, i) => (
<Link key={s.team.id} href={`/teams/${s.team.slug}`}> <Link key={s.team.id} href={`/teams/${s.team.slug}`}>
<div className="flex items-center gap-2 px-3 py-2 border-b hover:bg-[rgba(34,197,94,0.03)] cursor-pointer" <div className={`flex items-center gap-2 px-3 py-2 border-b hover:bg-green/[3%] cursor-pointer border-green/5 ${i < 2 ? 'bg-green/[2%]' : ''}`}>
style={{ borderColor: 'rgba(34,197,94,0.05)', background: i < 2 ? 'rgba(34,197,94,0.02)' : undefined }}>
<TeamFlag name={s.team.name} iso2={s.team.iso2} size="sm" /> <TeamFlag name={s.team.name} iso2={s.team.iso2} size="sm" />
<span className="flex-1 text-[13px] text-[#6abf7a] truncate">{s.team.name}</span> <span className="flex-1 text-[13px] text-green-sec truncate">{s.team.name}</span>
<span className="text-[11px] text-[#4a7a55] w-6 text-center">{s.played}</span> <span className="text-[11px] text-green-mid w-6 text-center">{s.played}</span>
<span className="text-[11px] text-[#4a7a55] w-6 text-center">{s.won}</span> <span className="text-[11px] text-green-mid w-6 text-center">{s.won}</span>
<span className="text-[11px] text-[#4a7a55] w-6 text-center">{s.drawn}</span> <span className="text-[11px] text-green-mid w-6 text-center">{s.drawn}</span>
<span className="text-[11px] text-[#4a7a55] w-6 text-center">{s.lost}</span> <span className="text-[11px] text-green-mid w-6 text-center">{s.lost}</span>
<span className="text-[11px] font-bold text-[#22c55e] w-6 text-center">{s.pts}</span> <span className="text-[11px] font-bold text-green w-6 text-center">{s.pts}</span>
</div> </div>
</Link> </Link>
))} ))}
@@ -216,10 +215,10 @@ export default function TournamentPage({ params }: { params: Promise<{ year: str
{/* Knockout rounds */} {/* Knockout rounds */}
{Object.keys(koByRound).length > 0 && ( {Object.keys(koByRound).length > 0 && (
<div> <div>
<h2 className="font-['Bebas_Neue'] text-2xl text-[#22c55e] mb-5">Knockout Stage</h2> <h2 className="font-['Bebas_Neue'] text-2xl text-green mb-5">Knockout Stage</h2>
{Object.entries(koByRound).map(([round, roundMatches]) => ( {Object.entries(koByRound).map(([round, roundMatches]) => (
<div key={round} className="mb-6"> <div key={round} className="mb-6">
<h3 className="text-[13px] font-bold text-[#22c55e] tracking-wide uppercase mb-3">{round}</h3> <h3 className="text-[13px] font-bold text-green tracking-wide uppercase mb-3">{round}</h3>
<div className="flex flex-col gap-3"> <div className="flex flex-col gap-3">
{roundMatches.map(m => ( {roundMatches.map(m => (
<div key={m.id} id={`match-${m.id}`}> <div key={m.id} id={`match-${m.id}`}>
@@ -237,22 +236,21 @@ export default function TournamentPage({ params }: { params: Promise<{ year: str
{/* Sidebar: top scorers */} {/* Sidebar: top scorers */}
<div> <div>
<div className="sticky top-[76px]"> <div className="sticky top-[76px]">
<h2 className="font-['Bebas_Neue'] text-xl text-[#22c55e] mb-4">TOP SCORERS</h2> <h2 className="font-['Bebas_Neue'] text-xl text-green mb-4">TOP SCORERS</h2>
<div className="glass-card"> <div className="glass-card">
{t.topScorers?.map((s: { playerName: string; goals: number; penalties: number; team?: { name: string; iso2?: string | null; slug: string } | null }, i: number) => ( {t.topScorers?.map((s: { playerName: string; goals: number; penalties: number; team?: { name: string; iso2?: string | null; slug: string } | null }, i: number) => (
<Link key={s.playerName} href={`/players/${encodeURIComponent(s.playerName)}`}> <Link key={s.playerName} href={`/players/${encodeURIComponent(s.playerName)}`}>
<div className="flex items-center gap-2.5 px-3.5 py-2.5 border-b hover:bg-[rgba(34,197,94,0.03)] cursor-pointer" <div className={`flex items-center gap-2.5 px-3.5 py-2.5 border-b hover:bg-green/[3%] cursor-pointer border-green/[6%] ${i === 0 ? 'bg-green/[4%]' : ''}`}>
style={{ borderColor: 'rgba(34,197,94,0.06)', background: i === 0 ? 'rgba(34,197,94,0.04)' : undefined }}> <span className="text-[10px] text-green-muted w-4 text-right font-bold flex-shrink-0">{i + 1}</span>
<span className="text-[10px] text-[#2a5c35] w-4 text-right font-bold flex-shrink-0">{i + 1}</span>
{s.team && <TeamFlag name={s.team.name} iso2={s.team.iso2} size="sm" />} {s.team && <TeamFlag name={s.team.name} iso2={s.team.iso2} size="sm" />}
<div className="flex-1 min-w-0"> <div className="flex-1 min-w-0">
<div className="text-[13px] font-semibold text-[#dff5e8] truncate">{s.playerName}</div> <div className="text-[13px] font-semibold text-text truncate">{s.playerName}</div>
{s.penalties > 0 && <div className="text-[9px] text-[#2a5c35]">{s.penalties} pen</div>} {s.penalties > 0 && <div className="text-[9px] text-green-muted">{s.penalties} pen</div>}
</div> </div>
<div className="w-12 h-1 rounded-full flex-shrink-0" style={{ background: 'rgba(34,197,94,0.1)' }}> <div className="w-12 h-1 rounded-full flex-shrink-0 bg-green/10">
<div className="h-full rounded-full bg-[#22c55e]" style={{ width: `${(s.goals / maxScorer) * 100}%` }} /> <div className="h-full rounded-full bg-green" style={{ width: `${(s.goals / maxScorer) * 100}%` }} />
</div> </div>
<span className="font-['Bebas_Neue'] text-xl text-[#22c55e] flex-shrink-0">{s.goals}</span> <span className="font-['Bebas_Neue'] text-xl text-green flex-shrink-0">{s.goals}</span>
</div> </div>
</Link> </Link>
))} ))}
@@ -260,15 +258,15 @@ export default function TournamentPage({ params }: { params: Promise<{ year: str
{t.thirdPlace && ( {t.thirdPlace && (
<div className="glass-card mt-4 rounded-xl p-4"> <div className="glass-card mt-4 rounded-xl p-4">
<div className="text-[9px] text-[#2a5c35] tracking-[0.1em] uppercase mb-2">3rd Place</div> <div className="text-[9px] text-green-muted tracking-[0.1em] uppercase mb-2">3rd Place</div>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<TeamFlag name={t.thirdPlace} size="sm" /> <TeamFlag name={t.thirdPlace} size="sm" />
<span className="text-sm text-[#6abf7a]">{t.thirdPlace}</span> <span className="text-sm text-green-sec">{t.thirdPlace}</span>
</div> </div>
{t.fourthPlace && ( {t.fourthPlace && (
<div className="flex items-center gap-2 mt-1.5"> <div className="flex items-center gap-2 mt-1.5">
<TeamFlag name={t.fourthPlace} size="sm" /> <TeamFlag name={t.fourthPlace} size="sm" />
<span className="text-sm text-[#4a7a55]">{t.fourthPlace}</span> <span className="text-sm text-green-mid">{t.fourthPlace}</span>
</div> </div>
)} )}
</div> </div>
+2 -2
View File
@@ -1,8 +1,8 @@
export function LiveBadge({ label = 'Live' }: { label?: string }) { export function LiveBadge({ label = 'Live' }: { label?: string }) {
return ( return (
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<span className="w-2 h-2 rounded-full bg-[#4ade80] flex-shrink-0 animate-live" /> <span className="w-2 h-2 rounded-full bg-green-light flex-shrink-0 animate-live" />
<span className="text-[11px] font-bold text-[#4ade80] tracking-[0.14em] uppercase">{label}</span> <span className="text-[11px] font-bold text-green-light tracking-[0.14em] uppercase">{label}</span>
</div> </div>
) )
} }
+16 -16
View File
@@ -32,19 +32,19 @@ export function MatchCard({ match, compact = false }: { match: Match; compact?:
if (compact) { if (compact) {
return ( return (
<Link href={`/tournaments/${match.year}#match-${match.id}`} className="block"> <Link href={`/tournaments/${match.year}#match-${match.id}`} className="block">
<div className="glass-card rounded-xl p-3.5 hover:border-[rgba(34,197,94,0.22)] transition-colors"> <div className="glass-card rounded-xl p-3.5 hover:border-green/[22%] transition-colors">
<div className="text-[9px] text-[#2a5c35] tracking-[0.1em] uppercase mb-2.5"> <div className="text-[9px] text-green-muted tracking-[0.1em] uppercase mb-2.5">
{match.round}{match.group ? ` · ${match.group}` : ''} · {match.date ? formatDate(match.date) : ''} {match.round}{match.group ? ` · ${match.group}` : ''} · {match.date ? formatDate(match.date) : ''}
</div> </div>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<div className="flex-1 flex items-center gap-2 overflow-hidden"> <div className="flex-1 flex items-center gap-2 overflow-hidden">
<TeamFlag name={match.team1.name} iso2={match.team1.iso2} size="sm" /> <TeamFlag name={match.team1.name} iso2={match.team1.iso2} size="sm" />
<span className={`text-sm font-medium truncate ${winner === 'home' ? 'text-[#dff5e8]' : 'text-[#4a7a55]'}`}> <span className={`text-sm font-medium truncate ${winner === 'home' ? 'text-text' : 'text-green-mid'}`}>
{match.team1.name} {match.team1.name}
</span> </span>
</div> </div>
<div className="flex-shrink-0 min-w-[52px] text-center"> <div className="flex-shrink-0 min-w-[52px] text-center">
<div className="font-['Bebas_Neue'] text-xl text-[#22c55e]"> <div className="font-['Bebas_Neue'] text-xl text-green">
{hasScore {hasScore
? match.scoreP ? match.scoreP
? `${match.scoreP[0]} ${match.scoreP[1]}` ? `${match.scoreP[0]} ${match.scoreP[1]}`
@@ -54,23 +54,23 @@ export function MatchCard({ match, compact = false }: { match: Match; compact?:
: match.isLive ? <LiveBadge label="•" /> : ''} : match.isLive ? <LiveBadge label="•" /> : ''}
</div> </div>
{match.scoreP && ( {match.scoreP && (
<div className="text-[8px] text-[#2a5c35] leading-none"> <div className="text-[8px] text-green-muted leading-none">
{ft![0]}{ft![1]} a.e.t. {ft![0]}{ft![1]} a.e.t.
</div> </div>
)} )}
{match.scoreEt && !match.scoreP && ( {match.scoreEt && !match.scoreP && (
<div className="text-[8px] text-[#2a5c35] leading-none">a.e.t.</div> <div className="text-[8px] text-green-muted leading-none">a.e.t.</div>
)} )}
</div> </div>
<div className="flex-1 flex items-center justify-end gap-2 overflow-hidden"> <div className="flex-1 flex items-center justify-end gap-2 overflow-hidden">
<span className={`text-sm font-medium truncate ${winner === 'away' ? 'text-[#dff5e8]' : 'text-[#4a7a55]'}`}> <span className={`text-sm font-medium truncate ${winner === 'away' ? 'text-text' : 'text-green-mid'}`}>
{match.team2.name} {match.team2.name}
</span> </span>
<TeamFlag name={match.team2.name} iso2={match.team2.iso2} size="sm" /> <TeamFlag name={match.team2.name} iso2={match.team2.iso2} size="sm" />
</div> </div>
</div> </div>
{match.scoreEt && !match.scoreP && ( {match.scoreEt && !match.scoreP && (
<div className="text-[9px] text-[#2a5c35] mt-1 text-center">a.e.t.</div> <div className="text-[9px] text-green-muted mt-1 text-center">a.e.t.</div>
)} )}
</div> </div>
</Link> </Link>
@@ -80,18 +80,18 @@ export function MatchCard({ match, compact = false }: { match: Match; compact?:
const matchHref = `/tournaments/${match.year}#match-${match.id}` const matchHref = `/tournaments/${match.year}#match-${match.id}`
return ( return (
<div className="glass-card-hero rounded-2xl px-5 py-6 sm:px-9 sm:py-9 hover:border-[rgba(34,197,94,0.45)] transition-colors"> <div className="glass-card-hero rounded-2xl px-5 py-6 sm:px-9 sm:py-9 hover:border-green/45 transition-colors">
{match.isLive && <div className="mb-4"><LiveBadge label="Live Now" /></div>} {match.isLive && <div className="mb-4"><LiveBadge label="Live Now" /></div>}
<div className="grid grid-cols-[1fr_auto_1fr] items-center gap-3 sm:gap-8"> <div className="grid grid-cols-[1fr_auto_1fr] items-center gap-3 sm:gap-8">
<Link href={match.team1.slug ? `/teams/${match.team1.slug}` : matchHref} <Link href={match.team1.slug ? `/teams/${match.team1.slug}` : matchHref}
className={`text-center block transition-colors hover:text-[#22c55e] ${winner === 'home' ? 'text-[#dff5e8]' : 'text-[#6abf7a]'}`}> className={`text-center block transition-colors hover:text-green ${winner === 'home' ? 'text-text' : 'text-green-sec'}`}>
<TeamFlag name={match.team1.name} iso2={match.team1.iso2} size="xl" className="mb-2" /> <TeamFlag name={match.team1.name} iso2={match.team1.iso2} size="xl" className="mb-2" />
<div className="font-['Bebas_Neue'] text-base sm:text-xl tracking-[0.07em] truncate"> <div className="font-['Bebas_Neue'] text-base sm:text-xl tracking-[0.07em] truncate">
{match.team1.name} {match.team1.name}
</div> </div>
</Link> </Link>
<Link href={matchHref} className="text-center flex-shrink-0 block"> <Link href={matchHref} className="text-center flex-shrink-0 block">
<div className="font-['Bebas_Neue'] text-[48px] sm:text-[76px] text-[#22c55e] leading-none hover:opacity-80 transition-opacity"> <div className="font-['Bebas_Neue'] text-[48px] sm:text-[76px] text-green leading-none hover:opacity-80 transition-opacity">
{hasScore {hasScore
? match.scoreP ? match.scoreP
? `${match.scoreP[0]}${match.scoreP[1]}` ? `${match.scoreP[0]}${match.scoreP[1]}`
@@ -101,16 +101,16 @@ export function MatchCard({ match, compact = false }: { match: Match; compact?:
: '??'} : '??'}
</div> </div>
{match.scoreP && ( {match.scoreP && (
<div className="text-[10px] text-[#2a5c35] mt-0.5">{ft![0]}{ft![1]} a.e.t.</div> <div className="text-[10px] text-green-muted mt-0.5">{ft![0]}{ft![1]} a.e.t.</div>
)} )}
{match.scoreEt && !match.scoreP && ( {match.scoreEt && !match.scoreP && (
<div className="text-[10px] text-[#2a5c35] mt-0.5">{ft![0]}{ft![1]} (a.e.t.)</div> <div className="text-[10px] text-green-muted mt-0.5">{ft![0]}{ft![1]} (a.e.t.)</div>
)} )}
<div className="text-[9px] text-[#2a5c35] tracking-[0.12em] uppercase mt-1.5">{match.round}</div> <div className="text-[9px] text-green-muted tracking-[0.12em] uppercase mt-1.5">{match.round}</div>
<div className="text-[10px] text-[#1a3a22] mt-0.5">{match.date ? formatDate(match.date) : ''}</div> <div className="text-[10px] text-green-dark mt-0.5">{match.date ? formatDate(match.date) : ''}</div>
</Link> </Link>
<Link href={match.team2.slug ? `/teams/${match.team2.slug}` : matchHref} <Link href={match.team2.slug ? `/teams/${match.team2.slug}` : matchHref}
className={`text-center block transition-colors hover:text-[#22c55e] ${winner === 'away' ? 'text-[#dff5e8]' : 'text-[#6abf7a]'}`}> className={`text-center block transition-colors hover:text-green ${winner === 'away' ? 'text-text' : 'text-green-sec'}`}>
<TeamFlag name={match.team2.name} iso2={match.team2.iso2} size="xl" className="mb-2" /> <TeamFlag name={match.team2.name} iso2={match.team2.iso2} size="xl" className="mb-2" />
<div className="font-['Bebas_Neue'] text-base sm:text-xl tracking-[0.07em] truncate"> <div className="font-['Bebas_Neue'] text-base sm:text-xl tracking-[0.07em] truncate">
{match.team2.name} {match.team2.name}
+15 -18
View File
@@ -40,15 +40,15 @@ export function Nav() {
return ( return (
<> <>
<nav <nav
className="fixed top-0 left-0 right-0 z-50 h-[60px]" className="fixed top-0 left-0 right-0 z-50 h-[60px] border-b border-green/[18%]"
style={{ background: 'rgba(4,13,8,0.97)', backdropFilter: 'blur(18px)', borderBottom: '1px solid rgba(34,197,94,0.18)' }} style={{ background: 'rgba(4,13,8,0.97)', backdropFilter: 'blur(18px)' }}
> >
<div className="max-w-[1200px] mx-auto px-7 h-full flex items-center"> <div className="max-w-[1200px] mx-auto px-7 h-full flex items-center">
{/* Logo */} {/* Logo */}
<Link href="/" className="flex items-center gap-2.5 flex-shrink-0 cursor-pointer select-none"> <Link href="/" className="flex items-center gap-2.5 flex-shrink-0 cursor-pointer select-none">
{/* eslint-disable-next-line @next/next/no-img-element */} {/* eslint-disable-next-line @next/next/no-img-element */}
<img src="/favicon.svg" style={{ height: '36px', width: 'auto' }} alt="" /> <img src="/favicon.svg" style={{ height: '36px', width: 'auto' }} alt="" />
<span className="font-['Bebas_Neue'] text-lg tracking-[3px] text-[#22c55e] whitespace-nowrap">WORLD CUP</span> <span className="font-['Bebas_Neue'] text-lg tracking-[3px] text-green whitespace-nowrap">WORLD CUP</span>
</Link> </Link>
{/* Desktop links */} {/* Desktop links */}
@@ -56,7 +56,7 @@ export function Nav() {
{NAV_LINKS.map(({ href, label }) => ( {NAV_LINKS.map(({ href, label }) => (
<Link key={href} href={href} <Link key={href} href={href}
className={`px-3.5 py-1.5 rounded-lg text-[13px] font-medium whitespace-nowrap transition-colors className={`px-3.5 py-1.5 rounded-lg text-[13px] font-medium whitespace-nowrap transition-colors
${isActive(href) ? 'bg-[rgba(34,197,94,0.12)] text-[#22c55e]' : 'text-[#4a7a55] hover:text-[#6abf7a]'}`}> ${isActive(href) ? 'bg-green/[12%] text-green' : 'text-green-mid hover:text-green-sec'}`}>
{label} {label}
</Link> </Link>
))} ))}
@@ -67,10 +67,9 @@ export function Nav() {
<input <input
type="text" value={q} onChange={e => setQ(e.target.value)} type="text" value={q} onChange={e => setQ(e.target.value)}
placeholder="Search…" placeholder="Search…"
className="w-44 pl-8 pr-3.5 py-1.5 rounded-[20px] text-[13px] text-[#dff5e8] outline-none" className="w-44 pl-8 pr-3.5 py-1.5 rounded-[20px] text-[13px] text-text outline-none bg-green/[6%] border border-green/[18%]"
style={{ background: 'rgba(34,197,94,0.06)', border: '1px solid rgba(34,197,94,0.18)' }}
/> />
<svg className="absolute left-2.5 top-1/2 -translate-y-1/2 opacity-30 pointer-events-none" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#dff5e8" strokeWidth="2.5"> <svg className="absolute left-2.5 top-1/2 -translate-y-1/2 opacity-30 pointer-events-none" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5">
<circle cx="11" cy="11" r="8" /><line x1="21" y1="21" x2="16.65" y2="16.65" /> <circle cx="11" cy="11" r="8" /><line x1="21" y1="21" x2="16.65" y2="16.65" />
</svg> </svg>
</form> </form>
@@ -78,13 +77,12 @@ export function Nav() {
{/* Hamburger */} {/* Hamburger */}
<button <button
onClick={() => setOpen(o => !o)} onClick={() => setOpen(o => !o)}
className="ml-auto md:hidden flex flex-col justify-center items-center w-9 h-9 gap-[5px] rounded-lg transition-colors" className={`ml-auto md:hidden flex flex-col justify-center items-center w-9 h-9 gap-[5px] rounded-lg transition-colors ${open ? 'bg-green/10' : ''}`}
style={{ background: open ? 'rgba(34,197,94,0.1)' : 'transparent' }}
aria-label="Menu" aria-label="Menu"
> >
<span className={`block w-5 h-[2px] bg-[#22c55e] rounded-full transition-all origin-center ${open ? 'rotate-45 translate-y-[7px]' : ''}`} /> <span className={`block w-5 h-[2px] bg-green rounded-full transition-all origin-center ${open ? 'rotate-45 translate-y-[7px]' : ''}`} />
<span className={`block w-5 h-[2px] bg-[#22c55e] rounded-full transition-all ${open ? 'opacity-0' : ''}`} /> <span className={`block w-5 h-[2px] bg-green rounded-full transition-all ${open ? 'opacity-0' : ''}`} />
<span className={`block w-5 h-[2px] bg-[#22c55e] rounded-full transition-all origin-center ${open ? '-rotate-45 -translate-y-[7px]' : ''}`} /> <span className={`block w-5 h-[2px] bg-green rounded-full transition-all origin-center ${open ? '-rotate-45 -translate-y-[7px]' : ''}`} />
</button> </button>
</div> </div>
</nav> </nav>
@@ -100,14 +98,14 @@ export function Nav() {
{/* Mobile menu panel */} {/* Mobile menu panel */}
<div <div
className={`fixed left-0 right-0 z-40 md:hidden transition-all duration-200 ${open ? 'top-[60px] opacity-100' : 'top-[48px] opacity-0 pointer-events-none'}`} className={`fixed left-0 right-0 z-40 md:hidden transition-all duration-200 border-b border-green/[18%] ${open ? 'top-[60px] opacity-100' : 'top-[48px] opacity-0 pointer-events-none'}`}
style={{ background: 'rgba(4,13,8,0.98)', borderBottom: '1px solid rgba(34,197,94,0.18)' }} style={{ background: 'rgba(4,13,8,0.98)' }}
> >
<div className="px-5 py-4 flex flex-col gap-1"> <div className="px-5 py-4 flex flex-col gap-1">
{NAV_LINKS.map(({ href, label }) => ( {NAV_LINKS.map(({ href, label }) => (
<Link key={href} href={href} <Link key={href} href={href}
className={`px-4 py-3 rounded-xl text-[15px] font-medium transition-colors className={`px-4 py-3 rounded-xl text-[15px] font-medium transition-colors
${isActive(href) ? 'bg-[rgba(34,197,94,0.12)] text-[#22c55e]' : 'text-[#6abf7a] hover:bg-[rgba(34,197,94,0.06)]'}`}> ${isActive(href) ? 'bg-green/[12%] text-green' : 'text-green-sec hover:bg-green/[6%]'}`}>
{label} {label}
</Link> </Link>
))} ))}
@@ -116,10 +114,9 @@ export function Nav() {
<input <input
type="text" value={q} onChange={e => setQ(e.target.value)} type="text" value={q} onChange={e => setQ(e.target.value)}
placeholder="Search players, teams, tournaments…" placeholder="Search players, teams, tournaments…"
className="w-full pl-9 pr-4 py-3 rounded-xl text-[14px] text-[#dff5e8] outline-none" className="w-full pl-9 pr-4 py-3 rounded-xl text-[14px] text-text outline-none bg-green/[6%] border border-green/[18%]"
style={{ background: 'rgba(34,197,94,0.06)', border: '1px solid rgba(34,197,94,0.18)' }}
/> />
<svg className="absolute left-3 top-1/2 -translate-y-1/2 opacity-30 pointer-events-none" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="#dff5e8" strokeWidth="2.5"> <svg className="absolute left-3 top-1/2 -translate-y-1/2 opacity-30 pointer-events-none" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5">
<circle cx="11" cy="11" r="8" /><line x1="21" y1="21" x2="16.65" y2="16.65" /> <circle cx="11" cy="11" r="8" /><line x1="21" y1="21" x2="16.65" y2="16.65" />
</svg> </svg>
</form> </form>
+1 -1
View File
@@ -31,7 +31,7 @@ export function TeamFlag({ name, iso2, size = 'md', className = '' }: Props) {
> >
<span style={{ <span style={{
fontSize: '0.38em', fontSize: '0.38em',
color: '#6abf7a', color: 'var(--color-green-sec)',
fontFamily: 'Space Grotesk, sans-serif', fontFamily: 'Space Grotesk, sans-serif',
fontWeight: 700, fontWeight: 700,
letterSpacing: '0.04em', letterSpacing: '0.04em',

Some files were not shown because too many files have changed in this diff Show More