⚽ FIFA WORLD CUP 2026     NJ-LIS-LON

SWEEPSTAKE • 11 JUN – 19 JUL 2026
CAN MEX USA
€60 pot
Live — last synced 12:07 • 0 matches played ⚽ Live scores
⚽ YOUR TEAMS PLAYING TODAY
MEX vs 🇿🇦 RSA 20:00 BST / 3:00pm ET • Mexico City
KOR vs CZE 03:00† BST / 10:00pm ET • Guadalajara
🔓Owner mode active

👤 Players

Add everyone taking part. You need at least 2 players to run the draw.

1
2
3
4
5
6
7
8
9
10
11
12

🅾 Pin Top-12 Teams

Optionally assign one top-12 team to a specific player. Pinned teams are locked in before the draw runs — max one pin per player.

1
2
3
4
5
6
7
8
9
10
11
12

💰 Pot (optional)

12 players × €5 = €60 total pot

📶 Live Results API

Enter your football-data.org API key to auto-sync results every time you refresh.

Connected ✔

🏆 All 48 Qualified Teams

Draw is seeded — every player gets 1 top-12 + 1 ranked 13–20. Official codes & flags shown.

FRA #1ESP #2ARG #3ENG #4POR #5BRA #6NED #7MAR #8BEL #9GER #10CRO #11COL #13SEN #14MEX #15USA #16URU #17JPN #18SUI #19KOR #22AUT #25🇦🇺 AUS #26ECU #28TUR #29ALG #30NOR #31SWE #33IRN #35SCO #36PAR #37CZE #38GHA #40EGY #41KSA #56PAN #57TUN #58CAN #59CIV #60NZL #63QAT #65BIH #66IRQ #68JOR #70COD #74🇿🇦 RSA #76HAI #83UZB #87CPV #90CUW #104

🎲 The Draw

Seeded draw — everyone gets at least 1 top-12 team and 1 ranked 13–20. Hit the button when everyone’s ready!

Draw complete — 12 players, all 48 teams assigned.

1
1
0 pts
ENG
ENG
England
★ #4
PAN
PAN
Panama
#57
SUI
SUI
Switzerland
#19
SCO
SCO
Scotland
#36
2
2
0 pts
ESP
ESP
Spain
★ #2
HAI
HAI
Haiti
#83
CPV
CPV
Cape Verde
#90
QAT
QAT
Qatar
#65
3
3
0 pts
FRA
FRA
France
★ #1
SWE
SWE
Sweden
#33
IRN
IRN
Iran
#35
TUR
TUR
Turkey
#29
4
4
0 pts
BRA
BRA
Brazil
★ #6
🇿🇦
RSA
South Africa
#76
ALG
ALG
Algeria
#30
IRQ
IRQ
Iraq
#68
5
5
0 pts
BEL
BEL
Belgium
★ #9
SEN
SEN
Senegal
#14
🇦🇺
AUS
Australia
#26
ECU
ECU
Ecuador
#28
6
6
0 pts
POR
POR
Portugal
★ #5
PAR
PAR
Paraguay
#37
TUN
TUN
Tunisia
#58
CZE
CZE
Czechia
#38
7
7
0 pts
NED
NED
Netherlands
★ #7
KSA
KSA
Saudi Arabia
#56
USA
USA
USA
#16
URU
URU
Uruguay
#17
8
8
0 pts
ARG
ARG
Argentina
★ #3
NZL
NZL
New Zealand
#63
CIV
CIV
Ivory Coast
#60
EGY
EGY
Egypt
#41
9
9
0 pts
GER
GER
Germany
★ #10
CUW
CUW
Curacao
#104
JOR
JOR
Jordan
#70
NOR
NOR
Norway
#31
1
10
0 pts
COL
COL
Colombia
#13
KOR
KOR
South Korea
#22
MEX
MEX
Mexico
#15
JPN
JPN
Japan
#18
1
11
0 pts
CRO
CRO
Croatia
#11
GHA
GHA
Ghana
#40
AUT
AUT
Austria
#25
BIH
BIH
Bosnia-Herz
#66
1
12
0 pts
MAR
MAR
Morocco
★ #8
UZB
UZB
Uzbekistan
#87
COD
COD
DR Congo
#74
CAN
CAN
Canada
#59
12
Players
€60
Total pot
48
Teams still in

🏆 Leaderboard

