eaglelandsonce commited on
Commit
f22fd2c
·
verified ·
1 Parent(s): 4b9875f

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +208 -53
index.html CHANGED
@@ -5,7 +5,149 @@
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
6
  <title>Simple Networking Jeopardy</title>
7
  <style>
8
- /* --- same CSS as your previous game, unchanged for brevity --- */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
  </style>
10
  </head>
11
  <body>
@@ -47,109 +189,110 @@
47
  "Private DNS"
48
  ];
49
 
 
50
  const questions = [
51
  // Hub & Spoke
52
  [
53
- { q: "What is the purpose of using a hub-and-spoke network in Azure?",
54
  a: [
55
- "To isolate workloads and centralize security and management",
56
- "To maximize outbound internet traffic without restriction",
57
- "To reduce virtual network peering performance"
58
  ], correct: 0 },
59
  { q: "Which network typically hosts shared services like Azure Firewall and DNS?",
60
  a: [
61
  "Hub network",
62
  "Spoke network",
63
- "Backend subnet"
64
  ], correct: 0 },
65
- { q: "Why connect hub and spoke networks using virtual network peering?",
66
  a: [
67
- "To enable secure communication between shared and application workloads",
68
- "To route all traffic directly to the public internet",
69
- "To disable subnet isolation"
70
  ], correct: 0 }
71
  ],
72
  // ASG & NSG
73
  [
74
- { q: "What is an Application Security Group (ASG) used for?",
75
  a: [
76
- "To simplify rule management for similar VMs",
77
- "To store DNS entries",
78
- "To encrypt storage accounts"
79
  ], correct: 0 },
80
- { q: "What does a Network Security Group (NSG) primarily do?",
81
  a: [
82
- "Filters inbound and outbound traffic using security rules",
83
- "Provides deep packet inspection",
84
- "Performs domain name resolution"
85
  ], correct: 0 },
86
- { q: "Why use both ASGs and NSGs together?",
87
  a: [
88
- "To apply fine-grained control and block unauthorized access between tiers",
89
- "To increase DNS query response times",
90
- "To disable subnet routing"
91
  ], correct: 0 }
92
  ],
93
  // Firewall
94
  [
95
- { q: "Where should the Azure Firewall be deployed in this architecture?",
96
  a: [
97
  "In the hub virtual network",
98
- "In each spoke’s backend subnet",
99
- "On every virtual machine"
100
  ], correct: 0 },
101
- { q: "What is one function of Azure Firewall application rules?",
102
  a: [
103
- "Allowing specific outbound FQDNs for updates",
104
- "Creating DNS zones for internal resolution",
105
- "Enforcing encryption for blob storage"
106
  ], correct: 0 },
107
- { q: "Why is centralized firewall protection important?",
108
  a: [
109
- "It ensures compliance, deep inspection, and centralized threat management",
110
- "It removes the need for network rules",
111
- "It limits internal visibility"
112
  ], correct: 0 }
113
  ],
114
  // Routing
115
  [
116
- { q: "What Azure feature enforces outbound traffic inspection through the firewall?",
117
  a: [
118
  "User-defined route (UDR) tables",
119
- "Network watcher flow logs",
120
- "Application Gateway"
121
  ], correct: 0 },
122
- { q: "Where should the custom route table be associated?",
123
  a: [
124
  "Frontend and backend subnets",
125
- "Only the hub network",
126
- "Azure DNS zone"
127
  ], correct: 0 },
128
- { q: "Why route all outbound traffic through the firewall?",
129
  a: [
130
- "To enforce consistent security and visibility of data leaving the network",
131
- "To improve public website performance",
132
- "To bypass Azure Policy controls"
133
  ], correct: 0 }
134
  ],
135
  // Private DNS
136
  [
137
  { q: "What is the purpose of a Private DNS Zone?",
138
  a: [
139
- "Provides internal name resolution without public exposure",
140
- "Improves internet-based name resolution speed",
141
- "Hosts firewall configuration policies"
142
  ], correct: 0 },
143
- { q: "Which record type is used to resolve internal VM names?",
144
  a: [
145
  "A-record",
146
  "MX-record",
147
- "CNAME-record"
148
  ], correct: 0 },
149
- { q: "Why link the Private DNS Zone to the virtual network?",
150
  a: [
151
- "To allow automatic DNS registration and internal communication",
152
- "To publish names to the public internet",
153
  "To disable DNS forwarding"
154
  ], correct: 0 }
155
  ]
@@ -157,6 +300,7 @@
157
 
158
  let score = 0, answered = 0;
159
  const total = 15;
 
160
  const board = document.getElementById("game-board"),
161
  qdisp = document.getElementById("question-display"),
162
  sdisp = document.getElementById("score"),
@@ -165,10 +309,14 @@
165
  const ddAudio = document.getElementById("dd-audio");
166
  const shuffleRegistry = new Map();
167
  const missedQuestions = [];
 
 
168
  const dailyDouble = { col: Math.floor(Math.random() * 5), row: Math.floor(Math.random() * 3) };
 
169
  document.getElementById('reset-btn').addEventListener('click', () => location.reload());
170
 
171
  function createBoard() {
 
172
  for (let row = 0; row < 3; row++) {
173
  for (let col = 0; col < 5; col++) {
174
  const card = document.createElement("div");
@@ -191,6 +339,7 @@
191
  board.appendChild(card);
192
  }
193
  }
 
194
  document.querySelector('.stage').style.visibility = 'visible';
195
  }
196
 
@@ -210,8 +359,7 @@
210
  const ring = document.createElement("div");
211
  ring.className = "flash-ring";
212
  card.appendChild(ring);
213
- ddAudio.currentTime = 0;
214
- ddAudio.play().catch(()=>{});
215
  ddOverlay.classList.add('active');
216
  ddOverlay.style.display = "flex";
217
  setTimeout(() => {
@@ -225,6 +373,7 @@
225
  function showQuestion(categoryIndex, difficulty, card, isDailyDouble){
226
  const q = questions[categoryIndex][difficulty];
227
  const options = q.a.map((text, origIdx) => ({ text, origIdx }));
 
228
  for (let i = options.length - 1; i > 0; i--) {
229
  const j = Math.floor(Math.random() * (i + 1));
230
  [options[i], options[j]] = [options[j], options[i]];
@@ -232,6 +381,7 @@
232
  const shuffledCorrectIndex = options.findIndex(o => o.origIdx === q.correct);
233
  const key = `${categoryIndex}-${difficulty}`;
234
  shuffleRegistry.set(key, { shuffledCorrectIndex, isDailyDouble });
 
235
  const dailyDoubleBanner = isDailyDouble ? `<div class="daily-double-banner">🎉 DAILY DOUBLE! 🎉</div>` : "";
236
  qdisp.innerHTML = `
237
  ${dailyDoubleBanner}
@@ -243,6 +393,7 @@
243
  ).join("")}
244
  </div>
245
  `;
 
246
  card.classList.add("disabled");
247
  document.querySelectorAll('.answer-btn').forEach(btn => {
248
  btn.addEventListener('click', () => {
@@ -260,9 +411,11 @@
260
  const isCorrect = (chosenShuffledIndex === reg.shuffledCorrectIndex);
261
  let val = (diff + 1) * 100;
262
  if (reg.isDailyDouble) val *= 2;
 
263
  document.querySelectorAll(".answer-btn").forEach(b => {
264
  b.disabled = true; b.classList.add("disabled");
265
  });
 
266
  if (isCorrect) {
267
  score += val;
268
  qdisp.innerHTML += `<p class="feedback" style="color:green;">✅ Correct! +$${val.toLocaleString()}</p>`;
@@ -280,6 +433,7 @@
280
  correctAnswer: correctText
281
  });
282
  }
 
283
  sdisp.textContent = `Score: ${score}`;
284
  if (++answered === total) endGame();
285
  }
@@ -302,6 +456,7 @@
302
  }
303
  }
304
 
 
305
  createBoard();
306
  </script>
307
  </body>
 
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
6
  <title>Simple Networking 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
+
41
+ /* Stage + board */
42
+ .stage{ perspective: 1200px; width:min(1100px, 95vw); visibility:hidden; }
43
+ #game-board{
44
+ display:grid;
45
+ grid-template-columns: repeat(5, 1fr);
46
+ grid-auto-rows: 120px;
47
+ gap: var(--board-gap);
48
+ padding: var(--board-gap);
49
+ border-radius:18px;
50
+ background: linear-gradient(180deg, #0e1a3a, #01060f);
51
+ box-shadow:
52
+ 0 20px 45px rgba(0,0,0,.35),
53
+ inset 0 0 0 4px #000;
54
+ transform: rotateX(8deg);
55
+ transform-origin: top center;
56
+ }
57
+ .category, .card{
58
+ position:relative;
59
+ border-radius:14px;
60
+ user-select:none;
61
+ transform-style: preserve-3d;
62
+ transition: transform .2s ease, box-shadow .2s ease, filter .2s ease;
63
+ box-shadow:
64
+ 0 var(--card-depth) calc(var(--card-depth) + 12px) rgba(0,0,0,.35),
65
+ inset 0 0 0 1px rgba(255,255,255,.15);
66
+ }
67
+ .category{
68
+ background: linear-gradient(180deg, #004fbf 0%, #003d93 60%, #003684 100%);
69
+ color:#fff; font-weight:800; text-transform:uppercase; letter-spacing:.3px;
70
+ display:flex; justify-content:center; align-items:center; text-align:center;
71
+ border:1px solid #00122c;
72
+ text-shadow:0 2px 0 rgba(0,0,0,.35);
73
+ padding:8px;
74
+ }
75
+ .card{
76
+ cursor:pointer; font-weight:900; color: var(--gold);
77
+ background:
78
+ radial-gradient(80% 80% at 50% 25%, rgba(255,255,255,.18), rgba(255,255,255,0) 60%),
79
+ linear-gradient(180deg, var(--blue) 0%, var(--blue-dark) 100%);
80
+ border:1px solid #031b3f;
81
+ display:flex; justify-content:center; align-items:center; text-align:center;
82
+ font-size: clamp(16px, 2.4vw, 26px);
83
+ text-shadow: 0 2px 0 #000, 0 0 10px rgba(255,210,74,.35);
84
+ padding:10px;
85
+ }
86
+ .card.tilt:hover{
87
+ transform: translateZ(10px) rotateX(var(--rx,0deg)) rotateY(var(--ry,0deg));
88
+ box-shadow:
89
+ 0 24px 48px rgba(0,0,0,.4),
90
+ 0 0 24px rgba(255,210,74,.15),
91
+ inset 0 0 0 1px rgba(255,255,255,.18);
92
+ filter: saturate(1.1);
93
+ }
94
+ .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); }
95
+ .card.disabled{ cursor:default; color:#bfc7da; background: linear-gradient(180deg,#6b7aa6,#4e5b85); text-shadow:none; filter:grayscale(.2) brightness(.92); }
96
+
97
+ #question-display{ width:min(1000px, 92vw); text-align:center; margin:16px 0 6px; }
98
+ #question-display h2{ margin:8px 0 6px; color:#0d2b6f }
99
+ #question-display p { font-size: 22px; line-height: 1.4; }
100
+ #score{ font-size:24px; font-weight:800; color:#0d2b6f; margin:0 0 8px 0 }
101
+
102
+ .answer-container{ display:flex; justify-content:center; flex-wrap:wrap; gap:10px; margin-top:14px }
103
+ .answer-btn{
104
+ margin:0; padding:10px 16px; font-size:18px; cursor:pointer;
105
+ border:2px solid #0d3a85; border-radius:10px; font-weight:800; color:#fff;
106
+ background: linear-gradient(180deg,#1362ff,#0d3a85);
107
+ box-shadow: 0 8px 18px rgba(0,0,0,.25);
108
+ transition: transform .12s ease, box-shadow .12s ease, filter .12s ease;
109
+ }
110
+ .answer-btn:hover{ transform: translateY(-2px); box-shadow:0 12px 26px rgba(0,0,0,.28) }
111
+ .answer-btn:active{ transform: translateY(0); box-shadow:0 8px 18px rgba(0,0,0,.25) }
112
+ .answer-btn.disabled{ background:#aab4cc; color:#445; cursor:not-allowed; border-color:#889 }
113
+ .feedback{ margin-top:10px; font-size:18px; font-weight:800 }
114
+
115
+ .dd-overlay{
116
+ position: fixed; inset:0; display:none; align-items:center; justify-content:center;
117
+ z-index: 9999; pointer-events:none;
118
+ background: radial-gradient(60% 60% at 50% 50%, rgba(255,255,255,.08), rgba(0,0,0,.7));
119
+ }
120
+ .dd-overlay.active{ animation: dd-bg 1.2s ease-in-out 2; }
121
+ .dd-text{
122
+ font-size: clamp(40px, 7vw, 120px);
123
+ font-weight: 900; color:#ffe17a; letter-spacing:2px;
124
+ text-shadow:
125
+ 0 0 12px rgba(255,225,122,.9),
126
+ 0 0 40px rgba(255,225,122,.6),
127
+ 0 6px 0 #000;
128
+ animation: flash 1.2s steps(2, jump-none) 2, wobble .9s ease-in-out 2;
129
+ }
130
+ @keyframes flash{ 0%,49%{opacity:1;filter:drop-shadow(0 0 24px rgba(255,225,122,.85));} 50%,100%{opacity:0;filter:none;} }
131
+ @keyframes wobble{ 0%{transform:scale(1) rotate(0)} 50%{transform:scale(1.06) rotate(-2deg)} 100%{transform:scale(1) rotate(0)} }
132
+ @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));} }
133
+ .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; }
134
+ @keyframes ring{ 0%{opacity:1;transform:scale(1)} 50%{opacity:.1;transform:scale(.96)} 100%{opacity:1;transform:scale(1)} }
135
+
136
+ .daily-double-banner{ color:#b30000; font-weight:900; font-size:22px; margin:8px 0 }
137
+
138
+ #review{
139
+ width:min(1000px, 92vw);
140
+ margin:14px 0 24px 0;
141
+ padding:12px;
142
+ background:#fff;
143
+ border:1px solid #ccd3e0;
144
+ border-radius:12px;
145
+ box-shadow:0 6px 20px rgba(0,0,0,.08);
146
+ }
147
+ #review h3{ margin:0 0 8px 0; color:#0d2b6f }
148
+ .missed{ margin:8px 0; text-align:left }
149
+ .missed .q{ font-weight:700 }
150
+ .missed .a{ margin-left:8px }
151
  </style>
152
  </head>
153
  <body>
 
189
  "Private DNS"
190
  ];
