r3gm commited on
Commit
c2083a2
·
verified ·
1 Parent(s): 3bd8c39

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +284 -205
index.html CHANGED
@@ -2,239 +2,317 @@
2
  <html lang="en">
3
  <head>
4
  <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>WordConjure: Play & Learn Languages!</title>
7
  <!-- Tailwind CSS CDN for unified styling -->
8
  <script src="https://cdn.tailwindcss.com"></script>
9
- <!-- Friendly, playful fonts from Google Fonts -->
10
- <link href="https://fonts.googleapis.com/css2?family=Fredoka:wght@300..700&family=Nunito:wght@300..900&display=swap" rel="stylesheet">
11
  <style>
12
  body {
13
- font-family: 'Fredoka', 'Nunito', sans-serif;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  }
15
  </style>
16
  </head>
17
- <body class="bg-gradient-to-br from-indigo-100 via-sky-50 to-emerald-50 min-h-screen p-6">
18
 
19
- <!-- Startup App Language Selection Popup Modal -->
20
- <div id="welcomeModal" class="fixed inset-0 bg-gray-900/80 backdrop-blur-sm flex items-center justify-center p-4 z-50">
21
- <div class="bg-white p-8 rounded-3xl shadow-2xl max-w-lg w-full border-4 border-indigo-200 flex flex-col items-center text-center animate-bounce-subtle">
22
- <div class="w-20 h-20 bg-amber-100 rounded-full flex items-center justify-center mb-4 text-4xl animate-pulse">
23
  🌍
24
  </div>
25
- <h2 class="text-3xl font-black text-indigo-900 mb-2">Welcome!</h2>
26
- <p class="text-gray-500 font-medium text-sm mb-6 leading-relaxed">
27
- Choose your App Language to begin your quest!<br>
28
- ¡Elige el idioma de la aplicación para comenzar tu aventura!<br>
29
- Choisissez la langue de l'application pour commencer !
30
  </p>
31
- <div class="w-full grid grid-cols-2 gap-3">
32
- <button onclick="selectInitialLang('English')" class="py-2.5 bg-sky-50 hover:bg-sky-100 border-b-4 border-sky-400 rounded-xl text-sky-700 font-extrabold text-sm transition-all active:translate-y-0.5 shadow-sm">English</button>
33
- <button onclick="selectInitialLang('Spanish')" class="py-2.5 bg-rose-50 hover:bg-rose-100 border-b-4 border-rose-400 rounded-xl text-rose-700 font-extrabold text-sm transition-all active:translate-y-0.5 shadow-sm">Español</button>
34
- <button onclick="selectInitialLang('French')" class="py-2.5 bg-emerald-50 hover:bg-emerald-100 border-b-4 border-emerald-400 rounded-xl text-emerald-700 font-extrabold text-sm transition-all active:translate-y-0.5 shadow-sm">Français</button>
35
- <button onclick="selectInitialLang('German')" class="py-2.5 bg-amber-50 hover:bg-amber-100 border-b-4 border-amber-400 rounded-xl text-amber-700 font-extrabold text-sm transition-all active:translate-y-0.5 shadow-sm">Deutsch</button>
36
- <button onclick="selectInitialLang('Chinese')" class="py-2.5 bg-red-50 hover:bg-red-100 border-b-4 border-red-400 rounded-xl text-red-700 font-extrabold text-sm transition-all active:translate-y-0.5 shadow-sm">中文</button>
37
- <button onclick="selectInitialLang('Japanese')" class="py-2.5 bg-indigo-50 hover:bg-indigo-100 border-b-4 border-indigo-400 rounded-xl text-indigo-700 font-extrabold text-sm transition-all active:translate-y-0.5 shadow-sm">日本語</button>
38
- <button onclick="selectInitialLang('Korean')" class="py-2.5 bg-cyan-50 hover:bg-cyan-100 border-b-4 border-cyan-400 rounded-xl text-cyan-700 font-extrabold text-sm transition-all active:translate-y-0.5 shadow-sm">한국어</button>
39
- <button onclick="selectInitialLang('Russian')" class="py-2.5 bg-purple-50 hover:bg-purple-100 border-b-4 border-purple-400 rounded-xl text-purple-700 font-extrabold text-sm transition-all active:translate-y-0.5 shadow-sm">Русский</button>
40
- <button onclick="selectInitialLang('Portuguese')" class="py-2.5 bg-teal-50 hover:bg-teal-100 border-b-4 border-teal-400 rounded-xl text-teal-700 font-extrabold text-sm transition-all active:translate-y-0.5 shadow-sm">Português</button>
41
- <button onclick="selectInitialLang('Italian')" class="py-2.5 bg-orange-50 hover:bg-orange-100 border-b-4 border-orange-400 rounded-xl text-orange-700 font-extrabold text-sm transition-all active:translate-y-0.5 shadow-sm">Italiano</button>
42
  </div>
43
  </div>
44
  </div>
45
 
46
- <div class="w-full max-w-3xl mx-auto bg-white rounded-3xl shadow-xl p-8 border-4 border-indigo-100 transition-all duration-300">
 
47
 
48
- <!-- App Language Selection Header -->
49
- <div class="flex justify-between items-center mb-6 border-b-4 border-indigo-50 pb-4">
50
- <div>
51
- <h1 id="uiTitle" class="text-3xl font-black text-indigo-900 tracking-tight flex items-center gap-2">
52
- WordConjure: Play & Learn!
53
- </h1>
54
- <p id="uiSubtitle" class="text-sm text-gray-500 font-medium">Embark on an audio-visual word adventure with games and custom art! 🌟</p>
55
- </div>
56
- <div class="text-right">
57
- <label id="uiAppLangLabel" class="block text-[10px] font-black text-indigo-300 uppercase tracking-wider mb-1">App Language</label>
58
- <select id="guiLangSelect" class="p-2 border-2 border-indigo-200 rounded-xl text-sm font-bold bg-indigo-50 text-indigo-800 outline-none cursor-pointer">
59
- <option value="English">English</option>
60
- <option value="Spanish">Español</option>
61
- <option value="French">Français</option>
62
- <option value="German">Deutsch</option>
63
- <option value="Chinese">中文</option>
64
- <option value="Japanese">日本語</option>
65
- <option value="Korean">한국어</option>
66
- <option value="Russian">Русский</option>
67
- <option value="Portuguese">Português</option>
68
- <option value="Italian">Italiano</option>
69
- </select>
70
- </div>
71
- </div>
72
-
73
- <!-- Dashboard Navigation Tabs -->
74
- <div class="flex gap-4 mb-6">
75
- <button id="tabVocabBtn" class="bg-indigo-500 text-white shadow-md shadow-indigo-100 rounded-2xl px-5 py-3 font-extrabold text-sm scale-105 transition-all outline-none duration-150">📖 My Word Book</button>
76
- <button id="tabGamesBtn" class="bg-white text-gray-500 hover:bg-indigo-50 border-2 border-indigo-100/50 rounded-2xl px-5 py-3 font-extrabold text-sm transition-all outline-none duration-150">🎮 Play Arena</button>
77
- </div>
78
-
79
- <!-- TAB 1: Vocabulary Workspace -->
80
- <div id="tabVocabContent" class="block">
81
- <!-- Advanced Settings Dropdown -->
82
- <details class="mb-6 bg-gradient-to-r from-violet-50 to-fuchsia-50 border-2 border-violet-100 rounded-2xl p-4 cursor-pointer group shadow-sm">
83
- <summary id="uiSettingsTitle" class="font-extrabold text-sm text-violet-800 select-none flex justify-between items-center outline-none">
84
- <span>🛠️ Wizard's Settings Panel</span>
85
- <span class="text-xs text-violet-400 group-open:rotate-180 transition-transform">▼</span>
86
- </summary>
87
- <div class="mt-4 border-t border-violet-100 pt-4 cursor-default flex flex-col gap-4">
88
- <!-- Word count selector -->
89
- <div>
90
- <label id="uiWordCountLabel" class="block text-xs font-black text-violet-700 uppercase tracking-wider mb-2">🔮 How many words to summon?</label>
91
- <input type="range" id="wordCount" min="1" max="10" value="5" class="w-full accent-indigo-500 h-2 bg-violet-100 rounded-lg cursor-pointer">
92
- <div class="flex justify-between text-xs text-violet-500 mt-1 font-bold">
93
- <span>1</span>
94
- <span id="wordCountVal" class="font-extrabold text-indigo-600">5 words</span>
95
- <span>10</span>
96
  </div>