🥇
1
1
ENG ENGPAN PANSUI SUISCO SCO
0pts
🥈
2
2
ESP ESPHAI HAICPV CPVQAT QAT
0pts
🥉
3
3
FRA FRASWE SWEIRN IRNTUR TUR
0pts
4
4
4
BRA BRA🇿🇦 RSAALG ALGIRQ IRQ
0pts
5
5
5
BEL BELSEN SEN🇦🇺 AUSECU ECU
0pts
6
6
6
POR PORPAR PARTUN TUNCZE CZE
0pts
7
7
7
NED NEDKSA KSAUSA USAURU URU
0pts
8
8
8
ARG ARGNZL NZLCIV CIVEGY EGY
0pts
9
9
9
GER GERCUW CUWJOR JORNOR NOR
0pts
10
1
10
COL COLKOR KORMEX MEXJPN JPN
0pts
11
1
11
CRO CROGHA GHAAUT AUTBIH BIH
0pts
12
1
12
MAR MARUZB UZBCOD CODCAN CAN
0pts
💰 PRIZE BREAKDOWN
🥇
1
1st place
€35
🥈
2
2nd place
€15
🥉
3
3rd place
€10

⛳ Update Results

If auto-sync is on, this updates automatically. You can also mark results manually.
Points: Group=1 • R32=2 • R16=4 • QF=6 • SF=9 • Runner-up=12 • Winner=20

FRA FRA France 3
ESP ESP Spain 2
ARG ARG Argentina 8
ENG ENG England 1
POR POR Portugal 6
BRA BRA Brazil 4
NED NED Netherlands 7
MAR MAR Morocco 12
BEL BEL Belgium 5
GER GER Germany 9
CRO CRO Croatia 11
COL COL Colombia 10
SEN SEN Senegal 5
MEX MEX Mexico 10
USA USA USA 7
URU URU Uruguay 7
JPN JPN Japan 10
SUI SUI Switzerland 1
KOR KOR South Korea 10
AUT AUT Austria 11
🇦🇺 AUS Australia 5
ECU ECU Ecuador 5
TUR TUR Turkey 3
ALG ALG Algeria 4
NOR NOR Norway 9
SWE SWE Sweden 3
IRN IRN Iran 3
SCO SCO Scotland 1
PAR PAR Paraguay 6
CZE CZE Czechia 6
GHA GHA Ghana 11
EGY EGY Egypt 8
KSA KSA Saudi Arabia 7
PAN PAN Panama 1
TUN TUN Tunisia 6
CAN CAN Canada 12
CIV CIV Ivory Coast 8
NZL NZL New Zealand 8
QAT QAT Qatar 2
BIH BIH Bosnia-Herz 11
IRQ IRQ Iraq 4
JOR JOR Jordan 9
COD COD DR Congo 12
🇿🇦 RSA South Africa 4
HAI HAI Haiti 2
UZB UZB Uzbekistan 12
CPV CPV Cape Verde 2
CUW CUW Curacao 9

📅 Match Schedule

All 104 matches • UK / BST times • 11 Jun – 19 Jul 2026 • = England or Scotland match

