geoquiz/index.html
joshii edfe198530
All checks were successful
Build geoquiz / build (push) Successful in 17s
Patch index.html to load config.js for local API
2026-03-15 21:34:17 +01:00

599 lines
34 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<script>
// Affiche le bouton uniquement sur iOS Safari hors standalone
(function() {
var isIOS = /iphone|ipad|ipod/i.test(navigator.userAgent);
var isSafari = /safari/i.test(navigator.userAgent) && !/crios|fxios/i.test(navigator.userAgent);
var isStandalone = navigator.standalone === true;
if (isIOS && isSafari && !isStandalone) {
var btn = document.getElementById('btn-ios-install');
if (btn) btn.style.display = 'inline-flex';
}
})();
function openIosInstallModal() {
var m = document.getElementById('ios-install-modal');
if (m) { m.style.display = 'flex'; applyTranslations(); }
}
function closeIosInstallModal() {
var m = document.getElementById('ios-install-modal');
if (m) m.style.display = 'none';
}
// Fermer en cliquant sur le fond
document.getElementById('ios-install-modal').addEventListener('click', function(e) {
if (e.target === this) closeIosInstallModal();
});
</script>
<html lang="fr">
<head>
<meta charset="UTF-8">
<!-- Google tag (gtag.js) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-220WPFE2DM"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag("js", new Date());
gtag("config", "G-220WPFE2DM");
</script>
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover, user-scalable=no, maximum-scale=1, minimum-scale=1">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="apple-mobile-web-app-title" content="LeGrandGeoQuiz">
<meta name="theme-color" content="#0d0f14">
<meta name="description" content="Le Grand GeoQuiz - Test your geography knowledge">
<meta property="og:title" content="LeGrandGeoQuiz">
<meta property="og:description" content="Test your geography knowledge with LeGrandGeoQuiz">
<meta property="og:image" content="/favicon.svg">
<title>LeGrandGeoQuiz</title>
<link rel="icon" type="image/svg+xml" href="favicon.svg">
<link rel="manifest" href="manifest.json">
<link rel="apple-touch-icon" href="favicon.svg">
<link href="https://fonts.googleapis.com/css2?family=Syne:wght@400;700;800&family=DM+Mono:wght@400;500&display=swap" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/twemoji@14.0.2/dist/twemoji.min.js" crossorigin="anonymous"></script>
<link rel="stylesheet" href="css/styles.css">
<script src="js/zoom-prevention.js"></script>
</head>
<body>
<div id="lang-switcher">
<button class="lang-btn" onclick="setLang('fr')">FR</button>
<button class="lang-btn" onclick="setLang('en')">EN</button>
<button class="lang-btn" onclick="setLang('ua')">UA</button>
<button class="lang-btn" onclick="setLang('de')">DE</button>
</div>
<div id="app">
<!-- SETUP -->
<div id="panel-setup" class="panel">
<div class="logo">◈ LeGrandGeoQuiz</div>
<h1>Geo<span class="highlight">Quiz</span></h1>
<p class="subtitle" data-i18n="subtitle"></p>
<div id="loader"><div class="dot-spin"></div>&nbsp;<span data-i18n="loading"></span></div>
<div id="setup-ready" class="hidden">
<ul class="rules">
<li><span class="ico">&#8594;</span><span data-i18n="rule1"></span></li>
<li><span class="ico">&#8594;</span><span data-i18n="rule2"></span></li>
<li><span class="ico">&#8594;</span><span data-i18n="rule3"></span></li>
<li><span class="ico">&#8594;</span><span data-i18n="rule4"></span></li>
<li><span class="ico">&#8594;</span><span data-i18n="rule5"></span></li>
</ul>
<div style="display:flex;flex-direction:column;gap:8px;margin-top:4px;">
<!-- Mode Daily ⚡ -->
<div style="border:1px solid rgba(245,200,66,0.4);border-radius:12px;padding:10px 12px;background:rgba(245,200,66,0.04);">
<button class="btn-daily" id="btn-daily" onclick="startDailyGame()">
🏆 <span data-i18n="btnDaily"></span>
<span class="daily-badge" id="daily-date-badge"></span>
</button>
<div class="daily-played-msg hidden" id="daily-played-msg" data-i18n="dailyAlreadyPlayed"></div>
<div class="daily-played-msg hidden" id="daily-offline-msg" data-i18n="dailyOffline"></div>
<div style="text-align:center;margin-top:6px;">
<button onclick="openLeaderboard()" style="background:none;border:none;color:#f5c842;font-family:'DM Mono',monospace;font-size:0.67em;cursor:pointer;opacity:0.8;text-decoration:underline;" data-i18n="dailyLeaderboardLink"></button>
</div>
</div>
<!-- Mode Normal -->
<div style="border:1px solid rgba(79,255,176,0.25);border-radius:12px;padding:10px 12px;background:rgba(79,255,176,0.04);">
<button class="btn-primary" style="display:block;width:100%;margin-top:0;" onclick="startGame('normal')" data-i18n="btnNormal"></button>
</div>
<!-- Mode Hardcore -->
<div style="border:1px solid rgba(255,61,90,0.25);border-radius:12px;padding:10px 12px;background:rgba(255,61,90,0.04);">
<button class="btn-hardcore" onclick="startGame('hardcore')" data-i18n="btnHardcore"></button>
</div>
<!-- Mode Reverse -->
<div style="border:1px solid rgba(245,200,66,0.3);border-radius:12px;padding:10px 12px;background:rgba(245,200,66,0.04);">
<button class="btn-reverse" onclick="startGame('reverse')" data-i18n="btnReverse"></button>
</div>
<!-- Mode Personnalisé + Seed -->
<div style="border:1px solid rgba(167,139,250,0.3);border-radius:12px;padding:10px 12px;background:rgba(167,139,250,0.04);">
<div style="margin-bottom:10px;">
<div style="font-family:'DM Mono',monospace;font-size:0.7em;color:var(--accent3);margin-bottom:6px;" data-i18n="seedLabel"></div>
<div style="display:flex;gap:8px;">
<input id="seed-input" type="text" data-i18n-placeholder="seedPlaceholder"
style="flex:1;padding:9px 12px;background:var(--surface2);border:1px solid rgba(167,139,250,0.3);border-radius:8px;color:var(--text);font-family:'DM Mono',monospace;font-size:0.75em;outline:none;">
<button style="margin-top:0;padding:9px 14px;font-size:0.8em;border-radius:8px;border:1px solid rgba(167,139,250,0.4);background:rgba(167,139,250,0.1);color:var(--accent3);font-family:'DM Mono',monospace;font-weight:700;cursor:pointer;" onclick="startWithSeedInput()" data-i18n="seedLoad"></button>
</div>
</div>
<button class="btn-custom" onclick="openCustomPanel()" data-i18n="btnCustom"></button>
</div>
</div>
<!-- GitHub link -->
<div style="margin-top:18px;text-align:center;">
<a href="https://github.com/mathieuviart/legrandgeoquiz" target="_blank" rel="noopener"
style="display:inline-flex;align-items:center;gap:7px;font-family:'DM Mono',monospace;font-size:0.68em;color:var(--muted);text-decoration:none;padding:6px 12px;border-radius:8px;border:1px solid var(--border);transition:all 0.15s;"
onmouseover="this.style.borderColor='var(--accent3)';this.style.color='var(--accent3)'"
onmouseout="this.style.borderColor='var(--border)';this.style.color='var(--muted)'">
<svg width="15" height="15" viewBox="0 0 24 24" fill="currentColor" style="flex-shrink:0">
<path d="M12 0C5.374 0 0 5.373 0 12c0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23A11.509 11.509 0 0112 5.803c1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576C20.566 21.797 24 17.3 24 12c0-6.627-5.373-12-12-12z"/>
</svg>
github.com/mathieuviart/legrandgeoquiz
</a>
<div style="margin-top:10px;text-align:center;">
<button id="btn-ios-install"
onclick="openIosInstallModal()"
style="display:none;background:none;border:1px solid rgba(245,200,66,0.35);border-radius:8px;padding:6px 14px;font-family:'DM Mono',monospace;font-size:0.68em;color:#f5c842;cursor:pointer;transition:all 0.15s;gap:6px;align-items:center;"
onmouseover="this.style.background='rgba(245,200,66,0.08)'"
onmouseout="this.style.background='none'">
📲 <span data-i18n="iosInstallBtn"></span>
</button>
</div>
<!-- Modal instructions iOS -->
<div id="ios-install-modal" style="display:none;position:fixed;inset:0;z-index:9000;background:rgba(0,0,0,0.7);backdrop-filter:blur(4px);align-items:flex-end;justify-content:center;">
<div style="width:100%;max-width:480px;background:var(--surface);border:1px solid rgba(245,200,66,0.4);border-radius:20px 20px 0 0;padding:24px 20px calc(env(safe-area-inset-bottom,0px) + 24px);position:relative;">
<button onclick="closeIosInstallModal()" style="position:absolute;top:14px;right:16px;background:none;border:none;color:var(--muted);font-size:1.3em;cursor:pointer;"></button>
<div style="font-family:'Syne',sans-serif;font-size:1em;font-weight:800;color:#f5c842;margin-bottom:16px;">📲 <span data-i18n="iosInstallTitle"></span></div>
<!-- Étape 1 -->
<div style="display:flex;align-items:flex-start;gap:12px;margin-bottom:14px;">
<div style="min-width:28px;height:28px;border-radius:50%;background:rgba(245,200,66,0.15);border:1px solid rgba(245,200,66,0.4);display:flex;align-items:center;justify-content:center;font-family:'DM Mono',monospace;font-size:0.75em;color:#f5c842;font-weight:700;">1</div>
<div style="font-family:'DM Mono',monospace;font-size:0.78em;color:var(--text);line-height:1.5;">
<span data-i18n="iosInstallStep1"></span><br>
<span style="font-size:1.8em;line-height:1.4;"></span>
</div>
</div>
<!-- Étape 2 -->
<div style="display:flex;align-items:flex-start;gap:12px;margin-bottom:20px;">
<div style="min-width:28px;height:28px;border-radius:50%;background:rgba(245,200,66,0.15);border:1px solid rgba(245,200,66,0.4);display:flex;align-items:center;justify-content:center;font-family:'DM Mono',monospace;font-size:0.75em;color:#f5c842;font-weight:700;">2</div>
<div style="font-family:'DM Mono',monospace;font-size:0.78em;color:var(--text);line-height:1.5;">
<span data-i18n="iosInstallStep2"></span><br>
<span style="color:#f5c842;font-weight:700;" data-i18n="iosInstallAdd"></span>
</div>
</div>
<div style="font-family:'DM Mono',monospace;font-size:0.68em;color:var(--muted);text-align:center;" data-i18n="iosInstallNote"></div>
</div>
</div>
</div>
</div>
</div>
<!-- CUSTOM SETTINGS -->
<div id="panel-custom" class="panel hidden">
<div class="logo">&#9672; LeGrandGeoQuiz</div>
<h1><span class="highlight" data-i18n="customTitle"></span></h1>
<div class="custom-section">
<span class="custom-label" data-i18n="customCountLabel"></span>
<div class="custom-value-display"><span id="custom-n-display">8</span> <span data-i18n="customCountUnit"></span></div>
<input type="range" class="custom-slider" id="custom-n-slider" min="2" max="16" value="8"
oninput="ribbonOnSliderChange(this.value)">
</div>
<div class="custom-section">
<span class="custom-label" data-i18n="customTimeLabel"></span>
<div class="time-slider-wrap">
<div class="time-slider-val" id="time-slider-val">20s</div>
<input type="range" class="custom-slider" id="time-slider"
min="0" max="7" value="4"
oninput="selectTimeSlider(this.value)">
<div class="time-slider-ticks">
<span>1s</span><span>5s</span><span>10s</span><span>15s</span>
<span class="active-tick">20s</span><span>30s</span><span>60s</span><span></span>
</div>
</div>
</div>
<div class="custom-section">
<span class="custom-label" data-i18n="customSubModeLabel"></span>
<div class="submode-pills">
<div class="submode-pill active-normal" id="submode-pill-normal" onclick="selectSubModePill('normal')">
<span class="sp-icon">🎯</span>
<span class="sp-label" data-i18n="btnNormal"></span>
</div>
<div class="submode-pill" id="submode-pill-hardcore" onclick="selectSubModePill('hardcore')">
<span class="sp-icon">💀</span>
<span class="sp-label" data-i18n="btnHardcore"></span>
</div>
<div class="submode-pill" id="submode-pill-reverse" onclick="selectSubModePill('reverse')">
<span class="sp-icon">🔄</span>
<span class="sp-label" data-i18n="btnReverse"></span>
</div>
</div>
</div>
<div class="custom-section">
<span class="custom-label">
<span data-i18n="customDraftLabel"></span>
<button class="draft-info-btn" onclick="toggleDraftInfo()" title="?">?</button>
</span>
<div class="draft-tooltip" id="draft-tooltip" data-i18n="customDraftInfo"></div>
<div class="draft-pills">
<div class="draft-pill active" id="draft-pill-auto" onclick="selectDraftPill('auto')">
<span class="dp-icon">🔀</span>
<span class="dp-label" data-i18n="draftAuto"></span>
</div>
<div class="draft-pill" id="draft-pill-cats" onclick="selectDraftPill('cats')">
<span class="dp-icon">📊</span>
<span class="dp-label" data-i18n="draftCats"></span>
</div>
<div class="draft-pill" id="draft-pill-countries" onclick="selectDraftPill('countries')">
<span class="dp-icon">🌍</span>
<span class="dp-label" data-i18n="draftCountries"></span>
</div>
</div>
</div>
<div style="display:flex;flex-direction:column;gap:10px;margin-top:4px;">
<!-- Country ribbon selector -->
<div class="ribbon-section">
<div class="ribbon-section-label">
<span data-i18n="ribbonCountriesTitle"></span>
<span class="ribbon-count" id="ribbon-incl-count">0 forcés</span>
</div>
<input type="text" class="ribbon-search" id="ribbon-search" data-i18n-placeholder="ribbonSearchCountry" oninput="ribbonFilter(this.value)">
<div class="ribbon-wrap">
<!-- EXCLUSION -->
<div class="ribbon-col">
<div class="ribbon-col-title excl" data-i18n="ribbonColExcl"></div>
<div class="ribbon-list excl" id="ribbon-excl" ondragover="ribbonDragOver(event)" ondrop="ribbonDrop(event,'excl')"></div>
</div>
<!-- Buttons Excl ↔ Poss -->
<div class="ribbon-btns" id="ribbon-btns-ep">
<button class="ribbon-btn danger" onclick="ribbonMove('excl','poss',false)" data-i18n-title="ribbonTitleToExcl"></button>
<button class="ribbon-btn danger" onclick="ribbonMove('excl','poss',true)" data-i18n-title="ribbonTitleAllToExcl">»</button>
<div class="ribbon-btn-sep"></div>
<button class="ribbon-btn" onclick="ribbonMove('poss','excl',false)" data-i18n-title="ribbonTitleExcl"></button>
<button class="ribbon-btn" onclick="ribbonMove('poss','excl',true)" data-i18n-title="ribbonTitleAllExcl">«</button>
</div>
<!-- POSSIBLE -->
<div class="ribbon-col">
<div class="ribbon-col-title poss" data-i18n="ribbonColPoss"></div>
<div class="ribbon-list poss" id="ribbon-poss" ondragover="ribbonDragOver(event)" ondrop="ribbonDrop(event,'poss')"></div>
</div>
<!-- Buttons Poss ↔ Incl -->
<div class="ribbon-btns" id="ribbon-btns-pi">
<button class="ribbon-btn success" onclick="ribbonMove('poss','incl',false)" data-i18n-title="ribbonTitleIncl"></button>
<div class="ribbon-btn-sep"></div>
<button class="ribbon-btn" onclick="ribbonMove('incl','poss',false)" data-i18n-title="ribbonTitleRemove"></button>
</div>
<!-- INCLUSION -->
<div class="ribbon-col">
<div class="ribbon-col-title incl" data-i18n="ribbonColIncl"></div>
<div class="ribbon-list incl" id="ribbon-incl" ondragover="ribbonDragOver(event)" ondrop="ribbonDrop(event,'incl')"></div>
</div>
</div>
<div class="ribbon-slots">
<span id="ribbon-slots-txt">0 / 8 slots forcés</span>
<div class="ribbon-slots-bar">
<div class="ribbon-slots-fill" id="ribbon-slots-fill" style="width:0%"></div>
</div>
</div>
</div>
<!-- Category ribbon selector -->
<div class="ribbon-section">
<div class="ribbon-section-label">
<span data-i18n="ribbonCatsTitle"></span>
<span class="ribbon-count" id="catribbon-incl-count">0 forcées</span>
</div>
<input type="text" class="ribbon-search" id="catribbon-search" data-i18n-placeholder="ribbonSearchCat" oninput="catRibbonFilter(this.value)">
<div class="ribbon-wrap">
<!-- EXCLUSION -->
<div class="ribbon-col">
<div class="ribbon-col-title excl" data-i18n="ribbonColExclCat"></div>
<div class="ribbon-list excl" id="catribbon-excl" ondragover="catRibbonDragOver(event)" ondrop="catRibbonDrop(event,'excl')"></div>
</div>
<!-- Buttons Excl ↔ Poss -->
<div class="ribbon-btns">
<button class="ribbon-btn danger" onclick="catRibbonMove('excl','poss',false)" data-i18n-title="ribbonTitleToExcl"></button>
<button class="ribbon-btn danger" onclick="catRibbonMove('excl','poss',true)" data-i18n-title="ribbonTitleAllToExcl">»</button>
<div class="ribbon-btn-sep"></div>
<button class="ribbon-btn" onclick="catRibbonMove('poss','excl',false)" data-i18n-title="ribbonTitleExcl"></button>
<button class="ribbon-btn" onclick="catRibbonMove('poss','excl',true)" data-i18n-title="ribbonTitleAllExcl">«</button>
</div>
<!-- POSSIBLE -->
<div class="ribbon-col">
<div class="ribbon-col-title poss" data-i18n="ribbonColPoss"></div>
<div class="ribbon-list poss" id="catribbon-poss" ondragover="catRibbonDragOver(event)" ondrop="catRibbonDrop(event,'poss')"></div>
</div>
<!-- Buttons Poss ↔ Incl -->
<div class="ribbon-btns">
<button class="ribbon-btn success" onclick="catRibbonMove('poss','incl',false)" data-i18n-title="ribbonTitleIncl"></button>
<div class="ribbon-btn-sep"></div>
<button class="ribbon-btn" onclick="catRibbonMove('incl','poss',false)" data-i18n-title="ribbonTitleRemove"></button>
</div>
<!-- INCLUSION -->
<div class="ribbon-col">
<div class="ribbon-col-title incl" data-i18n="ribbonColInclCat"></div>
<div class="ribbon-list incl" id="catribbon-incl" ondragover="catRibbonDragOver(event)" ondrop="catRibbonDrop(event,'incl')"></div>
</div>
</div>
<div class="ribbon-slots">
<span id="catribbon-slots-txt">0 / 8 slots forcés</span>
<div class="ribbon-slots-bar">
<div class="ribbon-slots-fill" id="catribbon-slots-fill" style="width:0%"></div>
</div>
</div>
</div>
<!-- Presets accordion -->
<div class="presets-section">
<button class="presets-toggle" id="presets-toggle" onclick="togglePresets()">
<span><span data-i18n="presetHeader"></span></span>
<span class="pt-arrow"></span>
</button>
<div class="presets-body" id="presets-body">
<div class="presets-grid">
<button class="preset-btn" onclick="applyPreset('no-russia',this)">
<span class="p-icon">🚫🇷🇺</span>
<span class="p-name" data-i18n="presetNoRussia"></span>
</button>
<button class="preset-btn" onclick="applyPreset('europe',this)">
<span class="p-icon">🇪🇺</span>
<span class="p-name" data-i18n="presetEuropean"></span>
</button>
<button class="preset-btn" onclick="applyPreset('africa',this)">
<span class="p-icon">🌍</span>
<span class="p-name" data-i18n="presetAfrican"></span>
</button>
<button class="preset-btn" onclick="applyPreset('americas',this)">
<span class="p-icon">🌎</span>
<span class="p-name" data-i18n="presetAmericas"></span>
</button>
<button class="preset-btn" onclick="applyPreset('asia',this)">
<span class="p-icon">🌏</span>
<span class="p-name" data-i18n="presetAsian"></span>
</button>
<button class="preset-btn" onclick="applyPreset('oceania',this)">
<span class="p-icon">🏝️</span>
<span class="p-name" data-i18n="presetOceanian"></span>
</button>
<button class="preset-btn" onclick="applyPreset('top100pib',this)">
<span class="p-icon">💰</span>
<span class="p-name" data-i18n="presetTop100PIB"></span>
</button>
<button class="preset-btn" onclick="applyPreset('sport',this)">
<span class="p-icon">🏆</span>
<span class="p-name" data-i18n="presetSport"></span>
</button>
<button class="preset-btn" onclick="applyPreset('chill',this)">
<span class="p-icon">😌</span>
<span class="p-name" data-i18n="presetChill"></span>
</button>
<button class="preset-btn" onclick="applyPreset('ultra',this)">
<span class="p-icon">💀🔥</span>
<span class="p-name" data-i18n="presetUltraHC"></span>
</button>
<button class="preset-btn" onclick="applyPreset('small',this)">
<span class="p-icon">🔬</span>
<span class="p-name" data-i18n="presetSmallPop"></span>
</button>
<button class="preset-btn" onclick="applyPreset('france-neighbors',this)">
<span class="p-icon">🇫🇷🤝</span>
<span class="p-name" data-i18n="presetNeighborsFR"></span>
</button>
<button class="preset-btn" onclick="applyPreset('landlocked',this)">
<span class="p-icon">🏔️</span>
<span class="p-name" data-i18n="presetLandlocked"></span>
</button>
<button class="preset-btn" onclick="applyPreset('islands',this)">
<span class="p-icon">🏝️</span>
<span class="p-name" data-i18n="presetIslands"></span>
</button>
<button class="preset-btn" onclick="applyPreset('flag-guesser',this)">
<span class="p-icon">🚩</span>
<span class="p-name" data-i18n="presetFlagGuesser"></span>
</button>
</div>
</div>
</div>
<button class="btn-custom" style="background:rgba(167,139,250,0.1);" onclick="startGame('custom')" data-i18n="customStart"></button>
<button class="btn-secondary" style="margin-top:0;" onclick="closeCustomPanel()" data-i18n="back"></button>
</div>
</div>
<!-- GAME -->
<div id="panel-game" class="panel hidden">
<div class="score-strip">
<div class="score-val"><span data-i18n="score"></span>&nbsp;:&nbsp;<span id="total-score">0</span></div>
<div class="turn-label" id="turn-label"></div>
</div>
<div id="game-seed-display" style="font-family:'DM Mono',monospace;font-size:0.65em;color:var(--muted);margin-bottom:10px;word-break:break-all;"></div>
<div class="timer-row">
<span class="timer-label" data-i18n="time"></span>
<span class="timer-num" id="timer-num">20</span>
<div class="progress-track"><div class="progress-fill" id="progress-fill"></div></div>
</div>
<div class="feedback" id="feedback"></div>
<!-- REVERSE MODE: active category display -->
<div id="reverse-cat-display">
<div class="reverse-cat-icon" id="reverse-cat-icon">?</div>
<div class="reverse-cat-name" id="reverse-cat-name"></div>
<div class="reverse-cat-info-row">
<span class="reverse-sort-btn" id="reverse-sort-btn" data-catid=""><span class="rsq">?</span></span>
<span class="reverse-info-toggle" onclick="toggleReverseCatInfo()" data-i18n="reverseInfoBtn"></span>
</div>
<div class="reverse-cat-tooltip" id="reverse-cat-tooltip"></div>
</div>
<!-- REVERSE MODE: country selection grid -->
<div id="countries-grid"></div>
<div class="country-block">
<div class="country-flag" id="country-flag">&#127757;</div>
<div class="country-info">
<div class="country-info-wrap">
<div class="country-name" id="country-name">---</div>
<button class="hint-btn hint-btn-1" id="hint-btn-1" onclick="revealHint1(event)">💡 <span data-i18n="hint1btn"></span></button>
<button class="hint-btn hint-btn-2" id="hint-btn-2" onclick="revealHint2(event)" style="display:none">🔍 <span data-i18n="hint2btn"></span></button>
</div>
<div class="turn-label" id="country-sub"></div>
</div>
</div>
<div id="hint-panel">
<span class="hint-label hint-label-1" id="hint-label-1"></span>
<div class="hint-line hint-line-1" id="hint-text-1"></div>
<div id="hint-block-2" style="display:none">
<span class="hint-label hint-label-2" id="hint-label-2"></span>
<div class="hint-line hint-line-2" id="hint-text-2"></div>
</div>
</div>
<div class="cats-grid" id="cats-grid"></div>
</div>
<!-- COUNTDOWN -->
<div id="countdown-overlay">
<div class="countdown-num" id="countdown-num">3</div>
<div class="countdown-sub" id="countdown-sub"></div>
</div>
<!-- REVEAL SCREEN -->
<div id="end-reveal-screen" style="display:none">
<div class="reveal-title-big" id="reveal-screen-title" data-i18n="revealTitle"></div>
<div class="reveal-rows" id="reveal-rows-container"></div>
<div class="reveal-running-score" id="reveal-running-score">0</div>
<div class="reveal-running-label" id="reveal-running-label" data-i18n="revealScoreLabel"></div>
</div>
<!-- END -->
<div id="panel-end" class="panel hidden">
<div class="logo" data-i18n="gameOver"></div>
<h1><span data-i18n="finalScore"></span><br><span class="highlight" data-i18n="final"></span></h1>
<div class="end-score" id="final-score">0</div>
<p class="end-tagline" id="end-tagline"></p>
<!-- Optimal score block -->
<div id="opt-block" style="margin:16px 0;background:var(--surface2);border:1px solid var(--border);border-radius:12px;padding:14px 16px;text-align:left;">
<div style="display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;gap:8px;">
<div>
<div style="font-family:'DM Mono',monospace;font-size:0.7em;color:var(--muted);letter-spacing:.08em;" data-i18n="optYours"></div>
<div style="font-size:1.6em;font-weight:800;color:var(--accent);" id="opt-your-score"></div>
</div>
<div style="font-size:1.4em;color:var(--muted);">vs</div>
<div style="text-align:right">
<div style="font-family:'DM Mono',monospace;font-size:0.7em;color:var(--muted);letter-spacing:.08em;" data-i18n="optBest"></div>
<div style="font-size:1.6em;font-weight:800;color:#4fc3f7;" id="opt-best-score"></div>
</div>
</div>
<div id="opt-diff-row" style="margin-top:8px;font-family:'DM Mono',monospace;font-size:0.78em;color:var(--muted);text-align:center;"></div>
<button id="opt-btn" class="btn-secondary" style="margin-top:12px;width:100%;font-size:0.82em;padding:10px;" onclick="showOptModal()" data-i18n="optBtn"></button>
</div>
<div class="seed-box" id="seed-display"></div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-bottom:16px;">
<button class="btn-secondary" style="margin:0;font-size:0.8em;" onclick="copySeed()" id="btn-copy-seed" data-i18n="copySeed"></button>
<button class="btn-secondary" style="margin:0;font-size:0.8em;border-color:rgba(79,255,176,0.4);color:var(--accent);" onclick="copyUrl()" id="btn-copy-url" data-i18n="copyUrl"></button>
</div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:8px;">
<button class="btn-secondary" style="margin:0;font-size:0.85em;" onclick="resetToMenu()" data-i18n="backToMenu"></button>
<button class="btn-primary" style="margin:0;font-size:0.85em;" onclick="replayGame()" data-i18n="playAgain"></button>
</div>
</div>
</div>
<!-- ── Daily leaderboard modal ─────────────────────────────────────────────── -->
<div id="daily-lb-overlay" onclick="if(event.target===this)closeLbModal()">
<div class="daily-modal-box">
<div class="daily-modal-title">🏆 <span data-i18n="dailyLbTitle"></span></div>
<div class="daily-modal-date" id="daily-lb-date"></div>
<div class="lb-header">
<span>#</span><span data-i18n="dailyLbColPlayer"></span><span style="text-align:right" data-i18n="dailyLbColScore"></span>
</div>
<div id="daily-lb-rows"><div class="lb-empty" data-i18n="dailyLbEmpty"></div></div>
<div class="lb-total" id="daily-lb-total"></div>
<button onclick="closeLbModal()" style="margin-top:16px;width:100%;padding:9px;background:var(--surface2);border:1px solid var(--border);border-radius:8px;color:var(--muted);font-family:'DM Mono',monospace;font-size:0.78em;cursor:pointer;" data-i18n="optClose"></button>
</div>
</div>
<!-- ── Daily submit score modal ─────────────────────────────────────────────── -->
<div id="daily-submit-overlay" onclick="if(event.target===this)skipDailySubmit()">
<div class="daily-modal-box">
<div class="daily-modal-title" style="margin-bottom:6px;">🏆 <span data-i18n="dailySubmitTitle"></span></div>
<div style="font-family:'DM Mono',monospace;font-size:0.73em;color:var(--muted);margin-bottom:14px;" data-i18n="dailySubmitDesc"></div>
<div style="font-family:'Syne',sans-serif;font-size:2.2em;font-weight:800;color:#f5c842;text-align:center;margin-bottom:16px;" id="daily-score-display"></div>
<input class="daily-pseudo-input" id="daily-pseudo-input" type="text" maxlength="20" data-i18n-placeholder="dailyPseudoPlaceholder"
onkeydown="if(event.key==='Enter')submitDailyScore()">
<button class="btn-daily-submit" onclick="submitDailyScore()" data-i18n="dailySubmitBtn"></button>
<div class="daily-submit-msg" id="daily-submit-msg"></div>
<button onclick="skipDailySubmit()" style="margin-top:8px;width:100%;padding:7px;background:none;border:none;color:var(--muted);font-family:'DM Mono',monospace;font-size:0.7em;cursor:pointer;text-decoration:underline;" data-i18n="dailySkip"></button>
</div>
</div>
<div id="country-tooltip"></div>
<!-- Optimal combo modal -->
<div id="opt-modal" style="display:none;position:fixed;inset:0;z-index:600;background:rgba(0,0,0,0.7);backdrop-filter:blur(4px);overflow-y:auto;padding:20px;">
<div style="max-width:480px;margin:auto;background:var(--surface);border:1px solid #4fc3f7;border-radius:16px;padding:24px;box-shadow:0 16px 48px rgba(0,0,0,0.6);">
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:16px;">
<div style="font-family:'Syne',sans-serif;font-size:1.1em;font-weight:800;color:#4fc3f7;" data-i18n="optTitle"></div>
<button onclick="hideOptModal()" style="background:none;border:none;color:var(--muted);font-size:1.4em;cursor:pointer;line-height:1;"></button>
</div>
<p id="opt-modal-explain" style="font-family:'DM Mono',monospace;font-size:0.75em;color:var(--muted);margin-bottom:16px;line-height:1.5;"></p>
<div id="opt-modal-rows"></div>
<div class="opt-footer">
<span class="opt-footer-label" data-i18n="optBest"></span>
<span class="opt-footer-opt" id="opt-modal-total"></span>
<span class="opt-footer-mine" id="opt-modal-mine"></span>
<span class="opt-footer-diff" id="opt-modal-diff-total"></span>
</div>
<button class="btn-secondary" style="margin-top:16px;width:100%;font-size:0.85em;" onclick="hideOptModal()" data-i18n="optClose"></button>
</div>
</div>
<div id="cat-tooltip">
<div class="tt-title" id="tt-title"></div>
<div class="tt-body" id="tt-body"></div>
</div>
<script src=config.js></script>
<script src="js/translations.js"></script>
<script src="js/data.js"></script>
<script src="js/utils.js"></script>
<script src="js/ui-effects.js"></script>
<script src="js/hints.js"></script>
<script src="js/ribbon.js"></script>
<script src="js/seed.js"></script>
<script src="js/setup.js"></script>
<script src="js/mobile.js"></script>
<script src="js/game.js"></script>
<script src="js/game-end.js"></script>
<script src="js/daily.js"></script>
<script>
// ─── BOOT ─────────────────────────────────────────────────────────────────────
setLang(currentLang);
initApp();
</script>
<script>
if ('serviceWorker' in navigator) {
window.addEventListener('load', function() {
navigator.serviceWorker.register('/legrandgeoquiz/sw.js').catch(function(err) {
console.warn('SW registration failed:', err);
});
});
}
</script>
</body>
</html>