97
- </div>
98
- <!-- Explanation language selector -->
99
- <div>
100
- <label id="uiExplLangLabel" class="block text-xs font-black text-violet-700 uppercase tracking-wider mb-2">🗣️ Explanation Language</label>
101
- <div class="flex flex-col sm:flex-row gap-4 mt-1">
102
- <label class="inline-flex items-center text-sm text-violet-800 font-bold cursor-pointer">
103
- <input type="radio" name="explLang" value="source" checked class="accent-indigo-500 h-4 w-4 mr-2">
104
- <span id="uiExplSource">App Language</span>
105
- </label>
106
- <label class="inline-flex items-center text-sm text-violet-800 font-bold cursor-pointer">
107
- <input type="radio" name="explLang" value="target" class="accent-indigo-500 h-4 w-4 mr-2">
108
- <span id="uiExplTarget">Language to Practice</span>
109
- </label>
110
  </div>
111
- </div>
112
- </div>
113
- </details>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
114
 
115
- <!-- Language options (Source is Hidden programmatically) -->
116
- <div class="flex flex-col sm:flex-row gap-4 mb-6 items-end">
117
- <div id="srcLangContainer" class="hidden">
118
- <label id="uiSourceLangLabel" class="block text-xs font-black text-gray-600 uppercase tracking-wider mb-2">🌍 My Native Tongue</label>
119
- <select id="srcLang" class="w-full p-2.5 border-2 border-gray-200 rounded-xl text-sm bg-white outline-none">
120
- <option value="English">English</option>
121
- <option value="Spanish">Spanish</option>
122
- <option value="French">French</option>
123
- <option value="German">German</option>
124
- <option value="Chinese">Chinese</option>
125
- <option value="Japanese">Japanese</option>
126
- <option value="Korean">Korean</option>
127
- <option value="Russian">Russian</option>
128
- <option value="Portuguese">Portuguese</option>
129
- <option value="Italian">Italian</option>
130
- </select>
131
  </div>
132
- <div class="flex-1 w-full">
133
- <label id="uiTargetLangLabel" class="block text-xs font-black text-indigo-800 uppercase tracking-wider mb-2">🎯 Language to Practice</label>
134
- <select id="tgtLang" class="w-full p-3 border-2 border-indigo-200 rounded-2xl text-sm font-extrabold bg-indigo-50/50 text-indigo-900 outline-none">
135
- <!-- Filled dynamically based on chosen App Language -->
 
 
 
 
 
 
 
 
 
136
  </select>
137
  </div>
138
- <button id="translateBtn" class="w-full sm:w-auto px-8 py-3 bg-gradient-to-r from-amber-500 to-orange-500 hover:from-amber-600 hover:to-orange-600 active:translate-y-0.5 text-white font-black text-sm rounded-2xl border-b-4 border-orange-700 shadow-lg transition-all">🪄 Summon Words!</button>
139
  </div>
140
 
141
- <!-- Vocabulary Table -->
142
- <div class="overflow-hidden rounded-2xl border-4 border-indigo-50 shadow-sm">
143
- <table class="min-w-full divide-y-4 divide-indigo-50 text-sm">
144
- <thead class="bg-indigo-50/70">
145
- <tr>
146
- <th id="thOriginal" class="px-5 py-4 text-left text-xs font-black text-indigo-900 uppercase tracking-wider">Original Word</th>
147
- <th id="thTranslation" class="px-5 py-4 text-left text-xs font-black text-indigo-900 uppercase tracking-wider">Magic Translation</th>
148
- <th id="thExplanation" class="px-5 py-4 text-left text-xs font-black text-indigo-900 uppercase tracking-wider max-w-xs">What does it mean?</th>
149
- <th id="thVisual" class="px-5 py-4 text-center text-xs font-black text-indigo-900 uppercase tracking-wider w-28">Art Card</th>
150
- <th id="thAudio" class="px-5 py-4 text-center text-xs font-black text-indigo-900 uppercase tracking-wider w-20">Hear It</th>
151
- </tr>
152
- </thead>
153
- <tbody id="resultsBody" class="bg-white divide-y-2 divide-indigo-50">
154
- <tr>
155
- <td colspan="5" id="tdInitialMsg" class="px-6 py-12 text-center text-sm font-bold text-gray-400">Select language and click 'Summon Words'.</td>
156
- </tr>
157
- </tbody>
158
- </table>
159
  </div>
160
- </div>
161
 
162
- <!-- TAB 2: Games Hub -->
163
- <div id="tabGamesContent" class="hidden animate-fade-in">
164
- <!-- Game Selection Panel -->
165
- <div id="gamesMenu">
166
- <h3 id="uiGameSelectionTitle" class="text-xl font-black text-indigo-900 mb-6">Select Your Word Challenge</h3>
167
-
168
- <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
169
- <!-- Flashcard Memory Match Selection Card -->
170
- <div class="border-4 border-amber-100 bg-amber-50/20 rounded-3xl p-6 hover:shadow-md hover:-translate-y-1 transition-all duration-200 flex flex-col justify-between">
 
 
 
 
 
 
 
171
  <div>
