!DOCTYPE html html lang=he dir=rtl head meta charset=UTF-8 meta name=viewport content=width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no titleקוויזראל חידוני מפות, דגלים וגיאוגרפיה בעבריתtitle !-- טעינת Tailwind CSS -- script src=httpscdn.tailwindcss.comscript !-- טעינת גופן Heebo -- link rel=preconnect href=httpsfonts.googleapis.com link rel=preconnect href=httpsfonts.gstatic.com crossorigin link href=httpsfonts.googleapis.comcss2family=Heebowght@400;500;700;800;900&display=swap rel=stylesheet !-- טעינת D3 ו-TopoJSON משרתים אמינים -- script src=httpscdn.jsdelivr.netnpmd3@7.8.5distd3.min.jsscript script src=httpscdn.jsdelivr.netnpmtopojson-client@3.1.0disttopojson-client.min.jsscript style body { font-family 'Heebo', sans-serif; background-color #f1f5f9; color #0f172a; overflow-x hidden; transition background-color 0.25s ease, color 0.25s ease; } מצב לילה (Dark Mode) body.dark-mode { background-color #090d16; color #f1f5f9; } body.dark-mode .bg-white { background-color #111827 !important; color #f1f5f9; } body.dark-mode .bg-slate-50 { background-color #1e293b !important; color #e2e8f0; } body.dark-mode .bg-slate-100 { background-color #1e293b !important; color #e2e8f0; } body.dark-mode .border-slate-200, body.dark-mode .border-slate-300, body.dark-mode .border-slate-100 { border-color #334155 !important; } body.dark-mode .text-slate-900, body.dark-mode .text-slate-800 { color #f8fafc !important; } body.dark-mode .text-slate-700, body.dark-mode .text-slate-600 { color #cbd5e1 !important; } body.dark-mode .text-slate-500 { color #94a3b8 !important; } body.dark-mode #map-wrapper { background-color #0c192c !important; border-color #1e293b !important; } body.dark-mode .neighbor-country { fill #1e293b !important; stroke #334155 !important; } body.dark-mode .ad-slot { background repeating-linear-gradient( -45deg, #111827, #111827 10px, #1e293b 10px, #1e293b 20px ); border-color #334155; color #94a3b8; } עיצוב מפת ה-SVG #map-container svg { width 100%; height 100%; display block; touch-action manipulation; } .neighbor-country { fill #cbd5e1; stroke #94a3b8; stroke-width 0.4px; pointer-events none; } .country-path { fill #2563eb; stroke #dbeafe; stroke-width 0.65px; transition fill 0.25s ease; cursor pointer; } .country-pathhover { fill #1d4ed8; } .country-path.guessed { fill #10b981 !important; stroke #064e3b !important; stroke-width 0.9px; } .country-path.missed { fill #f87171 !important; stroke #991b1b !important; stroke-width 0.9px; } .country-path.wrong-flash { fill #ef4444 !important; transition fill 0.12s ease; } .microstate-dot { fill #2563eb; stroke #ffffff; stroke-width 1.5px; transition all 0.25s ease; cursor pointer; } .microstate-dothover { fill #1d4ed8; } .microstate-dot.guessed { fill #10b981 !important; stroke #064e3b !important; } .microstate-dot.missed { fill #ef4444 !important; stroke #7f1d1d !important; } .microstate-dot.wrong-flash { fill #ef4444 !important; } מדינה שקיבלה רמז - אדומה קבועה (ללא הבהוב) .hint-active-country { fill #ef4444 !important; stroke #7f1d1d !important; stroke-width 1.5px !important; } .hint-letter-label { font-size 11px; font-weight 900; fill #ffffff; text-anchor middle; pointer-events none; user-select none; paint-order stroke; stroke #7f1d1d; stroke-width 3px; stroke-linecap round; stroke-linejoin round; } .country-label { font-size 8px; font-weight 800; fill #064e3b; text-anchor middle; pointer-events none; user-select none; paint-order stroke; stroke #ffffff; stroke-width 2.4px; stroke-linecap round; stroke-linejoin round; } .country-label.missed-label { fill #7f1d1d; } @keyframes pulseInput { 0% { box-shadow 0 0 0 0 rgba(16, 185, 129, 0.65); } 70% { box-shadow 0 0 0 10px rgba(16, 185, 129, 0); } 100% { box-shadow 0 0 0 0 rgba(16, 185, 129, 0); } } .input-success-flash { animation pulseInput 0.45s ease-out; border-color #10b981 !important; } .ad-slot { background repeating-linear-gradient( -45deg, #e2e8f0, #e2e8f0 10px, #f8fafc 10px, #f8fafc 20px ); border 1px dashed #94a3b8; color #64748b; display flex; flex-direction column; align-items center; justify-content center; text-align center; border-radius 0.75rem; overflow hidden; } style head body class=min-h-screen flex flex-col pb-16 mdpb-0 !-- סרגל ניווט עליון -- header class=bg-slate-900 text-white shadow-md sticky top-0 z-30 div class=max-w-7xl mx-auto px-4 py-3 flex items-center justify-between button onclick=showHomeView() class=flex items-center gap-3 text-right group focusoutline-none div class=w-10 h-10 rounded-xl bg-blue-600 group-hoverbg-blue-500 transition flex items-center justify-center font-black text-white text-xl shadow 🧭 div div h1 class=text-lg smtext-xl font-black tracking-tight text-whiteקוויזראלh1 p class=text-[11px] text-slate-400 hidden smblockחידוני מפות, דגלים וגיאוגרפיה בעבריתp div button nav class=flex items-center gap-1.5 smgap-2.5 text-xs smtext-sm font-medium text-slate-300 button id=btn-home-nav onclick=showHomeView() class=hidden bg-blue-60020 text-blue-300 hoverbg-blue-600 hovertext-white px-2.5 smpx-3 py-1.5 rounded-lg border border-blue-50030 transition font-bold 🏠 כל המפות button button id=btn-dark-mode onclick=toggleDarkMode() title=מצב לילה יום class=hovertext-white bg-slate-800 hoverbg-slate-700 px-2.5 py-1.5 rounded-lg transition flex items-center gap-1 border border-slate-700 span id=dark-mode-icon🌙span span class=hidden mdinline id=dark-mode-labelמצב לילהspan button button id=btn-mute onclick=toggleMute() title=השתק הפעל צלילים class=hovertext-white bg-slate-800 hoverbg-slate-700 px-2.5 py-1.5 rounded-lg transition flex items-center gap-1 border border-slate-700 span id=mute-icon🔊span span class=hidden mdinline id=mute-labelצליל פעילspan button button onclick=openInfoModal('rules') class=hovertext-white px-2 py-1 rounded-lg transition hidden sminlineאיך משחקיםbutton nav div header !-- באנר פרסומת עליון -- div class=max-w-7xl w-full mx-auto px-3 pt-3 div class=ad-slot w-full h-[56px] smh-[85px] mx-auto max-w-[728px] aria-label=אזור פרסומת עליון span class=text-[11px] font-bold uppercase tracking-wider text-slate-400פרסומת • Google AdSensespan span class=text-xs text-slate-500 hidden sminlineבאנר עליון (728x90)span div div !-- אזור תוכן מרכזי -- main class=flex-1 max-w-7xl w-full mx-auto px-3 py-4 grid grid-cols-1 lggrid-cols-12 gap-4 items-start !-- פרסומת צד ימין -- aside class=hidden lgflex lgcol-span-2 flex-col items-center sticky top-20 div class=ad-slot w-[160px] h-[600px] p-2 span class=text-[11px] font-bold text-slate-400פרסומתspan span class=text-xs mt-1באנר צדדיbr(160x600)span div aside !-- התוכן המשתנה דף הבית או מסך המשחק -- div class=lgcol-span-8 w-full !-- ================= דף הבית (בחירת מוד ומפה) ================= -- section id=home-view class=space-y-5 div class=bg-white rounded-3xl p-6 smp-8 shadow-sm border border-slate-200 text-center span class=inline-block bg-blue-100 text-blue-800 text-xs font-extrabold px-3 py-1 rounded-full mb-2ברוכים הבאים לקוויזראלspan h2 class=text-2xl smtext-4xl font-black text-slate-900 mb-2בחרו מצב משחק ומפהh2 p class=text-sm smtext-base text-slate-600 max-w-xl mx-auto mb-5 בחרו קודם את מצב המשחק הרצוי, ולאחר מכן לחצו על המפה כדי להתחיל ולשבור שיאים. p !-- שלב 1 בחירת מצב משחק בדף הבית -- div class=max-w-2xl mx-auto bg-slate-100 p-1.5 rounded-2xl border border-slate-200 grid grid-cols-3 gap-1.5 button onclick=setGameMode('type', false) id=home-mode-btn-type class=py-3 px-2 smpx-4 rounded-xl font-black text-xs smtext-base bg-slate-900 text-white shadow transition flex flex-col items-center justify-center gap-0.5 span class=flex items-center gap-1 smgap-1.5span⌨️spanspanהקלדהspanspan span class=text-[10px] smtext-[11px] font-medium opacity-80הקלידו שמותspan button button onclick=setGameMode('click', false) id=home-mode-btn-click class=py-3 px-2 smpx-4 rounded-xl font-black text-xs smtext-base text-slate-700 hoverbg-white70 transition flex flex-col items-center justify-center gap-0.5 span class=flex items-center gap-1 smgap-1.5span👆spanspanהצבעהspanspan span class=text-[10px] smtext-[11px] font-medium opacity-75מצאו במפהspan button button onclick=setGameMode('flags', false) id=home-mode-btn-flags class=py-3 px-2 smpx-4 rounded-xl font-black text-xs smtext-base text-slate-700 hoverbg-white70 transition flex flex-col items-center justify-center gap-0.5 span class=flex items-center gap-1 smgap-1.5span🚩spanspanדגליםspanspan span class=text-[10px] smtext-[11px] font-medium opacity-75זהו לפי דגלspan button div !-- כפתור שחק אחד על אחד -- div class=max-w-2xl mx-auto mt-3 button onclick=open1v1Modal() class=w-full bg-gradient-to-l from-purple-600 to-indigo-600 hoverfrom-purple-700 hoverto-indigo-700 text-white font-black text-sm smtext-base py-3 px-5 rounded-2xl shadow-md hovershadow-lg transition flex items-center justify-center gap-2 span class=text-xl⚔️span spanשחק אחד על אחד מול חבר (1v1)span button div div !-- רשת כרטיסי המפות -- div class=grid grid-cols-1 smgrid-cols-2 gap-4 id=maps-cards-container !-- כל העולם (עיצוב אחיד לחלוטין עם שאר המפות במצב יום ולילה) -- div onclick=selectMap('world') class=smcol-span-2 group bg-white rounded-2xl p-5 shadow-sm hovershadow-md border-2 border-slate-200 hoverborder-blue-500 transition cursor-pointer flex items-center justify-between div class=flex items-center gap-4 div class=w-14 h-14 rounded-2xl bg-blue-50 group-hoverbg-blue-600 group-hovertext-white text-blue-600 flex items-center justify-center text-3xl transition 🌐 div div div class=flex items-center gap-2 h3 class=text-lg smtext-xl font-black text-slate-900 group-hovertext-blue-600 transitionמפת כל העולםh3 span class=bg-blue-100 text-blue-800 text-[10px] font-black px-2 py-0.5 rounded-fullהאתגר הגדולspan div p class=text-xs text-slate-500 font-mediumכל 197 מדינות העולם בכל היבשותp div id=best-badge-world class=text-[11px] font-bold text-emerald-600 mt-1div div div span class=bg-slate-100 group-hoverbg-blue-600 group-hovertext-white text-slate-700 font-bold text-xs px-3.5 py-2 rounded-xl transitionשחק ←span div !-- אירופה -- div onclick=selectMap('europe') class=group bg-white rounded-2xl p-5 shadow-sm hovershadow-md border-2 border-slate-200 hoverborder-blue-500 transition cursor-pointer flex items-center justify-between div class=flex items-center gap-4 div class=w-14 h-14 rounded-2xl bg-blue-50 group-hoverbg-blue-600 group-hovertext-white text-blue-600 flex items-center justify-center text-3xl transition 🇪🇺 div div h3 class=text-lg font-black text-slate-900 group-hovertext-blue-600 transitionיבשת אירופהh3 p class=text-xs text-slate-500 font-medium46 מדינות כולל קוסובו ומיקרו-מדינותp div id=best-badge-europe class=text-[11px] font-bold text-emerald-600 mt-1div div div span class=bg-slate-100 group-hoverbg-blue-600 group-hovertext-white text-slate-700 font-bold text-xs px-3 py-2 rounded-xl transitionשחק ←span div !-- דרום אמריקה -- div onclick=selectMap('south_america') class=group bg-white rounded-2xl p-5 shadow-sm hovershadow-md border-2 border-slate-200 hoverborder-emerald-500 transition cursor-pointer flex items-center justify-between div class=flex items-center gap-4 div class=w-14 h-14 rounded-2xl bg-emerald-50 group-hoverbg-emerald-600 group-hovertext-white text-emerald-600 flex items-center justify-center text-3xl transition 🌎 div div h3 class=text-lg font-black text-slate-900 group-hovertext-emerald-600 transitionיבשת דרום אמריקהh3 p class=text-xs text-slate-500 font-medium12 מדינות עצמאיותp div id=best-badge-south_america class=text-[11px] font-bold text-emerald-600 mt-1div div div span class=bg-slate-100 group-hoverbg-emerald-600 group-hovertext-white text-slate-700 font-bold text-xs px-3 py-2 rounded-xl transitionשחק ←span div !-- אפריקה -- div onclick=selectMap('africa') class=group bg-white rounded-2xl p-5 shadow-sm hovershadow-md border-2 border-slate-200 hoverborder-amber-500 transition cursor-pointer flex items-center justify-between div class=flex items-center gap-4 div class=w-14 h-14 rounded-2xl bg-amber-50 group-hoverbg-amber-600 group-hovertext-white text-amber-600 flex items-center justify-center text-3xl transition 🌍 div div h3 class=text-lg font-black text-slate-900 group-hovertext-amber-600 transitionיבשת אפריקהh3 p class=text-xs text-slate-500 font-medium54 מדינות היבשתp div id=best-badge-africa class=text-[11px] font-bold text-emerald-600 mt-1div div div span class=bg-slate-100 group-hoverbg-amber-600 group-hovertext-white text-slate-700 font-bold text-xs px-3 py-2 rounded-xl transitionשחק ←span div !-- אסיה -- div onclick=selectMap('asia') class=group bg-white rounded-2xl p-5 shadow-sm hovershadow-md border-2 border-slate-200 hoverborder-rose-500 transition cursor-pointer flex items-center justify-between div class=flex items-center gap-4 div class=w-14 h-14 rounded-2xl bg-rose-50 group-hoverbg-rose-600 group-hovertext-white text-rose-600 flex items-center justify-center text-3xl transition 🌏 div div h3 class=text-lg font-black text-slate-900 group-hovertext-rose-600 transitionיבשת אסיהh3 p class=text-xs text-slate-500 font-medium48 מדינות אסיה והמזרח התיכוןp div id=best-badge-asia class=text-[11px] font-bold text-emerald-600 mt-1div div div span class=bg-slate-100 group-hoverbg-rose-600 group-hovertext-white text-slate-700 font-bold text-xs px-3 py-2 rounded-xl transitionשחק ←span div !-- המזרח התיכון -- div onclick=selectMap('middle_east') class=group bg-white rounded-2xl p-5 shadow-sm hovershadow-md border-2 border-slate-200 hoverborder-teal-500 transition cursor-pointer flex items-center justify-between div class=flex items-center gap-4 div class=w-14 h-14 rounded-2xl bg-teal-50 group-hoverbg-teal-600 group-hovertext-white text-teal-600 flex items-center justify-center text-3xl transition 🕌 div div h3 class=text-lg font-black text-slate-900 group-hovertext-teal-600 transitionהמזרח התיכוןh3 p class=text-xs text-slate-500 font-medium16 מדינות המזרח התיכוןp div id=best-badge-middle_east class=text-[11px] font-bold text-emerald-600 mt-1div div div span class=bg-slate-100 group-hoverbg-teal-600 group-hovertext-white text-slate-700 font-bold text-xs px-3 py-2 rounded-xl transitionשחק ←span div !-- ארצות הברית -- div onclick=selectMap('usa') class=group bg-white rounded-2xl p-5 shadow-sm hovershadow-md border-2 border-slate-200 hoverborder-indigo-500 transition cursor-pointer flex items-center justify-between div class=flex items-center gap-4 div class=w-14 h-14 rounded-2xl bg-indigo-50 group-hoverbg-indigo-600 group-hovertext-white text-indigo-600 flex items-center justify-center text-3xl transition 🇺🇸 div div h3 class=text-lg font-black text-slate-900 group-hovertext-indigo-600 transitionמפת ארצות הבריתh3 p class=text-xs text-slate-500 font-mediumזהו את כל 50 מדינות ארה״בp div id=best-badge-usa class=text-[11px] font-bold text-emerald-600 mt-1div div div span class=bg-slate-100 group-hoverbg-indigo-600 group-hovertext-white text-slate-700 font-bold text-xs px-3 py-2 rounded-xl transitionשחק ←span div div section !-- ================= מסך המשחק ================= -- section id=game-view class=hidden flex-col gap-3 !-- כותרת החידון + הגדרות זמן + כפתורי פעולה -- div class=bg-white rounded-2xl p-4 shadow-sm border border-slate-200 flex flex-col gap-3 div class=flex flex-col smflex-row smitems-center justify-between gap-2 div div class=flex flex-wrap items-center gap-2 mb-1 span id=game-category-badge class=inline-block bg-blue-100 text-blue-800 text-xs font-bold px-2.5 py-0.5 rounded-fullיבשתspan span id=game-1v1-badge class=hidden bg-purple-100 text-purple-800 text-xs font-extrabold px-2.5 py-0.5 rounded-full⚔️ מצב אחד על אחדspan span id=game-best-score-badge class=hidden bg-amber-100 text-amber-800 text-xs font-extrabold px-2.5 py-0.5 rounded-full🏆 שיא אישי -span div h2 id=game-title class=text-xl smtext-2xl font-black text-slate-800כותרת החידוןh2 div div class=flex flex-wrap items-center gap-2 self-start smself-center button onclick=showHomeView() class=px-3 py-2 rounded-xl text-xs smtext-sm font-bold bg-blue-50 text-blue-700 hoverbg-blue-100 border border-blue-200 transition 🏠 דף הבית button button id=btn-hint onclick=useHint() class=px-3 py-2 rounded-xl text-xs smtext-sm font-bold bg-amber-50 text-amber-700 hoverbg-amber-100 border border-amber-300 transition flex items-center gap-1 span💡 רמזspan span id=hints-used-badge class=text-[11px] opacity-80(0)span button button id=btn-restart onclick=resetGame() class=px-3 py-2 rounded-xl text-xs smtext-sm font-bold bg-slate-100 text-slate-700 hoverbg-slate-200 border border-slate-300 transition התחל מחדש button button id=btn-give-up onclick=confirmGiveUp() class=px-3 py-2 rounded-xl text-xs smtext-sm font-bold bg-rose-50 text-rose-600 hoverbg-rose-100 border border-rose-200 transition ויתור וחשיפה button div div !-- סרגל בחירת מצב משחק והגדרות זמן -- div class=bg-slate-50 rounded-xl p-2.5 border border-slate-200 flex flex-wrap items-center justify-between gap-2 text-xs !-- בחירת מצב משחק הקלדה, הצבעה או דגלים -- div class=flex items-center gap-1 bg-white p-1 rounded-xl border border-slate-300 button onclick=setGameMode('type', true) id=mode-btn-type class=px-2.5 py-1.5 rounded-lg font-extrabold bg-slate-900 text-white transition flex items-center gap-1 shadow-sm span⌨️span spanהקלדהspan button button onclick=setGameMode('click', true) id=mode-btn-click class=px-2.5 py-1.5 rounded-lg font-extrabold text-slate-600 hoverbg-slate-100 transition flex items-center gap-1 span👆span spanהצבעהspan button button onclick=setGameMode('flags', true) id=mode-btn-flags class=px-2.5 py-1.5 rounded-lg font-extrabold text-slate-600 hoverbg-slate-100 transition flex items-center gap-1 span🚩span spanדגליםspan button div !-- בחירת הגדרת זמן -- div class=flex flex-wrap items-center gap-1.5 id=timer-presets span class=font-bold text-slate-600 ml-1 hidden sminline⏱️ זמןspan button onclick=setTimerOption(180) data-seconds=180 class=timer-opt-btn px-2.5 py-1 rounded-lg font-bold border border-slate-300 bg-white text-slate-700 hoverbg-slate-100 transition3 דק׳button button onclick=setTimerOption(300) data-seconds=300 class=timer-opt-btn px-2.5 py-1 rounded-lg font-bold border border-slate-300 bg-white text-slate-700 hoverbg-slate-100 transition5 דק׳button button onclick=setTimerOption(600) data-seconds=600 class=timer-opt-btn px-2.5 py-1 rounded-lg font-bold border border-blue-600 bg-blue-600 text-white transition10 דק׳button button onclick=setTimerOption(900) data-seconds=900 class=timer-opt-btn px-2.5 py-1 rounded-lg font-bold border border-slate-300 bg-white text-slate-700 hoverbg-slate-100 transition15 דק׳button button onclick=setTimerOption(0) data-seconds=0 class=timer-opt-btn px-2.5 py-1 rounded-lg font-bold border border-slate-300 bg-white text-slate-700 hoverbg-slate-100 transitionללא זמן ∞button div div div !-- סרגל בקרה דביק (ניקוד + תיבת הקלדה יעד הצבעה + טיימר) -- div class=bg-slate-800 text-white rounded-2xl p-3 smp-4 shadow-lg sticky top-[62px] z-20 border border-slate-700 div class=flex items-center justify-between gap-2 smgap-4 !-- מונה מדינות -- div class=bg-slate-90090 border border-slate-700 rounded-xl px-3 py-2 text-center min-w-[78px] smmin-w-[96px] div class=text-[10px] text-slate-400 font-boldניחושיםdiv div class=text-base smtext-xl font-black text-emerald-400 tabular-nums id=score-display0 46div div !-- אזור מצב הקלדה -- div id=type-mode-container class=flex-1 relative input type=text id=country-input autocomplete=off autocorrect=off autocapitalize=off spellcheck=false placeholder=הקלידו שם מדינה בעברית... class=w-full bg-white text-slate-900 placeholder-slate-400 font-bold text-base smtext-lg px-4 py-2.5 smpy-3 rounded-xl border-2 border-transparent focusborder-emerald-400 focusoutline-none shadow-inner transition !-- תצוגת רמז תלוי במצב הקלדה -- div id=type-hint-banner class=hidden mt-1.5 text-xs smtext-sm font-black text-amber-300 tracking-widest text-center dir=rtldiv !-- חיווי ניחוש אחרון -- div id=last-guessed-badge class=hidden smflex items-center gap-1 absolute left-3 top-3 bg-emerald-100 text-emerald-800 text-xs font-bold px-2.5 py-1 rounded-lg pointer-events-none transition-opacity duration-300 opacity-0 span✓span span id=last-guessed-namespan div div !-- אזור מצב הצבעה על המפה (Click Mode) -- div id=click-mode-container class=hidden flex-1 bg-slate-90090 border-2 border-blue-50060 rounded-xl px-3 smpx-4 py-2 flex items-center justify-between gap-2 min-w-0 div class=flex flex-col text-right flex-1 min-w-0 span class=text-[10px] smtext-xs text-blue-300 font-boldלחצו על המפה איפה נמצאתspan div class=flex flex-wrap items-baseline gap-x-2 gap-y-0.5 span id=click-target-name class=text-base smtext-xl font-black text-white leading-snug break-wordsישראלspan span id=click-feedback-msg class=text-xs font-bold text-rose-400span div div button onclick=skipClickTarget() title=דלג למדינה הבאה class=shrink-0 bg-slate-700 hoverbg-slate-600 text-slate-200 text-xs font-bold px-2.5 smpx-3 py-2 rounded-lg border border-slate-600 transition דלג ⏭️ button div !-- אזור מצב דגלים (Flags Mode) -- div id=flags-mode-container class=hidden flex-1 bg-slate-90090 border-2 border-amber-50060 rounded-xl px-3 smpx-4 py-2 flex items-center justify-between gap-2 min-w-0 div class=flex items-center gap-3 text-right flex-1 min-w-0 img id=flag-target-img src= alt=דגל המדינה class=w-12 h-8 smw-16 smh-11 object-cover rounded-lg border border-slate-600 shadow bg-slate-800 shrink-0 div class=flex flex-col min-w-0 span class=text-[10px] smtext-xs text-amber-300 font-boldשל מי הדגל לחצו על המפהspan span id=flag-hint-banner class=hidden text-xs smtext-sm font-black text-amber-200 tracking-widestspan span id=flag-feedback-msg class=text-xs smtext-sm font-bold text-rose-400 min-h-[18px]span div div button onclick=skipClickTarget() title=דלג לדגל הבא class=shrink-0 bg-slate-700 hoverbg-slate-600 text-slate-200 text-xs font-bold px-2.5 smpx-3 py-2 rounded-lg border border-slate-600 transition דלג ⏭️ button div !-- שעון עצר -- div class=bg-slate-90090 border border-slate-700 rounded-xl px-3 py-2 text-center min-w-[78px] smmin-w-[96px] div id=timer-label class=text-[10px] text-slate-400 font-boldזמן נותרdiv div class=text-base smtext-xl font-black text-amber-400 tabular-nums id=timer-display1000div div div !-- פס התקדמות -- div class=w-full bg-slate-700 h-1.5 rounded-full mt-2.5 overflow-hidden div id=progress-bar class=bg-emerald-400 h-full transition-all duration-300 style=width 0%div div div !-- אזור המפה -- div class=bg-sky-10080 rounded-2xl border-2 border-slate-200 shadow-inner relative overflow-hidden aspect-[43] smaspect-[1611] flex items-center justify-center id=map-wrapper div id=map-loader class=flex flex-col items-center gap-2 text-slate-600 p-4 text-center div class=w-8 h-8 border-4 border-blue-600 border-t-transparent rounded-full animate-spindiv span class=text-sm font-boldטוען את המפה...span div div id=map-container class=w-full h-full hiddendiv !-- כפתורי זום -- div class=absolute bottom-3 left-3 flex flex-col gap-1.5 z-10 button onclick=zoomMap(1.3) title=הגדל מפה class=w-9 h-9 bg-white95 hoverbg-white text-slate-800 font-black rounded-xl shadow border border-slate-200 flex items-center justify-center text-lg+button button onclick=zoomMap(0.75) title=הקטן מפה class=w-9 h-9 bg-white95 hoverbg-white text-slate-800 font-black rounded-xl shadow border border-slate-200 flex items-center justify-center text-lg−button button onclick=resetZoom() title=איפוס תצוגה class=w-9 h-9 bg-white95 hoverbg-white text-slate-700 font-bold rounded-xl shadow border border-slate-200 flex items-center justify-center text-xsאיפוסbutton div !-- מקרא -- div class=absolute bottom-3 right-3 bg-white90 backdrop-blur-sm px-3 py-1.5 rounded-xl border border-slate-200 text-[11px] font-bold text-slate-600 flex items-center gap-3 shadow-sm span class=flex items-center gap-1span class=w-2.5 h-2.5 rounded-full bg-blue-600 inline-blockspan לא נוחשspan span class=flex items-center gap-1span class=w-2.5 h-2.5 rounded-full bg-emerald-500 inline-blockspan נוחשspan span class=flex items-center gap-1span class=w-2.5 h-2.5 rounded-full bg-red-500 inline-blockspan רמזspan div div !-- רשימת המדינות -- div class=bg-white rounded-2xl p-4 shadow-sm border border-slate-200 div class=flex items-center justify-between mb-3 h3 id=list-header-title class=font-extrabold text-slate-800 text-sm smtext-baseרשימת המדינותh3 span class=text-xs text-slate-500ממוין לפי סדר א'-ב'span div div id=countries-grid class=grid grid-cols-2 smgrid-cols-3 mdgrid-cols-4 gap-2 text-xs smtext-sm div div section div !-- פרסומת צד שמאל -- aside class=hidden lgflex lgcol-span-2 flex-col items-center sticky top-20 div class=ad-slot w-[160px] h-[600px] p-2 span class=text-[11px] font-bold text-slate-400פרסומתspan span class=text-xs mt-1באנר צדדיbr(160x600)span div aside main !-- באנר פרסומת תחתון במובייל -- div class=mdhidden fixed bottom-0 inset-x-0 z-30 bg-white95 backdrop-blur border-t border-slate-300 px-2 py-1 shadow-lg div class=ad-slot w-full h-[48px] span class=text-[10px] font-bold text-slate-400פרסומת מובייל צפה (320x50)span div div !-- פוטר -- footer class=bg-white border-t border-slate-200 mt-8 py-6 px-4 text-center text-xs text-slate-500 div class=max-w-4xl mx-auto flex flex-col smflex-row items-center justify-between gap-3 p© 2026 קוויזראל. כל הזכויות שמורות.p div class=flex items-center gap-4 font-medium button onclick=openInfoModal('about') class=hovertext-slate-800אודות האתרbutton button onclick=openInfoModal('privacy') class=hovertext-slate-800מדיניות פרטיותbutton button onclick=openInfoModal('rules') class=hovertext-slate-800חוקי המשחקbutton div div footer !-- חלונית אישור ויתור -- div id=giveup-modal class=fixed inset-0 bg-slate-90060 backdrop-blur-sm z-50 hidden items-center justify-center p-4 div class=bg-white rounded-2xl max-w-sm w-full p-6 shadow-2xl border border-slate-200 text-center div class=w-12 h-12 rounded-full bg-rose-100 text-rose-600 flex items-center justify-center mx-auto mb-3 text-2xl font-black!div h3 class=text-xl font-black text-slate-900 mb-2בטוחים שתרצו לוותרh3 p class=text-sm text-slate-600 mb-5המשחק ייעצר וכל המדינות שטרם ניחשתם ייחשפו על גבי המפה.p div class=flex gap-3 button onclick=executeGiveUp() class=flex-1 bg-rose-600 hoverbg-rose-700 text-white font-bold py-2.5 rounded-xl transitionכן, חשוף הכלbutton button onclick=closeGiveUpModal() class=flex-1 bg-slate-100 hoverbg-slate-200 text-slate-800 font-bold py-2.5 rounded-xl transitionהמשך לשחקbutton div div div !-- חלונית סיכום -- div id=summary-modal class=fixed inset-0 bg-slate-90070 backdrop-blur-sm z-50 hidden items-center justify-center p-4 div class=bg-white rounded-3xl max-w-md w-full p-6 smp-8 shadow-2xl border border-slate-200 text-center relative button onclick=closeSummaryModal() class=absolute top-4 left-4 w-8 h-8 rounded-full bg-slate-100 hoverbg-slate-200 text-slate-600 font-bold✕button div id=summary-emoji class=text-5xl mb-2🏆div h3 id=summary-title class=text-2xl font-black text-slate-900 mb-1כל הכבוד!h3 p id=summary-subtitle class=text-sm text-slate-500 mb-3השלמתם את האתגרp div id=summary-new-record class=hidden bg-amber-100 text-amber-800 text-xs font-black px-3 py-1.5 rounded-full mb-4 inline-block 🎉 שיא אישי חדש במפה זו! div div class=grid grid-cols-3 gap-2 bg-slate-50 p-4 rounded-2xl border border-slate-200 mb-5 div div class=text-xs text-slate-500 font-boldציוןdiv div id=summary-percent class=text-xl smtext-2xl font-black text-emerald-600100%div div div class=border-x border-slate-200 div class=text-xs text-slate-500 font-boldניחושיםdiv div id=summary-count class=text-xl smtext-2xl font-black text-slate-8004646div div div div class=text-xs text-slate-500 font-boldזמןdiv div id=summary-time class=text-xl smtext-2xl font-black text-amber-6000334div div div !-- כרטיס תוצאות 1v1 (מופיע במצב אחד על אחד) -- div id=summary-1v1-box class=hidden bg-purple-50 border border-purple-200 rounded-2xl p-4 mb-5 text-right div class=flex items-center justify-between mb-2 span class=text-xs font-black text-purple-800⚔️ דו-קרב 1v1span span id=summary-1v1-verdict class=text-xs font-black px-2.5 py-0.5 rounded-full bg-purple-200 text-purple-900ממתין ליריבspan div p id=summary-1v1-desc class=text-xs text-slate-700 mb-3שתפו את הקישור עם החבר כדי שיוכל לנסות לנצח את התוצאה שלכם!p div class=flex gap-2 button onclick=copy1v1ResultLink() class=flex-1 bg-purple-600 hoverbg-purple-700 text-white text-xs font-extrabold py-2.5 px-3 rounded-xl transition 📋 העתק קישור אתגר button button onclick=whatsapp1v1ResultLink() class=flex-1 bg-emerald-600 hoverbg-emerald-700 text-white text-xs font-extrabold py-2.5 px-3 rounded-xl transition 💬 שלח בוואטסאפ button div div div class=ad-slot w-full h-[90px] mb-5 span class=text-[10px] font-bold text-slate-400פרסומת • מסך סיוםspan div div class=flex flex-col smflex-row gap-2.5 button onclick=shareResults() class=flex-1 bg-emerald-600 hoverbg-emerald-700 text-white font-extrabold py-3 px-4 rounded-xl shadow transition flex items-center justify-center gap-2 spanשתפו תוצאהspan span📤span button button onclick=closeSummaryModal(); resetGame(); class=flex-1 bg-slate-800 hoverbg-slate-900 text-white font-extrabold py-3 px-4 rounded-xl shadow transition שחקו שוב 🔄 button div p id=share-feedback class=text-xs text-emerald-600 font-bold mt-2 h-4p div div !-- חלונית מידע -- div id=info-modal class=fixed inset-0 bg-slate-90060 backdrop-blur-sm z-50 hidden items-center justify-center p-4 div class=bg-white rounded-2xl max-w-lg w-full p-6 shadow-2xl border border-slate-200 text-right div class=flex items-center justify-between border-b border-slate-100 pb-3 mb-4 h3 id=info-modal-title class=text-lg font-black text-slate-900h3 button onclick=closeInfoModal() class=w-8 h-8 rounded-full bg-slate-100 hoverbg-slate-200 text-slate-600 font-bold✕button div div id=info-modal-body class=text-sm text-slate-600 space-y-3 leading-relaxed max-h-[60vh] overflow-y-autodiv div class=mt-5 text-left button onclick=closeInfoModal() class=bg-slate-800 text-white text-sm font-bold px-5 py-2 rounded-xlסגורbutton div div div !-- חלונית הקמת משחק אחד על אחד (1v1) -- div id=modal-1v1 class=fixed inset-0 bg-slate-90070 backdrop-blur-sm z-50 hidden items-center justify-center p-4 div class=bg-white rounded-3xl max-w-md w-full p-6 shadow-2xl border border-slate-200 text-right relative button onclick=close1v1Modal() class=absolute top-4 left-4 w-8 h-8 rounded-full bg-slate-100 hoverbg-slate-200 text-slate-600 font-bold✕button div class=flex items-center gap-2.5 mb-2 div class=w-10 h-10 rounded-xl bg-purple-100 text-purple-700 flex items-center justify-center text-xl font-black⚔️div div h3 class=text-xl font-black text-slate-900משחק אחד על אחדh3 p class=text-xs text-slate-500שתפו קישור זהה עם חבר ותתחרו על זמן וניקודp div div !-- שלב 1 הקישור להעתקה ושיתוף מיידי -- div class=bg-purple-50 border border-purple-200 rounded-2xl p-3.5 my-4 label class=block text-xs font-extrabold text-purple-900 mb-1.51. קישור ההזמנה לחבר (מתעדכן לפי הבחירה שלכם)label div class=flex items-center gap-1.5 mb-2.5 input type=text id=input-1v1-link readonly dir=ltr class=flex-1 bg-white text-slate-700 text-xs font-mono px-3 py-2 rounded-xl border border-purple-200 focusoutline-none button onclick=copy1v1InviteLink() class=shrink-0 bg-slate-900 hoverbg-slate-800 text-white text-xs font-extrabold px-3 py-2 rounded-xl transition 📋 Copy button div div class=flex gap-2 button onclick=share1v1WhatsApp() class=flex-1 bg-emerald-600 hoverbg-emerald-700 text-white text-xs font-extrabold py-2.5 px-3 rounded-xl shadow-sm transition flex items-center justify-center gap-1.5 span💬 שתף מיידית בוואטסאפspan button button onclick=nativeShare1v1() class=bg-white hoverbg-slate-50 text-slate-800 border border-slate-300 text-xs font-extrabold py-2.5 px-3 rounded-xl transition 📤 שתף button div p id=feedback-1v1-copy class=text-[11px] font-bold text-emerald-700 mt-1.5 h-4 text-centerp div !-- שלב 2 בחירת מוד, מפה וזמן -- div class=space-y-3 mb-5 div label class=block text-xs font-extrabold text-slate-700 mb-12. בחרו מוד משחקlabel div class=grid grid-cols-3 gap-1.5 bg-slate-100 p-1 rounded-xl border border-slate-200 button type=button onclick=set1v1Option('mode', 'type') data-1v1-mode=type class=opt-1v1-mode py-2 rounded-lg text-xs font-black bg-slate-900 text-white⌨️ הקלדהbutton button type=button onclick=set1v1Option('mode', 'click') data-1v1-mode=click class=opt-1v1-mode py-2 rounded-lg text-xs font-black text-slate-700👆 הצבעהbutton button type=button onclick=set1v1Option('mode', 'flags') data-1v1-mode=flags class=opt-1v1-mode py-2 rounded-lg text-xs font-black text-slate-700🚩 דגליםbutton div div div label class=block text-xs font-extrabold text-slate-700 mb-13. בחרו מפהlabel select id=select-1v1-map onchange=set1v1Option('map', this.value) class=w-full bg-slate-50 border border-slate-300 rounded-xl px-3 py-2.5 text-sm font-bold text-slate-800 focusoutline-none focusborder-purple-500 option value=europe🇪🇺 יבשת אירופה (46 מדינות)option option value=middle_east🕌 המזרח התיכון (16 מדינות)option option value=south_america🌎 יבשת דרום אמריקה (12 מדינות)option option value=africa🌍 יבשת אפריקה (54 מדינות)option option value=asia🌏 יבשת אסיה (48 מדינות)option option value=usa🇺🇸 מפת ארצות הברית (50 מדינות)option option value=world🌐 מפת כל העולם (197 מדינות)option select div div label class=block text-xs font-extrabold text-slate-700 mb-14. הגבלת זמןlabel div class=grid grid-cols-4 gap-1.5 button type=button onclick=set1v1Option('time', 180) data-1v1-time=180 class=opt-1v1-time py-1.5 rounded-lg text-xs font-bold border border-slate-300 bg-white text-slate-7003 דק׳button button type=button onclick=set1v1Option('time', 300) data-1v1-time=300 class=opt-1v1-time py-1.5 rounded-lg text-xs font-bold border border-purple-600 bg-purple-600 text-white5 דק׳button button type=button onclick=set1v1Option('time', 600) data-1v1-time=600 class=opt-1v1-time py-1.5 rounded-lg text-xs font-bold border border-slate-300 bg-white text-slate-70010 דק׳button button type=button onclick=set1v1Option('time', 0) data-1v1-time=0 class=opt-1v1-time py-1.5 rounded-lg text-xs font-bold border border-slate-300 bg-white text-slate-700ללא זמןbutton div div div button onclick=start1v1MatchAsHost() class=w-full bg-purple-600 hoverbg-purple-700 text-white font-black text-base py-3.5 rounded-2xl shadow-lg transition התחל את המשחק עכשיו ⚔️ button div div !-- חלונית קבלת הזמנה למשחק אחד על אחד (כשחבר נכנס לקישור) -- div id=modal-1v1-incoming class=fixed inset-0 bg-slate-90075 backdrop-blur-sm z-50 hidden items-center justify-center p-4 div class=bg-white rounded-3xl max-w-md w-full p-6 smp-7 shadow-2xl border-2 border-purple-500 text-center div class=w-14 h-14 rounded-2xl bg-purple-100 text-purple-700 flex items-center justify-center text-3xl mx-auto mb-3 font-black⚔️div span class=inline-block bg-purple-100 text-purple-800 text-xs font-black px-3 py-1 rounded-full mb-2הוזמנתם לדו-קרב 1v1!span h3 class=text-2xl font-black text-slate-900 mb-2מוכנים לאתגרh3 p id=incoming-1v1-details class=text-sm text-slate-600 mb-4 leading-relaxedp div id=incoming-1v1-opponent-score class=hidden bg-amber-50 border border-amber-200 rounded-xl p-3 mb-5 text-xs font-extrabold text-amber-900div div class=flex gap-2.5 button onclick=acceptIncoming1v1() class=flex-1 bg-purple-600 hoverbg-purple-700 text-white font-black py-3 rounded-xl shadow transition קבל אתגר והתחל! 🚀 button button onclick=declineIncoming1v1() class=bg-slate-100 hoverbg-slate-200 text-slate-700 font-bold px-4 py-3 rounded-xl transition ביטול button div div div script מאגרי נתונים והגדרות לכל 7 המפות באתר קוויזראל const MAPS_DATA = { europe { key europe, badge יבשת אירופה, title האם תצליחו לזהות את כל 46 מדינות אירופה, listTitle מדינות אירופה (46), defaultTime 600, atlasType world, projectionConfig { type azimuthal, rotate [-15, -53], scale 760, translateOffset [20, 30] }, items [ { id 008, name אלבניה, aliases [אלבניה], coords [20.1, 41.1] }, { id 020, name אנדורה, aliases [אנדורה], coords [1.55, 42.54], isMicro true }, { id 040, name אוסטריה, aliases [אוסטריה], coords [14.5, 47.5] }, { id 112, name בלארוס, aliases [בלארוס, בלרוס, רוסיה הלבנה], coords [27.9, 53.7] }, { id 056, name בלגיה, aliases [בלגיה], coords [4.4, 50.5] }, { id 070, name בוסניה והרצגובינה, aliases [בוסניה והרצגובינה, בוסניה, בוסניה הרצגובינה], coords [17.6, 43.9] }, { id 100, name בולגריה, aliases [בולגריה], coords [25.4, 42.7] }, { id 191, name קרואטיה, aliases [קרואטיה], coords [15.5, 45.1] }, { id 196, name קפריסין, aliases [קפריסין], coords [33.4, 35.1], isMicro true }, { id 203, name צ'כיה, aliases [צכיה, צ'כיה, הרפובליקה הצכית, הרפובליקה הצ'כית], coords [15.4, 49.8] }, { id 208, name דנמרק, aliases [דנמרק], coords [9.5, 56.2] }, { id 233, name אסטוניה, aliases [אסטוניה], coords [25.0, 58.6] }, { id 246, name פינלנד, aliases [פינלנד], coords [26.0, 62.5] }, { id 250, name צרפת, aliases [צרפת], coords [2.2, 46.6] }, { id 276, name גרמניה, aliases [גרמניה], coords [10.4, 51.1] }, { id 300, name יוון, aliases [יוון, יון], coords [21.8, 39.5] }, { id 348, name הונגריה, aliases [הונגריה], coords [19.5, 47.1] }, { id 352, name איסלנד, aliases [איסלנד], coords [-19.0, 64.9] }, { id 372, name אירלנד, aliases [אירלנד, הרפובליקה של אירלנד], coords [-8.2, 53.4] }, { id 380, name איטליה, aliases [איטליה], coords [12.5, 42.8] }, { id 383, name קוסובו, aliases [קוסובו], coords [20.9, 42.6], isMicro true }, { id 428, name לטביה, aliases [לטביה], coords [24.6, 56.8] }, { id 438, name ליכטנשטיין, aliases [ליכטנשטיין, ליכטנשטין], coords [9.55, 47.16], isMicro true }, { id 440, name ליטא, aliases [ליטא, ליטואניה], coords [23.8, 55.3] }, { id 442, name לוקסמבורג, aliases [לוקסמבורג, לוכסמבורג], coords [6.12, 49.81], isMicro true }, { id 470, name מלטה, aliases [מלטה], coords [14.45, 35.9], isMicro true }, { id 498, name מולדובה, aliases [מולדובה], coords [28.4, 47.2] }, { id 492, name מונקו, aliases [מונקו], coords [7.42, 43.73], isMicro true }, { id 499, name מונטנגרו, aliases [מונטנגרו], coords [19.3, 42.7] }, { id 528, name הולנד, aliases [הולנד, ארצות השפלה], coords [5.3, 52.2] }, { id 807, name צפון מקדוניה, aliases [צפון מקדוניה, מקדוניה, מקדוניה הצפונית], coords [21.7, 41.6] }, { id 578, name נורווגיה, aliases [נורווגיה, נורבגיה], coords [8.5, 61.5] }, { id 616, name פולין, aliases [פולין], coords [19.1, 52.0] }, { id 620, name פורטוגל, aliases [פורטוגל], coords [-8.2, 39.6] }, { id 642, name רומניה, aliases [רומניה], coords [25.0, 45.9] }, { id 643, name רוסיה, aliases [רוסיה], coords [38.0, 56.5] }, { id 674, name סן מרינו, aliases [סן מרינו], coords [12.45, 43.94], isMicro true }, { id 688, name סרביה, aliases [סרביה], coords [20.8, 44.2] }, { id 703, name סלובקיה, aliases [סלובקיה], coords [19.7, 48.7] }, { id 705, name סלובניה, aliases [סלובניה], coords [14.8, 46.1] }, { id 724, name ספרד, aliases [ספרד], coords [-3.7, 40.3] }, { id 752, name שוודיה, aliases [שוודיה, שבדיה], coords [15.5, 62.0] }, { id 756, name שווייץ, aliases [שווייץ, שוויץ, שוייץ], coords [8.2, 46.8] }, { id 804, name אוקראינה, aliases [אוקראינה], coords [31.2, 49.0] }, { id 826, name בריטניה, aliases [בריטניה, הממלכה המאוחדת, אנגליה], coords [-2.5, 54.0] }, { id 336, name הוותיקן, aliases [הוותיקן, ותיקן, קריית הוותיקן, הותיקן], coords [12.45, 41.90], isMicro true } ] }, south_america { key south_america, badge יבשת דרום אמריקה, title האם תצליחו לזהות את כל 12 מדינות דרום אמריקה, listTitle מדינות דרום אמריקה (12), defaultTime 300, atlasType world, projectionConfig { type mercator, center [-60, -23], scale 420, translateOffset [0, 0] }, items [ { id 032, name ארגנטינה, aliases [ארגנטינה], coords [-64.0, -34.0] }, { id 068, name בוליביה, aliases [בוליביה], coords [-64.5, -16.5] }, { id 076, name ברזיל, aliases [ברזיל], coords [-52.0, -10.0] }, { id 152, name צ'ילה, aliases [צ'ילה, צילה], coords [-71.0, -33.0] }, { id 170, name קולומביה, aliases [קולומביה], coords [-73.5, 4.0] }, { id 218, name אקוודור, aliases [אקוודור, אקוואדור], coords [-78.5, -1.5] }, { id 328, name גיאנה, aliases [גיאנה, גויאנה], coords [-59.0, 5.0] }, { id 600, name פרגוואי, aliases [פרגוואי, פרגוואיי], coords [-58.0, -23.5] }, { id 604, name פרו, aliases [פרו], coords [-75.5, -9.5] }, { id 740, name סורינאם, aliases [סורינאם, סורינם], coords [-56.0, 4.0] }, { id 858, name אורוגוואי, aliases [אורוגוואי, אורוגוואיי], coords [-56.0, -32.8] }, { id 862, name ונצואלה, aliases [ונצואלה], coords [-66.0, 7.0] } ] }, africa { key africa, badge יבשת אפריקה, title האם תצליחו לזהות את כל 54 מדינות אפריקה, listTitle מדינות אפריקה (54), defaultTime 600, atlasType world, projectionConfig { type mercator, center [18, 2], scale 380, translateOffset [0, 0] }, items [ { id 012, name אלג'יריה, aliases [אלג'יריה, אלגיריה], coords [2.5, 28.0] }, { id 024, name אנגולה, aliases [אנגולה], coords [17.5, -12.5] }, { id 204, name בנין, aliases [בנין], coords [2.3, 9.5] }, { id 072, name בוטסואנה, aliases [בוטסואנה, בוצוואנה], coords [24.0, -22.0] }, { id 854, name בורקינה פאסו, aliases [בורקינה פאסו, בורקינה פסו], coords [-1.5, 12.3] }, { id 108, name בורונדי, aliases [בורונדי], coords [29.9, -3.4] }, { id 132, name כף ורדה, aliases [כף ורדה, קייפ ורדה, קאבו ורדה], coords [-23.6, 15.1], isMicro true }, { id 120, name קמרון, aliases [קמרון], coords [12.5, 5.5] }, { id 140, name הרפובליקה המרכז-אפריקאית, aliases [הרפובליקה המרכז אפריקאית, מרכז אפריקה], coords [20.5, 6.6] }, { id 148, name צ'אד, aliases [צ'אד, צאד], coords [18.7, 15.4] }, { id 174, name קומורו, aliases [קומורו, איי קומורו], coords [43.3, -11.6], isMicro true }, { id 178, name הרפובליקה של קונגו, aliases [הרפובליקה של קונגו, קונגו, קונגו ברזוויל], coords [15.2, -0.8] }, { id 180, name הרפובליקה הדמוקרטית של קונגו, aliases [הרפובליקה הדמוקרטית של קונגו, קונגו הדמוקרטית, זאיר], coords [23.6, -2.8] }, { id 384, name חוף השנהב, aliases [חוף השנהב], coords [-5.5, 7.5] }, { id 262, name ג'יבוטי, aliases [ג'יבוטי, גיבוטי], coords [42.6, 11.8], isMicro true }, { id 818, name מצרים, aliases [מצרים], coords [30.0, 26.8] }, { id 226, name גינאה המשוונית, aliases [גינאה המשוונית, גיניאה המשוונית], coords [10.3, 1.6] }, { id 232, name אריתריאה, aliases [אריתריאה, אריתראה], coords [39.0, 15.2] }, { id 748, name אסוואטיני, aliases [אסוואטיני, סווזילנד, אסווטיני], coords [31.5, -26.5], isMicro true }, { id 231, name אתיופיה, aliases [אתיופיה], coords [39.5, 9.0] }, { id 266, name גבון, aliases [גבון], coords [11.8, -0.8] }, { id 270, name גמביה, aliases [גמביה], coords [-15.5, 13.4], isMicro true }, { id 288, name גאנה, aliases [גאנה, גנה], coords [-1.2, 7.9] }, { id 324, name גינאה, aliases [גינאה, גיניאה], coords [-10.8, 10.5] }, { id 624, name גינאה ביסאו, aliases [גינאה ביסאו, גיניאה ביסאו], coords [-15.0, 12.0] }, { id 404, name קניה, aliases [קניה], coords [37.9, 0.5] }, { id 426, name לסוטו, aliases [לסוטו], coords [28.2, -29.6], isMicro true }, { id 430, name ליבריה, aliases [ליבריה], coords [-9.4, 6.4] }, { id 434, name לוב, aliases [לוב], coords [17.2, 27.0] }, { id 450, name מדגסקר, aliases [מדגסקר], coords [46.8, -19.0] }, { id 454, name מלאווי, aliases [מלאווי, מלווי], coords [34.3, -13.2] }, { id 466, name מאלי, aliases [מאלי, מלי], coords [-3.5, 17.5] }, { id 478, name מאוריטניה, aliases [מאוריטניה, מוריטניה], coords [-10.5, 20.2] }, { id 480, name מאוריציוס, aliases [מאוריציוס, מוריציוס], coords [57.5, -20.2], isMicro true }, { id 504, name מרוקו, aliases [מרוקו], coords [-6.5, 31.8] }, { id 508, name מוזמביק, aliases [מוזמביק], coords [35.5, -18.5] }, { id 516, name נמיביה, aliases [נמיביה], coords [17.2, -22.5] }, { id 562, name ניז'ר, aliases [ניז'ר, ניזר], coords [8.5, 17.6] }, { id 566, name ניגריה, aliases [ניגריה], coords [8.0, 9.5] }, { id 646, name רואנדה, aliases [רואנדה], coords [29.9, -2.0] }, { id 678, name סאו טומה ופרינסיפה, aliases [סאו טומה ופרינסיפה, סאו טומה], coords [6.6, 0.2], isMicro true }, { id 686, name סנגל, aliases [סנגל], coords [-14.5, 14.5] }, { id 690, name סיישל, aliases [סיישל, איי סיישל], coords [55.4, -4.6], isMicro true }, { id 694, name סיירה לאון, aliases [סיירה לאון, סיירה ליאון], coords [-11.8, 8.5] }, { id 706, name סומליה, aliases [סומליה], coords [45.5, 5.5] }, { id 710, name דרום אפריקה, aliases [דרום אפריקה], coords [24.5, -29.0] }, { id 728, name דרום סודן, aliases [דרום סודן, דרום סודאן], coords [30.0, 7.5] }, { id 729, name סודן, aliases [סודן, סודאן], coords [30.0, 15.5] }, { id 834, name טנזניה, aliases [טנזניה], coords [34.8, -6.3] }, { id 768, name טוגו, aliases [טוגו], coords [1.0, 8.5] }, { id 788, name תוניסיה, aliases [תוניסיה, טוניסיה], coords [9.5, 34.0] }, { id 800, name אוגנדה, aliases [אוגנדה], coords [32.3, 1.3] }, { id 894, name זמביה, aliases [זמביה], coords [27.8, -13.5] }, { id 716, name זימבבואה, aliases [זימבבואה, זימבבווה], coords [29.8, -19.0] } ] }, asia { key asia, badge יבשת אסיה, title האם תצליחו לזהות את כל 48 מדינות אסיה, listTitle מדינות אסיה (48), defaultTime 600, atlasType world, projectionConfig { type mercator, center [88, 28], scale 340, translateOffset [0, 0] }, items [ { id 004, name אפגניסטן, aliases [אפגניסטן], coords [66.0, 33.9] }, { id 051, name ארמניה, aliases [ארמניה], coords [45.0, 40.1], isMicro true }, { id 031, name אזרבייג'ן, aliases [אזרבייג'ן, אזרביגן], coords [47.5, 40.3] }, { id 048, name בחריין, aliases [בחריין, בחרין], coords [50.55, 26.06], isMicro true }, { id 050, name בנגלדש, aliases [בנגלדש], coords [90.3, 23.7] }, { id 064, name בהוטן, aliases [בהוטן, בוטן], coords [90.4, 27.5] }, { id 096, name ברוניי, aliases [ברוניי, ברוני], coords [114.7, 4.5], isMicro true }, { id 116, name קמבודיה, aliases [קמבודיה], coords [104.9, 12.5] }, { id 156, name סין, aliases [סין, הרפובליקה העממית של סין], coords [103.0, 35.0] }, { id 268, name גאורגיה, aliases [גאורגיה, גרוזיה], coords [43.5, 42.1] }, { id 356, name הודו, aliases [הודו], coords [78.9, 22.0] }, { id 360, name אינדונזיה, aliases [אינדונזיה], coords [113.9, -2.0] }, { id 364, name איראן, aliases [איראן, אירן], coords [53.6, 32.4] }, { id 368, name עיראק, aliases [עיראק, עירק], coords [43.6, 33.2] }, { id 376, name ישראל, aliases [ישראל, מדינת ישראל], coords [35.0, 31.5], isMicro true }, { id 392, name יפן, aliases [יפן], coords [138.2, 36.2] }, { id 400, name ירדן, aliases [ירדן], coords [36.5, 31.2] }, { id 398, name קזחסטן, aliases [קזחסטן], coords [66.9, 48.0] }, { id 414, name כווית, aliases [כווית, כוויית], coords [47.5, 29.3], isMicro true }, { id 417, name קירגיזסטן, aliases [קירגיזסטן], coords [74.7, 41.2] }, { id 418, name לאוס, aliases [לאוס], coords [102.5, 19.8] }, { id 422, name לבנון, aliases [לבנון], coords [35.8, 33.8], isMicro true }, { id 458, name מלזיה, aliases [מלזיה], coords [102.0, 4.2] }, { id 462, name האיים המלדיביים, aliases [האיים המלדיביים, מלדיביים, המלדיביים], coords [73.5, 3.2], isMicro true }, { id 496, name מונגוליה, aliases [מונגוליה], coords [103.8, 46.8] }, { id 104, name מיאנמר, aliases [מיאנמר, בורמה], coords [96.0, 21.0] }, { id 524, name נפאל, aliases [נפאל], coords [84.1, 28.3] }, { id 408, name קוריאה הצפונית, aliases [קוריאה הצפונית, צפון קוריאה], coords [127.5, 40.3] }, { id 512, name עומאן, aliases [עומאן, עומן], coords [56.0, 21.0] }, { id 586, name פקיסטן, aliases [פקיסטן], coords [69.3, 30.3] }, { id 275, name הרשות הפלסטינית, aliases [הרשות הפלסטינית, פלסטין], coords [35.2, 31.9], isMicro true }, { id 608, name הפיליפינים, aliases [הפיליפינים, פיליפינים], coords [121.7, 12.8] }, { id 634, name קטר, aliases [קטר, קטאר], coords [51.2, 25.3], isMicro true }, { id 682, name ערב הסעודית, aliases [ערב הסעודית, סעודיה], coords [45.0, 23.8] }, { id 702, name סינגפור, aliases [סינגפור], coords [103.8, 1.35], isMicro true }, { id 410, name קוריאה הדרומית, aliases [קוריאה הדרומית, דרום קוריאה], coords [127.7, 36.5] }, { id 144, name סרי לנקה, aliases [סרי לנקה], coords [80.7, 7.8] }, { id 760, name סוריה, aliases [סוריה], coords [38.9, 34.8] }, { id 158, name טאיוואן, aliases [טאיוואן, טייוואן, טיוואן], coords [121.0, 23.7] }, { id 762, name טג'יקיסטן, aliases [טג'יקיסטן, טגיקיסטן], coords [71.2, 38.8] }, { id 764, name תאילנד, aliases [תאילנד], coords [100.9, 15.8] }, { id 626, name מזרח טימור, aliases [מזרח טימור, טימור המזרחית], coords [125.7, -8.8], isMicro true }, { id 792, name טורקיה, aliases [טורקיה, תורכיה], coords [35.2, 39.0] }, { id 795, name טורקמניסטן, aliases [טורקמניסטן], coords [59.5, 38.9] }, { id 784, name איחוד האמירויות הערביות, aliases [איחוד האמירויות הערביות, איחוד האמירויות, האמירויות], coords [54.0, 23.8] }, { id 860, name אוזבקיסטן, aliases [אוזבקיסטן], coords [64.5, 41.3] }, { id 704, name וייטנאם, aliases [וייטנאם, ויאטנם, ויטנאם], coords [108.2, 14.0] }, { id 887, name תימן, aliases [תימן], coords [48.5, 15.5] } ] }, middle_east { key middle_east, badge המזרח התיכון, title האם תצליחו לזהות את כל 16 מדינות המזרח התיכון, listTitle מדינות המזרח התיכון (16), defaultTime 300, atlasType world, projectionConfig { type mercator, center [44, 27], scale 880, translateOffset [0, 0] }, items [ { id 048, name בחריין, aliases [בחריין, בחרין], coords [50.55, 26.06], isMicro true }, { id 818, name מצרים, aliases [מצרים], coords [30.0, 26.8] }, { id 364, name איראן, aliases [איראן, אירן], coords [53.6, 32.4] }, { id 368, name עיראק, aliases [עיראק, עירק], coords [43.6, 33.2] }, { id 376, name ישראל, aliases [ישראל, מדינת ישראל], coords [35.0, 31.5], isMicro true }, { id 400, name ירדן, aliases [ירדן], coords [36.5, 31.2] }, { id 414, name כווית, aliases [כווית, כוויית], coords [47.5, 29.3], isMicro true }, { id 422, name לבנון, aliases [לבנון], coords [35.8, 33.8], isMicro true }, { id 512, name עומאן, aliases [עומאן, עומן], coords [56.0, 21.0] }, { id 275, name הרשות הפלסטינית, aliases [הרשות הפלסטינית, פלסטין], coords [35.2, 31.9], isMicro true }, { id 634, name קטר, aliases [קטר, קטאר], coords [51.2, 25.3], isMicro true }, { id 682, name ערב הסעודית, aliases [ערב הסעודית, סעודיה], coords [45.0, 23.8] }, { id 760, name סוריה, aliases [סוריה], coords [38.9, 34.8] }, { id 792, name טורקיה, aliases [טורקיה, תורכיה], coords [35.2, 39.0] }, { id 784, name איחוד האמירויות הערביות, aliases [איחוד האמירויות הערביות, איחוד האמירויות, האמירויות], coords [54.0, 23.8] }, { id 887, name תימן, aliases [תימן], coords [48.5, 15.5] } ] }, usa { key usa, badge ארצות הברית, title האם תצליחו לזהות את כל 50 מדינות ארצות הברית, listTitle מדינות ארה״ב (50), defaultTime 600, atlasType usa, projectionConfig { type albersUsa, scale 950, translateOffset [0, 0] }, items [ { id 01, name אלבמה, aliases [אלבמה], coords [-86.8, 32.8] }, { id 02, name אלסקה, aliases [אלסקה], coords [-152.0, 64.0] }, { id 04, name אריזונה, aliases [אריזונה], coords [-111.7, 34.3] }, { id 05, name ארקנסו, aliases [ארקנסו], coords [-92.4, 34.9] }, { id 06, name קליפורניה, aliases [קליפורניה], coords [-119.5, 37.2] }, { id 08, name קולורדו, aliases [קולורדו], coords [-105.5, 39.0] }, { id 09, name קונטיקט, aliases [קונטיקט], coords [-72.7, 41.6], isMicro true }, { id 10, name דלאוור, aliases [דלאוור, דלוור], coords [-75.5, 39.0], isMicro true }, { id 12, name פלורידה, aliases [פלורידה], coords [-81.6, 28.5] }, { id 13, name ג'ורג'יה, aliases [ג'ורג'יה, גורגיה], coords [-83.4, 32.6] }, { id 15, name הוואי, aliases [הוואי, הוואיי], coords [-157.5, 20.5] }, { id 16, name איידהו, aliases [איידהו, אידהו], coords [-114.5, 44.3] }, { id 17, name אילינוי, aliases [אילינוי, אילינויס], coords [-89.2, 40.0] }, { id 18, name אינדיאנה, aliases [אינדיאנה], coords [-86.3, 39.9] }, { id 19, name איווה, aliases [איווה, איובה], coords [-93.5, 42.0] }, { id 20, name קנזס, aliases [קנזס], coords [-98.3, 38.5] }, { id 21, name קנטקי, aliases [קנטקי, קנטאקי], coords [-85.3, 37.5] }, { id 22, name לואיזיאנה, aliases [לואיזיאנה], coords [-92.0, 31.0] }, { id 23, name מיין, aliases [מיין], coords [-69.2, 45.3] }, { id 24, name מרילנד, aliases [מרילנד], coords [-76.8, 39.0] }, { id 25, name מסצ'וסטס, aliases [מסצ'וסטס, מסצוסטס], coords [-71.8, 42.3] }, { id 26, name מישיגן, aliases [מישיגן], coords [-84.6, 43.5] }, { id 27, name מינסוטה, aliases [מינסוטה], coords [-94.3, 46.2] }, { id 28, name מיסיסיפי, aliases [מיסיסיפי], coords [-89.7, 32.7] }, { id 29, name מיזורי, aliases [מיזורי], coords [-92.5, 38.4] }, { id 30, name מונטנה, aliases [מונטנה], coords [-109.6, 47.0] }, { id 31, name נברסקה, aliases [נברסקה], coords [-99.8, 41.5] }, { id 32, name נבדה, aliases [נבדה, נוודה], coords [-116.6, 39.3] }, { id 33, name ניו המפשייר, aliases [ניו המפשייר, ניו המפשיר], coords [-71.5, 43.7] }, { id 34, name ניו ג'רזי, aliases [ניו ג'רזי, ניו גרזי], coords [-74.6, 40.1], isMicro true }, { id 35, name ניו מקסיקו, aliases [ניו מקסיקו], coords [-106.0, 34.4] }, { id 36, name ניו יורק, aliases [ניו יורק], coords [-75.5, 42.9] }, { id 37, name קרוליינה הצפונית, aliases [קרוליינה הצפונית, צפון קרוליינה], coords [-79.4, 35.5] }, { id 38, name דקוטה הצפונית, aliases [דקוטה הצפונית, צפון דקוטה], coords [-100.4, 47.4] }, { id 39, name אוהיו, aliases [אוהיו], coords [-82.8, 40.3] }, { id 40, name אוקלהומה, aliases [אוקלהומה], coords [-97.5, 35.5] }, { id 41, name אורגון, aliases [אורגון], coords [-120.5, 43.9] }, { id 42, name פנסילבניה, aliases [פנסילבניה], coords [-77.8, 40.9] }, { id 44, name רוד איילנד, aliases [רוד איילנד, רוד אילנד], coords [-71.5, 41.7], isMicro true }, { id 45, name קרוליינה הדרומית, aliases [קרוליינה הדרומית, דרום קרוליינה], coords [-80.9, 33.9] }, { id 46, name דקוטה הדרומית, aliases [דקוטה הדרומית, דרום דקוטה], coords [-100.2, 44.4] }, { id 47, name טנסי, aliases [טנסי], coords [-86.3, 35.8] }, { id 48, name טקסס, aliases [טקסס], coords [-99.3, 31.5] }, { id 49, name יוטה, aliases [יוטה], coords [-111.7, 39.3] }, { id 50, name ורמונט, aliases [ורמונט], coords [-72.6, 44.0] }, { id 51, name וירג'יניה, aliases [וירג'יניה, וירגיניה], coords [-78.8, 37.5] }, { id 53, name וושינגטון, aliases [וושינגטון, ושינגטון], coords [-120.5, 47.4] }, { id 54, name וירג'יניה המערבית, aliases [וירג'יניה המערבית, מערב וירג'יניה], coords [-80.6, 38.6] }, { id 55, name ויסקונסין, aliases [ויסקונסין], coords [-89.7, 44.6] }, { id 56, name ויומינג, aliases [ויומינג], coords [-107.5, 43.0] } ] }, world { key world, badge כל העולם, title האתגר הגדול האם תזהו את כל 197 מדינות העולם, listTitle כל מדינות העולם (197), defaultTime 900, atlasType world, projectionConfig { type naturalEarth, scale 155, translateOffset [0, 15] }, items [] } }; השלמת מדינות צפון אמריקה ואוקיאניה כדי להגיע ל-197 מדינות בעולם const EXTRA_WORLD_COUNTRIES = [ { id 028, name אנטיגואה וברבודה, aliases [אנטיגואה וברבודה, אנטיגואה], coords [-61.8, 17.05], isMicro true }, { id 044, name איי בהאמה, aliases [איי בהאמה, בהאמה, בהאמס], coords [-77.4, 25.0], isMicro true }, { id 052, name ברבדוס, aliases [ברבדוס], coords [-59.5, 13.2], isMicro true }, { id 084, name בליז, aliases [בליז], coords [-88.5, 17.2] }, { id 124, name קנדה, aliases [קנדה], coords [-106.3, 56.1] }, { id 188, name קוסטה ריקה, aliases [קוסטה ריקה], coords [-83.8, 9.7] }, { id 192, name קובה, aliases [קובה], coords [-77.8, 21.5] }, { id 212, name דומיניקה, aliases [דומיניקה], coords [-61.4, 15.4], isMicro true }, { id 214, name הרפובליקה הדומיניקנית, aliases [הרפובליקה הדומיניקנית, דומיניקנית], coords [-70.2, 18.7] }, { id 222, name אל סלוודור, aliases [אל סלוודור, אל סלבדור], coords [-88.9, 13.8] }, { id 308, name גרנדה, aliases [גרנדה], coords [-61.7, 12.1], isMicro true }, { id 320, name גואטמלה, aliases [גואטמלה, גווטמלה], coords [-90.2, 15.8] }, { id 332, name האיטי, aliases [האיטי, היטי], coords [-72.3, 19.0] }, { id 340, name הונדורס, aliases [הונדורס], coords [-86.2, 15.2] }, { id 388, name ג'מייקה, aliases [ג'מייקה, גמייקה], coords [-77.3, 18.1], isMicro true }, { id 484, name מקסיקו, aliases [מקסיקו], coords [-102.5, 23.6] }, { id 558, name ניקרגואה, aliases [ניקרגואה, ניקרגווה], coords [-85.2, 12.9] }, { id 591, name פנמה, aliases [פנמה], coords [-80.8, 8.5] }, { id 659, name סנט קיטס ונוויס, aliases [סנט קיטס ונוויס, סנט קיטס], coords [-62.7, 17.3], isMicro true }, { id 662, name סנט לוסיה, aliases [סנט לוסיה], coords [-61.0, 13.9], isMicro true }, { id 670, name סנט וינסנט והגרנדינים, aliases [סנט וינסנט והגרנדינים, סנט וינסנט], coords [-61.2, 13.2], isMicro true }, { id 780, name טרינידד וטובגו, aliases [טרינידד וטובגו, טרינידד], coords [-61.2, 10.7], isMicro true }, { id 840, name ארצות הברית, aliases [ארצות הברית, ארהב, ארהב, אמריקה], coords [-98.5, 39.8] }, { id 036, name אוסטרליה, aliases [אוסטרליה], coords [133.8, -25.3] }, { id 242, name פיג'י, aliases [פיג'י, פיגי], coords [178.0, -17.7], isMicro true }, { id 296, name קיריבטי, aliases [קיריבטי], coords [-157.4, 1.9], isMicro true }, { id 584, name איי מרשל, aliases [איי מרשל, מרשל], coords [171.2, 7.1], isMicro true }, { id 583, name מיקרונזיה, aliases [מיקרונזיה], coords [158.2, 6.9], isMicro true }, { id 520, name נאורו, aliases [נאורו], coords [166.9, -0.5], isMicro true }, { id 554, name ניו זילנד, aliases [ניו זילנד], coords [174.9, -40.9] }, { id 585, name פלאו, aliases [פלאו], coords [134.6, 7.5], isMicro true }, { id 598, name פפואה גינאה החדשה, aliases [פפואה גינאה החדשה, פפואה], coords [143.9, -6.3] }, { id 882, name סמואה, aliases [סמואה], coords [-172.1, -13.8], isMicro true }, { id 090, name איי שלמה, aliases [איי שלמה], coords [160.2, -9.6], isMicro true }, { id 776, name טונגה, aliases [טונגה], coords [-175.2, -21.2], isMicro true }, { id 798, name טובאלו, aliases [טובאלו], coords [179.2, -8.5], isMicro true }, { id 548, name ונואטו, aliases [ונואטו, וונואטו], coords [166.9, -15.4], isMicro true } ]; (function buildWorldMapItems() { const seen = new Set(); const allSources = [ ...MAPS_DATA.europe.items, ...MAPS_DATA.south_america.items, ...MAPS_DATA.africa.items, ...MAPS_DATA.asia.items, ...EXTRA_WORLD_COUNTRIES ]; allSources.forEach(item = { if (!seen.has(item.id)) { seen.add(item.id); MAPS_DATA.world.items.push(item); } }); })(); מיפוי קודי ISO לדגלים const ISO_NUM_TO_ALPHA2 = { 004af,008al,012dz,020ad,024ao,028ag,031az,032ar,036au,040at, 044bs,048bh,050bd,051am,052bb,056be,064bt,068bo,070ba,072bw, 076br,084bz,090sb,096bn,100bg,104mm,108bi,112by,116kh,120cm, 124ca,132cv,140cf,144lk,148td,152cl,156cn,158tw,170co,174km, 178cg,180cd,188cr,191hr,192cu,196cy,203cz,204bj,208dk,212dm, 214do,218ec,222sv,226gq,231et,232er,233ee,242fj,246fi,250fr, 262dj,266ga,268ge,270gm,275ps,276de,288gh,296ki,300gr,308gd, 320gt,324gn,328gy,332ht,336va,340hn,348hu,352is,356in,360id, 364ir,368iq,372ie,376il,380it,383xk,384ci,388jm,392jp,398kz, 400jo,404ke,408kp,410kr,414kw,417kg,418la,422lb,426ls,428lv, 430lr,434ly,438li,440lt,442lu,450mg,454mw,458my,462mv,466ml, 470mt,478mr,480mu,484mx,492mc,496mn,498md,499me,504ma,508mz, 512om,516na,520nr,524np,528nl,548vu,554nz,558ni,562ne,566ng, 578no,583fm,584mh,585pw,586pk,591pa,598pg,600py,604pe,608ph, 616pl,620pt,624gw,626tl,634qa,642ro,643ru,646rw,659kn,662lc, 670vc,674sm,678st,682sa,686sn,688rs,690sc,694sl,702sg,703sk, 704vn,705si,706so,710za,716zw,724es,728ss,729sd,740sr,748sz, 752se,756ch,760sy,762tj,764th,768tg,776to,780tt,784ae,788tn, 792tr,795tm,798tv,800ug,804ua,807mk,818eg,826gb,834tz,840us, 854bf,858uy,860uz,862ve,882ws,887ye,894zm }; const US_FIPS_TO_POSTAL = { 01us-al,02us-ak,04us-az,05us-ar,06us-ca,08us-co,09us-ct,10us-de, 12us-fl,13us-ga,15us-hi,16us-id,17us-il,18us-in,19us-ia,20us-ks, 21us-ky,22us-la,23us-me,24us-md,25us-ma,26us-mi,27us-mn,28us-ms, 29us-mo,30us-mt,31us-ne,32us-nv,33us-nh,34us-nj,35us-nm,36us-ny, 37us-nc,38us-nd,39us-oh,40us-ok,41us-or,42us-pa,44us-ri,45us-sc, 46us-sd,47us-tn,48us-tx,49us-ut,50us-vt,51us-va,53us-wa,54us-wv, 55us-wi,56us-wy }; function getFlagUrl(item) { if (currentMapConfig.atlasType === usa) { const code = US_FIPS_TO_POSTAL[item.id] us; return `httpsflagcdn.comw160${code}.png`; } const alpha2 = ISO_NUM_TO_ALPHA2[item.id] un; return `httpsflagcdn.comw160${alpha2}.png`; } משתני מצב כלליים let currentMapConfig = MAPS_DATA.europe; let currentGameMode = type; type click flags let clickTargetQueue = []; let currentClickTarget = null; let wrongClickCount = 0; let hintsUsedCount = 0; let activeHintsMap = new Map(); id - hangmanPattern let selectedTimeLimitSeconds = 600; let guessedIds = new Set(); let isGameActive = false; let hasTimerStarted = false; let timerSeconds = 600; let timerInterval = null; let isMuted = false; let isDarkMode = false; משתני D3 ומטמון טופולוגיה let cachedWorldTopology = null; let cachedUsaTopology = null; let currentSvg = null; let currentMapGroup = null; let currentZoomBehavior = null; let currentProjection = null; משתני מצב אחד על אחד (1v1) let active1v1Session = null; let pendingIncoming1v1 = null; let draft1v1 = { seed Math.floor(100000 + Math.random() 900000), map europe, mode type, time 300 }; מנוע סאונד (Web Audio API) let audioCtx = null; function ensureAudioContext() { if (!audioCtx) { const AudioContext = window.AudioContext window.webkitAudioContext; if (AudioContext) audioCtx = new AudioContext(); } if (audioCtx && audioCtx.state === suspended) { audioCtx.resume().catch(() = {}); } } function playSound(type) { if (isMuted) return; try { ensureAudioContext(); if (!audioCtx) return; const now = audioCtx.currentTime; const osc = audioCtx.createOscillator(); const gain = audioCtx.createGain(); osc.connect(gain); gain.connect(audioCtx.destination); if (type === success) { osc.type = sine; osc.frequency.setValueAtTime(523.25, now); osc.frequency.exponentialRampToValueAtTime(783.99, now + 0.12); gain.gain.setValueAtTime(0.14, now); gain.gain.exponentialRampToValueAtTime(0.001, now + 0.22); osc.start(now); osc.stop(now + 0.23); } else if (type === wrong) { osc.type = triangle; osc.frequency.setValueAtTime(190, now); osc.frequency.linearRampToValueAtTime(140, now + 0.14); gain.gain.setValueAtTime(0.12, now); gain.gain.exponentialRampToValueAtTime(0.001, now + 0.16); osc.start(now); osc.stop(now + 0.17); } else if (type === win) { const notes = [523.25, 659.25, 783.99, 1046.50]; notes.forEach((freq, idx) = { const o = audioCtx.createOscillator(); const g = audioCtx.createGain(); o.connect(g); g.connect(audioCtx.destination); o.type = sine; o.frequency.setValueAtTime(freq, now + idx 0.09); g.gain.setValueAtTime(0.13, now + idx 0.09); g.gain.exponentialRampToValueAtTime(0.001, now + idx 0.09 + 0.28); o.start(now + idx 0.09); o.stop(now + idx 0.09 + 0.3); }); } } catch (e) {} } function toggleMute() { isMuted = !isMuted; document.getElementById(mute-icon).textContent = isMuted 🔇 🔊; document.getElementById(mute-label).textContent = isMuted מושתק צליל פעיל; } מצב לילה (Dark Mode) function initDarkMode() { try { const saved = localStorage.getItem(quizrael_dark_mode); if (saved === 1) { isDarkMode = true; document.body.classList.add(dark-mode); document.getElementById(dark-mode-icon).textContent = ☀️; document.getElementById(dark-mode-label).textContent = מצב יום; } } catch (e) {} } function toggleDarkMode() { isDarkMode = !isDarkMode; document.body.classList.toggle(dark-mode, isDarkMode); document.getElementById(dark-mode-icon).textContent = isDarkMode ☀️ 🌙; document.getElementById(dark-mode-label).textContent = isDarkMode מצב יום מצב לילה; try { localStorage.setItem(quizrael_dark_mode, isDarkMode 1 0); } catch (e) {} } ניווט ובחירת מודים ומפות function showHomeView() { clearInterval(timerInterval); isGameActive = false; active1v1Session = null; document.getElementById(game-view).classList.add(hidden); document.getElementById(game-view).classList.remove(flex); document.getElementById(home-view).classList.remove(hidden); document.getElementById(btn-home-nav).classList.add(hidden); refreshAllBestScoreBadges(); } function setGameMode(mode, insideGame) { currentGameMode = mode; עדכון כפתורי הבחירה בדף הבית [type, click, flags].forEach(m = { const homeBtn = document.getElementById(`home-mode-btn-${m}`); if (homeBtn) { homeBtn.className = (m === mode) py-3 px-2 smpx-4 rounded-xl font-black text-xs smtext-base bg-slate-900 text-white shadow transition flex flex-col items-center justify-center gap-0.5 py-3 px-2 smpx-4 rounded-xl font-black text-xs smtext-base text-slate-700 hoverbg-white70 transition flex flex-col items-center justify-center gap-0.5; } const gameBtn = document.getElementById(`mode-btn-${m}`); if (gameBtn) { gameBtn.className = (m === mode) px-2.5 py-1.5 rounded-lg font-extrabold bg-slate-900 text-white transition flex items-center gap-1 shadow-sm px-2.5 py-1.5 rounded-lg font-extrabold text-slate-600 hoverbg-slate-100 transition flex items-center gap-1; } }); refreshAllBestScoreBadges(); if (insideGame && !document.getElementById(game-view).classList.contains(hidden)) { resetGame(); } } function selectMap(mapKey) { if (!MAPS_DATA[mapKey]) return; currentMapConfig = MAPS_DATA[mapKey]; selectedTimeLimitSeconds = currentMapConfig.defaultTime; document.getElementById(home-view).classList.add(hidden); document.getElementById(game-view).classList.remove(hidden); document.getElementById(game-view).classList.add(flex); document.getElementById(btn-home-nav).classList.remove(hidden); document.getElementById(game-category-badge).textContent = currentMapConfig.badge; document.getElementById(game-title).textContent = currentMapConfig.title; document.getElementById(list-header-title).textContent = currentMapConfig.listTitle; const badge1v1 = document.getElementById(game-1v1-badge); if (active1v1Session) { badge1v1.classList.remove(hidden); } else { badge1v1.classList.add(hidden); } updateTimerButtonsUI(); updateGameBestScoreBadge(); resetGame(); } ניהול שיאים אישיים (localStorage) function getBestScoreKey(mapKey, mode) { return `quizrael_best_${mapKey}_${mode}`; } function getBestScore(mapKey, mode) { try { const raw = localStorage.getItem(getBestScoreKey(mapKey, mode)); return raw JSON.parse(raw) null; } catch (e) { return null; } } function saveBestScoreIfBetter(mapKey, mode, count, total, elapsedSec) { const prev = getBestScore(mapKey, mode); let isNewRecord = false; if (!prev count prev.count (count === prev.count && count 0 && elapsedSec prev.elapsed)) { isNewRecord = true; try { localStorage.setItem(getBestScoreKey(mapKey, mode), JSON.stringify({ count, total, elapsed elapsedSec })); } catch (e) {} } return isNewRecord; } function refreshAllBestScoreBadges() { Object.keys(MAPS_DATA).forEach(mapKey = { const el = document.getElementById(`best-badge-${mapKey}`); if (!el) return; const best = getBestScore(mapKey, currentGameMode); if (best && best.count 0) { el.textContent = `🏆 שיא אישי ${best.count}${best.total} (${formatTime(best.elapsed)})`; } else { el.textContent = ; } }); } function updateGameBestScoreBadge() { const el = document.getElementById(game-best-score-badge); const best = getBestScore(currentMapConfig.key, currentGameMode); if (best && best.count 0) { el.textContent = `🏆 שיא אישי ${best.count}${best.total} (${formatTime(best.elapsed)})`; el.classList.remove(hidden); } else { el.classList.add(hidden); } } ניהול שעון עצר function formatTime(sec) { const s = Math.max(0, Math.floor(sec)); const mins = Math.floor(s 60); const rem = s % 60; return `${String(mins).padStart(2, 0)}${String(rem).padStart(2, 0)}`; } function setTimerOption(seconds) { selectedTimeLimitSeconds = seconds; updateTimerButtonsUI(); resetGame(); } function updateTimerButtonsUI() { document.querySelectorAll(.timer-opt-btn).forEach(btn = { const s = Number(btn.getAttribute(data-seconds)); if (s === selectedTimeLimitSeconds) { btn.className = timer-opt-btn px-2.5 py-1 rounded-lg font-bold border border-blue-600 bg-blue-600 text-white transition; } else { btn.className = timer-opt-btn px-2.5 py-1 rounded-lg font-bold border border-slate-300 bg-white text-slate-700 hoverbg-slate-100 transition; } }); } function startTimerIfNeeded() { if (hasTimerStarted !isGameActive) return; hasTimerStarted = true; clearInterval(timerInterval); timerInterval = setInterval(() = { if (!isGameActive) { clearInterval(timerInterval); return; } if (selectedTimeLimitSeconds 0) { timerSeconds--; document.getElementById(timer-display).textContent = formatTime(timerSeconds); if (timerSeconds = 0) { finishGame(false, true); } } else { timerSeconds++; document.getElementById(timer-display).textContent = formatTime(timerSeconds); } }, 1000); } function getElapsedSeconds() { if (selectedTimeLimitSeconds 0) { return Math.max(1, selectedTimeLimitSeconds - timerSeconds); } return Math.max(1, timerSeconds); } איפוס והתחלת משחק async function resetGame() { clearInterval(timerInterval); guessedIds = new Set(); activeHintsMap = new Map(); hintsUsedCount = 0; wrongClickCount = 0; hasTimerStarted = false; isGameActive = true; document.getElementById(hints-used-badge).textContent = (0); document.getElementById(type-hint-banner).classList.add(hidden); document.getElementById(type-hint-banner).textContent = ; document.getElementById(flag-hint-banner).classList.add(hidden); document.getElementById(flag-hint-banner).textContent = ; document.getElementById(click-feedback-msg).textContent = ; document.getElementById(flag-feedback-msg).textContent = ; if (selectedTimeLimitSeconds 0) { timerSeconds = selectedTimeLimitSeconds; document.getElementById(timer-label).textContent = זמן נותר; } else { timerSeconds = 0; document.getElementById(timer-label).textContent = זמן שעבר; } document.getElementById(timer-display).textContent = formatTime(timerSeconds); התאמת סרגל המשחק לפי המוד שנבחר const typeBox = document.getElementById(type-mode-container); const clickBox = document.getElementById(click-mode-container); const flagsBox = document.getElementById(flags-mode-container); typeBox.classList.add(hidden); clickBox.classList.add(hidden); flagsBox.classList.add(hidden); if (currentGameMode === type) { typeBox.classList.remove(hidden); const inputEl = document.getElementById(country-input); inputEl.value = ; inputEl.disabled = false; setTimeout(() = inputEl.focus(), 50); } else if (currentGameMode === click) { clickBox.classList.remove(hidden); prepareClickQueue(); advanceClickTarget(); } else if (currentGameMode === flags) { flagsBox.classList.remove(hidden); prepareClickQueue(); advanceClickTarget(); } updateScoreUI(); renderCountriesGrid(); await renderMap(); } function updateScoreUI() { const total = currentMapConfig.items.length; const current = Math.min(guessedIds.size, total); document.getElementById(score-display).textContent = `${current} ${total}`; const pct = total 0 Math.round((current total) 100) 0; document.getElementById(progress-bar).style.width = `${pct}%`; } הכנת תור יעדים למצב הצבעה ודגלים (עם תמיכה ב-Seed של 1v1) function prepareClickQueue() { const list = [...currentMapConfig.items]; const randFn = active1v1Session createSeededRandom(active1v1Session.seed) Math.random; for (let i = list.length - 1; i 0; i--) { const j = Math.floor(randFn() (i + 1)); [list[i], list[j]] = [list[j], list[i]]; } clickTargetQueue = list; } function advanceClickTarget() { while (clickTargetQueue.length 0 && guessedIds.has(clickTargetQueue[0].id)) { clickTargetQueue.shift(); } if (clickTargetQueue.length === 0) { currentClickTarget = null; return; } currentClickTarget = clickTargetQueue[0]; document.getElementById(click-feedback-msg).textContent = ; document.getElementById(flag-feedback-msg).textContent = ; if (currentGameMode === click) { document.getElementById(click-target-name).textContent = currentClickTarget.name; } else if (currentGameMode === flags) { const imgEl = document.getElementById(flag-target-img); imgEl.src = getFlagUrl(currentClickTarget); imgEl.alt = דגל; const flagHintEl = document.getElementById(flag-hint-banner); if (activeHintsMap.has(currentClickTarget.id)) { flagHintEl.textContent = activeHintsMap.get(currentClickTarget.id); flagHintEl.classList.remove(hidden); } else { flagHintEl.classList.add(hidden); } } } function skipClickTarget() { if (!isGameActive !currentClickTarget clickTargetQueue.length = 1) return; const skipped = clickTargetQueue.shift(); clickTargetQueue.push(skipped); advanceClickTarget(); } נרמול טקסט והתאמת שמות בהקלדה function normalizeHebrewText(str) { return (str ) .trim() .replace(['״׳-–—.,()]g, ) .replace(s+g, ) .toLowerCase(); } const aliasLookupMap = new Map(); function rebuildAliasLookup() { aliasLookupMap.clear(); currentMapConfig.items.forEach(item = { aliasLookupMap.set(normalizeHebrewText(item.name), item); (item.aliases []).forEach(al = { aliasLookupMap.set(normalizeHebrewText(al), item); }); }); } document.getElementById(country-input).addEventListener(input, function (e) { if (!isGameActive currentGameMode !== type) return; startTimerIfNeeded(); const val = normalizeHebrewText(e.target.value); if (!val) return; const matchedItem = aliasLookupMap.get(val); if (matchedItem && !guessedIds.has(matchedItem.id)) { markCountryGuessed(matchedItem); e.target.value = ; e.target.classList.remove(input-success-flash); void e.target.offsetWidth; e.target.classList.add(input-success-flash); const badge = document.getElementById(last-guessed-badge); document.getElementById(last-guessed-name).textContent = matchedItem.name; badge.classList.remove(opacity-0); clearTimeout(badge._hideTimer); badge._hideTimer = setTimeout(() = badge.classList.add(opacity-0), 1600); } }); טיפול בלחיצה על מדינה במפה (מצב הצבעה ומצב דגלים) function handleMapClick(clickedId) { if (!isGameActive (currentGameMode !== click && currentGameMode !== flags)) return; if (!currentClickTarget) return; אם השחקן לחץ על מדינה שכבר נוחשה קודם - מתעלמים לגמרי ללא טעות וללא הפרעה! if (guessedIds.has(clickedId)) { return; } startTimerIfNeeded(); if (clickedId === currentClickTarget.id) { markCountryGuessed(currentClickTarget); if (isGameActive) { advanceClickTarget(); } } else { wrongClickCount++; playSound(wrong); const wrongItem = currentMapConfig.items.find(it = it.id === clickedId); const wrongName = wrongItem wrongItem.name מדינה אחרת; if (currentGameMode === click) { document.getElementById(click-feedback-msg).textContent = `(לחצתם על ${wrongName})`; } else { document.getElementById(flag-feedback-msg).textContent = `טעות! לחצתם על ${wrongName}`; } הבהוב קצר רק למדינה השגויה שלחצו עליה if (currentMapGroup) { const targetEl = currentMapGroup.selectAll(`[data-id=${clickedId}]`); targetEl.classed(wrong-flash, true); setTimeout(() = targetEl.classed(wrong-flash, false), 450); } } } סימון מדינה שנוחשה בהצלחה function markCountryGuessed(item) { if (guessedIds.has(item.id)) return; guessedIds.add(item.id); playSound(success); הסרת רמז פעיל אם היה על מדינה זו if (activeHintsMap.has(item.id)) { activeHintsMap.delete(item.id); updateHintBannersAfterGuess(); } צביעה במפה והוספת תווית שם המדינה if (currentMapGroup) { currentMapGroup.selectAll(`.country-path[data-id=${item.id}]`) .classed(hint-active-country, false) .classed(guessed, true); currentMapGroup.selectAll(`.microstate-dot[data-id=${item.id}]`) .classed(hint-active-country, false) .classed(guessed, true) .attr(r, 5.5); currentMapGroup.selectAll(`.hint-letter-label[data-id=${item.id}]`).remove(); addCountryLabelToMap(item, false); } updateScoreUI(); updateGridItemGuessed(item.id, false); if (guessedIds.size = currentMapConfig.items.length) { finishGame(true, false); } } מנגנון הרמז צובע מדינה באדום קבוע (ללא הבהוב) ומציג קווים לפי מספר האותיות + אות רנדומלית במיקומה function buildHangmanPattern(countryName) { const chars = Array.from(countryName); const letterIndices = []; chars.forEach((ch, idx) = { if ([u0590-u05FFa-zA-Z0-9].test(ch)) { letterIndices.push(idx); } }); const chosenIdx = letterIndices.length 0 letterIndices[Math.floor(Math.random() letterIndices.length)] 0; return chars.map((ch, idx) = { if (ch === ) return ; if (![u0590-u05FFa-zA-Z0-9].test(ch)) return ch; return idx === chosenIdx ch _; }).join( ); } function useHint() { if (!isGameActive) return; startTimerIfNeeded(); let targetItem = null; if (currentGameMode === click currentGameMode === flags) { targetItem = currentClickTarget; } else { במצב הקלדה בוחרים מדינה שטרם נוחשה ועדיין אין עליה רמז (או אחת מהמדינות עם רמז) const unguessedWithoutHint = currentMapConfig.items.filter( it = !guessedIds.has(it.id) && !activeHintsMap.has(it.id) ); const pool = unguessedWithoutHint.length 0 unguessedWithoutHint currentMapConfig.items.filter(it = !guessedIds.has(it.id)); if (pool.length 0) { targetItem = pool[Math.floor(Math.random() pool.length)]; } } if (!targetItem) return; hintsUsedCount++; document.getElementById(hints-used-badge).textContent = `(${hintsUsedCount})`; const pattern = buildHangmanPattern(targetItem.name); activeHintsMap.set(targetItem.id, pattern); צביעה קבועה באדום על המפה (ללא הבהוב) + הצגת הקווים והאות על גבי המדינה if (currentMapGroup) { currentMapGroup.selectAll(`.country-path[data-id=${targetItem.id}]`) .classed(hint-active-country, true); currentMapGroup.selectAll(`.microstate-dot[data-id=${targetItem.id}]`) .classed(hint-active-country, true) .attr(r, 6.5); currentMapGroup.selectAll(`.hint-letter-label[data-id=${targetItem.id}]`).remove(); if (currentProjection && targetItem.coords) { const projected = currentProjection(targetItem.coords); if (projected && !isNaN(projected[0]) && !isNaN(projected[1])) { currentMapGroup.append(text) .attr(class, hint-letter-label) .attr(data-id, targetItem.id) .attr(x, projected[0]) .attr(y, projected[1] - (targetItem.isMicro 8 0)) .text(pattern); } } } הצגת תבנית הקווים והאות גם בתיבת ההקלדה הדגלים if (currentGameMode === type) { const banner = document.getElementById(type-hint-banner); banner.textContent = `💡 רמז למדינה האדומה ${pattern}`; banner.classList.remove(hidden); document.getElementById(country-input).focus(); } else if (currentGameMode === flags) { const flagHintEl = document.getElementById(flag-hint-banner); flagHintEl.textContent = `💡 רמז ${pattern}`; flagHintEl.classList.remove(hidden); } else if (currentGameMode === click) { document.getElementById(click-feedback-msg).textContent = `(סומנה באדום במפה!)`; } } function updateHintBannersAfterGuess() { const typeBanner = document.getElementById(type-hint-banner); if (activeHintsMap.size === 0) { typeBanner.classList.add(hidden); typeBanner.textContent = ; } else { const lastPattern = Array.from(activeHintsMap.values()).pop(); typeBanner.textContent = `💡 רמז למדינה האדומה ${lastPattern}`; } document.getElementById(flag-hint-banner).classList.add(hidden); } ויתור וסיום משחק function confirmGiveUp() { if (!isGameActive) return; const modal = document.getElementById(giveup-modal); modal.classList.remove(hidden); modal.classList.add(flex); } function closeGiveUpModal() { const modal = document.getElementById(giveup-modal); modal.classList.add(hidden); modal.classList.remove(flex); } function executeGiveUp() { closeGiveUpModal(); finishGame(false, false); } function finishGame(isFullWin, isTimeout) { isGameActive = false; clearInterval(timerInterval); const inputEl = document.getElementById(country-input); if (inputEl) inputEl.disabled = true; חשיפת מדינות שלא נוחשו currentMapConfig.items.forEach(item = { if (!guessedIds.has(item.id)) { if (currentMapGroup) { currentMapGroup.selectAll(`.country-path[data-id=${item.id}]`) .classed(hint-active-country, false) .classed(missed, true); currentMapGroup.selectAll(`.microstate-dot[data-id=${item.id}]`) .classed(hint-active-country, false) .classed(missed, true) .attr(r, 5); currentMapGroup.selectAll(`.hint-letter-label[data-id=${item.id}]`).remove(); addCountryLabelToMap(item, true); } updateGridItemGuessed(item.id, true); } }); const total = currentMapConfig.items.length; const count = Math.min(guessedIds.size, total); const percent = total 0 Math.round((count total) 100) 0; const elapsed = getElapsedSeconds(); if (isFullWin) { playSound(win); } const isNewRecord = saveBestScoreIfBetter(currentMapConfig.key, currentGameMode, count, total, elapsed); updateGameBestScoreBadge(); עדכון חלונית הסיכום document.getElementById(summary-emoji).textContent = isFullWin 🏆 (isTimeout ⏰ 🗺️); document.getElementById(summary-title).textContent = isFullWin כל הכבוד! השלמתם 100%! (isTimeout נגמר הזמן! המשחק הסתיים); document.getElementById(summary-subtitle).textContent = `מפת ${currentMapConfig.badge}`; document.getElementById(summary-percent).textContent = `${percent}%`; document.getElementById(summary-count).textContent = `${count}${total}`; document.getElementById(summary-time).textContent = formatTime(elapsed); const recEl = document.getElementById(summary-new-record); if (isNewRecord && count 0) { recEl.classList.remove(hidden); } else { recEl.classList.add(hidden); } טיפול בתצוגת 1v1 במסך הסיכום const box1v1 = document.getElementById(summary-1v1-box); if (active1v1Session) { box1v1.classList.remove(hidden); active1v1Session.myScore = count; active1v1Session.myElapsed = elapsed; const verdictEl = document.getElementById(summary-1v1-verdict); const descEl = document.getElementById(summary-1v1-desc); if (active1v1Session.opponentScore !== undefined && active1v1Session.opponentScore !== null) { const oppScore = Number(active1v1Session.opponentScore); const oppTime = Number(active1v1Session.opponentTime 0); let didWin = false; let isTie = false; if (count oppScore) didWin = true; else if (count === oppScore && elapsed oppTime) didWin = true; else if (count === oppScore && elapsed === oppTime) isTie = true; if (isTie) { verdictEl.textContent = תיקו מוחלט! 🤝; verdictEl.className = text-xs font-black px-2.5 py-0.5 rounded-full bg-amber-200 text-amber-900; } else if (didWin) { verdictEl.textContent = ניצחתם! 🎉; verdictEl.className = text-xs font-black px-2.5 py-0.5 rounded-full bg-emerald-200 text-emerald-900; } else { verdictEl.textContent = היריב ניצח 😅; verdictEl.className = text-xs font-black px-2.5 py-0.5 rounded-full bg-rose-200 text-rose-900; } descEl.textContent = `התוצאה שלכם ${count}${total} (${formatTime(elapsed)}) תוצאת היריב ${oppScore}${total} (${formatTime(oppTime)})`; } else { verdictEl.textContent = ממתין ליריב; verdictEl.className = text-xs font-black px-2.5 py-0.5 rounded-full bg-purple-200 text-purple-900; descEl.textContent = `קבעתם רף של ${count}${total} בזמן ${formatTime(elapsed)}! שלחו לחבר כדי לראות אם יצליח לנצח אתכם.`; } } else { box1v1.classList.add(hidden); } document.getElementById(share-feedback).textContent = ; const modal = document.getElementById(summary-modal); modal.classList.remove(hidden); modal.classList.add(flex); } function closeSummaryModal() { const modal = document.getElementById(summary-modal); modal.classList.add(hidden); modal.classList.remove(flex); } טעינת מפות D3 + TopoJSON עם גיבוי כפול (jsDelivr + unpkg) async function fetchTopologyWithFallback(urls) { for (const url of urls) { try { const res = await fetch(url); if (res.ok) { return await res.json(); } } catch (e) {} } throw new Error(Failed to fetch map topology); } async function getTopology(atlasType) { if (atlasType === usa) { if (!cachedUsaTopology) { cachedUsaTopology = await fetchTopologyWithFallback([ httpscdn.jsdelivr.netnpmus-atlas@3states-10m.json, httpsunpkg.comus-atlas@3states-10m.json ]); } return cachedUsaTopology; } else { if (!cachedWorldTopology) { cachedWorldTopology = await fetchTopologyWithFallback([ httpscdn.jsdelivr.netnpmworld-atlas@2countries-110m.json, httpsunpkg.comworld-atlas@2countries-110m.json ]); } return cachedWorldTopology; } } async function renderMap() { rebuildAliasLookup(); const loader = document.getElementById(map-loader); const container = document.getElementById(map-container); loader.classList.remove(hidden); container.classList.add(hidden); container.innerHTML = ; try { const topology = await getTopology(currentMapConfig.atlasType); const width = 800; const height = 550; const svg = d3.select(#map-container) .append(svg) .attr(viewBox, `0 0 ${width} ${height}`) .attr(preserveAspectRatio, xMidYMid meet); const g = svg.append(g); currentSvg = svg; currentMapGroup = g; הגדרת היטל המפה (Projection) const cfg = currentMapConfig.projectionConfig; let projection; if (cfg.type === albersUsa) { projection = d3.geoAlbersUsa() .scale(cfg.scale) .translate([width 2 + cfg.translateOffset[0], height 2 + cfg.translateOffset[1]]); } else if (cfg.type === azimuthal) { projection = d3.geoAzimuthalEqualArea() .rotate(cfg.rotate) .scale(cfg.scale) .translate([width 2 + cfg.translateOffset[0], height 2 + cfg.translateOffset[1]]); } else if (cfg.type === naturalEarth) { projection = d3.geoNaturalEarth1() .scale(cfg.scale) .translate([width 2 + cfg.translateOffset[0], height 2 + cfg.translateOffset[1]]); } else { projection = d3.geoMercator() .center(cfg.center) .scale(cfg.scale) .translate([width 2 + cfg.translateOffset[0], height 2 + cfg.translateOffset[1]]); } currentProjection = projection; const pathGenerator = d3.geoPath().projection(projection); const targetIdsSet = new Set(currentMapConfig.items.map(it = it.id)); const objKey = currentMapConfig.atlasType === usa states countries; const geoFeatures = topojson.feature(topology, topology.objects[objKey]).features; ציור שכבות הרקע של מדינות שכנות (שאינן חלק מהחידון הנוכחי) if (currentMapConfig.atlasType === world) { g.selectAll(.neighbor-country) .data(geoFeatures.filter(d = !targetIdsSet.has(String(d.id).padStart(3, 0)))) .enter() .append(path) .attr(class, neighbor-country) .attr(d, pathGenerator); } ציור המדינות הפעילות בחידון const activeFeatures = geoFeatures.filter(d = { const normId = currentMapConfig.atlasType === usa String(d.id).padStart(2, 0) String(d.id).padStart(3, 0); return targetIdsSet.has(normId); }); g.selectAll(.country-path) .data(activeFeatures) .enter() .append(path) .attr(class, country-path) .attr(data-id, d = currentMapConfig.atlasType === usa String(d.id).padStart(2, 0) String(d.id).padStart(3, 0)) .attr(d, pathGenerator) .on(click, function (event, d) { event.stopPropagation(); const normId = currentMapConfig.atlasType === usa String(d.id).padStart(2, 0) String(d.id).padStart(3, 0); handleMapClick(normId); }); ציור נקודות לחיצה ייעודיות למיקרו-מדינות ולקוסובו const microItems = currentMapConfig.items.filter(it = it.isMicro); microItems.forEach(item = { const pt = projection(item.coords); if (pt && !isNaN(pt[0]) && !isNaN(pt[1])) { g.append(circle) .attr(class, microstate-dot) .attr(data-id, item.id) .attr(cx, pt[0]) .attr(cy, pt[1]) .attr(r, currentMapConfig.key === world 3.2 4.5) .on(click, function (event) { event.stopPropagation(); handleMapClick(item.id); }); } }); הגדרת זום וגרירה (Zoom & Pan) const zoom = d3.zoom() .scaleExtent([1, 8]) .on(zoom, (event) = { g.attr(transform, event.transform); }); svg.call(zoom); currentZoomBehavior = zoom; loader.classList.add(hidden); container.classList.remove(hidden); } catch (err) { loader.innerHTML = `span class=text-rose-600 font-boldשגיאה בטעינת המפה. בדקו חיבור לאינטרנט ונסו שוב.span`; } } function addCountryLabelToMap(item, isMissed) { if (!currentMapGroup !currentProjection !item.coords) return; const pt = currentProjection(item.coords); if (!pt isNaN(pt[0]) isNaN(pt[1])) return; currentMapGroup.append(text) .attr(class, isMissed country-label missed-label country-label) .attr(data-id, item.id) .attr(x, pt[0]) .attr(y, pt[1] + (item.isMicro -6 2)) .text(item.name); } function zoomMap(factor) { if (currentSvg && currentZoomBehavior) { currentSvg.transition().duration(250).call(currentZoomBehavior.scaleBy, factor); } } function resetZoom() { if (currentSvg && currentZoomBehavior) { currentSvg.transition().duration(300).call(currentZoomBehavior.transform, d3.zoomIdentity); } } טבלת המדינות מתחת למפה function renderCountriesGrid() { const grid = document.getElementById(countries-grid); grid.innerHTML = ; const sorted = [...currentMapConfig.items].sort((a, b) = a.name.localeCompare(b.name, he)); sorted.forEach(item = { const cell = document.createElement(div); cell.id = `grid-item-${item.id}`; cell.className = px-3 py-2 rounded-xl border border-slate-200 bg-slate-50 text-slate-400 font-bold truncate transition; cell.textContent = ; grid.appendChild(cell); }); } function updateGridItemGuessed(id, isMissed) { const item = currentMapConfig.items.find(it = it.id === id); const cell = document.getElementById(`grid-item-${id}`); if (!item !cell) return; cell.textContent = item.name; if (isMissed) { cell.className = px-3 py-2 rounded-xl border border-rose-200 bg-rose-50 text-rose-700 font-extrabold truncate transition; } else { cell.className = px-3 py-2 rounded-xl border border-emerald-200 bg-emerald-50 text-emerald-800 font-extrabold truncate transition; } } מערכת משחק אחד על אחד (1v1) עם קישור שיתוף ו-Seed קבוע function createSeededRandom(seed) { let s = Number(seed) 123456; return function () { s = (s 1664525 + 1013904223) % 4294967296; return s 4294967296; }; } function build1v1ShareUrl(paramsObj) { const url = new URL(window.location.href.split()[0].split(#)[0]); url.searchParams.set(duel, 1); url.searchParams.set(seed, String(paramsObj.seed)); url.searchParams.set(map, paramsObj.map); url.searchParams.set(mode, paramsObj.mode); url.searchParams.set(time, String(paramsObj.time)); if (paramsObj.score !== undefined && paramsObj.score !== null) { url.searchParams.set(score, String(paramsObj.score)); url.searchParams.set(elapsed, String(paramsObj.elapsed 0)); } return url.toString(); } function open1v1Modal() { draft1v1.seed = Math.floor(100000 + Math.random() 900000); draft1v1.mode = currentGameMode; document.getElementById(select-1v1-map).value = draft1v1.map; update1v1ModalUI(); document.getElementById(feedback-1v1-copy).textContent = ; const modal = document.getElementById(modal-1v1); modal.classList.remove(hidden); modal.classList.add(flex); } function close1v1Modal() { const modal = document.getElementById(modal-1v1); modal.classList.add(hidden); modal.classList.remove(flex); } function set1v1Option(key, value) { draft1v1[key] = value; update1v1ModalUI(); } function update1v1ModalUI() { document.querySelectorAll(.opt-1v1-mode).forEach(btn = { const m = btn.getAttribute(data-1v1-mode); btn.className = (m === draft1v1.mode) opt-1v1-mode py-2 rounded-lg text-xs font-black bg-slate-900 text-white shadow-sm opt-1v1-mode py-2 rounded-lg text-xs font-black text-slate-700 hoverbg-white60; }); document.querySelectorAll(.opt-1v1-time).forEach(btn = { const t = Number(btn.getAttribute(data-1v1-time)); btn.className = (t === Number(draft1v1.time)) opt-1v1-time py-1.5 rounded-lg text-xs font-bold border border-purple-600 bg-purple-600 text-white opt-1v1-time py-1.5 rounded-lg text-xs font-bold border border-slate-300 bg-white text-slate-700; }); document.getElementById(input-1v1-link).value = build1v1ShareUrl(draft1v1); } function copyTextToClipboardFallback(text, feedbackEl, msg) { const temp = document.createElement(textarea); temp.value = text; document.body.appendChild(temp); temp.select(); try { document.execCommand(copy); if (feedbackEl) feedbackEl.textContent = msg; } catch (e) {} document.body.removeChild(temp); } function copy1v1InviteLink() { const link = document.getElementById(input-1v1-link).value; copyTextToClipboardFallback(link, document.getElementById(feedback-1v1-copy), הקישור הועתק! שלחו אותו לחבר ✓); } function share1v1WhatsApp() { const link = document.getElementById(input-1v1-link).value; const mapName = MAPS_DATA[draft1v1.map].badge מפות; const text = `⚔️ אני מזמין אותך למשחק אחד על אחד בקוויזראל על מפת ${mapName}! כנס לקישור ונראה מי מנצחn${link}`; window.open(`httpswa.metext=${encodeURIComponent(text)}`, _blank); } function nativeShare1v1() { const link = document.getElementById(input-1v1-link).value; const mapName = MAPS_DATA[draft1v1.map].badge מפות; if (navigator.share) { navigator.share({ title קוויזראל - אחד על אחד, text `⚔️ אתגר אחד על אחד על מפת ${mapName}!`, url link }).catch(() = {}); } else { copy1v1InviteLink(); } } function start1v1MatchAsHost() { close1v1Modal(); active1v1Session = { seed draft1v1.seed, map draft1v1.map, mode draft1v1.mode, time Number(draft1v1.time), opponentScore null, opponentTime null }; setGameMode(active1v1Session.mode, false); selectMap(active1v1Session.map); selectedTimeLimitSeconds = active1v1Session.time; updateTimerButtonsUI(); resetGame(); } function copy1v1ResultLink() { if (!active1v1Session) return; const link = build1v1ShareUrl({ seed active1v1Session.seed, map active1v1Session.map, mode active1v1Session.mode, time active1v1Session.time, score active1v1Session.myScore, elapsed active1v1Session.myElapsed }); copyTextToClipboardFallback(link, document.getElementById(share-feedback), קישור האתגר עם התוצאה שלך הועתק! ✓); } function whatsapp1v1ResultLink() { if (!active1v1Session) return; const link = build1v1ShareUrl({ seed active1v1Session.seed, map active1v1Session.map, mode active1v1Session.mode, time active1v1Session.time, score active1v1Session.myScore, elapsed active1v1Session.myElapsed }); const total = currentMapConfig.items.length; const text = `⚔️ סיימתי ${active1v1Session.myScore}${total} במפת ${currentMapConfig.badge} בזמן ${formatTime(active1v1Session.myElapsed)} בקוויזראל! נראה אותך מנצח אותיn${link}`; window.open(`httpswa.metext=${encodeURIComponent(text)}`, _blank); } function checkIncoming1v1FromUrl() { try { const params = new URLSearchParams(window.location.search); if (params.get(duel) !== 1) return; const mapKey = params.get(map); if (!MAPS_DATA[mapKey]) return; const mode = [type, click, flags].includes(params.get(mode)) params.get(mode) type; const seed = Number(params.get(seed)) 123456; const time = Number(params.get(time)) 0; const scoreParam = params.get(score); const elapsedParam = params.get(elapsed); pendingIncoming1v1 = { seed, map mapKey, mode, time, opponentScore scoreParam !== null Number(scoreParam) null, opponentTime elapsedParam !== null Number(elapsedParam) null }; const modeNames = { type הקלדה, click הצבעה על המפה, flags חידון דגלים }; const timeLabel = time 0 `${Math.round(time 60)} דקות` ללא הגבלת זמן; document.getElementById(incoming-1v1-details).textContent = `מפה ${MAPS_DATA[mapKey].badge} מוד ${modeNames[mode]} זמן ${timeLabel}`; const oppBox = document.getElementById(incoming-1v1-opponent-score); if (pendingIncoming1v1.opponentScore !== null) { const total = MAPS_DATA[mapKey].items.length; oppBox.textContent = `🏆 התוצאה שעליכם לנצח ${pendingIncoming1v1.opponentScore}${total} בזמן ${formatTime(pendingIncoming1v1.opponentTime)}`; oppBox.classList.remove(hidden); } else { oppBox.classList.add(hidden); } const modal = document.getElementById(modal-1v1-incoming); modal.classList.remove(hidden); modal.classList.add(flex); } catch (e) {} } function acceptIncoming1v1() { if (!pendingIncoming1v1) return; const modal = document.getElementById(modal-1v1-incoming); modal.classList.add(hidden); modal.classList.remove(flex); active1v1Session = { ...pendingIncoming1v1 }; setGameMode(active1v1Session.mode, false); selectMap(active1v1Session.map); selectedTimeLimitSeconds = active1v1Session.time; updateTimerButtonsUI(); resetGame(); } function declineIncoming1v1() { const modal = document.getElementById(modal-1v1-incoming); modal.classList.add(hidden); modal.classList.remove(flex); pendingIncoming1v1 = null; } שיתוף תוצאה וחלוניות מידע function shareResults() { const total = currentMapConfig.items.length; const guessedCount = Math.min(guessedIds.size, total); const percent = Math.round((guessedCount total) 100); const timeText = document.getElementById(summary-time).textContent; const shareText = `🧭 זיהיתי ${guessedCount} מתוך ${total} במפת ${currentMapConfig.badge} (${percent}%) בזמן של ${timeText} בקוויזראל! חושבים שתצליחו לנצח אותי`; copyTextToClipboardFallback( shareText, document.getElementById(share-feedback), התוצאה הועתקה! אפשר להדביק ולשתף בוואטסאפ ✓ ); } function openInfoModal(type) { const titleEl = document.getElementById(info-modal-title); const bodyEl = document.getElementById(info-modal-body); if (type === rules) { titleEl.textContent = איך משחקים בקוויזראל; bodyEl.innerHTML = ` pstrongבחירת מוד ומפהstrong בראש דף הבית בוחרים בין מצב הקלדה, הצבעה על המפה או חידון דגלים, ולאחר מכן בוחרים את המפה הרצויה (כולל מפת כל 197 מדינות העולם).p pstrongכפתור רמזstrong לחיצה על רמז צובעת מדינה באדום קבוע ומציגה את מספר האותיות שלה עם אות אחת חשופה במיקומה הנכון.p pstrongמצב אחד על אחד (1v1)strong ניתן ליצור קישור אתגר ולשלוח לחבר כדי לשחק על אותו סדר מדינות ולהשוות תוצאות.p `; } else if (type === privacy) { titleEl.textContent = מדיניות פרטיות ועוגיות; bodyEl.innerHTML = ` pאתר קוויזראל מכבד את פרטיות המשתמשים ופועל בהתאם לתקני הפרטיות המקובלים. השיאים האישיים והעדפות התצוגה נשמרים מקומית בדפדפן שלכם בלבד.p pהאתר עשוי להציג פרסומות באמצעות Google AdSense המשתמשות בקובצי Cookie להתאמת תוכן.p `; } else { titleEl.textContent = אודות קוויזראל; bodyEl.innerHTML = ` pstrongקוויזראלstrong הוא אתר טריוויה ומפות אינטראקטיבי בעברית המאפשר לתרגל ולשחק בזיהוי מדינות, דגלים ויבשות ברחבי העולם.p `; } const modal = document.getElementById(info-modal); modal.classList.remove(hidden); modal.classList.add(flex); } function closeInfoModal() { const modal = document.getElementById(info-modal); modal.classList.add(hidden); modal.classList.remove(flex); } אתחול ראשוני בעת טעינת העמוד window.addEventListener(DOMContentLoaded, () = { initDarkMode(); refreshAllBestScoreBadges(); checkIncoming1v1FromUrl(); }); script body html