Thu 11 Jun Today
MEXMEX vs RSA🇿🇦
20:00 BST Mexico City Group A
KORKOR vs CZECZE
03:00† BST Guadalajara Group A
Fri 12 Jun Tomorrow
CANCAN vs BIHBIH
20:00 BST Toronto Group B
USAUSA vs PARPAR
02:00† BST Los Angeles Group D
Sat 13 Jun In 2 days
QATQAT vs SUISUI
20:00 BST San Francisco Group B
BRABRA vs MARMAR
23:00 BST New York/NJ Group C
HAIHAI vs SCOSCO
02:00† BST Boston Group C
🇦🇺AUS vs TURTUR
05:00† BST Vancouver Group D
Sun 14 Jun In 3 days
GERGER vs CUWCUW
19:00 BST Houston Group E
NEDNED vs JPNJPN
22:00 BST Dallas Group F
CIVCIV vs ECUECU
01:00† BST Philadelphia Group E
SWESWE vs TUNTUN
04:00† BST Monterrey Group F
Mon 15 Jun In 4 days
ESPESP vs CPVCPV
18:00 BST Atlanta Group H
BELBEL vs EGYEGY
21:00 BST Vancouver Group G
KSAKSA vs URUURU
00:00† BST Miami Group H
IRNIRN vs NZLNZL
05:00† BST Los Angeles Group G
Tue 16 Jun In 5 days
FRAFRA vs SENSEN
21:00 BST New York/NJ Group I
IRQIRQ vs NORNOR
00:00† BST Boston Group I
ARGARG vs ALGALG
03:00† BST Kansas City Group J
AUTAUT vs JORJOR
08:00† BST San Francisco Group J
Wed 17 Jun In 6 days
PORPOR vs CODCOD
19:00 BST Houston Group K
ENGENG vs CROCRO
22:00 BST Dallas Group L
GHAGHA vs PANPAN
01:00† BST Toronto Group L
UZBUZB vs COLCOL
04:00† BST Mexico City Group K
Thu 18 Jun In 7 days
CZECZE vs RSA🇿🇦
18:00 BST Atlanta Group A
SUISUI vs BIHBIH
21:00 BST Los Angeles Group B
CANCAN vs QATQAT
02:00† BST Vancouver Group B
MEXMEX vs KORKOR
04:00† BST Guadalajara Group A
Fri 19 Jun
🇿🇦RSA vs MARMAR
21:00 BST Boston Group C
USAUSA vs AUS🇦🇺
22:00 BST Seattle Group D
BRABRA vs HAIHAI
02:00† BST Philadelphia Group C
TURTUR vs PARPAR
04:00† BST San Francisco Group D
Sat 20 Jun
NEDNED vs SWESWE
19:00 BST Houston Group F
GERGER vs CIVCIV
22:00 BST Toronto Group E
ECUECU vs CUWCUW
02:00† BST Kansas City Group E
TUNTUN vs JPNJPN
06:00† BST Monterrey Group F
Sun 21 Jun
ESPESP vs KSAKSA
18:00 BST Atlanta Group H
BELBEL vs IRNIRN
21:00 BST Los Angeles Group G
URUURU vs CPVCPV
00:00† BST Miami Group H
NZLNZL vs EGYEGY
05:00† BST Vancouver Group G
Mon 22 Jun
ARGARG vs AUTAUT
19:00 BST Dallas Group J
FRAFRA vs IRQIRQ
23:00 BST Philadelphia Group I
NORNOR vs SENSEN
02:00† BST New York/NJ Group I
JORJOR vs ALGALG
07:00† BST San Francisco Group J
Tue 23 Jun
PORPOR vs UZBUZB
19:00 BST Houston Group K
ENGENG vs GHAGHA
22:00 BST Seattle Group L
CROCRO vs PANPAN
01:00† BST Toronto Group L
COLCOL vs CODCOD
05:00† BST Kansas City Group K
Wed 24 Jun
MEXMEX vs CZECZE
20:00 BST Mexico City Group A
KORKOR vs RSA🇿🇦
20:00 BST Guadalajara Group A
BIHBIH vs QATQAT
23:00 BST Toronto Group B
SUISUI vs CANCAN
23:00 BST Vancouver Group B
Thu 25 Jun
SCOSCO vs BRABRA
20:00 BST Philadelphia Group C
MARMAR vs HAIHAI
20:00 BST New York/NJ Group C
PARPAR vs AUS🇦🇺
23:00 BST Los Angeles Group D
TURTUR vs USAUSA
23:00 BST Seattle Group D
Fri 26 Jun
CUWCUW vs GERGER
20:00 BST Kansas City Group E
ECUECU vs CIVCIV
20:00 BST Philadelphia Group E
JPNJPN vs NEDNED
23:00 BST Dallas Group F
TUNTUN vs SWESWE
23:00 BST Monterrey Group F
Sat 27 Jun
EGYEGY vs BELBEL
20:00 BST Vancouver Group G
NZLNZL vs IRNIRN
20:00 BST Los Angeles Group G
CPVCPV vs ESPESP
23:00 BST Miami Group H
URUURU vs KSAKSA
23:00 BST Atlanta Group H
Sun 28 Jun
SENSEN vs FRAFRA
20:00 BST New York/NJ Group I
NORNOR vs IRQIRQ
20:00 BST Boston Group I
ALGALG vs ARGARG
23:00 BST Kansas City Group J
JORJOR vs AUTAUT
23:00 BST San Francisco Group J
Mon 29 Jun
CODCOD vs PORPOR
20:00 BST Houston Group K
COLCOL vs UZBUZB
20:00 BST Mexico City Group K
PANPAN vs ENGENG
23:00 BST Toronto Group L
GHAGHA vs CROCRO
23:00 BST Dallas Group L
Fri 3 Jul – Mon 7 Jul
Round of 32 (8 matches)
KNOCKOUT
Sat 5 Jul – Tue 8 Jul
Round of 16 (8 matches)
KNOCKOUT
Fri 10 Jul – Sun 12 Jul
Quarter-finals (4 matches)
KNOCKOUT
Wed 15 – Thu 16 Jul
Semi-finals
KNOCKOUT
Sun 18 Jul
3rd place play-off — Miami
23:00 BSTKNOCKOUT
Sun 19 Jul
🏆 FINAL — New York / New Jersey
20:00 BSTKNOCKOUT