172
- <div class="text-4xl mb-3">🧩</div>
173
- <h4 id="uiGameMemoryTitle" class="text-lg font-black text-gray-800 mb-2">Flashcard Memory Match</h4>
174
- <p id="uiGameMemoryDesc" class="text-sm text-gray-500 font-medium mb-4">Flip face-down cards to match original terms with their translations and visual cards.</p>
 
 
 
 
175
  </div>
176
- <button id="playMemoryBtn" class="w-full py-2.5 bg-amber-500 hover:bg-amber-600 active:translate-y-0.5 text-white rounded-xl text-sm font-black border-b-4 border-amber-700 transition-all cursor-pointer">Play Now</button>
177
- </div>
178
-
179
- <!-- Word Monster Selection Card -->
180
- <div class="border-4 border-emerald-100 bg-emerald-50/20 rounded-3xl p-6 hover:shadow-md hover:-translate-y-1 transition-all duration-200 flex flex-col justify-between">
181
  <div>
182
- <div class="text-4xl mb-3">👾</div>
183
- <h4 id="uiGameMonsterTitle" class="text-lg font-black text-gray-800 mb-2">Feed the Hungry Word Monster</h4>
184
- <p id="uiGameMonsterDesc" class="text-sm text-gray-500 font-medium mb-4">The monster is starving! Feed it the correct translation card matching its request.</p>
 
 
 
 
 
 
 
 
185
  </div>
186
- <button id="playMonsterBtn" class="w-full py-2.5 bg-emerald-500 hover:bg-emerald-600 active:translate-y-0.5 text-white rounded-xl text-sm font-black border-b-4 border-emerald-700 transition-all cursor-pointer">Play Now</button>
187
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
188
 
189
- <!-- Audio-Visual Quiz Selection Card -->
190
- <div class="border-4 border-purple-100 bg-purple-50/20 rounded-3xl p-6 hover:shadow-md hover:-translate-y-1 transition-all duration-200 flex flex-col justify-between">
191
- <div>
192
- <div class="text-4xl mb-3">🏆</div>
193
- <h4 id="uiGameQuizTitle" class="text-lg font-black text-gray-800 mb-2">Audio-Visual Quiz</h4>
194
- <p id="uiGameQuizDesc" class="text-sm text-gray-500 font-medium mb-4">Listen to the pronunciation or inspect the visual card, and choose the correct original term.</p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
195
  </div>
196
- <button id="playQuizBtn" class="w-full py-2.5 bg-purple-500 hover:bg-purple-600 active:translate-y-0.5 text-white rounded-xl text-sm font-black border-b-4 border-purple-700 transition-all cursor-pointer">Play Now</button>
197
- </div>
198
 
199
- <!-- Scrambled Word Selection Card -->
200
- <div class="border-4 border-cyan-100 bg-cyan-50/20 rounded-3xl p-6 hover:shadow-md hover:-translate-y-1 transition-all duration-200 flex flex-col justify-between">
201
- <div>
202
- <div class="text-4xl mb-3">✏️</div>
203
- <h4 id="uiGameScrambleTitle" class="text-lg font-black text-gray-800 mb-2">Scrambled Word Builder</h4>
204
- <p id="uiGameScrambleDesc" class="text-sm text-gray-500 font-medium mb-4">Arrange the scrambled letters in the correct order to spell the translation of the given word.</p>
 
 
205
  </div>
206
- <button id="playScrambleBtn" class="w-full py-2.5 bg-cyan-500 hover:bg-cyan-600 active:translate-y-0.5 text-white rounded-xl text-sm font-black border-b-4 border-cyan-700 transition-all cursor-pointer">Play Now</button>
207
- </div>
208
 
209
- <!-- Visual Word Linker Selection Card -->
210
- <div class="border-4 border-orange-100 bg-orange-50/20 rounded-3xl p-6 hover:shadow-md hover:-translate-y-1 transition-all duration-200 flex flex-col justify-between">
211
- <div>
212
- <div class="text-4xl mb-3">🔗</div>
213
- <h4 id="uiGameLinkerTitle" class="text-lg font-black text-gray-800 mb-2">Visual Word Linker</h4>
214
- <p id="uiGameLinkerDesc" class="text-sm text-gray-500 font-medium mb-4">Match visual cards on the left with their corresponding practice words on the right, side by side.</p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
215
  </div>
216
- <button id="playLinkerBtn" class="w-full py-2.5 bg-orange-500 hover:bg-orange-600 active:translate-y-0.5 text-white rounded-xl text-sm font-black border-b-4 border-orange-700 transition-all cursor-pointer">Play Now</button>
217
  </div>
218
  </div>
219
- </div>
220
 
221
- <!-- Active Game Stage -->
222
- <div id="gameStage" class="hidden border-4 border-indigo-50 rounded-3xl p-6 bg-white shadow-inner animate-scale-up">
223
- <div class="flex justify-between items-center mb-6 pb-2 border-b-2 border-indigo-50">
224
- <button id="backToMenuBtn" class="text-xs font-black text-gray-400 hover:text-indigo-600 hover:scale-105 transition-all outline-none">← Back to Menu</button>
225
- <div id="gameScoreDisplay" class="text-base font-black text-indigo-600 bg-indigo-50 px-4 py-1.5 rounded-full">Score: 0</div>
 
 
226
  </div>
227
- <div id="gameArea"></div>
228
  </div>
229
  </div>
230
  </div>
231
 
232
  <!-- Modal for full size image preview -->
233
- <div id="imageModal" class="hidden fixed inset-0 bg-black/60 flex items-center justify-center p-4 z-50 transition-opacity" onclick="closeModal()">
234
- <div class="bg-white p-6 rounded-3xl shadow-2xl max-w-sm w-full border-4 border-indigo-100 flex flex-col items-center" onclick="event.stopPropagation()">
235
- <h3 id="modalTitle" class="text-xl font-black text-indigo-900 mb-4 capitalize">Word Card</h3>
236
- <img id="modalImage" class="w-64 h-64 border-2 border-indigo-50 rounded-2xl shadow-inner object-contain bg-gray-50" src="" alt="Full preview">
237
- <button class="mt-5 px-6 py-2 bg-indigo-100 hover:bg-indigo-200 active:translate-y-0.5 rounded-2xl text-sm font-bold text-indigo-800 transition-all border-b-4 border-indigo-300" onclick="closeModal()">Close</button>
238
  </div>
239
  </div>
240
 
@@ -338,6 +416,7 @@
338
 
339
  document.getElementById("uiTitle").innerText = loc.title;
340
  document.getElementById("uiSubtitle").innerText = loc.subtitle;
 
341
  document.getElementById("uiSettingsTitle").firstElementChild.innerText = loc.settings;
342
  document.getElementById("uiWordCountLabel").innerText = loc.word_count_label;