191
 
192
+ // 15 questions (3 per category). Correct answers randomized at click time.
193
  const questions = [
194
  // Hub & Spoke
195
  [
196
+ { q: "What is the main benefit of a hub-and-spoke network in Azure?",
197
  a: [
198
+ "Isolation of workloads with centralized security & management",
199
+ "Bypassing all security controls for faster internet access",
200
+ "Eliminating the need for subnets entirely"
201
  ], correct: 0 },
202
  { q: "Which network typically hosts shared services like Azure Firewall and DNS?",
203
  a: [
204
  "Hub network",
205
  "Spoke network",
206
+ "Frontend subnet"
207
  ], correct: 0 },
208
+ { q: "Why use VNet peering between hub and spoke?",
209
  a: [
210
+ "Secure communication between shared and application networks",
211
+ "Automatic public exposure of private endpoints",
212
+ "To disable routing between subnets"
213
  ], correct: 0 }
214
  ],
215
  // ASG & NSG
216
  [
217
+ { q: "What does an Application Security Group (ASG) help you do?",
218
  a: [
219
+ "Group similar VMs to simplify rule management",
220
+ "Create DNS zones for private name resolution",
221
+ "Encrypt disks at rest automatically"
222
  ], correct: 0 },
223
+ { q: "What is the primary role of a Network Security Group (NSG)?",
224
  a: [
225
+ "Filter inbound/outbound traffic with allow/deny rules",
226
+ "Provide deep packet inspection and threat intel",
227
+ "Host a reverse proxy for web apps"
228
  ], correct: 0 },
229
+ { q: "Why combine ASGs and NSGs on subnets and NICs?",
230
  a: [
231
+ "Fine-grained segmentation and blocking of unauthorized tier-to-tier access",
232
+ "To increase public DNS response times",
233
+ "To bypass route tables"
234
  ], correct: 0 }
235
  ],
236
  // Firewall
237
  [
238
+ { q: "Where is Azure Firewall placed in this design?",
239
  a: [
240
  "In the hub virtual network",
241
+ "Inside every spoke VM",
242
+ "In a public subnet of each spoke"
243
  ], correct: 0 },
244
+ { q: "What is a typical use of Azure Firewall application rules?",
245
  a: [
246
+ "Permit outbound FQDNs (e.g., Azure DevOps) for updates",
247
+ "Create A-records for VM names",
248
+ "Auto-scale a VM scale set"
249
  ], correct: 0 },
250
+ { q: "Why centralize protection with Azure Firewall?",
251
  a: [
252
+ "Deep inspection, threat intelligence, logging, and compliance",
253
+ "To remove the need for any NSGs",
254
+ "To disable hub-and-spoke peering"
255
  ], correct: 0 }
256
  ],
257
  // Routing
258
  [
259
+ { q: "What Azure feature forces outbound traffic to pass through the firewall?",
260
  a: [
261
  "User-defined route (UDR) tables",
262
+ "Private endpoint policies",
263
+ "NSG flow logs"
264
  ], correct: 0 },
265
+ { q: "Where should the route table be associated to enforce inspection?",
266
  a: [
267
  "Frontend and backend subnets",
268
+ "Only the hub VNet",
269
+ "The Private DNS zone"
270
  ], correct: 0 },
271
+ { q: "Why route all outbound traffic via the firewall?",
272
  a: [
273
+ "Consistent policy enforcement and full visibility of egress",
274
+ "To speed up public internet browsing",
275
+ "To bypass Azure Policy"
276
  ], correct: 0 }
277
  ],
278
  // Private DNS
279
  [
280
  { q: "What is the purpose of a Private DNS Zone?",
281
  a: [
282
+ "Internal name resolution without public exposure",
283
+ "Hosting WAF policies",
284
+ "Publicly advertising internal hostnames"
285
  ], correct: 0 },
286
+ { q: "Which record type is commonly used to resolve VM names internally?",
287
  a: [
288
  "A-record",
289
  "MX-record",
290
+ "NS-record"
291
  ], correct: 0 },
292
+ { q: "Why link the Private DNS Zone to the VNet (and enable auto-registration)?",
293
  a: [
294
+ "To allow internal name resolution and automatic record management",
295
+ "To publish records to the public internet",
296
  "To disable DNS forwarding"
297
  ], correct: 0 }
298
  ]
 
300
 
301
  let score = 0, answered = 0;
302
  const total = 15;
303
+
304
  const board = document.getElementById("game-board"),
305
  qdisp = document.getElementById("question-display"),
306
  sdisp = document.getElementById("score"),
 
309
  const ddAudio = document.getElementById("dd-audio");
310
  const shuffleRegistry = new Map();
311
  const missedQuestions = [];
312
+
313
+ // Random Daily Double position
314
  const dailyDouble = { col: Math.floor(Math.random() * 5), row: Math.floor(Math.random() * 3) };
315
+
316
  document.getElementById('reset-btn').addEventListener('click', () => location.reload());
317
 
318
  function createBoard() {
319
+ // Inject 3 rows x 5 cols of value cards
320
  for (let row = 0; row < 3; row++) {
321
  for (let col = 0; col < 5; col++) {
322
  const card = document.createElement("div");
 
339
  board.appendChild(card);
340
  }
341
  }
342
+ // Reveal after injection to avoid flash
343
  document.querySelector('.stage').style.visibility = 'visible';
344
  }
345
 
 
359
  const ring = document.createElement("div");
360
  ring.className = "flash-ring";
361
  card.appendChild(ring);
362
+ if (ddAudio) { try { ddAudio.currentTime = 0; ddAudio.play().catch(()=>{}); } catch(e){} }
 
363
  ddOverlay.classList.add('active');
364
  ddOverlay.style.display = "flex";
365
  setTimeout(() => {
 
373
  function showQuestion(categoryIndex, difficulty, card, isDailyDouble){
374
  const q = questions[categoryIndex][difficulty];
375
  const options = q.a.map((text, origIdx) => ({ text, origIdx }));
376
+ // Shuffle choices so the correct answer position is random each time
377
  for (let i = options.length - 1; i > 0; i--) {
378
  const j = Math.floor(Math.random() * (i + 1));
379
  [options[i], options[j]] = [options[j], options[i]];
 
381
  const shuffledCorrectIndex = options.findIndex(o => o.origIdx === q.correct);
382
  const key = `${categoryIndex}-${difficulty}`;
383
  shuffleRegistry.set(key, { shuffledCorrectIndex, isDailyDouble });
384
+
385
  const dailyDoubleBanner = isDailyDouble ? `<div class="daily-double-banner">🎉 DAILY DOUBLE! 🎉</div>` : "";
386
  qdisp.innerHTML = `
387
  ${dailyDoubleBanner}
 
393
  ).join("")}
394
  </div>
395
  `;
396
+
397
  card.classList.add("disabled");
398
  document.querySelectorAll('.answer-btn').forEach(btn => {
399
  btn.addEventListener('click', () => {
 
411
  const isCorrect = (chosenShuffledIndex === reg.shuffledCorrectIndex);
412
  let val = (diff + 1) * 100;
413
  if (reg.isDailyDouble) val *= 2;
414
+
415
  document.querySelectorAll(".answer-btn").forEach(b => {
416
  b.disabled = true; b.classList.add("disabled");
417
  });
418
+
419
  if (isCorrect) {
420
  score += val;
421
  qdisp.innerHTML += `<p class="feedback" style="color:green;">✅ Correct! +$${val.toLocaleString()}</p>`;
 
433
  correctAnswer: correctText
434
  });
435
  }
436
+
437
  sdisp.textContent = `Score: ${score}`;
438
  if (++answered === total) endGame();
439
  }
 
456
  }
457
  }
458
 
459
+ // Build board on load
460
  createBoard();
461
  </script>
462
  </body>