💬 Share to WhatsApp

💾 Download

Save the app as a single HTML file. Share it with family — they open it in any browser.

🗣 Banter Board Live

Family chat — trash talk welcome. Messages are shared live across all devices.

1
1211 Jun 12:02
hello
1
1210 Jun 23:35
hello
1
1210 Jun 18:27
13
1
1210 Jun 16:12
1-2-3
N
Nina10 Jun 14:48
testing
1
1210 Jun 14:46
hello
N
Nina10 Jun 14:44
test
TU
Test User10 Jun 12:54
Hello from console
TU
Test User10 Jun 12:48
Hello from console
TU
Test User10 Jun 12:48
Hello from console
1
110 Jun 12:36
test
1
110 Jun 12:36
test
1
110 Jun 12:35
test
1
110 Jun 12:32
hi
1
110 Jun 12:31
hi
1
110 Jun 12:31
hi
N
Nina10 Jun 12:09
test
N
Nina10 Jun 10:36
test
N
Nina10 Jun 10:16
test

🏆 Route to the Final

Predict the knockout bracket — in R32 use the dropdowns to pick which team from each group advances, then tap a team to pick the match winner. They advance automatically all the way to the final.

Uses the 12 official WC 2026 groups

',inject+''); var blob=new Blob([html],{type:'text/html'}); var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download='wc2026-sweepstake.html';a.click(); } /* -- BOOT -- */ /* -- TODAY'S MATCHES BAR -- */ /* -- TIME HELPERS -- */ function bstToET(bstStr){ // bstStr like "20:00" or "02:00" (dagger already stripped by caller) var parts=bstStr.split(':'); if(parts.length<2)return ''; var h=parseInt(parts[0],10); var m=parts[1]; // NJ/NY is EDT = UTC-4, BST = UTC+1, so ET = BST - 5 var eth=((h-5)+24)%24; var ampm=eth<12?'am':'pm'; var h12=eth%12||12; return h12+':'+m+ampm+' ET'; } function renderTodayBar(){ var bar=document.getElementById('today-bar'); var label=document.getElementById('today-bar-label'); var feed=document.getElementById('today-matches'); if(!bar||!feed)return; var now=new Date(); var days=['Sun','Mon','Tue','Wed','Thu','Fri','Sat']; var months=['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']; var todayStr=days[now.getDay()]+' '+now.getDate()+' '+months[now.getMonth()]; var myTeamCodes=[]; if(state.drawn){ Object.values(state.assignments).forEach(function(teams){ teams.forEach(function(tn){ var t=TEAMS.find(function(x){return x.name===tn}); if(t)myTeamCodes.push(t.code); }); }); } // Find today's matches involving drawn teams var todayMatches=SCHEDULE.filter(function(m){ return m.d===todayStr&&m.t.length===2&&myTeamCodes.length&&m.t.some(function(c){return myTeamCodes.indexOf(c)>=0}); }); // Find next 2 upcoming matches (any) if no matches today for my teams var nextMatches=[]; if(!todayMatches.length){ // walk schedule to find first 2 future group matches var found=0; for(var i=0;i=0; var mine2=myTeamCodes.indexOf(m.t[1])>=0; var f1=flagCache[m.t[0]]?'':(t1.emoji||m.t[0]); var f2=flagCache[m.t[1]]?'':(t2.emoji||m.t[1]); var bstClean=m.uk.replace('\u2020',''); var etStr=bstToET(bstClean); return '
' +f1+' '+m.t[0]+'' +' vs ' +f2+' '+m.t[1]+'' +' '+m.uk+' BST / '+etStr+' • '+m.v+'' +'
'; }).join(''); } else { // Show "no matches today, next up" if(label)label.innerHTML='📅 NEXT UPCOMING MATCHES'; bar.style.background='linear-gradient(135deg,rgba(42,57,141,.15),rgba(2,15,42,.3))'; bar.style.borderBottomColor='rgba(42,57,141,.4)'; feed.innerHTML=nextMatches.map(function(m){ var t1=TEAMS.find(function(x){return x.code===m.t[0]})||{emoji:'',code:m.t[0]}; var t2=TEAMS.find(function(x){return x.code===m.t[1]})||{emoji:'',code:m.t[1]}; var f1=flagCache[m.t[0]]?'':(t1.emoji||m.t[0]); var f2=flagCache[m.t[1]]?'':(t2.emoji||m.t[1]); var bstClean=m.uk.replace('\u2020',''); var etStr=bstToET(bstClean); return '
' +''+m.d+' ' +f1+' '+m.t[0]+'' +' vs ' +f2+' '+m.t[1]+'' +' '+m.uk+' BST / '+etStr+' • '+m.v+'' +'
'; }).join(''); } } /* -- TEAM MODAL -- */ function openTeamModal(teamName){ var t=TEAMS.find(function(x){return x.name===teamName}); if(!t)return; var modal=document.getElementById('team-modal'); var inner=document.getElementById('team-modal-content'); if(!modal||!inner)return; // Find next matches for this team var upcoming=SCHEDULE.filter(function(m){ return m.t.indexOf(t.code)>=0&&m.uk; }).slice(0,3); var stage=state.teamStages[teamName]||'tbd'; var stageInfo=STAGES[stage]||{label:'Not played yet',pts:0}; // Find who owns this team var owner=Object.entries(state.assignments).find(function(e){return e[1].indexOf(teamName)>=0}); var flagHtml=flagCache[t.code] ?'' :(t.emoji?''+t.emoji+'':''); var matchRows=upcoming.length ?upcoming.map(function(m){ var opp=m.t[0]===t.code?m.t[1]:m.t[0]; var oppT=TEAMS.find(function(x){return x.code===opp})||{emoji:'',code:opp}; var oppFlag=flagCache[opp]?'':(oppT.emoji||opp); return '
' +''+m.uk+' BST / '+bstToET(m.uk.replace("\u2020",""))+'' +''+m.d+'' +'vs '+oppFlag+' '+opp+'' +''+m.v+'' +'
'; }).join('') :'

No upcoming group fixtures

'; inner.innerHTML= '
' +flagHtml +'
' +'
'+t.name+'
' +'
FIFA Rank #'+t.rank+(t.rank<=10?' • ★ Top 10':t.rank<=20?' • Top 20':'')+'
' +(owner?'
Drawn by '+owner[0]+'
':'') +'
' +'
' +'
' +'Current stage' +''+stageInfo.label+'' +'
' +'
UPCOMING FIXTURES
' +matchRows; modal.style.display='flex'; } function closeTeamModal(){ var modal=document.getElementById('team-modal'); if(modal)modal.style.display='none'; } /* -- LIVE MATCH INDICATOR -- */ function getLiveTeams(){ var now=new Date(); var days=['Sun','Mon','Tue','Wed','Thu','Fri','Sat']; var months=['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']; var todayStr=days[now.getDay()]+' '+now.getDate()+' '+months[now.getMonth()]; var liveSet={}; SCHEDULE.forEach(function(m){ if(m.d!==todayStr||!m.uk||!m.t.length)return; var timeStr=m.uk.replace('\u2020',''); var parts=timeStr.split(':'); if(parts.length<2)return; var h=parseInt(parts[0],10),mi=parseInt(parts[1],10); var kickoff=new Date(now); kickoff.setUTCHours(h-1,mi,0,0); var diff=(now-kickoff)/60000; if(diff>=0&&diff<=105)m.t.forEach(function(c){liveSet[c]=true;}); }); return liveSet; } /* -- BANTER BOARD (Firebase realtime) -- */ var replyToId=null; var _fbApp=null; var _fbDb=null; var _fbRef=null; var _fbMessages=[]; function initFirebase(){ if(_fbApp)return; // Dynamically load Firebase SDKs then connect function loadScript(src,cb){ var s=document.createElement('script'); s.src=src; s.onload=cb; s.onerror=function(){ document.getElementById('banter-status').textContent='Offline (CDN blocked)'; document.getElementById('banter-status').style.color='var(--gray)'; }; document.head.appendChild(s); } var appUrl='https://www.gstatic.com/firebasejs/9.23.0/firebase-app-compat.js'; var dbUrl='https://www.gstatic.com/firebasejs/9.23.0/firebase-database-compat.js'; loadScript(appUrl,function(){ loadScript(dbUrl,function(){ try{ var firebaseConfig={ apiKey:'AIzaSyBU6vWqHUbHSnIPdjcGpC3BlwzlwhL24jg', authDomain:'wc2026-sweepstake-dbd56.firebaseapp.com', databaseURL:'https://wc2026-sweepstake-dbd56-default-rtdb.europe-west1.firebasedatabase.app', projectId:'wc2026-sweepstake-dbd56', storageBucket:'wc2026-sweepstake-dbd56.firebasestorage.app', messagingSenderId:'11571340466', appId:'1:11571340466:web:ebfbf6f935ce22ea98d5ab' }; _fbApp=firebase.initializeApp(firebaseConfig); _fbDb=firebase.database(); _fbRef=_fbDb.ref('banter'); _fbRef.on('value',function(snapshot){ var data=snapshot.val(); _fbMessages=[]; if(data){ Object.keys(data).forEach(function(k){_fbMessages.push(data[k]);}); _fbMessages.sort(function(a,b){return a.id-b.id;}); } renderBanter(); updateBanterDot(); }); document.getElementById('banter-status').textContent='Live'; document.getElementById('banter-status').style.color='var(--wc-green)'; }catch(e){ console.warn('Firebase init failed:',e); document.getElementById('banter-status').textContent='Offline'; document.getElementById('banter-status').style.color='var(--gray)'; } }); }); } function updateBanterDot(){ var lastSeen=parseInt(localStorage.getItem('banter-last-seen')||'0',10); var hasNew=_fbMessages.some(function(m){return m.id>lastSeen;}); var dot=document.getElementById('banter-dot'); if(dot)dot.style.display=hasNew?'inline-block':'none'; } function setReply(id){ var msg=_fbMessages.find(function(m){return m.id===id;}); if(!msg)return; replyToId=id; var preview=document.getElementById('banter-reply-preview'); var previewText=document.getElementById('banter-reply-text'); if(preview&&previewText){ previewText.innerHTML=''+msg.name+': '+msg.text.slice(0,60)+(msg.text.length>60?'...':''); preview.style.display='flex'; } var ta=document.getElementById('banter-msg'); if(ta)ta.focus(); } function clearReply(){ replyToId=null; var preview=document.getElementById('banter-reply-preview'); if(preview)preview.style.display='none'; } function renderBanter(){ var sel=document.getElementById('banter-name'); if(sel){ var cur=sel.value; sel.innerHTML=state.players.length ?state.players.map(function(p){return '';}).join('') :''; } var lastSeen=parseInt(localStorage.getItem('banter-last-seen')||'0',10); var msgs=_fbMessages; var feed=document.getElementById('banter-feed'); if(!feed)return; if(!msgs.length){ feed.innerHTML='
No messages yet. Start the banter! 🗣
'; return; } feed.innerHTML=msgs.slice().reverse().map(function(m,i){ var pi=state.players.indexOf(m.name); var col=pi>=0?pc(pi):{bg:'#444'}; var initials=m.name.split(' ').map(function(w){return w[0];}).join('').toUpperCase().slice(0,2); var ts=new Date(m.ts).toLocaleTimeString('en-GB',{hour:'2-digit',minute:'2-digit'}); var dateStr=new Date(m.ts).toLocaleDateString('en-GB',{day:'numeric',month:'short'}); var isNew=m.id>lastSeen; var replyHtml=''; if(m.replyTo){ var orig=_fbMessages.find(function(x){return x.id===m.replyTo;}); if(orig){ var origPi=state.players.indexOf(orig.name); var origCol=origPi>=0?pc(origPi):{bg:'#444'}; replyHtml='
' +''+orig.name+' ' +''+orig.text.slice(0,60)+(orig.text.length>60?'...':'')+'' +'
'; } } return '
' +'
'+initials+'
' +'
' +replyHtml +'
' +''+m.name+'' +(isNew?'':'') +''+dateStr+' '+ts+'' +'' +'' +'
' +'
'+m.text+'
' +'
' +'
'; }).join(''); } function scrollToBanter(id){ var el=document.getElementById('banter-msg-'+id); if(el){el.scrollIntoView({behavior:'smooth',block:'center'});el.style.background='rgba(240,180,41,.1)';setTimeout(function(){el.style.background='';},1200);} } function markBanterRead(){ if(!_fbMessages.length)return; var maxId=Math.max.apply(null,_fbMessages.map(function(m){return m.id;})); localStorage.setItem('banter-last-seen',maxId); var dot=document.getElementById('banter-dot'); if(dot)dot.style.display='none'; } function postBanter(){ var name=document.getElementById('banter-name').value; var msg=document.getElementById('banter-msg').value.trim(); if(!name||!msg)return; if(!_fbRef){alert('Not connected to Firebase yet. Please wait a moment and try again.');return;} var entry={id:Date.now(),name:name,text:msg,ts:new Date().toISOString()}; if(replyToId)entry.replyTo=replyToId; _fbRef.push(entry); document.getElementById('banter-msg').value=''; clearReply(); markBanterRead(); } function deleteBanter(id){ if(!_fbRef)return; // Find the Firebase key for this message _fbRef.once('value',function(snapshot){ snapshot.forEach(function(child){ if(child.val().id===id){ child.ref.remove(); } }); }); } /* -- BRACKET PREDICTOR -- */ /* Bracket structure: 32 teams -> R32 (16 matches) -> R16 (8) -> QF (4) -> SF (2) -> Final (1) state.bracket = { rounds: [ [matchObj,...], ... ] // 5 rounds: r32, r16, qf, sf, final } matchObj = { t: [teamNameOrNull, teamNameOrNull], winner: teamNameOrNull } */ var BRACKET_ROUND_NAMES=['Round of 32','Round of 16','Quarter-finals','Semi-finals','Final']; function initBracket(){ if(!state.drawn)return; // WC 2026 official R32 matchup slots by group position // Format: [slot description, group codes for team options] // Each match: {label, groups} where groups are the pool of teams to pick from // Based on official FIFA WC2026 bracket: 12 group winners + 12 runners-up + 8 best 3rds // We simplify: show all teams from the relevant groups as options, user taps to pick var R32_SLOTS=[ // Match 1-16 based on official WC2026 bracket structure // Group winners vs best 3rds / runners-up {a:['A'],b:['B']}, // 1A v 2B {a:['C'],b:['D']}, // 1C v 2D {a:['E'],b:['F']}, // 1E v 2F {a:['G'],b:['H']}, // 1G v 2H {a:['I'],b:['J']}, // 1I v 2J {a:['K'],b:['L']}, // 1K v 2L {a:['B'],b:['A']}, // 1B v 2A {a:['D'],b:['C']}, // 1D v 2C {a:['F'],b:['E']}, // 1F v 2E {a:['H'],b:['G']}, // 1H v 2G {a:['J'],b:['I']}, // 1J v 2I {a:['L'],b:['K']}, // 1L v 2K // Last 4 matches involve 3rd-place qualifiers - use cross-group pools {a:['A','B'],b:['C','D']}, {a:['E','F'],b:['G','H']}, {a:['I','J'],b:['K','L']}, {a:['A','C','E'],b:['B','D','F']} ]; // Build a lookup: group letter -> drawn teams in that group var groupMap={}; var SCHEDULE_GROUPS={ A:['MEX','RSA','KOR','CZE'],B:['CAN','BIH','QAT','SUI'], C:['BRA','MAR','HAI','SCO'],D:['USA','PAR','AUS','TUR'], E:['GER','CUW','CIV','ECU'],F:['NED','JPN','SWE','TUN'], G:['BEL','EGY','IRN','NZL'],H:['ESP','CPV','KSA','URU'], I:['FRA','SEN','IRQ','NOR'],J:['ARG','ALG','AUT','JOR'], K:['POR','COD','UZB','COL'],L:['ENG','CRO','GHA','PAN'] }; var drawnCodes={}; Object.values(state.assignments).forEach(function(ts){ ts.forEach(function(tn){ var t=TEAMS.find(function(x){return x.name===tn;}); if(t)drawnCodes[t.code]=tn; }); }); Object.keys(SCHEDULE_GROUPS).forEach(function(g){ groupMap[g]=SCHEDULE_GROUPS[g].filter(function(c){return drawnCodes[c];}).map(function(c){return drawnCodes[c];}); }); var matches=R32_SLOTS.map(function(slot){ // pool for side a: all drawn teams from those groups var poolA=[],poolB=[]; slot.a.forEach(function(g){poolA=poolA.concat(groupMap[g]||[]);}); slot.b.forEach(function(g){poolB=poolB.concat(groupMap[g]||[]);}); // pick first from each pool as default slot (user can change by tapping) return {t:[poolA[0]||null,poolB[0]||null],poolA:poolA,poolB:poolB,winner:null}; }); var rounds=[matches]; for(var r=0;r<4;r++){ var prev=rounds[r]; var next=[]; for(var j=0;j=4)return; var m=state.bracket.rounds[round][match]; if(!m)return; // if the old team (being replaced) was the winner, clear their downstream too var oldTeam=m.t[slot]; if(oldTeam&&m.winner===oldTeam){ m.winner=null; var nextMatch=Math.floor(match/2); var nextSlot=match%2; clearDownstream(round+1,nextMatch,oldTeam,nextSlot); if(state.bracket.rounds[round+1][nextMatch]){ state.bracket.rounds[round+1][nextMatch].t[nextSlot]=null; } } } function resetBracket(){ if(!confirm('Reset bracket prediction?'))return; state.bracket=null; save(); renderBracket(); } function renderBracket(){ var el=document.getElementById('bracket-content'); var champCard=document.getElementById('bracket-champion-card'); if(!el)return; if(!state.drawn){el.innerHTML='
Do the draw first to unlock the bracket predictor.
';if(champCard)champCard.style.display='none';return;} if(!state.bracket||!state.bracket.rounds||!state.bracket.rounds[0]||!state.bracket.rounds[0].length){ el.innerHTML='

Uses the 12 official WC 2026 groups

'; if(champCard)champCard.style.display='none'; return; } var rounds=state.bracket.rounds; var html='
'; for(var r=0;r'; html+='
'; for(var m=0;m=0;}); var flagHtml=flagCache[ct.code]?'':(ct.emoji?''+ct.emoji+'':''); document.getElementById('bracket-champion-display').innerHTML= '
' +'
\uD83C\uDFC6
' +'
'+flagHtml+'
' +'
'+champ+'
' +(owner?'
Drawn by '+owner[0]+'
':'') +'
'; } else if(champCard){ champCard.style.display='none'; } } function renderBracketMatch(round,matchIdx,m){ var t0=m.t[0]; var t1=m.t[1]; var w=m.winner; function teamHtml(tn,slot){ var pool=slot===0?(m.poolA||[]):(m.poolB||[]); if(!tn&&!pool.length){ return '
TBD
'; } // If round 0 and pool has multiple options, show a mini-select if(round===0&&pool.length>1){ var selOpts=pool.map(function(ptn){ var pt=TEAMS.find(function(x){return x.name===ptn;})||{code:'???'}; return ''; }).join(''); var curT=tn?TEAMS.find(function(x){return x.name===tn;})||{code:'???',emoji:'',rank:99}:{code:'?',emoji:'',rank:99}; var flagHtml=tn&&flagCache[curT.code]?'': (tn&&curT.emoji?''+curT.emoji+'':''); return '
' +flagHtml +'' +(w===tn?'\u2714':'') +(tn?'':'') +'
'; } if(!tn){ return '
TBD
'; } var t=TEAMS.find(function(x){return x.name===tn;})||{code:'???',emoji:'',rank:99}; var isW=w===tn; var isL=w&&w!==tn; var flagHtml2=flagCache[t.code]?'':(t.emoji?''+t.emoji+'':''); var owner=Object.entries(state.assignments).find(function(e){return e[1].indexOf(tn)>=0;}); var ownerInitials=owner?owner[0].split(' ').map(function(w2){return w2[0];}).join('').toUpperCase().slice(0,2):''; var pi=owner?state.players.indexOf(owner[0]):-1; var ownerCol=pi>=0?pc(pi).bg:'#666'; return '
' +flagHtml2 +''+t.code+'' +(ownerInitials?''+ownerInitials+'':'') +(isW?'\u2714':'') +'
'; } return '
'+teamHtml(t0,0)+teamHtml(t1,1)+'
'; } function swapBracketSlot(round,match,slot,teamName){ if(!state.bracket)return; var m=state.bracket.rounds[round][match]; if(!m)return; m.t[slot]=teamName; if(m.winner&&m.winner!==m.t[0]&&m.winner!==m.t[1])m.winner=null; save();renderBracket(); } function shareBracket(){ if(!state.bracket)return; var rounds=state.bracket.rounds; var rnames=['R32','R16','QF','SF','Final']; var txt='\u26BD WC 2026 BRACKET PREDICTION \u26BD\n'; for(var r=0;rfetchResults()); } else { setSyncStatus('','No API key set \u2014 add one in Setup for live results'); }