eaglelandsonce commited on
Commit
9678889
Β·
verified Β·
1 Parent(s): 525fb42

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +435 -18
index.html CHANGED
@@ -1,19 +1,436 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  </html>
 
1
+ <!DOCTYPE html>
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>Microservices Strategies Jeopardy</title>
7
+ <style>
8
+ :root{
9
+ --blue:#0a49a6;
10
+ --blue-dark:#073a84;
11
+ --gold:#ffd24a;
12
+ --board-gap:10px;
13
+ --card-depth:28px;
14
+ }
15
+ *{box-sizing:border-box}
16
+ body{
17
+ font-family: system-ui, Arial, sans-serif;
18
+ display:flex;flex-direction:column;align-items:center;
19
+ background: radial-gradient(1200px 700px at 50% -200px, #f2f6ff 0%, #e9efff 30%, #cfdafc 100%) fixed;
20
+ margin:0; min-height:100vh;
21
+ }
22
+ h1{ color:#173e8c; margin:22px 0 6px; text-shadow:0 2px 0 #fff;}
23
+ a.source{ font-size:14px; color:#334; margin-bottom:8px; text-decoration:none}
24
+ a.source:hover{ text-decoration:underline }
25
+ .topbar {
26
+ width:min(1100px,95vw);
27
+ display:flex;
28
+ justify-content:space-between;
29
+ align-items:center;
30
+ gap:10px;
31
+ margin-bottom:8px;
32
+ }
33
+ .btn-reset{
34
+ padding:8px 12px; border-radius:10px; font-weight:800; cursor:pointer;
35
+ border:2px solid #0d3a85; color:#fff; background:linear-gradient(180deg,#1362ff,#0d3a85);
36
+ box-shadow:0 8px 18px rgba(0,0,0,.25);
37
+ }
38
+ .btn-reset:hover{ transform: translateY(-1px) }
39
+ .btn-reset:active{ transform: translateY(0) }
40
+ .stage{ perspective: 1200px; width:min(1100px, 95vw); }
41
+ #game-board{
42
+ display:grid;
43
+ grid-template-columns: repeat(5, 1fr);
44
+ grid-auto-rows: 120px;
45
+ gap: var(--board-gap);
46
+ padding: var(--board-gap);
47
+ border-radius:18px;
48
+ background: linear-gradient(180deg, #0e1a3a, #01060f);
49
+ box-shadow:
50
+ 0 20px 45px rgba(0,0,0,.35),
51
+ inset 0 0 0 4px #000;
52
+ transform: rotateX(8deg);
53
+ transform-origin: top center;
54
+ }
55
+ .category, .card{
56
+ position:relative;
57
+ border-radius:14px;
58
+ user-select:none;
59
+ transform-style: preserve-3d;
60
+ transition: transform .2s ease, box-shadow .2s ease, filter .2s ease;
61
+ box-shadow:
62
+ 0 var(--card-depth) calc(var(--card-depth) + 12px) rgba(0,0,0,.35),
63
+ inset 0 0 0 1px rgba(255,255,255,.15);
64
+ }
65
+ .category{
66
+ background: linear-gradient(180deg, #004fbf 0%, #003d93 60%, #003684 100%);
67
+ color:#fff; font-weight:800; text-transform:uppercase; letter-spacing:.3px;
68
+ display:flex; justify-content:center; align-items:center; text-align:center;
69
+ border:1px solid #00122c;
70
+ text-shadow:0 2px 0 rgba(0,0,0,.35);
71
+ padding:8px;
72
+ }
73
+ .card{
74
+ cursor:pointer; font-weight:900; color: var(--gold);
75
+ background:
76
+ radial-gradient(80% 80% at 50% 25%, rgba(255,255,255,.18), rgba(255,255,255,0) 60%),
77
+ linear-gradient(180deg, var(--blue) 0%, var(--blue-dark) 100%);
78
+ border:1px solid #031b3f;
79
+ display:flex; justify-content:center; align-items:center; text-align:center;
80
+ font-size: clamp(16px, 2.4vw, 26px);
81
+ text-shadow: 0 2px 0 #000, 0 0 10px rgba(255,210,74,.35);
82
+ padding:10px;
83
+ }
84
+ .card.tilt:hover{
85
+ transform: translateZ(10px) rotateX(var(--rx,0deg)) rotateY(var(--ry,0deg));
86
+ box-shadow:
87
+ 0 24px 48px rgba(0,0,0,.4),
88
+ 0 0 24px rgba(255,210,74,.15),
89
+ inset 0 0 0 1px rgba(255,255,255,.18);
90
+ filter: saturate(1.1);
91
+ }
92
+ .card:active{ transform: translateZ(0) scale(.985); box-shadow: 0 12px 18px rgba(0,0,0,.45), inset 0 0 0 1px rgba(255,255,255,.12); }
93
+ .card.disabled{ cursor:default; color:#bfc7da; background: linear-gradient(180deg,#6b7aa6,#4e5b85); text-shadow:none; filter:grayscale(.2) brightness(.92); }
94
+ #question-display{ width:min(1000px, 92vw); text-align:center; margin:16px 0 6px; }
95
+ #question-display h2{ margin:8px 0 6px; color:#0d2b6f }
96
+ #question-display p { font-size: 22px; line-height: 1.4; }
97
+ #score{ font-size:24px; font-weight:800; color:#0d2b6f; margin:0 0 8px 0 }
98
+ .answer-container{ display:flex; justify-content:center; flex-wrap:wrap; gap:10px; margin-top:14px }
99
+ .answer-btn{
100
+ margin:0; padding:10px 16px; font-size:18px; cursor:pointer;
101
+ border:2px solid #0d3a85; border-radius:10px; font-weight:800; color:#fff;
102
+ background: linear-gradient(180deg,#1362ff,#0d3a85);
103
+ box-shadow: 0 8px 18px rgba(0,0,0,.25);
104
+ transition: transform .12s ease, box-shadow .12s ease, filter .12s ease;
105
+ }
106
+ .answer-btn:hover{ transform: translateY(-2px); box-shadow:0 12px 26px rgba(0,0,0,.28) }
107
+ .answer-btn:active{ transform: translateY(0); box-shadow:0 8px 18px rgba(0,0,0,.25) }
108
+ .answer-btn.disabled{ background:#aab4cc; color:#445; cursor:not-allowed; border-color:#889 }
109
+ .feedback{ margin-top:10px; font-size:18px; font-weight:800 }
110
+ .dd-overlay{
111
+ position: fixed; inset:0; display:none; align-items:center; justify-content:center;
112
+ z-index: 9999; pointer-events:none;
113
+ background: radial-gradient(60% 60% at 50% 50%, rgba(255,255,255,.08), rgba(0,0,0,.7));
114
+ animation: dd-bg 1.2s ease-in-out 2;
115
+ }
116
+ .dd-text{
117
+ font-size: clamp(40px, 7vw, 120px);
118
+ font-weight: 900; color:#ffe17a; letter-spacing:2px;
119
+ text-shadow:
120
+ 0 0 12px rgba(255,225,122,.9),
121
+ 0 0 40px rgba(255,225,122,.6),
122
+ 0 6px 0 #000;
123
+ animation: flash 1.2s steps(2, jump-none) 2, wobble .9s ease-in-out 2;
124
+ }
125
+ @keyframes flash{ 0%,49%{opacity:1;filter:drop-shadow(0 0 24px rgba(255,225,122,.85));} 50%,100%{opacity:0;filter:none;} }
126
+ @keyframes wobble{ 0%{transform:scale(1) rotate(0)} 50%{transform:scale(1.06) rotate(-2deg)} 100%{transform:scale(1) rotate(0)} }
127
+ @keyframes dd-bg{ 0%{background: radial-gradient(40% 40% at 50% 50%, rgba(255,255,255,.12), rgba(0,0,0,.9));} 100%{background: radial-gradient(60% 60% at 50% 50%, rgba(255,255,255,.08), rgba(0,0,0,.7));} }
128
+ .flash-ring{ position:absolute; inset:-3px; border-radius:14px; pointer-events:none; box-shadow:0 0 0 3px rgba(255,225,122,.95), 0 0 30px 6px rgba(255,225,122,.6); animation: ring 1.2s ease-in-out 2; }
129
+ @keyframes ring{ 0%{opacity:1;transform:scale(1)} 50%{opacity:.1;transform:scale(.96)} 100%{opacity:1;transform:scale(1)} }
130
+ .daily-double-banner{ color:#b30000; font-weight:900; font-size:22px; margin:8px 0 }
131
+ #review{
132
+ width:min(1000px, 92vw);
133
+ margin:14px 0 24px 0;
134
+ padding:12px;
135
+ background:#fff;
136
+ border:1px solid #ccd3e0;
137
+ border-radius:12px;
138
+ box-shadow:0 6px 20px rgba(0,0,0,.08);
139
+ }
140
+ #review h3{ margin:0 0 8px 0; color:#0d2b6f }
141
+ .missed{ margin:8px 0; text-align:left }
142
+ .missed .q{ font-weight:700 }
143
+ .missed .a{ margin-left:8px }
144
+ </style>
145
+ </head>
146
+ <body>
147
+ <h1>Microservices Strategies Jeopardy</h1>
148
+ <a class="source" href="https://www.linkedin.com/pulse/transitioning-microservices-challenges-strategies-emerging-lively-8z54e/" target="_blank">
149
+ Source: Transitioning to Microservices β€” Challenges, Strategies & Emerging Patterns (LinkedIn)
150
+ </a>
151
+
152
+ <div class="topbar">
153
+ <div id="score">Score: 0</div>
154
+ <button class="btn-reset" id="reset-btn" title="Start a fresh round">Reset Game</button>
155
+ </div>
156
+
157
+ <div class="stage">
158
+ <div id="game-board">
159
+ <div class="category">Adoption Challenges</div>
160
+ <div class="category">Transition Strategies</div>
161
+ <div class="category">Business Drivers</div>
162
+ <div class="category">DevOps & Observability</div>
163
+ <div class="category">DOMA & Case Study</div>
164
+ <!-- cards injected -->
165
+ </div>
166
+ </div>
167
+
168
+ <div id="question-display"></div>
169
+ <div id="review" style="display:none;"></div>
170
+
171
+ <audio id="dd-audio" preload="auto">
172
+ <source src="daily-double.mp3" type="audio/mpeg">
173
+ </audio>
174
+ <div id="dd-overlay" class="dd-overlay"><div class="dd-text">DAILY&nbsp;DOUBLE!</div></div>
175
+
176
+ <script>
177
+ const categories = [
178
+ "Adoption Challenges",
179
+ "Transition Strategies",
180
+ "Business Drivers",
181
+ "DevOps & Observability",
182
+ "DOMA & Case Study"
183
+ ];
184
+
185
+ // 15 questions, correct indices evenly distributed: five 0s, five 1s, five 2s
186
+ const questions = [
187
+ // Adoption Challenges
188
+ [
189
+ { q: "What makes service boundary design hard when moving from a monolith?", a: [
190
+ "You must define clear domain and data ownership to avoid a mini-monolith or a chatty mesh",
191
+ "Always make services as tiny as possible, regardless of coupling",
192
+ "Share one database among all services to keep things simple"
193
+ ], correct: 0 },
194
+ { q: "Which approach reflects modern microservices security?", a: [
195
+ "Implicit trust inside the cluster is fine; service calls don’t need auth",
196
+ "Zero Trust: every service-to-service call is authenticated/authorized; avoid shared databases",
197
+ "A single global API key in an environment variable is sufficient"
198
+ ], correct: 1 },
199
+ { q: "Why is testing harder with microservices than with a monolith?", a: [
200
+ "Only unit tests are needed for each service",
201
+ "End-to-end tests replace all other test types",
202
+ "Each service needs unit, integration, and contract tests; dependencies increase CI/CD complexity"
203
+ ], correct: 2 }
204
+ ],
205
+
206
+ // Transition Strategies
207
+ [
208
+ { q: "The Strangler Pattern primarily aims to:", a: [
209
+ "Incrementally replace monolith features with new services while both systems coexist",
210
+ "Fork the monolith into multiple teams without architectural change",
211
+ "Freeze the monolith and expose it only via a single proxy forever"
212
+ ], correct: 0 },
213
+ { q: "The Lego Method focuses on:", a: [
214
+ "Deleting the monolith before any new code ships",
215
+ "Augmenting the monolith with new microservices, retiring pieces over time",
216
+ "Migrating the database first and leaving services for later"
217
+ ], correct: 1 },
218
+ { q: "The Nuclear Method is best described as:", a: [
219
+ "Writing wrappers around the monolith only",
220
+ "Gradually extracting one module at a time",
221
+ "A greenfield rebuild while the monolith continues running (high risk/high reward)"
222
+ ], correct: 2 }
223
+ ],
224
+
225
+ // Business Drivers
226
+ [
227
+ { q: "How do microservices improve uptime?", a: [
228
+ "They isolate failures, limiting the blast radius to a single service",
229
+ "They bundle all features into one release to reduce change",
230
+ "They remove the need for monitoring in production"
231
+ ], correct: 0 },
232
+ { q: "Which agility benefit is unique to microservices?", a: [
233
+ "Quarterly synchronized releases are easier",
234
+ "Independent service deployments accelerate feature delivery",
235
+ "All services must deploy together to avoid drift"
236
+ ], correct: 1 },
237
+ { q: "How does service scoping aid information sharing?", a: [
238
+ "Central enterprise data layers required for all reads/writes",
239
+ "Each service exposes only data it needs; services map to business capabilities",
240
+ "All services share a single schema to guarantee consistency"
241
+ ], correct: 2 }
242
+ ],
243
+
244
+ // DevOps & Observability
245
+ [
246
+ { q: "Why are DevOps practices essential for microservices?", a: [
247
+ "Automated CI/CD and team ownership keep many services deployable and healthy",
248
+ "They replace the need for tests entirely",
249
+ "They allow once-a-year release cycles"
250
+ ], correct: 0 },
251
+ { q: "What reflects modern observability in 2025?", a: [
252
+ "Single-host log tailing is enough for distributed systems",
253
+ "Aggregated logs, metrics, and traces with eBPF/AI-driven anomaly detection",
254
+ "Manual dashboards updated monthly"
255
+ ], correct: 1 },
256
+ { q: "Why is Kubernetes commonly used with microservices?", a: [
257
+ "It eliminates the need for containers",
258
+ "It stores all service data by default",
259
+ "It orchestrates scheduling, scaling, and self-healing across many containerized services"
260
+ ], correct: 2 }
261
+ ],
262
+
263
+ // DOMA & Case Study
264
+ [
265
+ { q: "What is Domain-Oriented Microservices Architecture (DOMA)?", a: [
266
+ "Grouping services by business domains with minimized cross-domain chatter via gateways",
267
+ "A single massive service per company to simplify governance",
268
+ "Only using databases named after domains"
269
+ ], correct: 0 },
270
+ { q: "Why did Uber move away from a monolith?", a: [
271
+ "They wanted fewer features to manage",
272
+ "Global growth made the monolith a bottleneck; they needed independent deployments and scale",
273
+ "They had no REST APIs to begin with"
274
+ ], correct: 1 },
275
+ { q: "How did Uber reduce complexity as services multiplied?", a: [
276
+ "By scaling the monolith vertically only",
277
+ "By forcing all inter-service calls through one global gateway",
278
+ "By organizing services into domains with dedicated gateways and clearer boundaries (DOMA)"
279
+ ], correct: 2 }
280
+ ]
281
+ ];
282
+
283
+ let score = 0, answered = 0;
284
+ const total = 15;
285
+ const board = document.getElementById("game-board"),
286
+ qdisp = document.getElementById("question-display"),
287
+ sdisp = document.getElementById("score"),
288
+ review = document.getElementById("review");
289
+ const ddOverlay = document.getElementById("dd-overlay");
290
+ const ddAudio = document.getElementById("dd-audio");
291
+ const shuffleRegistry = new Map();
292
+ const missedQuestions = [];
293
+ const dailyDouble = { col: Math.floor(Math.random() * 5), row: Math.floor(Math.random() * 3) };
294
+
295
+ document.getElementById('reset-btn').addEventListener('click', () => location.reload());
296
+
297
+ function createBoard() {
298
+ // header row already has categories; now inject 15 value cards
299
+ for (let row = 0; row < 3; row++) {
300
+ for (let col = 0; col < 5; col++) {
301
+ const card = document.createElement("div");
302
+ card.className = "card tilt";
303
+ card.textContent = `$${(row + 1) * 100}`;
304
+ card.dataset.col = col;
305
+ card.dataset.row = row;
306
+ card.addEventListener("mousemove", (e) => {
307
+ const r = card.getBoundingClientRect();
308
+ const x = (e.clientX - r.left) / r.width;
309
+ const y = (e.clientY - r.top) / r.height;
310
+ card.style.setProperty("--ry", `${(x - 0.5) * 10}deg`);
311
+ card.style.setProperty("--rx", `${(0.5 - y) * 10}deg`);
312
+ });
313
+ card.addEventListener("mouseleave", () => {
314
+ card.style.removeProperty("--ry");
315
+ card.style.removeProperty("--rx");
316
+ });
317
+ card.onclick = () => handleCardClick(card);
318
+ board.appendChild(card);
319
+ }
320
+ }
321
+ }
322
+
323
+ function handleCardClick(card){
324
+ if (card.classList.contains("disabled")) return;
325
+ const col = +card.dataset.col;
326
+ const row = +card.dataset.row;
327
+ const isDD = (col === dailyDouble.col && row === dailyDouble.row);
328
+ if (isDD){
329
+ triggerDailyDouble(card, () => showQuestion(col, row, card, true));
330
+ } else {
331
+ showQuestion(col, row, card, false);
332
+ }
333
+ }
334
+
335
+ function triggerDailyDouble(card, onDone){
336
+ const ring = document.createElement("div");
337
+ ring.className = "flash-ring";
338
+ card.appendChild(ring);
339
+ ddAudio.currentTime = 0;
340
+ ddAudio.play().catch(()=>{});
341
+ ddOverlay.style.display = "flex";
342
+ setTimeout(() => {
343
+ ddOverlay.style.display = "none";
344
+ ring.remove();
345
+ onDone();
346
+ }, 2400);
347
+ }
348
+
349
+ function showQuestion(categoryIndex, difficulty, card, isDailyDouble){
350
+ const q = questions[categoryIndex][difficulty];
351
+ const options = q.a.map((text, origIdx) => ({ text, origIdx }));
352
+ // shuffle options for display
353
+ for (let i = options.length - 1; i > 0; i--) {
354
+ const j = Math.floor(Math.random() * (i + 1));
355
+ [options[i], options[j]] = [options[j], options[i]];
356
+ }
357
+ const shuffledCorrectIndex = options.findIndex(o => o.origIdx === q.correct);
358
+ const key = `${categoryIndex}-${difficulty}`;
359
+ shuffleRegistry.set(key, { shuffledCorrectIndex, isDailyDouble });
360
+
361
+ const dailyDoubleBanner = isDailyDouble ? `<div class="daily-double-banner">πŸŽ‰ DAILY DOUBLE! πŸŽ‰</div>` : "";
362
+ qdisp.innerHTML = `
363
+ ${dailyDoubleBanner}
364
+ <h2>${categories[categoryIndex]} for $${(difficulty + 1) * 100}${isDailyDouble ? " (x2)" : ""}</h2>
365
+ <p>${q.q}</p>
366
+ <div class="answer-container">
367
+ ${options.map((opt, i) =>
368
+ `<button class="answer-btn" data-ans="${i}" data-key="${key}">${opt.text}</button>`
369
+ ).join("")}
370
+ </div>
371
+ `;
372
+ card.classList.add("disabled");
373
+ document.querySelectorAll('.answer-btn').forEach(btn => {
374
+ btn.addEventListener('click', () => {
375
+ if (btn.classList.contains('disabled')) return;
376
+ const chosenIndex = parseInt(btn.getAttribute('data-ans'), 10);
377
+ const k = btn.getAttribute('data-key');
378
+ checkAnswer(categoryIndex, difficulty, chosenIndex, k);
379
+ }, { once: true });
380
+ });
381
+ }
382
+
383
+ function checkAnswer(cat, diff, chosenShuffledIndex, key){
384
+ const q = questions[cat][diff];
385
+ const reg = shuffleRegistry.get(key);
386
+ const isCorrect = (chosenShuffledIndex === reg.shuffledCorrectIndex);
387
+ let val = (diff + 1) * 100;
388
+ if (reg.isDailyDouble) val *= 2;
389
+
390
+ document.querySelectorAll(".answer-btn").forEach(b => {
391
+ b.disabled = true; b.classList.add("disabled");
392
+ });
393
+
394
+ if (isCorrect) {
395
+ score += val;
396
+ qdisp.innerHTML += `<p class="feedback" style="color:green;">βœ… Correct! +$${val.toLocaleString()}</p>`;
397
+ } else {
398
+ score -= val;
399
+ const correctText = q.a[q.correct];
400
+ const chosenBtn = document.querySelector(`.answer-btn[data-ans="${chosenShuffledIndex}"][data-key="${key}"]`);
401
+ const chosenPretty = chosenBtn ? chosenBtn.textContent : "(your choice)";
402
+ qdisp.innerHTML += `<p class="feedback" style="color:#b00020;">❌ Wrong! βˆ’$${val.toLocaleString()}<br/>Correct answer: <em>${correctText}</em></p>`;
403
+ missedQuestions.push({
404
+ category: categories[cat],
405
+ value: `$${(diff+1)*100}${reg.isDailyDouble ? " (x2)" : ""}`,
406
+ question: q.q,
407
+ yourAnswer: chosenPretty,
408
+ correctAnswer: correctText
409
+ });
410
+ }
411
+ sdisp.textContent = `Score: ${score}`;
412
+ if (++answered === total) endGame();
413
+ }
414
+
415
+ function endGame(){
416
+ qdisp.innerHTML += `<h2 style="margin-top:12px">Game Over!</h2><p>Your final score: $${score.toLocaleString()}</p>`;
417
+ if (missedQuestions.length){
418
+ const items = missedQuestions.map(m =>
419
+ `<div class="missed">
420
+ <div class="q">(${m.category} β€’ ${m.value}) ${m.question}</div>
421
+ <div class="a">Your answer: <em>${m.yourAnswer}</em></div>
422
+ <div class="a">Correct: <strong>${m.correctAnswer}</strong></div>
423
+ </div>`
424
+ ).join("");
425
+ review.style.display = "block";
426
+ review.innerHTML = `<h3>Review: Questions to Revisit (${missedQuestions.length})</h3>${items}`;
427
+ } else {
428
+ review.style.display = "block";
429
+ review.innerHTML = `<h3>Perfect Round!</h3><p>You answered all questions correctly πŸŽ‰</p>`;
430
+ }
431
+ }
432
+
433
+ createBoard();
434
+ </script>
435
+ </body>
436
  </html>