343
  document.getElementById("uiExplLangLabel").innerText = loc.expl_lang_label;
@@ -368,19 +447,19 @@
368
  document.getElementById("uiExplTarget").innerText = loc.target_lang;
369
  }
370
 
371
- // 3. Tab Switching events with playful animations
372
  tabVocabBtn.addEventListener("click", () => {
373
  tabVocabContent.classList.replace("hidden", "block");
374
  tabGamesContent.classList.replace("block", "hidden");
375
- tabVocabBtn.className = "bg-indigo-500 text-white shadow-md shadow-indigo-100 rounded-2xl px-5 py-3 font-extrabold text-sm scale-105 transition-all outline-none duration-150";
376
- tabGamesBtn.className = "bg-white text-gray-500 hover:bg-indigo-50 border-2 border-indigo-100/50 rounded-2xl px-5 py-3 font-extrabold text-sm transition-all outline-none duration-150";
377
  });
378
 
379
  tabGamesBtn.addEventListener("click", () => {
380
  tabVocabContent.classList.replace("block", "hidden");
381
  tabGamesContent.classList.replace("hidden", "block");
382
- tabGamesBtn.className = "bg-indigo-500 text-white shadow-md shadow-indigo-100 rounded-2xl px-5 py-3 font-extrabold text-sm scale-105 transition-all outline-none duration-150";
383
- tabVocabBtn.className = "bg-white text-gray-500 hover:bg-indigo-50 border-2 border-indigo-100/50 rounded-2xl px-5 py-3 font-extrabold text-sm transition-all outline-none duration-150";
384
  });
385
 
