-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathword-train.html
More file actions
943 lines (888 loc) · 70.1 KB
/
Copy pathword-train.html
File metadata and controls
943 lines (888 loc) · 70.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
<title>Word Train</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Bubblegum+Sans&family=Comic+Neue:wght@400;700&display=swap">
<style>
:root{
--bg:#F1EFE8;
--bg-alt:#E7E3D6;
--card:#FFFEFA;
--ink:#232A3B;
--ink-soft:#5B6478;
--accent:#D64545;
--accent-ink:#7A2020;
--accent-soft:#F6D9D6;
--blue:#3E7CB1;
--blue-deep:#234C6E;
--blue-soft:#DCE8F2;
--yellow:#E8B34B;
--yellow-deep:#8A5E14;
--yellow-soft:#FBEBC9;
--good:#4C8C5A;
--good-soft:#E1EEE0;
--bad:#C1584A;
--bad-soft:#F5DED9;
--border:rgba(35,42,59,0.14);
--shadow:rgba(35,42,59,0.18);
--track:#6B6F76;
--wood:#8B5E34;
}
@media (prefers-color-scheme: dark){
:root:not([data-theme="light"]){
--bg:#181C24;
--bg-alt:#20242E;
--card:#1D212A;
--ink:#EDEBE2;
--ink-soft:#A6ABBB;
--accent:#E8746F;
--accent-ink:#FFD3CE;
--accent-soft:#3A2224;
--blue:#6FA8D6;
--blue-deep:#9FC6E8;
--blue-soft:#20303F;
--yellow:#F0C572;
--yellow-deep:#FBE2A8;
--yellow-soft:#39301A;
--good:#8DC79A;
--good-soft:#213328;
--bad:#E2917F;
--bad-soft:#3A241F;
--border:rgba(237,235,226,0.16);
--shadow:rgba(0,0,0,0.45);
--track:#9A9FA8;
--wood:#A87B4E;
}
}
:root[data-theme="dark"]{
--bg:#181C24;
--bg-alt:#20242E;
--card:#1D212A;
--ink:#EDEBE2;
--ink-soft:#A6ABBB;
--accent:#E8746F;
--accent-ink:#FFD3CE;
--accent-soft:#3A2224;
--blue:#6FA8D6;
--blue-deep:#9FC6E8;
--blue-soft:#20303F;
--yellow:#F0C572;
--yellow-deep:#FBE2A8;
--yellow-soft:#39301A;
--good:#8DC79A;
--good-soft:#213328;
--bad:#E2917F;
--bad-soft:#3A241F;
--border:rgba(237,235,226,0.16);
--shadow:rgba(0,0,0,0.45);
--track:#9A9FA8;
--wood:#A87B4E;
}
*{box-sizing:border-box;}
html,body{margin:0;padding:0;}
body{
background:
repeating-linear-gradient(90deg, transparent 0 38px, rgba(35,42,59,0.03) 38px 40px),
var(--bg);
color:var(--ink);
font-family:'Comic Neue', system-ui, sans-serif;
min-height:100vh;
display:flex;
justify-content:center;
padding:clamp(16px,4vw,40px) 16px;
}
@media (prefers-color-scheme: dark){
:root:not([data-theme="light"]) body{
background:
repeating-linear-gradient(90deg, transparent 0 38px, rgba(237,235,226,0.035) 38px 40px),
var(--bg);
}
}
:root[data-theme="dark"] body{
background:
repeating-linear-gradient(90deg, transparent 0 38px, rgba(237,235,226,0.035) 38px 40px),
var(--bg);
}
.app{ width:100%; max-width:560px; }
.eyebrow{
font-family:'Comic Neue',sans-serif;
font-weight:700;
font-size:0.78rem;
letter-spacing:0.12em;
text-transform:uppercase;
color:var(--blue-deep);
text-align:center;
margin:0 0 6px;
}
h1,h2,h3{font-family:'Bubblegum Sans', system-ui, sans-serif; text-wrap:balance; margin:0; font-weight:400;}
.card{
background:var(--card);
border:1px solid var(--border);
border-radius:24px;
box-shadow:0 18px 40px -18px var(--shadow), 0 2px 0 var(--border);
padding:clamp(22px,5vw,36px);
}
.screen{display:none;}
.screen.active{display:block; animation:rise 0.4s ease both;}
@media (prefers-reduced-motion: reduce){ .screen.active{animation:none;} }
@keyframes rise{ from{opacity:0; transform:translateY(10px);} to{opacity:1; transform:none;} }
/* ---- Home ---- */
.hero{text-align:center; margin-bottom:20px;}
.hero-title{font-size:clamp(2rem,7vw,2.6rem); color:var(--accent-ink); line-height:1.05;}
.hero-sub{font-size:1.02rem; color:var(--ink-soft); font-weight:700; margin-top:8px;}
.hero-scene{width:min(300px,78%); margin:16px auto 4px;}
.back-link{
background:none; border:none; cursor:pointer; padding:0 0 14px;
font-family:'Comic Neue',sans-serif; font-weight:700; font-size:0.85rem;
color:var(--blue-deep); display:inline-flex; align-items:center; gap:6px;
}
.back-link:focus-visible{outline:2px solid var(--blue-deep); outline-offset:3px;}
.back-link svg{width:16px; height:16px;}
.lesson-card{padding:16px 18px; margin-bottom:12px;}
.lesson-top{display:flex; align-items:center; gap:14px;}
.lesson-icon{width:52px; height:52px; flex:none;}
.lesson-info{flex:1; min-width:0;}
.lesson-tag-label{font-size:0.7rem; font-weight:700; text-transform:uppercase; letter-spacing:0.06em; color:var(--blue-deep);}
.lesson-title{font-family:'Bubblegum Sans',sans-serif; font-size:1.08rem; margin-top:2px; line-height:1.25;}
.mini-stars{display:flex; gap:2px; margin-top:6px;}
.mini-stars svg{width:15px; height:15px;}
.lesson-card .btn{margin-top:14px; padding:12px 16px; font-size:0.98rem; box-shadow:0 4px 0 var(--accent-ink), 0 7px 12px -6px var(--shadow);}
.final-card{border:2px solid var(--yellow); background:linear-gradient(135deg, var(--yellow-soft), var(--card));}
.final-badge{color:var(--yellow-deep);}
/* ---- Buttons ---- */
.btn{
font-family:'Bubblegum Sans', sans-serif;
font-size:1.1rem;
border:none;
border-radius:16px;
padding:16px 20px;
cursor:pointer;
color:#3A1414;
background:var(--accent);
box-shadow:0 6px 0 var(--accent-ink), 0 10px 18px -8px var(--shadow);
transition:transform 0.12s ease, box-shadow 0.12s ease;
width:100%;
}
.btn:hover{transform:translateY(-1px);}
.btn:active{transform:translateY(3px); box-shadow:0 3px 0 var(--accent-ink), 0 6px 12px -8px var(--shadow);}
.btn:focus-visible{outline:3px solid var(--blue-deep); outline-offset:3px;}
.btn.secondary{
background:transparent;
color:var(--blue-deep);
box-shadow:none;
border:2px solid var(--blue);
}
.btn.secondary:active{transform:translateY(1px);}
.btn-row{display:flex; gap:12px; margin-top:18px;}
.btn-row .btn{width:auto; flex:1;}
/* ---- Flashcards ---- */
.flash-dots{display:flex; justify-content:center; gap:8px; margin-bottom:18px;}
.flash-dots span{width:8px; height:8px; border-radius:50%; background:var(--border);}
.flash-dots span.on{background:var(--blue);}
.flash-icon{width:76px; height:76px; margin:0 auto 14px; display:block;}
.flash-lesson-label{text-align:center; font-size:0.78rem; font-weight:700; letter-spacing:0.06em; text-transform:uppercase; color:var(--ink-soft); margin-bottom:14px;}
.flash-title{font-size:1.3rem; font-family:'Bubblegum Sans',sans-serif; color:var(--blue-deep); text-align:center;}
.flash-text{font-size:1.12rem; line-height:1.55; text-align:center; margin-top:12px; color:var(--ink);}
/* ---- Quiz header ---- */
.quiz-head{display:flex; align-items:center; gap:14px; margin-bottom:18px;}
.quiz-train-mini{width:76px; height:44px; flex:none;}
.quiz-progress{flex:1;}
.quiz-progress-label{font-size:0.82rem; font-weight:700; color:var(--ink-soft); text-transform:uppercase; letter-spacing:0.06em;}
.track-bar{height:10px; border-radius:6px; background:var(--bg-alt); overflow:hidden; margin-top:6px; border:1px solid var(--border);}
.track-fill{height:100%; background:linear-gradient(90deg, var(--blue), var(--accent)); border-radius:6px; transition:width 0.4s ease;}
.q-kicker{font-size:0.78rem; font-weight:700; letter-spacing:0.08em; text-transform:uppercase; color:var(--blue-deep); margin-bottom:8px;}
.q-text{font-size:1.35rem; font-family:'Bubblegum Sans',sans-serif; line-height:1.3; margin-bottom:18px;}
.opt{
display:flex; align-items:center; gap:12px;
width:100%; text-align:left;
background:var(--bg-alt);
border:2px solid var(--border);
border-radius:16px;
padding:14px 16px;
font-family:'Comic Neue',sans-serif;
font-weight:700;
font-size:1.05rem;
color:var(--ink);
cursor:pointer;
margin-bottom:10px;
transition:border-color 0.15s ease, transform 0.1s ease, background 0.15s ease;
}
.opt:hover{border-color:var(--blue);}
.opt:active{transform:scale(0.99);}
.opt:focus-visible{outline:3px solid var(--blue-deep); outline-offset:2px;}
.opt .bullet{width:22px; height:22px; flex:none; border-radius:50%; border:2px solid var(--ink-soft); opacity:0.55;}
.opt.correct{background:var(--good-soft); border-color:var(--good); color:var(--ink);}
.opt.correct .bullet{border-color:var(--good); background:var(--good);}
.opt.wrong{background:var(--bad-soft); border-color:var(--bad);}
.opt.wrong .bullet{border-color:var(--bad); background:var(--bad);}
.opt[disabled]{cursor:default;}
.tf-row{display:flex; gap:14px;}
.tf-btn{
flex:1; padding:26px 10px; border-radius:16px; border:2px solid var(--border);
background:var(--bg-alt); font-family:'Bubblegum Sans',sans-serif; font-size:1.15rem;
display:flex; flex-direction:column; align-items:center; gap:8px; cursor:pointer; color:var(--ink);
transition:border-color 0.15s ease, transform 0.1s ease;
}
.tf-btn svg{width:34px; height:34px;}
.tf-btn:hover{border-color:var(--blue);}
.tf-btn:active{transform:scale(0.98);}
.tf-btn:focus-visible{outline:3px solid var(--blue-deep); outline-offset:2px;}
.tf-btn.correct{background:var(--good-soft); border-color:var(--good);}
.tf-btn.wrong{background:var(--bad-soft); border-color:var(--bad);}
.tf-btn[disabled]{cursor:default;}
.feedback{
margin-top:16px; padding:14px 16px; border-radius:16px; font-weight:700; font-size:1rem;
display:none; align-items:flex-start; gap:10px; line-height:1.45;
}
.feedback.show{display:flex; animation:pop 0.3s ease both;}
@media (prefers-reduced-motion: reduce){ .feedback.show{animation:none;} }
@keyframes pop{ from{opacity:0; transform:scale(0.95);} to{opacity:1; transform:none;} }
.feedback.good{background:var(--good-soft); color:var(--ink);}
.feedback.bad{background:var(--bad-soft); color:var(--ink);}
.feedback svg{width:22px; height:22px; flex:none; margin-top:1px;}
.next-wrap{margin-top:18px; display:none;}
.next-wrap.show{display:block;}
/* ---- Results ---- */
#screen-results .card{text-align:center;}
.result-train{width:min(280px,80%); margin:6px auto 8px;}
.stars{display:flex; justify-content:center; gap:6px; margin:10px 0 4px;}
.stars svg{width:38px; height:38px;}
.result-score{font-size:1.4rem; font-family:'Bubblegum Sans',sans-serif; color:var(--accent-ink); margin-top:6px;}
.result-msg{font-size:1.08rem; color:var(--ink-soft); font-weight:700; margin-top:8px; line-height:1.5;}
/* ---- Train SVG piece reveal ---- */
.piece{opacity:0; transform:scale(0.5); transform-box:fill-box; transform-origin:center; transition:opacity 0.35s ease, transform 0.35s cubic-bezier(.34,1.56,.64,1);}
.piece.revealed{opacity:1; transform:scale(1);}
@media (prefers-reduced-motion: reduce){ .piece{transition:opacity 0.2s ease;} .piece.revealed{transform:none;} }
.piece.base{opacity:1; transform:none; transition:none;}
</style>
<div class="app">
<p class="eyebrow">English 2 · Word Train</p>
<!-- HOME / LESSON MAP -->
<section id="screen-home" class="screen active">
<div class="hero">
<h1 class="hero-title">Word Train</h1>
<p class="hero-sub">Pick a lesson and keep the train rolling! Question and answer order shuffle every time, so you really have to know each answer — not just remember the order. Try the Final Mock Exam once you've finished every lesson!</p>
<svg class="hero-scene" viewBox="0 0 300 110" role="img" aria-label="A little train on a track">
<rect x="0" y="90" width="300" height="3" fill="var(--track)"/>
<g>
<rect x="216" y="52" width="34" height="26" rx="3" fill="var(--accent)"/>
<rect x="222" y="38" width="16" height="16" fill="var(--accent)"/>
<rect x="244" y="30" width="7" height="14" fill="var(--ink-soft)"/>
<circle cx="224" cy="80" r="6" fill="var(--ink)"/>
<circle cx="242" cy="80" r="6" fill="var(--ink)"/>
</g>
<g>
<rect x="176" y="58" width="30" height="20" rx="3" fill="var(--yellow)"/>
<text x="191" y="73" font-family="Bubblegum Sans, sans-serif" font-size="13" text-anchor="middle" fill="var(--ink)">A</text>
<circle cx="184" cy="80" r="6" fill="var(--ink)"/>
<circle cx="198" cy="80" r="6" fill="var(--ink)"/>
</g>
<g>
<rect x="136" y="58" width="30" height="20" rx="3" fill="var(--blue)"/>
<text x="151" y="73" font-family="Bubblegum Sans, sans-serif" font-size="13" text-anchor="middle" fill="var(--card)">B</text>
<circle cx="144" cy="80" r="6" fill="var(--ink)"/>
<circle cx="158" cy="80" r="6" fill="var(--ink)"/>
</g>
<circle cx="264" cy="26" r="14" fill="var(--yellow)" opacity="0.85"/>
</svg>
</div>
<div id="home-list"></div>
</section>
<!-- FLASHCARDS -->
<section id="screen-flash" class="screen">
<div class="card">
<button class="back-link" id="back-from-flash"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><polyline points="15,5 8,12 15,19"/></svg>Lesson List</button>
<p class="flash-lesson-label" id="flash-lesson-label"></p>
<div class="flash-dots" id="flash-dots"></div>
<div id="flash-body"></div>
<div class="btn-row">
<button class="btn secondary" id="btn-flash-prev">Back</button>
<button class="btn" id="btn-flash-next">Next</button>
</div>
</div>
</section>
<!-- QUIZ -->
<section id="screen-quiz" class="screen">
<div class="card">
<button class="back-link" id="back-from-quiz"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><polyline points="15,5 8,12 15,19"/></svg>Lesson List</button>
<div class="quiz-head">
<svg class="quiz-train-mini" viewBox="0 0 160 100" role="img" aria-label="A train growing as you answer">
<g id="train-mini"></g>
</svg>
<div class="quiz-progress">
<div class="quiz-progress-label" id="q-count">Question 1 of 8</div>
<div class="track-bar"><div class="track-fill" id="track-fill" style="width:0%"></div></div>
</div>
</div>
<div class="q-kicker" id="q-kicker">Choose the correct answer</div>
<div class="q-text" id="q-text"></div>
<div id="q-options"></div>
<div class="feedback" id="q-feedback"></div>
<div class="next-wrap" id="next-wrap">
<button class="btn" id="btn-next">Next →</button>
</div>
</div>
</section>
<!-- RESULTS -->
<section id="screen-results" class="screen">
<div class="card">
<h2 style="font-size:1.5rem;color:var(--blue-deep);">All Aboard — Quiz Complete!</h2>
<svg class="result-train" viewBox="0 0 160 100" role="img" aria-label="Your finished train">
<g id="train-final"></g>
</svg>
<div class="stars" id="stars"></div>
<div class="result-score" id="result-score"></div>
<p class="result-msg" id="result-msg"></p>
<div class="btn-row">
<button class="btn secondary" id="btn-retry">Retry Lesson</button>
<button class="btn" id="btn-go-home">Lesson List</button>
</div>
</div>
</section>
</div>
<script>
(function(){
"use strict";
var CHECK_ICON = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><polyline points="4,13 9,18 20,6"/></svg>';
var X_ICON = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><line x1="5" y1="5" x2="19" y2="19"/><line x1="19" y1="5" x2="5" y2="19"/></svg>';
function shuffle(arr){
var a = arr.slice();
for (var i = a.length - 1; i > 0; i--){
var j = Math.floor(Math.random() * (i + 1));
var t = a[i]; a[i] = a[j]; a[j] = t;
}
return a;
}
function mc(q, opts, good, bad){
return { type:'mc', q:q, options: opts.map(function(o){ return {text:o[0], correct:o[1]}; }), good:good, bad:bad };
}
function tf(q, answer, good, bad){
return { type:'tf', q:q, answer:answer, good:good, bad:bad };
}
function prepareQuestion(item){
if (item.type === 'mc') return { type:'mc', q:item.q, options: shuffle(item.options), good:item.good, bad:item.bad };
return item;
}
function buildQuizSet(lesson){
return shuffle(lesson.quiz).map(prepareQuestion);
}
var STORAGE_KEY = 'wordtrain_progress_v1';
function loadProgress(){ try{ return JSON.parse(localStorage.getItem(STORAGE_KEY)) || {}; }catch(e){ return {}; } }
function saveProgress(p){ try{ localStorage.setItem(STORAGE_KEY, JSON.stringify(p)); }catch(e){} }
var progress = loadProgress();
var FINAL_EXAM_PER_LESSON = 3;
function starsFor(pct){
if (pct >= 1) return 3;
if (pct >= 0.8) return 2;
if (pct >= 0.5) return 1;
return 0;
}
/* ================= LESSONS ================= */
var lessons = [
{
tag: 'Week 1 · Day 2',
title: 'Review of the Alphabet',
stars: 0,
icon: '<circle cx="38" cy="38" r="34" fill="var(--yellow-soft)"/><rect x="20" y="24" width="36" height="28" rx="6" fill="var(--yellow)"/><text x="38" y="45" font-family="Bubblegum Sans, sans-serif" font-size="18" text-anchor="middle" fill="var(--ink)">Aa</text>',
flashcards: [
{ title:'THE ALPHABET', icon:'<circle cx="38" cy="38" r="34" fill="var(--yellow-soft)"/><rect x="20" y="24" width="36" height="28" rx="6" fill="var(--yellow)"/><text x="38" y="45" font-family="Bubblegum Sans, sans-serif" font-size="18" text-anchor="middle" fill="var(--ink)">Aa</text>', text:'The alphabet is the set of letters that we use to write and read words.' },
{ title:'BIG LETTERS (CAPITAL)', icon:'<circle cx="38" cy="38" r="34" fill="var(--blue-soft)"/><text x="38" y="50" font-family="Bubblegum Sans, sans-serif" font-size="34" text-anchor="middle" fill="var(--blue)">B</text>', text:'Capital letters are the big letters, like A, B, C. We use them to begin sentences and names.' },
{ title:'SMALL LETTERS (LOWERCASE)', icon:'<circle cx="38" cy="38" r="34" fill="var(--accent-soft)"/><text x="38" y="50" font-family="Bubblegum Sans, sans-serif" font-size="30" text-anchor="middle" fill="var(--accent)">b</text>', text:'Small letters are the little letters, like a, b, c. Most words are written with small letters.' },
{ title:'LETTER ORDER', icon:'<circle cx="38" cy="38" r="34" fill="var(--good-soft)"/><path d="M20 46c6-16 30-16 36 0" fill="none" stroke="var(--good)" stroke-width="3" stroke-linecap="round"/><circle cx="20" cy="46" r="3" fill="var(--good)"/><circle cx="56" cy="46" r="3" fill="var(--good)"/>', text:'The alphabet always goes in the same order, from A to Z. Knowing the order helps us find words in a dictionary.' }
],
quiz: [
mc('What do we call the set of letters we use to write and read words?', [['The Alphabet',true],['The Dictionary',false],['The Story',false]], 'That’s right! It’s called the Alphabet.', 'The correct answer is The Alphabet — the set of letters we use to write and read.'),
tf('The alphabet has 26 letters.', true, 'Correct! There are 26 letters in the alphabet.', 'The answer should be True — the alphabet has 26 letters.'),
mc('Which of these is a capital (big) letter?', [['B',true],['g',false],['n',false]], 'Yes! B is a capital letter.', 'B is the capital letter — the others are small letters.'),
tf('Capital letters are used to begin sentences and names.', true, 'That’s right! Capital letters begin sentences and names.', 'The answer should be True — capital letters begin sentences and names.'),
mc('What letter comes right after D in the alphabet?', [['E',true],['C',false],['G',false]], 'Correct! E comes right after D.', 'The letter that comes right after D is E.'),
tf('Small letters are also called lowercase letters.', true, 'Yes! Small letters and lowercase mean the same thing.', 'The answer should be True — small letters are also called lowercase letters.'),
mc('What letter comes right before H?', [['G',true],['I',false],['F',false]], 'That’s right! G comes right before H.', 'The letter that comes right before H is G.'),
tf('The alphabet is not always in the same order.', false, 'Correct! The alphabet is always in the same order, A to Z.', 'The answer should be False — the alphabet is always in the same order.'),
mc('Which of these is a small (lowercase) letter?', [['g',true],['G',false],['B',false]], 'Yes! "g" is a small letter.', '"g" is the small letter — the others are capital letters.'),
tf('Most words are written using small letters.', true, 'Correct! Most words use small letters.', 'The answer should be True — most words are written with small letters.'),
mc('What letter comes right before B in the alphabet?', [['A',true],['C',false],['Z',false]], 'That’s right! A comes right before B.', 'The letter that comes right before B is A.'),
tf('We use capital letters to begin every word in a sentence.', false, 'Correct! Capital letters begin sentences and names, not every word.', 'The answer should be False — capital letters begin sentences and names, not every single word.')
]
},
{
tag: 'Week 1 · Day 3',
title: 'Onset and Rime',
stars: 0,
icon: '<circle cx="38" cy="38" r="34" fill="var(--blue-soft)"/><rect x="18" y="30" width="40" height="22" rx="4" fill="var(--blue)"/><rect x="30" y="20" width="10" height="10" fill="var(--blue-deep)"/><circle cx="28" cy="54" r="5" fill="var(--ink)"/><circle cx="48" cy="54" r="5" fill="var(--ink)"/>',
flashcards: [
{ title:'ONSET', icon:'<circle cx="38" cy="38" r="34" fill="var(--accent-soft)"/><text x="38" y="50" font-family="Bubblegum Sans, sans-serif" font-size="28" text-anchor="middle" fill="var(--accent)">c</text>', text:'The beginning consonant sound that comes before the vowel sound in a word.' },
{ title:'RIME', icon:'<circle cx="38" cy="38" r="34" fill="var(--blue-soft)"/><text x="38" y="50" font-family="Bubblegum Sans, sans-serif" font-size="26" text-anchor="middle" fill="var(--blue)">at</text>', text:'The rest of the sounds in a word — it includes the vowel sound and the sounds that follow it.' },
{ title:'EXAMPLE: CAT', icon:'<circle cx="38" cy="38" r="34" fill="var(--yellow-soft)"/><rect x="14" y="30" width="20" height="22" rx="4" fill="var(--accent)"/><rect x="36" y="30" width="26" height="22" rx="4" fill="var(--blue)"/><text x="24" y="46" font-family="Bubblegum Sans, sans-serif" font-size="13" text-anchor="middle" fill="var(--card)">c</text><text x="49" y="46" font-family="Bubblegum Sans, sans-serif" font-size="13" text-anchor="middle" fill="var(--card)">at</text>', text:'In the word cat, /k/ is the onset and /at/ is the rime.' },
{ title:'EXAMPLE: DOG', icon:'<circle cx="38" cy="38" r="34" fill="var(--good-soft)"/><rect x="14" y="30" width="20" height="22" rx="4" fill="var(--accent)"/><rect x="36" y="30" width="26" height="22" rx="4" fill="var(--blue)"/><text x="24" y="46" font-family="Bubblegum Sans, sans-serif" font-size="13" text-anchor="middle" fill="var(--card)">d</text><text x="49" y="46" font-family="Bubblegum Sans, sans-serif" font-size="13" text-anchor="middle" fill="var(--card)">og</text>', text:'In the word dog, /d/ is the onset and /og/ is the rime.' }
],
quiz: [
mc('What do we call the beginning consonant sound of a word?', [['Onset',true],['Rime',false],['Alphabet',false]], 'Yes! That is the onset.', 'The beginning consonant sound is called the Onset.'),
tf('The rime includes the vowel sound and the sounds that follow it.', true, 'Correct! That is exactly what the rime is.', 'The answer should be True — the rime includes the vowel sound and the sounds that follow it.'),
mc('In the word "cat", what is the onset?', [['/k/',true],['/at/',false],['/c-a/',false]], 'That’s right! /k/ is the onset in "cat".', 'The onset in "cat" is /k/, and /at/ is the rime.'),
tf('In the word "dog", the rime is /og/.', true, 'Correct! /og/ is the rime in "dog".', 'The answer should be True — the rime in "dog" is /og/.'),
mc('If you put the onset /b/ with the rime /at/, what word do you get?', [['Bat',true],['Sit',false],['Dog',false]], 'Yes! /b/ + /at/ makes "bat".', 'Putting /b/ with /at/ makes the word "bat".'),
tf('Onset always comes after the rime in a word.', false, 'Correct! The onset comes before the rime.', 'The answer should be False — the onset comes before the rime, not after.'),
mc('What is the onset in the word "pin"?', [['/p/',true],['/in/',false],['/n/',false]], 'That’s right! /p/ is the onset in "pin".', 'The onset in "pin" is /p/, and /in/ is the rime.'),
tf('Onset and rime can help us build new words by mixing sounds.', true, 'Yes! Mixing onsets and rimes helps us build new words.', 'The answer should be True — mixing onsets and rimes helps us build new words.'),
mc('In the word "dog", what is the onset?', [['/d/',true],['/og/',false],['/d-o/',false]], 'Yes! /d/ is the onset in "dog".', 'The onset in "dog" is /d/, and /og/ is the rime.'),
tf('The onset is the beginning consonant sound of a word.', true, 'Correct! That is exactly what the onset is.', 'The answer should be True — the onset is the beginning consonant sound of a word.'),
mc('If you put the onset /s/ with the rime /it/, what word do you get?', [['Sit',true],['Bat',false],['Dog',false]], 'That’s right! /s/ + /it/ makes "sit".', 'Putting /s/ with /it/ makes the word "sit".'),
tf('The rime comes before the onset in a word.', false, 'Correct! The onset comes before the rime, not after.', 'The answer should be False — the onset comes before the rime, not the other way around.')
]
},
{
tag: 'Week 2',
title: 'CVC Words',
stars: 0,
icon: '<circle cx="38" cy="38" r="34" fill="var(--accent-soft)"/><rect x="14" y="28" width="16" height="20" rx="3" fill="var(--accent)"/><rect x="31" y="28" width="16" height="20" rx="3" fill="var(--yellow)"/><rect x="48" y="28" width="16" height="20" rx="3" fill="var(--blue)"/>',
flashcards: [
{ title:'WHAT IS A CVC WORD', icon:'<circle cx="38" cy="38" r="34" fill="var(--accent-soft)"/><rect x="14" y="28" width="16" height="20" rx="3" fill="var(--accent)"/><rect x="31" y="28" width="16" height="20" rx="3" fill="var(--yellow)"/><rect x="48" y="28" width="16" height="20" rx="3" fill="var(--blue)"/>', text:'C-V-C words follow the pattern consonant-vowel-consonant, like the word bit.' },
{ title:'SHORT A', icon:'<circle cx="38" cy="38" r="34" fill="var(--yellow-soft)"/><text x="38" y="50" font-family="Bubblegum Sans, sans-serif" font-size="30" text-anchor="middle" fill="var(--yellow-deep)">a</text>', text:'Words like cat, bat, and map use the short a sound.' },
{ title:'SHORT O', icon:'<circle cx="38" cy="38" r="34" fill="var(--blue-soft)"/><text x="38" y="50" font-family="Bubblegum Sans, sans-serif" font-size="30" text-anchor="middle" fill="var(--blue)">o</text>', text:'Words like dog, hop, and pot use the short o sound.' },
{ title:'WHY CVC WORDS MATTER', icon:'<circle cx="38" cy="38" r="34" fill="var(--good-soft)"/><path d="M38 16l16 6v12c0 12-7 20-16 24-9-4-16-12-16-24V22z" fill="var(--good)"/><polyline points="30,38 36,44 47,31" fill="none" stroke="var(--card)" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>', text:'Reading CVC words helps us sound out and read many simple words accurately.' }
],
quiz: [
mc('What pattern do CVC words follow?', [['Consonant-Vowel-Consonant',true],['Vowel-Consonant-Vowel',false],['Consonant-Consonant-Vowel',false]], 'That’s right! CVC means Consonant-Vowel-Consonant.', 'CVC words follow the pattern Consonant-Vowel-Consonant.'),
tf('"Cat" is an example of a CVC word.', true, 'Correct! "Cat" follows the consonant-vowel-consonant pattern.', 'The answer should be True — "cat" is a CVC word.'),
mc('Which word below is a CVC word with the short a sound?', [['Map',true],['Dog',false],['Sun',false]], 'Yes! "Map" has the short a sound.', '"Map" is the CVC word with the short a sound.'),
tf('"Dog" uses the short o sound.', true, 'That’s right! "Dog" has the short o sound.', 'The answer should be True — "dog" uses the short o sound.'),
mc('Which word matches: Ben has a red ___?', [['Cap',true],['Elephant',false],['Umbrella',false]], 'Correct! "Cap" fits the CVC pattern and the sentence.', 'The word that fits is "cap" — a short, CVC word.'),
mc('Which of these words has the short u sound?', [['Sun',true],['Pig',false],['Bed',false]], 'Yes! "Sun" has the short u sound.', '"Sun" is the word with the short u sound.'),
tf('CVC words help us read and sound out simple words.', true, 'Correct! That’s exactly why CVC words matter.', 'The answer should be True — CVC words help us read and sound out simple words.'),
mc('Which word completes: "The ___ can hop."?', [['Dog',true],['Chair',false],['Book',false]], 'That’s right! "The dog can hop."', 'The word that completes the sentence is "dog".'),
mc('Which word below is a CVC word with the short o sound?', [['Pot',true],['Sun',false],['Map',false]], 'Yes! "Pot" has the short o sound.', '"Pot" is the CVC word with the short o sound.'),
tf('"Bit" follows the consonant-vowel-consonant pattern.', true, 'Correct! "Bit" is a CVC word.', 'The answer should be True — "bit" follows the consonant-vowel-consonant pattern.'),
mc('Which word matches: Tom sat on the ___?', [['Mat',true],['Elephant',false],['Umbrella',false]], 'That’s right! "Mat" fits the CVC pattern and the sentence.', 'The word that fits is "mat" — a short, CVC word.'),
tf('Reading CVC words does not help us read other simple words.', false, 'Correct! Reading CVC words actually helps us sound out many simple words.', 'The answer should be False — reading CVC words helps us sound out and read many simple words.')
]
},
{
tag: 'Week 2 · Day 4',
title: 'High-Frequency & Math Words',
stars: 0,
icon: '<circle cx="38" cy="38" r="34" fill="var(--good-soft)"/><path d="M38 24c-6-4-14-4-20 0v28c6-4 14-4 20 0" fill="none" stroke="var(--good)" stroke-width="3"/><path d="M38 24c6-4 14-4 20 0v28c-6-4-14-4-20 0" fill="none" stroke="var(--good)" stroke-width="3"/><line x1="38" y1="24" x2="38" y2="52" stroke="var(--good)" stroke-width="3"/>',
flashcards: [
{ title:'HIGH-FREQUENCY WORDS', icon:'<circle cx="38" cy="38" r="34" fill="var(--good-soft)"/><path d="M38 24c-6-4-14-4-20 0v28c6-4 14-4 20 0" fill="none" stroke="var(--good)" stroke-width="3"/><path d="M38 24c6-4 14-4 20 0v28c-6-4-14-4-20 0" fill="none" stroke="var(--good)" stroke-width="3"/><line x1="38" y1="24" x2="38" y2="52" stroke="var(--good)" stroke-width="3"/>', text:'Words that are often used in speaking, reading, and writing, like the, and, and you.' },
{ title:'WHY THEY MATTER', icon:'<circle cx="38" cy="38" r="34" fill="var(--blue-soft)"/><path d="M24 44c4-14 22-14 26 0" fill="none" stroke="var(--blue)" stroke-width="3" stroke-linecap="round"/><circle cx="37" cy="24" r="8" fill="var(--blue)"/>', text:'Knowing high-frequency words by sight helps improve your reading fluency, accuracy, and speed.' },
{ title:'MATH-SPECIFIC WORDS', icon:'<circle cx="38" cy="38" r="34" fill="var(--accent-soft)"/><text x="38" y="48" font-family="Bubblegum Sans, sans-serif" font-size="26" text-anchor="middle" fill="var(--accent)">+</text>', text:'Special words we use in math, like add, subtract, and equal, that help us solve problems.' },
{ title:'ADD & SUBTRACT', icon:'<circle cx="38" cy="38" r="34" fill="var(--yellow-soft)"/><text x="30" y="46" font-family="Bubblegum Sans, sans-serif" font-size="20" text-anchor="middle" fill="var(--yellow-deep)">+</text><text x="48" y="46" font-family="Bubblegum Sans, sans-serif" font-size="20" text-anchor="middle" fill="var(--yellow-deep)">−</text>', text:'Add means to put numbers together. Subtract means to take away.' }
],
quiz: [
mc('What do we call words that are often used in speaking, reading, and writing?', [['High-frequency words',true],['Math words',false],['Long words',false]], 'That’s right! Those are high-frequency words.', 'Words used often in speaking, reading, and writing are called High-frequency words.'),
tf('Knowing high-frequency words helps improve your reading fluency and speed.', true, 'Correct! That’s exactly why they matter.', 'The answer should be True — high-frequency words improve reading fluency and speed.'),
mc('Which of these is a high-frequency word?', [['The',true],['Elephant',false],['Dictionary',false]], 'Yes! "The" is a high-frequency word.', '"The" is a common high-frequency word.'),
tf('Math-specific words help us understand what to do in math problems.', true, 'That’s right! Math words guide us on what to do.', 'The answer should be True — math-specific words help us know what to do.'),
mc('What does "add" mean in math?', [['To put numbers together',true],['To take away',false],['To read a word',false]], 'Correct! Add means to put numbers together.', '"Add" means to put numbers together.'),
mc('What does "subtract" mean in math?', [['To take away',true],['To put together',false],['To spell',false]], 'Yes! Subtract means to take away.', '"Subtract" means to take away.'),
tf('"Sum" is the answer to a subtraction problem.', false, 'Correct! "Sum" is the answer to an addition problem.', 'The answer should be False — "Sum" is the answer to an addition problem, not subtraction.'),
mc('In "8 − 3 = 5", what math word describes the answer 5?', [['Difference',true],['Sum',false],['Equal',false]], 'That’s right! The answer to subtraction is called the difference.', 'The answer to a subtraction problem is called the Difference.'),
mc('Which of these is a high-frequency word?', [['You',true],['Dinosaur',false],['Umbrella',false]], 'Yes! "You" is a high-frequency word.', '"You" is a common high-frequency word.'),
tf('Math-specific words are only used outside of math class.', false, 'Correct! Math-specific words are used to help us solve math problems.', 'The answer should be False — math-specific words help us solve problems in math.'),
mc('In "5 + 3 = 8", what math word describes the answer 8?', [['Sum',true],['Difference',false],['Subtract',false]], 'That’s right! The answer to addition is called the sum.', 'The answer to an addition problem is called the Sum.'),
tf('High-frequency words are words we rarely use in reading and writing.', false, 'Correct! High-frequency words are used very often, not rarely.', 'The answer should be False — high-frequency words are used very often in reading and writing.')
]
},
{
tag: 'Week 3 · Day 1',
title: 'Common and Proper Nouns',
stars: 0,
icon: '<circle cx="38" cy="38" r="34" fill="var(--blue-soft)"/><rect x="16" y="28" width="44" height="22" rx="6" fill="var(--card)" stroke="var(--blue)" stroke-width="2"/><circle cx="27" cy="39" r="4" fill="var(--blue)"/><rect x="36" y="35" width="18" height="3" fill="var(--blue)"/><rect x="36" y="42" width="12" height="3" fill="var(--ink-soft)"/>',
flashcards: [
{ title:'WHAT IS A NOUN', icon:'<circle cx="38" cy="38" r="34" fill="var(--blue-soft)"/><rect x="16" y="28" width="44" height="22" rx="6" fill="var(--card)" stroke="var(--blue)" stroke-width="2"/><circle cx="27" cy="39" r="4" fill="var(--blue)"/><rect x="36" y="35" width="18" height="3" fill="var(--blue)"/><rect x="36" y="42" width="12" height="3" fill="var(--ink-soft)"/>', text:'A noun is a word that names a person, place, animal, thing, or event.' },
{ title:'COMMON NOUN', icon:'<circle cx="38" cy="38" r="34" fill="var(--good-soft)"/><text x="38" y="50" font-family="Bubblegum Sans, sans-serif" font-size="26" text-anchor="middle" fill="var(--good)">girl</text>', text:'Names any general person, thing, animal, or place, and begins with a small letter, like girl or school.' },
{ title:'PROPER NOUN', icon:'<circle cx="38" cy="38" r="34" fill="var(--accent-soft)"/><text x="38" y="50" font-family="Bubblegum Sans, sans-serif" font-size="20" text-anchor="middle" fill="var(--accent)">Anna</text>', text:'Names a specific person, thing, animal, or place, and begins with a capital letter, like Abbygayle or Fun Ranch.' },
{ title:'TELLING THEM APART', icon:'<circle cx="38" cy="38" r="34" fill="var(--yellow-soft)"/><path d="M28 30l10 20 10-20" fill="none" stroke="var(--yellow-deep)" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>', text:'If it names something specific and starts with a capital letter, it’s a proper noun. If it’s general, it’s a common noun.' }
],
quiz: [
mc('What is a noun?', [['A word that names a person, place, animal, thing, or event',true],['A word that describes an action',false],['A word that asks a question',false]], 'That’s right! A noun names a person, place, animal, thing, or event.', 'A noun is a word that names a person, place, animal, thing, or event.'),
tf('A common noun begins with a small letter.', true, 'Correct! Common nouns begin with a small letter.', 'The answer should be True — common nouns begin with a small letter.'),
mc('Which of these is a proper noun?', [['Abbygayle',true],['girl',false],['school',false]], 'Yes! "Abbygayle" is a proper noun.', '"Abbygayle" is the proper noun — it names a specific person.'),
tf('"School" is an example of a common noun.', true, 'That’s right! "School" is a common noun.', 'The answer should be True — "school" is a common noun.'),
mc('Which of these is a common noun?', [['Book',true],['Blue Corner',false],['Fun Ranch',false]], 'Correct! "Book" is a common noun.', '"Book" is the common noun — the others name specific places.'),
tf('Proper nouns always begin with a capital letter.', true, 'Yes! Proper nouns always begin with a capital letter.', 'The answer should be True — proper nouns always begin with a capital letter.'),
mc('What kind of noun is "restaurant"?', [['Common noun',true],['Proper noun',false],['Not a noun',false]], 'That’s right! "Restaurant" is a common noun.', '"Restaurant" is a common noun — it names a general place.'),
tf('Common nouns name a specific person or place.', false, 'Correct! Proper nouns name specific things, not common nouns.', 'The answer should be False — proper nouns, not common nouns, name specific things.'),
mc('Which of these is a common noun?', [['dog',true],['Rex',false],['Manila',false]], 'Yes! "dog" is a common noun.', '"dog" is the common noun — the others name specific things.'),
tf('Proper nouns name any general person, place, animal, or thing.', false, 'Correct! Proper nouns name specific things, common nouns name general things.', 'The answer should be False — proper nouns name specific things, while common nouns name general things.'),
mc('What kind of noun is "Philippines"?', [['Proper noun',true],['Common noun',false],['Not a noun',false]], 'That’s right! "Philippines" is a proper noun.', '"Philippines" is a proper noun — it names a specific country.'),
tf('A noun can name a person, place, animal, thing, or event.', true, 'Correct! That is exactly what a noun is.', 'The answer should be True — a noun names a person, place, animal, thing, or event.')
]
},
{
tag: 'Week 3 · Day 3',
title: 'Gender Nouns',
stars: 0,
icon: '<circle cx="38" cy="38" r="34" fill="var(--accent-soft)"/><circle cx="28" cy="28" r="7" fill="var(--blue)"/><rect x="22" y="37" width="12" height="18" rx="3" fill="var(--blue)"/><circle cx="50" cy="28" r="7" fill="var(--accent)"/><path d="M42 37h16l-3 18h-10z" fill="var(--accent)"/>',
flashcards: [
{ title:'GENDER NOUNS', icon:'<circle cx="38" cy="38" r="34" fill="var(--accent-soft)"/><circle cx="28" cy="28" r="7" fill="var(--blue)"/><rect x="22" y="37" width="12" height="18" rx="3" fill="var(--blue)"/><circle cx="50" cy="28" r="7" fill="var(--accent)"/><path d="M42 37h16l-3 18h-10z" fill="var(--accent)"/>', text:'Nouns can have gender: masculine or feminine.' },
{ title:'MASCULINE NOUNS', icon:'<circle cx="38" cy="38" r="34" fill="var(--blue-soft)"/><circle cx="38" cy="28" r="8" fill="var(--blue)"/><rect x="30" y="38" width="16" height="18" rx="3" fill="var(--blue)"/>', text:'Refer to the name of a boy or a man, like uncle, prince, and king.' },
{ title:'FEMININE NOUNS', icon:'<circle cx="38" cy="38" r="34" fill="var(--accent-soft)"/><circle cx="38" cy="28" r="8" fill="var(--accent)"/><path d="M28 40h20l-4 18h-12z" fill="var(--accent)"/>', text:'Refer to the name of a girl or a woman, like aunt, princess, and queen.' },
{ title:'MATCHING PAIRS', icon:'<circle cx="38" cy="38" r="34" fill="var(--good-soft)"/><circle cx="26" cy="38" r="9" fill="var(--blue)"/><circle cx="50" cy="38" r="9" fill="var(--accent)"/><line x1="35" y1="38" x2="41" y2="38" stroke="var(--good)" stroke-width="3" stroke-linecap="round"/>', text:'Many gender nouns come in pairs, like king and queen, or boy and girl.' }
],
quiz: [
mc('What is the feminine word for "king"?', [['Queen',true],['Princess',false],['Aunt',false]], 'That’s right! Queen is the feminine word for king.', 'The feminine word for "king" is Queen.'),
tf('"Uncle" is a masculine noun.', true, 'Correct! "Uncle" is a masculine noun.', 'The answer should be True — "uncle" is a masculine noun.'),
mc('What is the masculine word for "aunt"?', [['Uncle',true],['Prince',false],['Niece',false]], 'Yes! Uncle is the masculine word for aunt.', 'The masculine word for "aunt" is Uncle.'),
tf('"Princess" refers to the name of a boy or man.', false, 'Correct! "Princess" refers to a girl or woman.', 'The answer should be False — "princess" refers to a girl or woman.'),
mc('What is the feminine word for "actor"?', [['Actress',true],['Policewoman',false],['Sister',false]], 'That’s right! Actress is the feminine word for actor.', 'The feminine word for "actor" is Actress.'),
mc('What is the masculine word for "grandmother"?', [['Grandfather',true],['Uncle',false],['Sir',false]], 'Correct! Grandfather is the masculine word for grandmother.', 'The masculine word for "grandmother" is Grandfather.'),
tf('"Policewoman" is the feminine word for "policeman".', true, 'Yes! "Policewoman" is the feminine word for "policeman".', 'The answer should be True — "policewoman" is the feminine word for "policeman".'),
mc('What is the feminine word for "son"?', [['Daughter',true],['Niece',false],['Aunt',false]], 'That’s right! Daughter is the feminine word for son.', 'The feminine word for "son" is Daughter.'),
mc('What is the feminine word for "prince"?', [['Princess',true],['Queen',false],['Aunt',false]], 'That’s right! Princess is the feminine word for prince.', 'The feminine word for "prince" is Princess.'),
tf('"Waiter" is a feminine noun.', false, 'Correct! "Waiter" is a masculine noun — "waitress" is feminine.', 'The answer should be False — "waiter" is a masculine noun, and "waitress" is the feminine form.'),
mc('What is the masculine word for "queen"?', [['King',true],['Prince',false],['Uncle',false]], 'Yes! King is the masculine word for queen.', 'The masculine word for "queen" is King.'),
tf('Nouns can only have one gender: masculine.', false, 'Correct! Nouns can be masculine or feminine.', 'The answer should be False — nouns can have gender: masculine or feminine.')
]
},
{
tag: 'Week 4 · Day 2',
title: 'Action Verbs',
stars: 0,
icon: '<circle cx="38" cy="38" r="34" fill="var(--yellow-soft)"/><circle cx="34" cy="24" r="6" fill="var(--yellow-deep)"/><path d="M34 30v14M34 34l-12 8M34 34l14-4M34 44l-8 12M34 44l10 10" fill="none" stroke="var(--yellow-deep)" stroke-width="3" stroke-linecap="round"/>',
flashcards: [
{ title:'ACTION VERBS', icon:'<circle cx="38" cy="38" r="34" fill="var(--yellow-soft)"/><circle cx="34" cy="24" r="6" fill="var(--yellow-deep)"/><path d="M34 30v14M34 34l-12 8M34 34l14-4M34 44l-8 12M34 44l10 10" fill="none" stroke="var(--yellow-deep)" stroke-width="3" stroke-linecap="round"/>', text:'Words that talk about the action of people or animals, like walk, run, or jump.' },
{ title:'VERBS IN STORIES', icon:'<circle cx="38" cy="38" r="34" fill="var(--blue-soft)"/><path d="M22 30h28v18H36l-6 6v-6h-8z" fill="var(--blue)"/>', text:'We use action verbs to talk about what happens in a story, like grumble, reply, scream, or call.' },
{ title:'VERBS WE CAN SEE', icon:'<circle cx="38" cy="38" r="34" fill="var(--good-soft)"/><path d="M20 44c8-14 30-14 38 0" fill="none" stroke="var(--good)" stroke-width="3" stroke-linecap="round"/><circle cx="38" cy="26" r="7" fill="var(--good)"/>', text:'Flying, feeding, walking, crawling, dancing, and swimming are all action verbs.' },
{ title:'FINDING THE VERB', icon:'<circle cx="38" cy="38" r="34" fill="var(--accent-soft)"/><circle cx="38" cy="38" r="16" fill="none" stroke="var(--accent)" stroke-width="3"/><line x1="49" y1="49" x2="58" y2="58" stroke="var(--accent)" stroke-width="4" stroke-linecap="round"/>', text:'In a sentence, the action verb tells us what someone or something is doing.' }
],
quiz: [
mc('What do we call words that tell about the action of people or animals?', [['Action verbs',true],['Nouns',false],['Adjectives',false]], 'That’s right! Those are action verbs.', 'Words that tell about action are called Action verbs.'),
tf('"Run" is an example of an action verb.', true, 'Correct! "Run" is an action verb.', 'The answer should be True — "run" is an action verb.'),
mc('Which word is an action verb?', [['Dancing',true],['Happy',false],['Table',false]], 'Yes! "Dancing" is an action verb.', '"Dancing" is the action verb — it tells us what someone is doing.'),
tf('Action verbs tell us what someone or something is doing.', true, 'That’s right! That is exactly what action verbs do.', 'The answer should be True — action verbs tell us what someone or something is doing.'),
mc('In "Teacher Gayle is talking," what is the action verb?', [['Talking',true],['Teacher',false],['Gayle',false]], 'Correct! "Talking" is the action verb.', 'The action verb in that sentence is "talking".'),
mc('Which of these words describes something flying or swimming?', [['Action verb',true],['Common noun',false],['Proper noun',false]], 'That’s right! Flying and swimming are action verbs.', 'Words like flying and swimming are Action verbs.'),
tf('"Table" is an action verb.', false, 'Correct! "Table" is a noun, not an action verb.', 'The answer should be False — "table" is a noun, not an action verb.'),
mc('Which action verb best completes: "The dog is ___ in the yard."?', [['Running',true],['Table',false],['Happy',false]], 'Yes! "Running" is the action verb that fits.', 'The action verb that fits is "running".'),
mc('Which word is an action verb?', [['Swimming',true],['Chair',false],['Blue',false]], 'Yes! "Swimming" is an action verb.', '"Swimming" is the action verb — it tells us what someone is doing.'),
tf('"Scream" can be used as an action verb in a story.', true, 'Correct! "Scream" is an action verb often used in stories.', 'The answer should be True — "scream" is an action verb used in stories.'),
mc('In "The bird is flying," what is the action verb?', [['Flying',true],['Bird',false],['The',false]], 'That’s right! "Flying" is the action verb.', 'The action verb in that sentence is "flying".'),
tf('Action verbs tell us the color of something.', false, 'Correct! Action verbs tell us what someone or something is doing, not its color.', 'The answer should be False — action verbs tell us about action, not color.')
]
},
{
tag: 'Week 4 · Day 3',
title: 'Adjectives',
stars: 0,
icon: '<circle cx="38" cy="38" r="34" fill="var(--blue-soft)"/><path d="M38 18a20 20 0 1 0 6 39c-2-3 0-6 3-6h9a8 8 0 0 0 8-8 20 20 0 0 0-26-25z" fill="var(--blue)"/><circle cx="30" cy="32" r="3" fill="var(--accent)"/><circle cx="40" cy="26" r="3" fill="var(--yellow)"/><circle cx="48" cy="34" r="3" fill="var(--good)"/>',
flashcards: [
{ title:'ADJECTIVES', icon:'<circle cx="38" cy="38" r="34" fill="var(--blue-soft)"/><path d="M38 18a20 20 0 1 0 6 39c-2-3 0-6 3-6h9a8 8 0 0 0 8-8 20 20 0 0 0-26-25z" fill="var(--blue)"/><circle cx="30" cy="32" r="3" fill="var(--accent)"/><circle cx="40" cy="26" r="3" fill="var(--yellow)"/><circle cx="48" cy="34" r="3" fill="var(--good)"/>', text:'Words that describe people, places, animals, and things.' },
{ title:'DESCRIBING PEOPLE', icon:'<circle cx="38" cy="38" r="34" fill="var(--accent-soft)"/><circle cx="38" cy="30" r="9" fill="var(--accent)"/><path d="M24 56c2-10 9-14 14-14s12 4 14 14" fill="none" stroke="var(--accent)" stroke-width="3" stroke-linecap="round"/>', text:'Adjectives like kind, beautiful, and fast describe how people look or act.' },
{ title:'DESCRIBING PLACES & ANIMALS', icon:'<circle cx="38" cy="38" r="34" fill="var(--good-soft)"/><polygon points="20,50 34,26 44,42 50,30 58,50" fill="var(--good)"/>', text:'Adjectives like peaceful describe places, and elegant or lazy describe animals.' },
{ title:'DESCRIBING THINGS', icon:'<circle cx="38" cy="38" r="34" fill="var(--yellow-soft)"/><circle cx="38" cy="38" r="14" fill="var(--yellow)"/><circle cx="32" cy="32" r="3" fill="var(--card)" opacity="0.8"/>', text:'Adjectives like sparkling, red, or new describe how things look.' }
],
quiz: [
mc('What do we call words that describe people, places, animals, and things?', [['Adjectives',true],['Verbs',false],['Pronouns',false]], 'That’s right! Those are adjectives.', 'Words that describe are called Adjectives.'),
tf('"Beautiful" is an adjective that can describe a person.', true, 'Correct! "Beautiful" describes a person.', 'The answer should be True — "beautiful" can describe a person.'),
mc('Which word is an adjective?', [['Kind',true],['Run',false],['School',false]], 'Yes! "Kind" is an adjective.', '"Kind" is the adjective — it describes a person.'),
tf('"Peaceful" can be used to describe a place.', true, 'That’s right! "Peaceful" can describe a place.', 'The answer should be True — "peaceful" can describe a place.'),
mc('In "The lazy cat slept on the bed," which word is the adjective?', [['Lazy',true],['Cat',false],['Bed',false]], 'Correct! "Lazy" is the adjective.', 'The adjective in that sentence is "lazy" — it describes the cat.'),
mc('Which adjective could describe jewels?', [['Sparkling',true],['Walk',false],['Teacher',false]], 'That’s right! "Sparkling" describes jewels.', '"Sparkling" is an adjective that could describe jewels.'),
tf('Adjectives can only describe animals, not things or places.', false, 'Correct! Adjectives can describe people, places, animals, and things.', 'The answer should be False — adjectives describe people, places, animals, and things.'),
mc('In "I have a red ball," what does "red" describe?', [['The ball',true],['The action',false],['Nothing',false]], 'Yes! "Red" describes the ball.', '"Red" describes "the ball" in that sentence.'),
mc('Which word is an adjective that describes an animal?', [['Elegant',true],['Run',false],['Book',false]], 'Yes! "Elegant" can describe an animal.', '"Elegant" is an adjective — it can describe an animal.'),
tf('Adjectives can describe how things look.', true, 'Correct! Adjectives like "red" or "new" describe how things look.', 'The answer should be True — adjectives can describe how things look.'),
mc('In "The peaceful garden was quiet," which word is the adjective?', [['Peaceful',true],['Garden',false],['Was',false]], 'That’s right! "Peaceful" is the adjective.', 'The adjective in that sentence is "peaceful" — it describes the garden.'),
tf('"Fast" is an adjective that can describe how a person moves.', true, 'Correct! "Fast" describes how a person moves.', 'The answer should be True — "fast" is an adjective that can describe a person.')
]
},
{
tag: 'Week 4 · Day 4',
title: 'Personal Pronouns',
stars: 0,
icon: '<circle cx="38" cy="38" r="34" fill="var(--good-soft)"/><circle cx="38" cy="38" r="18" fill="none" stroke="var(--good)" stroke-width="3"/><circle cx="38" cy="38" r="3" fill="var(--good)"/><line x1="38" y1="38" x2="38" y2="20" stroke="var(--good)" stroke-width="3" stroke-linecap="round"/><line x1="38" y1="38" x2="52" y2="46" stroke="var(--good)" stroke-width="3" stroke-linecap="round"/>',
flashcards: [
{ title:'PERSONAL PRONOUNS', icon:'<circle cx="38" cy="38" r="34" fill="var(--good-soft)"/><circle cx="38" cy="38" r="18" fill="none" stroke="var(--good)" stroke-width="3"/><circle cx="38" cy="38" r="3" fill="var(--good)"/><line x1="38" y1="38" x2="38" y2="20" stroke="var(--good)" stroke-width="3" stroke-linecap="round"/><line x1="38" y1="38" x2="52" y2="46" stroke="var(--good)" stroke-width="3" stroke-linecap="round"/>', text:'Words we use instead of the names of people, things, or animals, like I, you, he, she, it, we, they.' },
{ title:'ONE PERSON OR THING', icon:'<circle cx="38" cy="38" r="34" fill="var(--blue-soft)"/><circle cx="38" cy="30" r="8" fill="var(--blue)"/><rect x="30" y="40" width="16" height="16" rx="4" fill="var(--blue)"/>', text:'I, you, he, she, and it refer to just one person, thing, or animal.' },
{ title:'MORE THAN ONE', icon:'<circle cx="38" cy="38" r="34" fill="var(--accent-soft)"/><circle cx="28" cy="32" r="7" fill="var(--accent)"/><circle cx="48" cy="32" r="7" fill="var(--accent)"/><rect x="22" y="41" width="12" height="14" rx="3" fill="var(--accent)"/><rect x="42" y="41" width="12" height="14" rx="3" fill="var(--accent)"/>', text:'We and they refer to more than one person, thing, or animal.' },
{ title:'USING PRONOUNS', icon:'<circle cx="38" cy="38" r="34" fill="var(--yellow-soft)"/><text x="38" y="48" font-family="Bubblegum Sans, sans-serif" font-size="20" text-anchor="middle" fill="var(--yellow-deep)">he/she/it</text>', text:'We use "he" for a male, "she" for a female, and "it" for a thing or animal already mentioned.' }
],
quiz: [
mc('What do we call words that replace the names of people, things, or animals?', [['Personal pronouns',true],['Adjectives',false],['Action verbs',false]], 'That’s right! Those are personal pronouns.', 'Words that replace names are called Personal pronouns.'),
tf('"I" and "you" are personal pronouns.', true, 'Correct! "I" and "you" are personal pronouns.', 'The answer should be True — "I" and "you" are personal pronouns.'),
mc('Which pronoun refers to more than one person or thing?', [['They',true],['He',false],['It',false]], 'Yes! "They" refers to more than one.', '"They" is the pronoun that refers to more than one person or thing.'),
tf('"She" is used to refer to a male person.', false, 'Correct! "She" refers to a female person.', 'The answer should be False — "she" refers to a female person, not male.'),
mc('"This is my dog. ___ is brown." Which pronoun completes the sentence?', [['It',true],['She',false],['You',false]], 'That’s right! "It" refers to the dog.', 'The pronoun that fits is "It" — it refers to the dog.'),
mc('"Ben and I are friends. ___ play together." Which pronoun fits?', [['We',true],['They',false],['He',false]], 'Correct! "We" refers to Ben and I.', 'The pronoun that fits is "We" — it refers to Ben and the speaker.'),
tf('"We" refers to the speaker and other people.', true, 'Yes! "We" includes the speaker and others.', 'The answer should be True — "we" refers to the speaker and other people.'),
mc('Which pronoun would you use to talk about yourself?', [['I',true],['He',false],['They',false]], 'That’s right! "I" is used to talk about yourself.', 'The pronoun used to talk about yourself is "I".'),
mc('Which pronoun would you use to refer to a boy who was already mentioned?', [['He',true],['She',false],['They',false]], 'Yes! "He" refers to a male already mentioned.', '"He" is used to refer to a male person already mentioned.'),
tf('"It" is used for a thing or animal already mentioned.', true, 'Correct! "It" refers to a thing or animal already mentioned.', 'The answer should be True — "it" is used for a thing or animal already mentioned.'),
mc('"The girls are playing. ___ are having fun." Which pronoun completes the sentence?', [['They',true],['He',false],['I',false]], 'That’s right! "They" refers to the girls.', 'The pronoun that fits is "They" — it refers to the girls.'),
tf('Personal pronouns can only refer to people, never to things or animals.', false, 'Correct! Personal pronouns like "it" can refer to things and animals too.', 'The answer should be False — personal pronouns like "it" can refer to things and animals, not just people.')
]
}
];
/* ================= Train SVG ================= */
function trainMarkup(){
return ''
+ '<rect class="piece base" data-piece="0" x="2" y="86" width="156" height="3" fill="var(--track)"/>'
+ '<g class="piece" data-piece="1">'
+ '<rect x="126" y="58" width="30" height="22" rx="3" fill="var(--accent)"/>'
+ '<rect x="132" y="44" width="14" height="14" fill="var(--accent)"/>'
+ '<rect x="144" y="34" width="6" height="12" fill="var(--ink-soft)"/>'
+ '<circle cx="134" cy="82" r="6" fill="var(--ink)"/><circle cx="150" cy="82" r="6" fill="var(--ink)"/>'
+ '</g>'
+ '<g class="piece" data-piece="2">'
+ '<circle cx="146" cy="26" r="6" fill="var(--bg-alt)" opacity="0.85"/>'
+ '<circle cx="152" cy="16" r="4" fill="var(--bg-alt)" opacity="0.7"/>'
+ '</g>'
+ '<g class="piece" data-piece="3">'
+ '<rect x="104" y="60" width="20" height="20" rx="3" fill="var(--yellow)"/>'
+ '<text x="114" y="75" font-family="Bubblegum Sans, sans-serif" font-size="13" text-anchor="middle" fill="var(--ink)">A</text>'
+ '<circle cx="110" cy="82" r="5" fill="var(--ink)"/><circle cx="120" cy="82" r="5" fill="var(--ink)"/>'
+ '</g>'
+ '<g class="piece" data-piece="4">'
+ '<rect x="82" y="60" width="20" height="20" rx="3" fill="var(--blue)"/>'
+ '<text x="92" y="75" font-family="Bubblegum Sans, sans-serif" font-size="13" text-anchor="middle" fill="var(--card)">B</text>'
+ '<circle cx="88" cy="82" r="5" fill="var(--ink)"/><circle cx="98" cy="82" r="5" fill="var(--ink)"/>'
+ '</g>'
+ '<g class="piece" data-piece="5">'
+ '<rect x="60" y="60" width="20" height="20" rx="3" fill="var(--accent)"/>'
+ '<text x="70" y="75" font-family="Bubblegum Sans, sans-serif" font-size="13" text-anchor="middle" fill="var(--card)">C</text>'
+ '<circle cx="66" cy="82" r="5" fill="var(--ink)"/><circle cx="76" cy="82" r="5" fill="var(--ink)"/>'
+ '</g>'
+ '<g class="piece" data-piece="6">'
+ '<rect x="38" y="60" width="20" height="20" rx="3" fill="var(--yellow)"/>'
+ '<text x="48" y="75" font-family="Bubblegum Sans, sans-serif" font-size="13" text-anchor="middle" fill="var(--ink)">D</text>'
+ '<circle cx="44" cy="82" r="5" fill="var(--ink)"/><circle cx="54" cy="82" r="5" fill="var(--ink)"/>'
+ '</g>'
+ '<g class="piece" data-piece="7">'
+ '<rect x="16" y="60" width="20" height="20" rx="3" fill="var(--blue)"/>'
+ '<text x="26" y="75" font-family="Bubblegum Sans, sans-serif" font-size="13" text-anchor="middle" fill="var(--card)">E</text>'
+ '<circle cx="22" cy="82" r="5" fill="var(--ink)"/><circle cx="32" cy="82" r="5" fill="var(--ink)"/>'
+ '</g>'
+ '<g class="piece" data-piece="8">'
+ '<rect x="2" y="62" width="16" height="18" rx="3" fill="var(--accent)"/>'
+ '<circle cx="7" cy="82" r="4" fill="var(--ink)"/><circle cx="15" cy="82" r="4" fill="var(--ink)"/>'
+ '<rect x="9" y="50" width="2" height="12" fill="var(--wood)"/><polygon points="11,50 24,55 11,60" fill="var(--good)"/>'
+ '</g>';
}
document.getElementById('train-mini').innerHTML = trainMarkup();
document.getElementById('train-final').innerHTML = trainMarkup();
function resetTrain(){
document.querySelectorAll('.piece[data-piece]:not([data-piece="0"])').forEach(function(el){ el.classList.remove('revealed'); });
}
function starsMarkup(filledCount, total){
var out = '';
for (var i = 1; i <= total; i++){
var filled = i <= filledCount;
out += '<svg viewBox="0 0 24 24" fill="' + (filled ? 'var(--accent)' : 'none') + '" stroke="var(--accent)" stroke-width="' + (total > 3 ? '2' : '1.6') + '"><polygon points="12,2 15,9 22,9.5 16.5,14.2 18.5,21.5 12,17.5 5.5,21.5 7.5,14.2 2,9.5 9,9"/></svg>';
}
return out;
}
/* ================= Screens ================= */
var screens = ['home','flash','quiz','results'];
function showScreen(name){
screens.forEach(function(s){
document.getElementById('screen-'+s).classList.toggle('active', s === name);
});
}
/* ================= Home ================= */
function renderHome(){
var list = document.getElementById('home-list');
var finalTotal = lessons.length * FINAL_EXAM_PER_LESSON;
var finalBest = progress['final'] || 0;
var finalStars = starsFor(finalBest / finalTotal);
var finalCard = '<div class="card lesson-card final-card">' +
'<div class="lesson-top">' +
'<svg class="lesson-icon" viewBox="0 0 76 76"><circle cx="38" cy="38" r="34" fill="var(--yellow-soft)"/><polygon points="38,14 44,30 61,31 47,41 52,58 38,48 24,58 29,41 15,31 32,30" fill="var(--yellow)"/></svg>' +
'<div class="lesson-info">' +
'<div class="lesson-tag-label final-badge">Final Mock Exam</div>' +
'<div class="lesson-title">Word Train Review</div>' +
'<div class="mini-stars">' + starsMarkup(finalStars, 3) + '</div>' +
'</div>' +
'</div>' +
'<button class="btn" id="btn-final-exam">' + (finalBest > 0 ? 'Retry Exam' : 'Start') + '</button>' +
'</div>';
var lessonCards = lessons.map(function(l, i){
var total = l.quiz.length;
var best = progress[i] || 0;
var stars = starsFor(best / total);
return '<div class="card lesson-card">' +
'<div class="lesson-top">' +
'<svg class="lesson-icon" viewBox="0 0 76 76">' + l.icon + '</svg>' +
'<div class="lesson-info">' +
'<div class="lesson-tag-label">' + l.tag + '</div>' +
'<div class="lesson-title">' + l.title + '</div>' +
'<div class="mini-stars">' + starsMarkup(stars, 3) + '</div>' +
'</div>' +
'</div>' +
'<button class="btn" data-lesson="' + i + '">' + (best > 0 ? 'Retry Lesson' : 'Start') + '</button>' +
'</div>';
}).join('');
list.innerHTML = finalCard + lessonCards;
document.getElementById('btn-final-exam').addEventListener('click', function(){
startFinalExam();
});
list.querySelectorAll('button[data-lesson]').forEach(function(b){
b.addEventListener('click', function(){
currentLesson = parseInt(b.getAttribute('data-lesson'), 10);
flashIdx = 0;
renderFlash();
showScreen('flash');
});
});
}
function goHome(){ renderHome(); showScreen('home'); }
document.getElementById('back-from-flash').addEventListener('click', goHome);
document.getElementById('back-from-quiz').addEventListener('click', goHome);
document.getElementById('btn-go-home').addEventListener('click', goHome);
/* ================= Flashcards ================= */
var currentLesson = 0;
var flashIdx = 0;
function renderFlash(){
var lesson = lessons[currentLesson];
var f = lesson.flashcards[flashIdx];
document.getElementById('flash-lesson-label').textContent = lesson.title;
document.getElementById('flash-body').innerHTML =
'<svg class="flash-icon" viewBox="0 0 76 76">' + f.icon + '</svg>' +
'<h3 class="flash-title">' + f.title + '</h3>' +
'<p class="flash-text">' + f.text + '</p>';
document.getElementById('flash-dots').innerHTML = lesson.flashcards.map(function(_, i){
return '<span class="' + (i === flashIdx ? 'on' : '') + '"></span>';
}).join('');
document.getElementById('btn-flash-prev').style.visibility = flashIdx === 0 ? 'hidden' : 'visible';
document.getElementById('btn-flash-next').textContent = flashIdx === lesson.flashcards.length - 1 ? 'Start Quiz' : 'Next';
}
document.getElementById('btn-flash-prev').addEventListener('click', function(){
if (flashIdx > 0){ flashIdx--; renderFlash(); }
});
document.getElementById('btn-flash-next').addEventListener('click', function(){
var lesson = lessons[currentLesson];
if (flashIdx < lesson.flashcards.length - 1){ flashIdx++; renderFlash(); }
else { startQuiz(); }
});
/* ================= Quiz ================= */
var qIdx = 0, score = 0, answered = false;
var currentQuizSet = [];
var currentQuizMeta = null;
function revealProgress(){
var n = Math.round((score / currentQuizSet.length) * 8);
for (var p = 1; p <= 8; p++){
document.querySelectorAll('[data-piece="' + p + '"]').forEach(function(el){
el.classList.toggle('revealed', p <= n);
});
}
}
function startQuiz(){
var lesson = lessons[currentLesson];
currentQuizSet = buildQuizSet(lesson);
currentQuizMeta = { id: currentLesson, title: lesson.title };
qIdx = 0; score = 0; resetTrain();
showScreen('quiz');
renderQuestion();
}
function startFinalExam(){
var qs = [];
lessons.forEach(function(l){
qs = qs.concat(shuffle(l.quiz).slice(0, FINAL_EXAM_PER_LESSON).map(prepareQuestion));
});
currentQuizSet = shuffle(qs);
currentQuizMeta = { id: 'final', title: 'Word Train Review' };
qIdx = 0; score = 0; resetTrain();
showScreen('quiz');
renderQuestion();
}
function decode(str){
return str
.replace(/“/g,'“').replace(/”/g,'”')
.replace(/’/g,'’').replace(/—/g,'—').replace(/−/g,'−').replace(/&/g,'&');
}
function renderQuestion(){
answered = false;
var item = currentQuizSet[qIdx];
document.getElementById('q-count').textContent = 'Question ' + (qIdx + 1) + ' of ' + currentQuizSet.length + (currentQuizMeta.id === 'final' ? ' — ' + decode(currentQuizMeta.title) : '');
document.getElementById('track-fill').style.width = Math.round((qIdx / currentQuizSet.length) * 100) + '%';
document.getElementById('q-kicker').textContent = item.type === 'tf' ? 'True or False?' : 'Choose the correct answer';
document.getElementById('q-text').textContent = decode(item.q);
var fb = document.getElementById('q-feedback');
fb.className = 'feedback'; fb.innerHTML = '';
document.getElementById('next-wrap').classList.remove('show');
var optWrap = document.getElementById('q-options');
optWrap.innerHTML = '';
if (item.type === 'tf'){
var row = document.createElement('div');
row.className = 'tf-row';
var trueBtn = document.createElement('button');
trueBtn.className = 'tf-btn'; trueBtn.innerHTML = CHECK_ICON + '<span>True</span>';
var falseBtn = document.createElement('button');
falseBtn.className = 'tf-btn'; falseBtn.innerHTML = X_ICON + '<span>False</span>';
trueBtn.addEventListener('click', function(){ handleTF(true, trueBtn); });
falseBtn.addEventListener('click', function(){ handleTF(false, falseBtn); });
row.appendChild(trueBtn); row.appendChild(falseBtn);
optWrap.appendChild(row);
} else {
item.options.forEach(function(opt){
var b = document.createElement('button');
b.className = 'opt';
b.innerHTML = '<span class="bullet"></span><span>' + decode(opt.text) + '</span>';
b.addEventListener('click', function(){ handleMC(opt, b, optWrap); });
optWrap.appendChild(b);
});
}
}
function lockOptions(){
document.querySelectorAll('.opt, .tf-btn').forEach(function(el){ el.disabled = true; });
}
function showFeedback(isCorrect){
var item = currentQuizSet[qIdx];
var fb = document.getElementById('q-feedback');
fb.className = 'feedback show ' + (isCorrect ? 'good' : 'bad');
fb.innerHTML = (isCorrect ? CHECK_ICON : X_ICON) + '<span>' + decode(isCorrect ? item.good : item.bad) + '</span>';
document.getElementById('next-wrap').classList.add('show');
if (isCorrect) score++;
revealProgress();
}
function handleMC(opt, btnEl, optWrap){
if (answered) return;
answered = true;
lockOptions();
var item = currentQuizSet[qIdx];
optWrap.querySelectorAll('.opt').forEach(function(el, i){
var thisOpt = item.options[i];
if (thisOpt.correct) el.classList.add('correct');
else if (el === btnEl) el.classList.add('wrong');
});
showFeedback(opt.correct);
}
function handleTF(choice, chosenBtn){
if (answered) return;
answered = true;
lockOptions();
var correct = currentQuizSet[qIdx].answer;
var isRight = (choice === correct);
chosenBtn.classList.add(isRight ? 'correct' : 'wrong');
if (!isRight){
var rightBtn = (correct === true) ? chosenBtn.parentElement.children[0] : chosenBtn.parentElement.children[1];
rightBtn.classList.add('correct');
}
showFeedback(isRight);
}
document.getElementById('btn-next').addEventListener('click', function(){
if (qIdx < currentQuizSet.length - 1){ qIdx++; renderQuestion(); }
else { finishQuiz(); }
});
function finishQuiz(){
document.getElementById('track-fill').style.width = '100%';
var total = currentQuizSet.length;
var starCount = starsFor(score / total);
var best = Math.max(progress[currentQuizMeta.id] || 0, score);
progress[currentQuizMeta.id] = best;
saveProgress(progress);
document.getElementById('stars').innerHTML = starsMarkup(starCount, 3);
document.getElementById('result-score').textContent = 'You got ' + score + ' out of ' + total + ' questions right on ' + decode(currentQuizMeta.title) + '!';
var msg;
if (starCount === 3) msg = 'Choo choo! Your train is complete — you’re a Word Train champion!';
else if (starCount === 2) msg = 'Great job! Your train is almost finished — try again to add the last cars!';
else msg = 'Good try! Let’s review the lesson and hop back on the train — you can do it!';
document.getElementById('result-msg').textContent = msg;
showScreen('results');
}
document.getElementById('btn-retry').addEventListener('click', function(){
if (currentQuizMeta.id === 'final') startFinalExam();
else startQuiz();
});
renderHome();
})();
</script>