386
  wordCount.addEventListener("input", (e) => {
@@ -400,9 +479,9 @@
400
 
401
  resultsBody.innerHTML = `
402
  <tr>
403
- <td colspan="5" class="px-6 py-12 text-center text-sm text-indigo-600 font-bold">
404
- <span class="inline-block animate-bounce text-xl mb-2">🪄 Summoning Words...</span>
405
- <div class="text-xs text-gray-400 font-medium">Generating explanations, beautiful visuals, and clear audio pronunciations...</div>
406
  </td>
407
  </tr>
408
  `;
@@ -416,25 +495,25 @@
416
  window.loadedVocabulary.forEach(row => {
417
  const [original, translated, explanation, visualB64, audioB64] = row;
418
  const tr = document.createElement("tr");
419
- tr.className = "hover:bg-amber-50/40 transition-colors";
420
 
421
  tr.innerHTML = `
422
- <td class="px-5 py-5 text-gray-800 font-bold text-base">${original}</td>
423
- <td class="px-5 py-5 text-indigo-600 font-extrabold text-lg">${translated}</td>
424
- <td class="px-5 py-5 text-gray-600 text-sm font-medium leading-relaxed max-w-xs break-words">${explanation}</td>
425
- <td class="px-5 py-5 text-center">
426
  ${visualB64 ? `
427
  <div class="relative inline-block group">
428
  <img src="data:image/png;base64,${visualB64}"
429
- class="w-14 h-14 mx-auto rounded-xl border-2 border-amber-300 shadow-md hover:scale-110 hover:rotate-3 active:scale-95 cursor-pointer transition-transform duration-150 object-cover"
430
  alt="${translated}"
431
  data-src="data:image/png;base64,${visualB64}"
432
  data-word="${translated}">
433
  </div>
434
  ` : '-'}
435
  </td>
436
- <td class="px-5 py-5 text-center">
437
- <button class="play-preload-btn w-11 h-11 bg-indigo-50 hover:bg-indigo-100 border-b-2 border-indigo-200 active:translate-y-0.5 rounded-full shadow-inner flex items-center justify-center text-lg transition-transform duration-100"
438
  data-audio="data:audio/mp3;base64,${audioB64}">
439
  🔊
440
  </button>
@@ -466,8 +545,8 @@
466
  } catch (error) {
467
  resultsBody.innerHTML = `
468
  <tr>
469
- <td colspan="5" class="px-6 py-8 text-center text-sm text-red-500 font-medium">
470
- Error summoning words: ${error.message}
471
  </td>
472
  </tr>
473
  `;
 
2
  <html lang="en">
3
  <head>
4
  <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0, user-scalable=yes">
6
+ <title>WordConjure: Multimodal Vocabulary Practice</title>
7
  <!-- Tailwind CSS CDN for unified styling -->
8
  <script src="https://cdn.tailwindcss.com"></script>
9
+ <!-- Premium sans-serif typography suitable for high school, university, and adult students -->
10
+ <link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
11
  <style>
12
  body {
13
+ font-family: 'Inter', 'Plus Jakarta Sans', sans-serif;
14
+ }
15
+ h1, h2, h3, h4, th, .btn-brand {
16
+ font-family: 'Plus Jakarta Sans', sans-serif;
17
+ }
18
+ /* Touch scrollbars styling to avoid blocking touch inputs on mobile wrappers */
19
+ .scrollbar-thin::-webkit-scrollbar {
20
+ height: 4px;
21
+ width: 4px;
22
+ }
23
+ .scrollbar-thin::-webkit-scrollbar-track {
24
+ background: transparent;
25
+ }
26
+ .scrollbar-thin::-webkit-scrollbar-thumb {
27
+ background: #cbd5e1;
28
+ border-radius: 2px;
29
  }
30
  </style>
31
  </head>
32
+ <body class="bg-gradient-to-br from-[#f8fafc] via-[#f1f5f9] to-[#e2e8f0] min-h-screen p-4 md:p-8 text-slate-800">
33
 
34
+ <!-- Mobile-Optimized Language Selection Modal with swipe/scroll bounds checks -->
35
+ <div id="welcomeModal" class="fixed inset-0 bg-slate-900/60 backdrop-blur-xs flex items-center justify-center p-4 z-50 overflow-y-auto" style="-webkit-overflow-scrolling: touch; touch-action: auto;">
36
+ <div class="bg-white p-6 md:p-8 rounded-2xl shadow-2xl max-w-lg w-full border border-slate-200 flex flex-col items-center text-center my-auto max-h-[85vh] overflow-y-auto scrollbar-thin" style="-webkit-overflow-scrolling: touch;">
37
+ <div class="w-14 h-14 bg-indigo-50 rounded-full flex items-center justify-center mb-4 text-2xl shadow-inner">
38
  🌍
39
  </div>
40
+ <h2 class="text-xl font-bold text-slate-900 mb-1">Welcome</h2>
41
+ <p class="text-slate-500 font-medium text-xs mb-5 leading-relaxed">
42
+ Select your preferred language to customize the workspace application interface.<br>
43
+ Seleccione su idioma de preferencia para configurar la aplicação.
 
44
  </p>
45
+ <div class="w-full grid grid-cols-2 gap-2.5">
46
+ <button onclick="selectInitialLang('English')" class="py-2.5 px-3 bg-slate-50 hover:bg-indigo-50 hover:text-indigo-600 border border-slate-200 hover:border-indigo-200 rounded-xl font-semibold text-xs transition-all shadow-xs">English</button>
47
+ <button onclick="selectInitialLang('Spanish')" class="py-2.5 px-3 bg-slate-50 hover:bg-indigo-50 hover:text-indigo-600 border border-slate-200 hover:border-indigo-200 rounded-xl font-semibold text-xs transition-all shadow-xs">Español</button>
48
+ <button onclick="selectInitialLang('French')" class="py-2.5 px-3 bg-slate-50 hover:bg-indigo-50 hover:text-indigo-600 border border-slate-200 hover:border-indigo-200 rounded-xl font-semibold text-xs transition-all shadow-xs">Français</button>
49
+ <button onclick="selectInitialLang('German')" class="py-2.5 px-3 bg-slate-50 hover:bg-indigo-50 hover:text-indigo-600 border border-slate-200 hover:border-indigo-200 rounded-xl font-semibold text-xs transition-all shadow-xs">Deutsch</button>
50
+ <button onclick="selectInitialLang('Chinese')" class="py-2.5 px-3 bg-slate-50 hover:bg-indigo-50 hover:text-indigo-600 border border-slate-200 hover:border-indigo-200 rounded-xl font-semibold text-xs transition-all shadow-xs">中文</button>
51
+ <button onclick="selectInitialLang('Japanese')" class="py-2.5 px-3 bg-slate-50 hover:bg-indigo-50 hover:text-indigo-600 border border-slate-200 hover:border-indigo-200 rounded-xl font-semibold text-xs transition-all shadow-xs">日本語</button>
52
+ <button onclick="selectInitialLang('Korean')" class="py-2.5 px-3 bg-slate-50 hover:bg-indigo-50 hover:text-indigo-600 border border-slate-200 hover:border-indigo-200 rounded-xl font-semibold text-xs transition-all shadow-xs">한국어</button>
53
+ <button onclick="selectInitialLang('Russian')" class="py-2.5 px-3 bg-slate-50 hover:bg-indigo-50 hover:text-indigo-600 border border-slate-200 hover:border-indigo-200 rounded-xl font-semibold text-xs transition-all shadow-xs">Русский</button>
54
+ <button onclick="selectInitialLang('Portuguese')" class="py-2.5 px-3 bg-slate-50 hover:bg-indigo-50 hover:text-indigo-600 border border-slate-200 hover:border-indigo-200 rounded-xl font-semibold text-xs transition-all shadow-xs">Português</button>
55
+ <button onclick="selectInitialLang('Italian')" class="py-2.5 px-3 bg-slate-50 hover:bg-indigo-50 hover:text-indigo-600 border border-slate-200 hover:border-indigo-200 rounded-xl font-semibold text-xs transition-all shadow-xs">Italiano</button>
56
  </div>
57
  </div>
58
  </div>
59
 
60
+ <!-- Centered Structured Workspace Container -->
61
+ <div class="w-full max-w-3xl mx-auto space-y-4">
62
 
63
+ <!-- Submission Details Accordion: Located in the upper section, short size, expanding vertically -->
64
+ <details class="bg-white rounded-2xl shadow-xs p-4 border border-slate-200 cursor-pointer group transition-all duration-300">
65
+ <summary class="font-bold text-xs text-slate-500 select-none flex justify-between items-center outline-none">
66
+ <span class="flex items-center gap-2">📋 Submission Details & Verification Checklist (Click to Expand)</span>
67
+ <span class="text-[10px] text-slate-400 group-open:rotate-180 transition-transform">▼</span>
68
+ </summary>
69
+ <div class="mt-3 border-t border-slate-100 pt-3 cursor-default text-xs space-y-3 text-slate-600 font-normal leading-relaxed">
70
+ <p>This application is designed for the <strong>Build Small, Play Big Hackathon</strong>. Below is the compliance tracking checklist for validation requirements:</p>
71
+
72
+ <ul class="space-y-2.5">
73
+ <li class="flex items-start gap-2">
74
+ <span class="text-emerald-600 font-bold mt-0.5"></span>
75
+ <div>
76
+ <strong class="text-slate-800">REQ-01: Stay under 32B Parameter Limit</strong>
77
+ <p class="text-slate-400">Operates 100% within constraints with a cumulative parameter count of <strong>17.3 Billion parameters</strong>:</p>
78
+ <ul class="list-disc pl-4 text-slate-400 mt-0.5 space-y-0.5">
79
+ <li>Language Engine: bartowski/Qwen2.5-14B-Instruct-GGUF (14.0B)</li>
80
+ <li>Audio TTS Synthesis: Qwen/Qwen3-TTS-12Hz-1.7B-CustomVoice (1.7B)</li>
81
+ <li>Visual Flashcard Diffusion: Efficient-Large-Model/Sana_Sprint_1.6B (1.6B)</li>
82
+ </ul>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
83
  </div>
84
+ </li>
85
+ <li class="flex items-start gap-2">
86
+ <span class="text-emerald-600 font-bold mt-0.5">✓</span>
87
+ <div>
88
+ <strong class="text-slate-800">REQ-02: Ship a Gradio App</strong>
89
+ <p class="text-slate-500">Deploys dynamically via a Gradio mounting container leveraging a FastAPI backend architecture.</p>
 
 
 
 
 
 
 
90
  </div>
91
+ </li>
92
+ <li class="flex items-start gap-2">
93
+ <span class="text-emerald-600 font-bold mt-0.5">✓</span>
94
+ <div>
95
+ <strong class="text-slate-800">REQ-03 & REQ-04: Video Demonstration & Social Media Post</strong>
96
+ <p class="text-slate-500">The illustrative video walkthrough is hosted and embedded directly inside the social media announcement post:</p>
97
+ <div class="mt-1.5 p-2 bg-slate-50 rounded border border-slate-100 text-slate-500 flex items-center gap-2">
98
+ 🎥 <span>Announcement & Demo: <a href="https://x.com/_r3gm/status/2066206438712558019" target="_blank" rel="noopener noreferrer" class="text-indigo-600 hover:underline font-semibold">View Announcement & Demo Video on X</a></span>
99
+ </div>
100
+ </div>
101
+ </li>
102
+ <li class="flex items-start gap-2">
103
+ <span class="text-emerald-600 font-bold mt-0.5">✓</span>
104
+ <div>
105
+ <strong class="text-slate-800">REQ-05: Mind the GPU Limit</strong>
106
+ <p class="text-slate-500">Optimized for low footprint environments using sequential processing buffers and native FP16 execution maps.</p>
107
+ </div>
108
+ </li>
109
+ </ul>
110
+ </div>
111
+ </details>
112
 
113
+ <!-- Main Workspace Card (Premium Minimal Style) -->
114
+ <div class="bg-white rounded-2xl shadow-sm p-6 md:p-8 border border-slate-200/80 transition-all duration-300">
115
+
116
+ <!-- App Language Selection Header -->
117
+ <div class="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4 mb-4 border-b border-slate-100 pb-4">
118
+ <div>
119
+ <h1 id="uiTitle" class="text-xl md:text-2xl font-bold text-slate-900 tracking-tight flex items-center gap-2">
120
+ 📘 WordConjure: Multimodal Vocabulary Practice
121
+ </h1>
122
+ <p id="uiSubtitle" class="text-xs text-slate-500 font-medium">An educational system that automatically generates context-rich translations, clean pronunciation guides, and visual cards to optimize foreign language acquisition.</p>
 
 
 
 
 
 
123
  </div>
124
+ <div class="text-right w-full sm:w-auto">
125
+ <label id="uiAppLangLabel" class="block text-[9px] font-bold text-slate-400 uppercase tracking-wider mb-1">App Language</label>
126
+ <select id="guiLangSelect" class="w-full sm:w-auto p-2 border border-slate-200 rounded-xl text-xs font-semibold bg-slate-50 text-slate-700 outline-none cursor-pointer">
127
+ <option value="English">English</option>
128
+ <option value="Spanish">Español</option>
129
+ <option value="French">Français</option>
130
+ <option value="German">Deutsch</option>
131
+ <option value="Chinese">中文</option>
132
+ <option value="Japanese">日本語</option>
133
+ <option value="Korean">한국어</option>
134
+ <option value="Russian">Русский</option>
135
+ <option value="Portuguese">Português</option>
136
+ <option value="Italian">Italiano</option>
137
  </select>
138
  </div>
 
139
  </div>
140
 
141
+ <!-- Localized 2-Sentence Tutorial Section -->
142
+ <div class="mb-6 p-3 bg-slate-50 border border-slate-200/60 rounded-xl flex items-start gap-2.5 text-xs text-slate-600 font-normal leading-relaxed">
143
+ <span class="text-sm mt-0.5">💡</span>
144
+ <p id="uiTutorial">
145
+ <strong>First:</strong> Select your target preferences below and click <strong>"Generate Vocabulary"</strong> to load your custom multimodal study deck.
146
+ <strong>Then:</strong> Navigate to the <strong>"Practice Exercises"</strong> tab above to interactively test your memory through structured games.
147
+ </p>
 
 
 
 
 
 
 
 
 
 
 
148
  </div>
 
149
 
150
+ <!-- Dashboard Navigation Tabs -->
151
+ <div class="flex gap-3 mb-6">
152
+ <button id="tabVocabBtn" class="bg-indigo-600 hover:bg-indigo-700 text-white shadow-xs rounded-xl px-4 py-2 font-bold text-xs transition-all outline-none">📖 Vocabulary Deck</button>
153
+ <button id="tabGamesBtn" class="bg-white text-slate-600 hover:bg-slate-50 border border-slate-200 rounded-xl px-4 py-2 font-bold text-xs transition-all outline-none">🎮 Practice Exercises</button>
154
+ </div>
155
+
156
+ <!-- TAB 1: Vocabulary Workspace -->
157
+ <div id="tabVocabContent" class="block">
158
+ <!-- Advanced Settings Dropdown -->
159
+ <details class="mb-5 bg-slate-50 border border-slate-200 rounded-2xl p-4 cursor-pointer group shadow-xs">
160
+ <summary id="uiSettingsTitle" class="font-bold text-xs text-slate-700 select-none flex justify-between items-center outline-none">
161
+ <span>⚙️ Session Configuration</span>
162
+ <span class="text-xs text-slate-400 group-open:rotate-180 transition-transform">▼</span>
163
+ </summary>
164
+ <div class="mt-4 border-t border-slate-200 pt-4 cursor-default flex flex-col gap-4">
165
+ <!-- Word count selector -->
166
  <div>
167
+ <label id="uiWordCountLabel" class="block text-xs font-bold text-slate-600 uppercase tracking-wider mb-2">🔢 Vocabulary size to generate:</label>
168
+ <input type="range" id="wordCount" min="1" max="10" value="5" class="w-full accent-indigo-600 h-1 bg-slate-200 rounded-lg cursor-pointer">
169
+ <div class="flex justify-between text-[10px] text-slate-500 mt-1 font-semibold">
170
+ <span>1</span>
171
+ <span id="wordCountVal" class="font-bold text-indigo-600">5 words</span>
172
+ <span>10</span>
173
+ </div>
174
  </div>
175
+ <!-- Explanation language selector -->
 
 
 
 
176
  <div>
177
+ <label id="uiExplLangLabel" class="block text-xs font-bold text-slate-600 uppercase tracking-wider mb-2">🗣️ Explanation Language</label>
178
+ <div class="flex flex-col sm:flex-row gap-4 mt-1">
179
+ <label class="inline-flex items-center text-xs text-slate-700 font-semibold cursor-pointer">
180
+ <input type="radio" name="explLang" value="source" checked class="accent-indigo-600 h-4 w-4 mr-2">
181
+ <span id="uiExplSource">App Language</span>
182
+ </label>
183
+ <label class="inline-flex items-center text-xs text-slate-700 font-semibold cursor-pointer">
184
+ <input type="radio" name="explLang" value="target" class="accent-indigo-600 h-4 w-4 mr-2">
185
+ <span id="uiExplTarget">Language to Practice</span>
186
+ </label>
187
+ </div>
188
  </div>
 
189
  </div>
190
+ </details>
191
+
192
+ <!-- Language Options (Source is Hidden programmatically) -->
193
+ <div class="flex flex-col sm:flex-row gap-3 mb-5 items-end">
194
+ <div id="srcLangContainer" class="hidden">
195
+ <label id="uiSourceLangLabel" class="block text-[10px] font-bold text-slate-500 uppercase tracking-wider mb-1.5">🌍 Source Language (Native)</label>
196
+ <select id="srcLang" class="w-full p-2 border border-slate-200 rounded-xl text-xs bg-white outline-none">
197
+ <option value="English">English</option>
198
+ <option value="Spanish">Spanish</option>
199
+ <option value="French">French</option>
200
+ <option value="German">German</option>
201
+ <option value="Chinese">Chinese</option>
202
+ <option value="Japanese">Japanese</option>
203
+ <option value="Korean">Korean</option>
204
+ <option value="Russian">Russian</option>
205
+ <option value="Portuguese">Portuguese</option>
206
+ <option value="Italian">Italian</option>
207
+ </select>
208
+ </div>
209
+ <div class="flex-1 w-full">
210
+ <label id="uiTargetLangLabel" class="block text-[10px] font-bold text-slate-600 uppercase tracking-wider mb-1.5">🎯 Target Language to Practice</label>
211
+ <select id="tgtLang" class="w-full p-3 border border-slate-200 rounded-xl text-xs font-semibold bg-slate-50 text-slate-800 outline-none">
212
+ <!-- Filled dynamically based on chosen App Language -->
213
+ </select>
214
+ </div>
215
+ <button id="translateBtn" class="w-full sm:w-auto px-6 py-3 bg-indigo-600 hover:bg-indigo-700 active:translate-y-0.5 text-white font-bold text-xs rounded-xl shadow-xs transition-all">⚡ Generate Vocabulary</button>
216
+ </div>
217
 
218
+ <!-- Vocabulary Table Scroll Container (Touch/Swipe Optimized for Mobile Devices) -->
219
+ <div class="overflow-x-auto w-full rounded-xl border border-slate-200 shadow-xs" style="-webkit-overflow-scrolling: touch; touch-action: pan-x pan-y;">
220
+ <table class="min-w-full divide-y divide-slate-200 text-xs table-auto">
221
+ <thead class="bg-slate-50">
222
+ <tr>
223
+ <th id="thOriginal" class="px-4 py-3 text-left text-[10px] font-bold text-slate-500 uppercase tracking-wider">Target Word</th>
224
+ <th id="thTranslation" class="px-4 py-3 text-left text-[10px] font-bold text-slate-500 uppercase tracking-wider">Translation</th>
225
+ <th id="thExplanation" class="px-4 py-3 text-left text-[10px] font-bold text-slate-500 uppercase tracking-wider max-w-xs">Contextual Definition</th>
226
+ <th id="thVisual" class="px-4 py-3 text-center text-[10px] font-bold text-slate-500 uppercase tracking-wider w-24">Visual Card</th>
227
+ <th id="thAudio" class="px-4 py-3 text-center text-[10px] font-bold text-slate-500 uppercase tracking-wider w-20">Pronunciation</th>
228
+ </tr>
229
+ </thead>
230
+ <tbody id="resultsBody" class="bg-white divide-y divide-slate-100">
231
+ <tr>
232
+ <td colspan="5" id="tdInitialMsg" class="px-4 py-12 text-center text-xs font-semibold text-slate-400">Configure preferences and generate vocabulary above to populate target dataset.</td>
233
+ </tr>
234
+ </tbody>
235
+ </table>
236
+ </div>
237
+ </div>
238
+
239
+ <!-- TAB 2: Games Hub -->
240
+ <div id="tabGamesContent" class="hidden">
241
+ <!-- Game Selection Panel -->
242
+ <div id="gamesMenu">
243
+ <h3 id="uiGameSelectionTitle" class="text-sm font-bold text-slate-800 mb-4">Select Your Practice Exercise</h3>
244
+
245
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
246
+ <!-- Flashcard Memory Match Selection Card -->
247
+ <div class="border border-slate-200 bg-slate-50/40 rounded-xl p-5 hover:shadow-xs transition-all duration-200 flex flex-col justify-between">
248
+ <div>
249
+ <div class="text-2xl mb-2">🧩</div>
250
+ <h4 id="uiGameMemoryTitle" class="text-xs font-bold text-slate-800 mb-1">Interactive Memory Association</h4>
251
+ <p id="uiGameMemoryDesc" class="text-[11px] text-slate-500 font-medium mb-3 leading-relaxed">Match target terms with their translated counterparts and generated visual cards to reinforce semantic retention.</p>
252
+ </div>
253
+ <button id="playMemoryBtn" class="w-full py-2 bg-indigo-600 hover:bg-indigo-700 active:translate-y-0.5 text-white rounded-xl text-[10px] font-semibold transition-all cursor-pointer shadow-xs">Start Practice</button>
254
  </div>
 
 
255
 
256
+ <!-- Word Monster Selection Card -->
257
+ <div class="border border-slate-200 bg-slate-50/40 rounded-xl p-5 hover:shadow-xs transition-all duration-200 flex flex-col justify-between">
258
+ <div>
259
+ <div class="text-2xl mb-2">👾</div>
260
+ <h4 id="uiGameMonsterTitle" class="text-xs font-bold text-slate-800 mb-1">Target Word Association (Word Monster)</h4>
261
+ <p id="uiGameMonsterDesc" class="text-[11px] text-slate-500 font-medium mb-3 leading-relaxed">Select and present the appropriate translation card that accurately matches the requested target concept.</p>
262
+ </div>
263
+ <button id="playMonsterBtn" class="w-full py-2 bg-indigo-600 hover:bg-indigo-700 active:translate-y-0.5 text-white rounded-xl text-[10px] font-semibold transition-all cursor-pointer shadow-xs">Start Practice</button>
264
  </div>
 
 
265
 
266
+ <!-- Audio-Visual Quiz Selection Card -->
267
+ <div class="border border-slate-200 bg-slate-50/40 rounded-xl p-5 hover:shadow-xs transition-all duration-200 flex flex-col justify-between">
268
+ <div>
269
+ <div class="text-2xl mb-2">🏆</div>
270
+ <h4 id="uiGameQuizTitle" class="text-xs font-bold text-slate-800 mb-1">Acoustic & Visual Assessment</h4>
271
+ <p id="uiGameQuizDesc" class="text-[11px] text-slate-500 font-medium mb-3 leading-relaxed">Examine the audio pronunciation or visual cue and identify the correct matching term from multiple choices.</p>
272
+ </div>
273
+ <button id="playQuizBtn" class="w-full py-2 bg-indigo-600 hover:bg-indigo-700 active:translate-y-0.5 text-white rounded-xl text-[10px] font-semibold transition-all cursor-pointer shadow-xs">Start Practice</button>
274
+ </div>
275
+
276
+ <!-- Scrambled Word Selection Card -->
277
+ <div class="border border-slate-200 bg-slate-50/40 rounded-xl p-5 hover:shadow-xs transition-all duration-200 flex flex-col justify-between">
278
+ <div>
279
+ <div class="text-2xl mb-2">✏️</div>
280
+ <h4 id="uiGameScrambleTitle" class="text-xs font-bold text-slate-800 mb-1">Orthographic Word Reconstruction</h4>
281
+ <p id="uiGameScrambleDesc" class="text-[11px] text-slate-500 font-medium mb-3 leading-relaxed">Reassemble scrambled character sequences into the correct spelling of the translated target term.</p>
282
+ </div>
283
+ <button id="playScrambleBtn" class="w-full py-2 bg-indigo-600 hover:bg-indigo-700 active:translate-y-0.5 text-white rounded-xl text-[10px] font-semibold transition-all cursor-pointer shadow-xs">Start Practice</button>
284
+ </div>
285
+
286
+ <!-- Visual Word Linker Selection Card -->
287
+ <div class="border border-slate-200 bg-slate-50/40 rounded-xl p-5 hover:shadow-xs transition-all duration-200 flex flex-col justify-between">
288
+ <div>
289
+ <div class="text-2xl mb-2">🔗</div>
290
+ <h4 id="uiGameLinkerTitle" class="text-xs font-bold text-slate-800 mb-1">Visual Term Correspondence Mapping</h4>
291
+ <p id="uiGameLinkerDesc" class="text-[11px] text-slate-500 font-medium mb-3 leading-relaxed">Perform bilateral matching between generated visual cues and target practice words to solidify associations.</p>
292
+ </div>
293
+ <button id="playLinkerBtn" class="w-full py-2 bg-indigo-600 hover:bg-indigo-700 active:translate-y-0.5 text-white rounded-xl text-[10px] font-semibold transition-all cursor-pointer shadow-xs">Start Practice</button>
294
  </div>
 
295
  </div>
296
  </div>
 
297
 
298
+ <!-- Active Game Stage -->
299
+ <div id="gameStage" class="hidden border border-slate-200 rounded-xl p-5 bg-white shadow-xs">
300
+ <div class="flex justify-between items-center mb-5 pb-2 border-b border-slate-100">
301
+ <button id="backToMenuBtn" class="text-xs font-bold text-slate-400 hover:text-indigo-600 transition-all outline-none">← Back to Menu</button>
302
+ <div id="gameScoreDisplay" class="text-xs font-bold text-indigo-600 bg-indigo-50 px-4 py-1.5 rounded-full">Score: 0</div>
303
+ </div>
304
+ <div id="gameArea"></div>
305
  </div>
 
306
  </div>
307
  </div>
308
  </div>
309
 
310
  <!-- Modal for full size image preview -->
311
+ <div id="imageModal" class="hidden fixed inset-0 bg-slate-900/60 flex items-center justify-center p-4 z-50 transition-opacity" onclick="closeModal()">
312
+ <div class="bg-white p-6 rounded-2xl shadow-xl max-w-sm w-full border border-slate-200 flex flex-col items-center" onclick="event.stopPropagation()">
313
+ <h3 id="modalTitle" class="text-base font-bold text-slate-900 mb-4 capitalize">Word Card</h3>
314
+ <img id="modalImage" class="w-64 h-64 border border-slate-100 rounded-xl shadow-inner object-contain bg-slate-50" src="" alt="Full preview">
315
+ <button class="mt-5 px-6 py-2 bg-slate-50 hover:bg-slate-100 active:translate-y-0.5 rounded-xl text-xs font-bold text-slate-700 transition-all border border-slate-200" onclick="closeModal()">Close</button>
316
  </div>
317
  </div>
318
 
 
416
 
417
  document.getElementById("uiTitle").innerText = loc.title;
418
  document.getElementById("uiSubtitle").innerText = loc.subtitle;
419
+ document.getElementById("uiTutorial").innerHTML = loc.tutorial_text;
420
  document.getElementById("uiSettingsTitle").firstElementChild.innerText = loc.settings;
421
  document.getElementById("uiWordCountLabel").innerText = loc.word_count_label;
422
  document.getElementById("uiExplLangLabel").innerText = loc.expl_lang_label;
 
447
  document.getElementById("uiExplTarget").innerText = loc.target_lang;
448
  }
449
 
450
+ // 3. Tab Switching events with clean layouts
451
  tabVocabBtn.addEventListener("click", () => {
452
  tabVocabContent.classList.replace("hidden", "block");
453
  tabGamesContent.classList.replace("block", "hidden");
454
+ tabVocabBtn.className = "bg-indigo-600 text-white shadow-xs rounded-xl px-4 py-2 font-bold text-xs transition-all outline-none";
455
+ tabGamesBtn.className = "bg-white text-slate-600 hover:bg-slate-50 border border-slate-200 rounded-xl px-4 py-2 font-bold text-xs transition-all outline-none";
456
  });
457
 
458
  tabGamesBtn.addEventListener("click", () => {
459
  tabVocabContent.classList.replace("block", "hidden");
460
  tabGamesContent.classList.replace("hidden", "block");
461
+ tabGamesBtn.className = "bg-indigo-600 text-white shadow-xs rounded-xl px-4 py-2 font-bold text-xs transition-all outline-none";
462
+ tabVocabBtn.className = "bg-white text-slate-600 hover:bg-slate-50 border border-slate-200 rounded-xl px-4 py-2 font-bold text-xs transition-all outline-none";
463
  });
464
 
465
  wordCount.addEventListener("input", (e) => {
 
479
 
480
  resultsBody.innerHTML = `
481
  <tr>
482
+ <td colspan="5" class="px-4 py-12 text-center text-xs text-indigo-600 font-semibold">
483
+ <span class="inline-block animate-pulse text-xs mb-1"> Processing Multimodal Vocab Generation...</span>
484
+ <div class="text-[10px] text-slate-400 font-medium">Generating explanations, visual context, and native audio tracks sequentially...</div>
485
  </td>
486
  </tr>
487
  `;
 
495
  window.loadedVocabulary.forEach(row => {
496
  const [original, translated, explanation, visualB64, audioB64] = row;
497
  const tr = document.createElement("tr");
498
+ tr.className = "hover:bg-slate-50 transition-colors";
499
 
500
  tr.innerHTML = `
501
+ <td class="px-4 py-4 text-slate-800 font-semibold text-xs">${original}</td>
502
+ <td class="px-4 py-4 text-indigo-600 font-bold text-sm">${translated}</td>
503
+ <td class="px-4 py-4 text-slate-500 text-[11px] font-medium leading-relaxed max-w-xs break-words">${explanation}</td>
504
+ <td class="px-4 py-4 text-center">
505
  ${visualB64 ? `
506
  <div class="relative inline-block group">
507
  <img src="data:image/png;base64,${visualB64}"
508
+ class="w-10 h-10 mx-auto rounded-lg border border-slate-200 shadow-xs hover:scale-105 active:scale-95 cursor-pointer transition-transform duration-150 object-cover"
509
  alt="${translated}"
510
  data-src="data:image/png;base64,${visualB64}"
511
  data-word="${translated}">
512
  </div>
513
  ` : '-'}
514
  </td>
515
+ <td class="px-4 py-4 text-center">
516
+ <button class="play-preload-btn w-8 h-8 bg-slate-50 hover:bg-indigo-50 hover:text-indigo-600 border border-slate-200 active:translate-y-0.5 rounded-full flex items-center justify-center text-xs transition-transform duration-100"
517
  data-audio="data:audio/mp3;base64,${audioB64}">
518
  🔊
519
  </button>
 
545
  } catch (error) {
546
  resultsBody.innerHTML = `
547
  <tr>
548
+ <td colspan="5" class="px-4 py-8 text-center text-xs text-red-500 font-medium">
549
+ Error generating vocabulary: ${error.message}
550
  </td>
551
  </tr>
552
  `;