-
-
Notifications
You must be signed in to change notification settings - Fork 36
Expand file tree
/
Copy pathquiz.html
More file actions
2249 lines (2075 loc) · 148 KB
/
Copy pathquiz.html
File metadata and controls
2249 lines (2075 loc) · 148 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
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html>
<html lang="de" data-bs-theme="light">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="Vokabel-Quiz — WordFeather. Teste dein Deutsch nach Niveau oder finde dein aktuelles CEFR-Level.">
<meta name="theme-color" content="#1d4ed8">
<link rel="icon" type="image/x-icon" href="/icons/favicon.ico">
<link rel="icon" type="image/png" sizes="32x32" href="/icons/32.png">
<link rel="icon" type="image/png" sizes="96x96" href="/icons/96.png">
<link rel="icon" type="image/png" sizes="192x192" href="/icons/192.png">
<link rel="apple-touch-icon" sizes="180x180" href="/icons/180.png">
<link rel="manifest" href="/manifest.json">
<meta name="apple-mobile-web-app-title" content="WordFeather">
<title>Vokabel-Quiz — WordFeather</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<style>
:root {
--accent: #1d4ed8;
--accent-soft: #eef2ff;
--good: #16a34a;
--bad: #dc2626;
}
body { background: #f8fafc; }
[data-bs-theme="dark"] body { background: #0f172a; }
.quiz-card {
max-width: 640px;
margin: 0 auto;
border-radius: 1rem;
box-shadow: 0 0.5rem 1.5rem rgba(0,0,0,.06);
}
.level-check {
display: inline-flex;
align-items: center;
justify-content: center;
width: 3.2rem;
height: 3.2rem;
border-radius: 0.75rem;
border: 2px solid #e2e8f0;
font-weight: 700;
cursor: pointer;
user-select: none;
transition: all .15s ease;
background: #fff;
}
[data-bs-theme="dark"] .level-check { background: #1e293b; border-color: #334155; color: #e2e8f0; }
.level-check.active {
border-color: var(--accent);
background: var(--accent);
color: #fff;
}
.level-check input { display: none; }
/* The real checkbox is hidden for the custom tile look, so keyboard
navigation needs its own visible focus indicator on the label itself —
otherwise tabbing through the level tiles shows no focus state at all. */
.level-check:has(input:focus-visible) {
outline: 2px solid var(--accent);
outline-offset: 2px;
}
@media (prefers-reduced-motion: reduce) {
.quiz-progress-bar .progress-bar,
.level-check,
.btn {
transition: none !important;
}
}
.direction-toggle .btn-check:checked + label {
background: var(--accent);
border-color: var(--accent);
color: #fff;
}
.quiz-progress-bar { height: 6px; }
.prompt-word {
font-size: 2.1rem;
font-weight: 700;
text-align: center;
}
.prompt-meta {
text-align: center;
color: #64748b;
font-size: .85rem;
}
.passage-card {
background: #fff; border: 1px solid #e2e8f0; border-radius: .85rem;
padding: 1.1rem 1.3rem; max-height: 300px; overflow-y: auto; line-height: 1.6;
}
[data-bs-theme="dark"] .passage-card { background: #1e293b; border-color: #334155; }
.passage-card p { margin-bottom: .65rem; }
.play-btn {
width: 5rem; height: 5rem; border-radius: 50%;
border: none; background: var(--accent); color: #fff;
font-size: 2rem; display: flex; align-items: center; justify-content: center;
margin: 0 auto; cursor: pointer; transition: all .15s ease;
box-shadow: 0 4px 14px rgba(29,78,216,.35);
}
.play-btn:hover:not(:disabled) { transform: scale(1.05); }
.play-btn:disabled { background: #94a3b8; box-shadow: none; cursor: not-allowed; }
.play-btn.playing { animation: placementPulse 1s infinite; }
@keyframes placementPulse { 0%,100% { box-shadow: 0 0 0 0 rgba(29,78,216,.4); } 50% { box-shadow: 0 0 0 14px rgba(29,78,216,0); } }
.play-status { text-align: center; font-size: .85rem; color: #64748b; }
.option-btn {
text-align: left;
padding: 0.85rem 1.1rem;
border-radius: 0.65rem;
border: 2px solid #e2e8f0;
background: #fff;
font-size: 1.05rem;
transition: all .12s ease;
}
[data-bs-theme="dark"] .option-btn { background: #1e293b; border-color: #334155; color: #e2e8f0; }
.option-btn:hover:not(:disabled) { border-color: var(--accent); background: var(--accent-soft); }
[data-bs-theme="dark"] .option-btn:hover:not(:disabled) { background: #1e3a5f; }
.option-btn:disabled { cursor: default; }
.option-btn.correct-choice { border-color: var(--good); background: #dcfce7; color: #166534; font-weight: 600; }
.option-btn.incorrect-choice { border-color: var(--bad); background: #fee2e2; color: #991b1b; font-weight: 600; }
[data-bs-theme="dark"] .option-btn.correct-choice { background: #052e16; color: #86efac; }
[data-bs-theme="dark"] .option-btn.incorrect-choice { background: #450a0a; color: #fca5a5; }
.option-letter {
display: inline-flex;
align-items: center;
justify-content: center;
width: 1.75rem;
height: 1.75rem;
border-radius: 50%;
background: #f1f5f9;
font-weight: 700;
font-size: 0.85rem;
margin-right: 0.6rem;
}
[data-bs-theme="dark"] .option-letter { background: #334155; }
/* Mode-tab subtitles (English translation under the German label): needs
to stay legible against BOTH the plain-card background (inactive tab)
and the solid blue fill (active tab) — a single "text-muted" grey looks
fine on white but goes low-contrast on blue. */
#modeTabs .nav-link .small { color: #64748b; }
#modeTabs .nav-link.active .small { color: rgba(255, 255, 255, 0.85); }
.feedback-box {
border-radius: 0.75rem;
padding: 1rem 1.25rem;
display: none;
}
.feedback-box.correct { background: #dcfce7; color: #166534; display: block; }
.feedback-box.incorrect { background: #fee2e2; color: #991b1b; display: block; }
.answer-explanation { border-top-color: currentColor !important; opacity: 0.85; font-size: 0.95rem; }
[data-bs-theme="dark"] .feedback-box.correct { background: #052e16; color: #86efac; }
[data-bs-theme="dark"] .feedback-box.incorrect { background: #450a0a; color: #fca5a5; }
.score-ring {
width: 140px;
height: 140px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 2rem;
font-weight: 800;
margin: 0 auto;
}
.level-result-badge {
display: inline-flex;
align-items: center;
justify-content: center;
width: 4rem;
height: 4rem;
border-radius: 50%;
background: var(--accent);
color: #fff;
font-weight: 800;
font-size: 1.5rem;
}
.hidden { display: none !important; }
</style>
</head>
<body>
<div id="header-placeholder"></div>
<script>
(function () {
var saved = localStorage.getItem('theme') || (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
document.documentElement.setAttribute('data-bs-theme', saved);
var headerFallback = '<nav class="navbar navbar-expand-lg navbar-dark bg-primary shadow-sm sticky-top"><div class="container"><a class="navbar-brand" href="index.html">🪶 WordFeather</a><button class="navbar-toggler border-0" type="button" data-bs-toggle="collapse" data-bs-target="#siteNavbar" aria-controls="siteNavbar" aria-expanded="false" aria-label="Toggle navigation"><span class="navbar-toggler-icon"></span></button><div class="collapse navbar-collapse" id="siteNavbar"><ul class="navbar-nav me-auto mb-2 mb-lg-0 ms-lg-2" id="nav-main-links"><li class="nav-item"><a class="nav-link" href="index.html" id="nav-home">Home</a></li><li class="nav-item dropdown"><a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false" id="nav-levels">Levels</a><ul class="dropdown-menu"><li><a class="dropdown-item" href="A1/index.html" data-level="A1">A1 – Beginner</a></li><li><a class="dropdown-item" href="A2/index.html" data-level="A2">A2 – Elementary</a></li><li><hr class="dropdown-divider"></li><li><a class="dropdown-item" href="B1/index.html" data-level="B1">B1 – Intermediate</a></li><li><a class="dropdown-item" href="B2/index.html" data-level="B2">B2 – Upper-Intermediate</a></li><li><hr class="dropdown-divider"></li><li><a class="dropdown-item" href="C1/index.html" data-level="C1">C1 – Advanced</a></li><li><a class="dropdown-item" href="C2/index.html" data-level="C2">C2 – Mastery</a></li></ul></li><li class="nav-item"><a class="nav-link" href="dictionary.html" id="nav-dictionary">📖 Dictionary</a></li><li class="nav-item"><a class="nav-link ext-highlight quiz-highlight" href="quiz.html" id="nav-quiz">🎯 Quiz</a></li><li class="nav-item"><a class="nav-link ext-highlight leben-highlight" href="https://leben.wordfeather.com" target="_blank" rel="noopener" id="nav-leben"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="12" viewBox="0 0 5 3" style="vertical-align:middle;margin-right:3px;border-radius:1px" aria-hidden="true"><rect width="5" height="1" y="0" fill="#000"/><rect width="5" height="1" y="1" fill="#D00"/><rect width="5" height="1" y="2" fill="#FFCE00"/></svg>Leben in Deutschland</a></li></ul><div class="d-flex ms-lg-3 mt-2 mt-lg-0"><button id="themeToggle" class="btn btn-outline-light btn-sm theme-toggle" type="button" aria-label="Toggle color theme" title="Toggle color theme">🌙 Dark</button></div></div></div></nav>';
function renderHeader(html) {
// header.html's own markup uses "BASE/..." as a placeholder path
// (since the same file is fetched from every page, some nested
// deeper than others) — every OTHER page on the site replaces this
// with the real root-relative "/" before injecting it, but this
// step was missing here, so Home/Dictionary/Levels links on this
// page were literally pointing at "/BASE/index.html" etc., a URL
// that doesn't exist. WordFeather is hosted at the domain root, so
// BASE is simply "/" everywhere.
html = html.replace(/BASE\//g, '/');
document.getElementById('header-placeholder').innerHTML = html;
var btn = document.getElementById('themeToggle');
if (btn) {
function syncBtn() {
var dark = document.documentElement.getAttribute('data-bs-theme') === 'dark';
btn.textContent = dark ? '☀️ Light' : '🌙 Dark';
}
syncBtn();
btn.addEventListener('click', function () {
var next = document.documentElement.getAttribute('data-bs-theme') === 'dark' ? 'light' : 'dark';
document.documentElement.setAttribute('data-bs-theme', next);
localStorage.setItem('theme', next);
syncBtn();
});
}
}
fetch('/header.html')
.then(function (r) { return r.ok ? r.text() : Promise.reject(new Error('header fetch failed')); })
.then(function (html) { renderHeader(html); })
.catch(function () { renderHeader(headerFallback); });
})();
</script>
<main class="container py-4">
<p class="mb-4"><a href="/">Home</a> <span class="text-muted">/</span> <span class="text-muted">Quiz</span></p>
<!-- ============ SCREEN 1: Mode & options selection ============ -->
<section id="setupScreen">
<div class="text-center mb-4">
<h1 class="h3">🧠 Vokabel-Quiz</h1>
<p class="text-muted">Teste dein Deutsch — wähle ein Niveau oder finde dein aktuelles CEFR-Level.</p>
</div>
<div class="card quiz-card">
<div class="card-body p-4">
<ul class="nav nav-pills nav-fill mb-3 flex-wrap" id="modeTabs" role="tablist" aria-label="Quiz-Modus wählen / Choose quiz mode">
<li class="nav-item" role="presentation">
<button class="nav-link active" id="tab-practice" data-mode="practice" role="tab" aria-selected="true" aria-controls="practiceOptions">
<span class="d-block">📚 Wortschatz üben</span>
<span class="d-block small" style="font-weight:400;">Vocabulary</span>
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="tab-hoeren" data-mode="hoeren" role="tab" aria-selected="false" aria-controls="hoerenOptions">
<span class="d-block">🎧 Hören üben</span>
<span class="d-block small" style="font-weight:400;">Listening</span>
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="tab-lesen" data-mode="lesen" role="tab" aria-selected="false" aria-controls="lesenOptions">
<span class="d-block">📰 Lesen üben</span>
<span class="d-block small" style="font-weight:400;">Reading</span>
</button>
</li>
<li class="nav-item" role="presentation">
<a class="nav-link" href="grammar-quiz.html" title="Öffnet den Grammatik-Test / Opens the grammar test">
<span class="d-block">🔤 Grammatik-Test ↗</span>
<span class="d-block small" style="font-weight:400;">Grammar practice</span>
</a>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="tab-mistakes" data-mode="mistakes" role="tab" aria-selected="false" aria-controls="mistakesOptions">
<span class="d-block">❌ Meine Fehler</span>
<span class="d-block small" style="font-weight:400;">My mistakes</span>
</button>
</li>
</ul>
<!-- Placement/level tests — kept in their own small group, deliberately
separate from the practice-mode tablist above. These two always
render side by side regardless of viewport width, since it's a
fixed 2-item flex row rather than part of the larger nav-fill bar
(which redistributes items per row based on available width and
would otherwise split this pair apart unpredictably). -->
<div class="mb-4">
<p class="small text-muted fw-semibold mb-2">Einstufungstests <span class="text-muted fw-normal">/ Level tests</span></p>
<div class="d-flex gap-2 flex-wrap nav nav-pills">
<button class="nav-link border rounded flex-fill" id="tab-placement" data-mode="placement" style="min-width:200px;text-align:center;">
<span class="d-block">🎯 Niveau (Wortschatz)</span>
<span class="d-block small" style="font-weight:400;">Level test — vocabulary</span>
</button>
<a class="nav-link border rounded flex-fill" href="placement-test.html" title="Öffnet den Grammatik-Einstufungstest / Opens the grammar placement test" style="min-width:200px;text-align:center;">
<span class="d-block">🎯 Niveau (Grammatik) ↗</span>
<span class="d-block small" style="font-weight:400;">Level test — grammar</span>
</a>
</div>
</div>
<!-- Practice-by-level options (vocab) -->
<div id="practiceOptions" role="tabpanel" aria-labelledby="tab-practice" tabindex="0">
<label class="form-label fw-semibold">Niveau(s) auswählen <span class="text-muted fw-normal">/ Choose level(s)</span></label>
<div class="d-flex gap-2 flex-wrap mb-4" id="levelChecks">
<!-- filled by JS -->
</div>
<label class="form-label fw-semibold">Richtung <span class="text-muted fw-normal">/ Direction</span></label>
<div class="btn-group direction-toggle mb-4 w-100" role="group">
<input type="radio" class="btn-check" name="direction" id="dirDeEn" value="de-en" checked>
<label class="btn btn-outline-secondary" for="dirDeEn">DE → EN</label>
<input type="radio" class="btn-check" name="direction" id="dirEnDe" value="en-de">
<label class="btn btn-outline-secondary" for="dirEnDe">EN → DE</label>
<input type="radio" class="btn-check" name="direction" id="dirMixed" value="mixed">
<label class="btn btn-outline-secondary" for="dirMixed">Gemischt <span style="opacity:.75">/ Mixed</span></label>
</div>
<label class="form-label fw-semibold">Anzahl Fragen <span class="text-muted fw-normal">/ Number of questions</span></label>
<select class="form-select mb-4" id="questionCount">
<option value="10">10</option>
<option value="20" selected>20</option>
<option value="30">30</option>
<option value="50">50</option>
</select>
</div>
<!-- Hören practice options -->
<div id="hoerenOptions" class="hidden" role="tabpanel" aria-labelledby="tab-hoeren" tabindex="0">
<label class="form-label fw-semibold">Niveau auswählen <span class="text-muted fw-normal">/ Choose a level</span></label>
<div class="d-flex gap-2 flex-wrap mb-3" id="hoerenLevelChecks"></div>
<div class="alert alert-info small" id="hoerenLevelInfo"></div>
<p class="text-muted small mb-1">Jeder Text wird nur <strong>einmal</strong> vorgelesen, um die Hörverstehensübung anspruchsvoller zu machen.</p>
<p class="text-muted small" style="opacity:.75">Each text is played only <strong>once</strong> to make the listening practice more challenging.</p>
</div>
<!-- Lesen practice options -->
<div id="lesenOptions" class="hidden" role="tabpanel" aria-labelledby="tab-lesen" tabindex="0">
<label class="form-label fw-semibold">Niveau auswählen <span class="text-muted fw-normal">/ Choose a level</span></label>
<div class="d-flex gap-2 flex-wrap mb-3" id="lesenLevelChecks"></div>
<div class="alert alert-info small" id="lesenLevelInfo"></div>
<p class="text-muted small mb-1">Der Text bleibt sichtbar — Sie können jederzeit nachlesen.</p>
<p class="text-muted small" style="opacity:.75">The text stays visible — reread it anytime.</p>
</div>
<!-- Placement test explanation -->
<div id="placementOptions" class="hidden" role="tabpanel" aria-labelledby="tab-placement" tabindex="0">
<div class="alert alert-info">
<div>Der Level-Test beginnt bei <strong>A1</strong> mit Wortschatz (18 Fragen), Leseverstehen und
Hörverstehen. Bestehst du das gesamte Niveau (≥70%), geht es weiter mit A2, dann B1 — bis C2 oder
bis du ein Niveau nicht bestehst.</div>
<div class="mt-2" style="opacity:.75">The level test starts at <strong>A1</strong> with vocabulary
(18 questions), reading, and listening. If you pass the whole level (≥70%), it continues to A2,
then B1 — up to C2, or until you fail a level.</div>
<div class="mt-3 pt-2 border-top">⚠️ Deine Antworten hier zählen <strong>nicht</strong> zu deinem Fortschritt (Mein Fortschritt bleibt bei 0). Nutze „Wortschatz üben", um Fortschritt aufzubauen.</div>
<div style="opacity:.75">⚠️ Your answers here do <strong>not</strong> count toward your practice progress (My progress stays at 0). Use "Wortschatz üben" (Vocabulary) to build up progress.</div>
</div>
</div>
<div id="loadError" class="alert alert-danger hidden"></div>
<!-- Mistake Notebook options -->
<div id="mistakesOptions" class="hidden" role="tabpanel" aria-labelledby="tab-mistakes" tabindex="0">
<div class="alert alert-info" id="mistakesInfo">
<div>Lade Fehler...</div>
<div style="opacity:.75">Loading mistakes...</div>
</div>
<p class="text-muted small mb-1">Diese Wörter hast du zuletzt falsch beantwortet. Sobald du sie richtig beantwortest, verschwinden sie automatisch aus dieser Liste.</p>
<p class="text-muted small" style="opacity:.75">These are words you most recently got wrong. Once you answer them correctly, they automatically leave this list.</p>
</div>
<button class="btn btn-primary btn-lg w-100" id="startBtn">Quiz starten →</button>
<button class="btn btn-link w-100 mt-2" id="viewProgressBtn">📊 Meinen Fortschritt anzeigen / View my progress</button>
</div>
</div>
</section>
<!-- ============ SCREEN 2: Active quiz ============ -->
<section id="quizScreen" class="hidden">
<div class="quiz-card">
<div class="progress quiz-progress-bar mb-3">
<div class="progress-bar bg-primary" id="quizProgressBar" style="width:0%"></div>
</div>
<p class="text-center text-muted small mb-4" id="quizProgressText">Frage 1 / 20</p>
<!-- Vocab (Wortschatz) card — shown for kind='vocab' -->
<div class="card p-4 mb-3" id="vocabPromptCard">
<p class="prompt-meta mb-1" id="promptMeta">A1 · Nomen</p>
<p class="mb-2">
<span class="badge d-inline-flex align-items-center" id="promptLangBadge" style="background:#1d4ed8;"><svg xmlns="http://www.w3.org/2000/svg" width="18" height="13" viewBox="0 0 5 3" style="margin-right:4px;border-radius:2px" aria-hidden="true"><rect width="5" height="1" y="0" fill="#000"/><rect width="5" height="1" y="1" fill="#D00"/><rect width="5" height="1" y="2" fill="#FFCE00"/></svg>Deutsch</span>
</p>
<p class="prompt-word mb-0" id="promptWord">Haus</p>
</div>
<!-- Lesen passage — shown for kind='lesen'; stays visible the whole
time (no lock), matching real Lesen exam conditions. -->
<div id="lesenPanel" class="hidden">
<p class="prompt-meta mb-1 text-center" id="lesenMeta">A1 · Leseverstehen</p>
<p class="text-center fw-semibold mb-2" id="lesenTitle">Nachricht</p>
<div class="passage-card mb-3" id="lesenPassageCard"></div>
<p class="prompt-word mb-0 text-center" id="lesenQuestionText" style="font-size:1.25rem;">Frage?</p>
</div>
<!-- Hören play button — shown for kind='hoeren'; one-shot playback,
locked the instant it's clicked, matching real Hören conditions. -->
<div id="hoerenPanel" class="hidden">
<div class="card p-4 mb-3 text-center">
<p class="prompt-meta mb-1" id="hoerenMeta">A1 · Hörverstehen</p>
<p class="fw-semibold mb-3" id="hoerenTitle">Dialog</p>
<button class="play-btn" id="placementPlayBtn" type="button" aria-label="Text anhören">🔊</button>
<p class="play-status mt-2 mb-0" id="hoerenPlayStatus">Klicken Sie, um den Text einmal zu hören (Click to hear the text once)</p>
</div>
<p class="prompt-word mb-0 text-center" id="hoerenQuestionText" style="font-size:1.25rem;">Frage?</p>
</div>
<form id="answerForm" autocomplete="off">
<div id="optionsContainer" class="d-grid gap-2 mb-3"></div>
<div class="feedback-box mb-3" id="feedbackBox"></div>
<button type="button" class="btn btn-outline-secondary btn-lg w-100 mt-2 hidden" id="nextBtn">Weiter / Next →</button>
</form>
</div>
</section>
<!-- ============ SCREEN 3: Results (practice mode) ============ -->
<section id="resultsScreen" class="hidden">
<div class="quiz-card text-center">
<div class="card p-4">
<h2 class="h4 mb-4">Ergebnis <span class="text-muted fw-normal">/ Result</span></h2>
<div class="score-ring bg-primary-subtle text-primary mb-3" id="scoreRing">0%</div>
<p class="mb-4" id="scoreDetail">0 von 0 richtig</p>
<div class="d-flex gap-2 justify-content-center">
<button class="btn btn-primary" id="retryBtn">Nochmal üben → <span style="opacity:.75">/ Practice again →</span></button>
<a href="/dictionary.html" class="btn btn-outline-secondary">Zum Wörterbuch <span style="opacity:.75">/ To the dictionary</span></a>
</div>
</div>
</div>
</section>
<!-- ============ SCREEN 4: Placement test result ============ -->
<section id="placementResultScreen" class="hidden">
<div class="quiz-card text-center">
<div class="card p-4">
<h2 class="h4 mb-3">Dein wahrscheinliches Niveau <span class="text-muted fw-normal">/ Your likely level</span></h2>
<div class="level-result-badge mb-3" id="placementLevelBadge">A1</div>
<p class="mb-2" id="placementSummary"></p>
<p class="text-muted small mb-4">
Der Test gibt dir eine ungefähre Einschätzung deines aktuellen Niveaus. Er ersetzt keine offizielle Sprachprüfung.<br>
This test gives you an approximate estimate of your current level. It does not replace an official language exam.
</p>
<div class="table-responsive mb-4">
<table class="table table-sm">
<thead><tr><th>Niveau</th><th>Richtig <span class="text-muted fw-normal">/ Correct</span></th><th>Erreicht? <span class="text-muted fw-normal">/ Reached?</span></th></tr></thead>
<tbody id="placementBreakdown"></tbody>
</table>
</div>
<div class="d-flex gap-2 justify-content-center">
<button class="btn btn-primary" id="practiceThisLevelBtn">Auf diesem Niveau üben → <span style="opacity:.75">/ Practice at this level →</span></button>
<button class="btn btn-outline-secondary" id="placementRetryBtn">Test wiederholen <span style="opacity:.75">/ Retake test</span></button>
</div>
</div>
</div>
</section>
<!-- ============ SCREEN 4b: Level-passed transition ============ -->
<section id="placementTransitionScreen" class="hidden">
<div class="quiz-card text-center">
<div class="card p-4">
<div class="mb-2" style="font-size:2.5rem;">🎉</div>
<h2 class="h4 mb-2">
<span id="transitionPassedLevel">A1</span>-Niveau erreicht! <span style="opacity:.75">/ level reached!</span>
</h2>
<p class="text-muted mb-3" id="transitionStats">18 / 18 <span class="fw-semibold">richtig</span> <span style="opacity:.75">/ correct</span> (100%)</p>
<p class="mb-4">
Weiter geht's mit <strong id="transitionNextLevel">A2</strong> (moving on to this level).
</p>
<button class="btn btn-primary btn-lg w-100" id="transitionContinueBtn">Weiter → / Continue →</button>
</div>
</div>
</section>
<!-- ============ SCREEN 5: Progress overview ============ -->
<section id="progressScreen" class="hidden">
<div class="quiz-card">
<div class="card p-4">
<h2 class="h4 mb-1">📊 Mein Fortschritt <span class="text-muted fw-normal">/ My progress</span></h2>
<p class="text-muted small mb-1">Gespeichert auf diesem Gerät — nicht mit anderen Geräten synchronisiert.</p>
<p class="text-muted small mb-4" style="opacity:.75">Saved on this device only — not synced across devices.</p>
<div class="table-responsive mb-4">
<table class="table table-sm align-middle">
<thead><tr><th>Niveau</th><th>Gesehen <span class="text-muted fw-normal">/ Seen</span></th><th>Gemeistert <span class="text-muted fw-normal">/ Mastered</span></th><th>Fällig <span class="text-muted fw-normal">/ Due now</span></th></tr></thead>
<tbody id="progressBreakdown"></tbody>
</table>
</div>
<div class="d-flex gap-2 justify-content-center flex-wrap">
<button class="btn btn-primary" id="progressBackBtn">← Zurück <span style="opacity:.75">/ Back</span></button>
<button class="btn btn-outline-danger" id="resetProgressBtn">Fortschritt zurücksetzen <span style="opacity:.75">/ Reset progress</span></button>
</div>
</div>
</div>
</section>
</main>
<div id="footer-placeholder"></div>
<script>
(function() {
var footerFallback = '<footer class="site-footer mt-5 py-4 border-top"><div class="container"><div class="row g-3 align-items-center"><div class="col-lg text-center text-lg-start"><p class="mb-1 fw-semibold">🪶 WordFeather — Goethe-Zertifikat A1 to C2</p><p class="mb-0 text-secondary small">Official certification materials for German language proficiency</p></div><div class="col-lg-auto"><div class="d-flex justify-content-center gap-2 flex-wrap"><a href="https://www.goethe.de" class="btn btn-sm btn-outline-secondary" target="_blank" rel="noopener">Goethe-Institut ↗</a><a href="https://github.com/abdullahbutt/wordfeather" class="btn btn-sm btn-outline-secondary" target="_blank" rel="noopener">⭐ Star on GitHub</a><a href="https://www.paypal.com/paypalme/abdullahbuttde" class="btn btn-sm fw-semibold" style="background:#ffdd00;border-color:#ffdd00;color:#1a1a1a;" target="_blank" rel="noopener">☕ Buy me a Coffee</a></div></div></div><hr class="my-3" style="opacity:0.15;"><div class="d-flex justify-content-center gap-3 flex-wrap small"><a href="privacy.html" class="text-secondary text-decoration-none">Privacy & Impressum</a><span class="text-secondary">·</span><a href="https://github.com/abdullahbutt/wordfeather/issues" target="_blank" rel="noopener" class="text-secondary text-decoration-none">Contact (GitHub Issues)</a></div></div></footer>';
fetch('/footer.html?v=' + Date.now())
.then(function(r) { return r.ok ? r.text() : Promise.reject(new Error('footer fetch failed')); })
.then(function(html) { html = html.replace(/BASE\//g, '/'); document.getElementById('footer-placeholder').innerHTML = html; })
.catch(function() { document.getElementById('footer-placeholder').innerHTML = footerFallback; });
})();
</script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
<script>
(function () {
'use strict';
// =================================================================
// SESSION 2 — Persistence & spaced repetition (localStorage-based)
// =================================================================
// Note: this runs on the real deployed site (wordfeather.com), not inside
// a Claude artifact preview — so it uses the browser's own localStorage,
// not the Claude-only window.storage API.
var STORAGE_KEY = 'wf_quiz_progress_v1';
// Every storage read/write is wrapped in try/catch: localStorage can throw
// in private/incognito browsing in some browsers, or if the user has
// disabled site storage — in that case the quiz should keep working, just
// without persistence, rather than crash outright.
function loadProgress() {
try {
var raw = localStorage.getItem(STORAGE_KEY);
return raw ? JSON.parse(raw) : {};
} catch (e) {
console.warn('WordFeather quiz: could not read saved progress', e);
return {};
}
}
function saveProgress(progress) {
try {
localStorage.setItem(STORAGE_KEY, JSON.stringify(progress));
return true;
} catch (e) {
console.warn('WordFeather quiz: could not save progress', e);
return false;
}
}
var progressData = loadProgress();
// A word's dictionary entry has no guaranteed unique ID field, so build a
// stable composite key from level + article + de. This keeps two
// different-level entries that happen to share the same spelling from
// colliding in storage.
function wordKey(word) {
return (word.level || '?') + '|' + (word.article || '') + '|' + (word.de || '');
}
// Lesen/Hören practice questions have no word-like identity (no .de/.article),
// so reusing wordKey() for them would collide every question at the same level
// into a single key. Build a key from what actually identifies them instead —
// the question's own text is already unique within its reading/listening item.
function questionKey(item) {
if (item.kind === 'lesen' || item.kind === 'hoeren') {
return item.kind + '|' + item.level + '|' + (item.itemTitle || '') + '|' + item.prompt;
}
return wordKey(item);
}
var DAY_MS = 24 * 60 * 60 * 1000;
// Interval ladder in days for each consecutive correct streak level.
// A wrong answer resets the streak to 0 and brings the word back due
// almost immediately (10 minutes) rather than waiting a full day, so it
// resurfaces again within the same study session.
var INTERVAL_LADDER_DAYS = [0, 1, 2, 4, 7, 14, 30, 60];
function recordAnswer(word, correct) {
var key = questionKey(word);
var entry = progressData[key] || { streak: 0, timesCorrect: 0, timesWrong: 0, lastSeen: 0, nextDue: 0 };
entry.lastSeen = Date.now();
if (correct) {
entry.streak = Math.min(entry.streak + 1, INTERVAL_LADDER_DAYS.length - 1);
entry.timesCorrect++;
var intervalDays = INTERVAL_LADDER_DAYS[entry.streak];
entry.nextDue = Date.now() + intervalDays * DAY_MS;
} else {
entry.streak = 0;
entry.timesWrong++;
entry.nextDue = Date.now() + 10 * 60 * 1000; // due again in 10 minutes
}
progressData[key] = entry;
saveProgress(progressData);
}
function getEntry(word) {
return progressData[questionKey(word)] || null;
}
function isDue(word) {
var entry = getEntry(word);
if (!entry) return true; // never studied = always due
return entry.nextDue <= Date.now();
}
// "Mastered" = at least 3 correct answers in a row (streak >= 3),
// regardless of whether it's currently due for review again. "Due" is a
// separate, independent concept — see isDue() — so a word can be both
// "mastered" and "due" at the same time (e.g. a well-known word whose
// scheduled review has simply come around again).
function isMastered(word) {
var entry = getEntry(word);
return !!entry && entry.streak >= 3;
}
function computeProgressSummary() {
var summary = {};
LEVELS.forEach(function (lvl) {
summary[lvl] = { total: 0, seen: 0, mastered: 0, due: 0 };
});
allWords.forEach(function (w) {
if (!summary[w.level]) return;
summary[w.level].total++;
var entry = getEntry(w);
if (entry) {
summary[w.level].seen++;
if (isMastered(w)) summary[w.level].mastered++;
}
if (isDue(w)) summary[w.level].due++;
});
return summary;
}
function resetProgress() {
progressData = {};
try { localStorage.removeItem(STORAGE_KEY); } catch (e) { /* ignore */ }
}
// Mistake Notebook: an item counts as a "current mistake" if its last
// recorded attempt was wrong (streak reset to 0 by recordAnswer) and it
// has been gotten wrong at least once. This naturally shrinks on its own
// as the learner answers correctly in normal practice — no separate
// "clear mistake" action needed, since a correct answer already resets
// the streak upward and removes it from this list.
//
// Covers all three practice kinds — vocab words plus Lesen/Hören practice
// questions — since all three are now recorded via recordAnswer(). Lesen/
// Hören questions come only from the *practice* builders (not the
// placement ones), matching the same practice-only rule vocab already
// follows.
function getMistakeWords() {
var mistakes = [];
allWords.forEach(function (w) {
var entry = getEntry(w);
if (entry && entry.streak === 0 && entry.timesWrong > 0) {
mistakes.push(w);
}
});
LEVELS.forEach(function (lvl) {
var nonVocab = buildLesenPracticeQuestions(lvl).concat(buildHoerenPracticeQuestions(lvl));
nonVocab.forEach(function (q) {
var entry = getEntry(q);
if (entry && entry.streak === 0 && entry.timesWrong > 0) {
mistakes.push(q);
}
});
});
return mistakes;
}
var LEVELS = ['A1', 'A2', 'B1', 'B2', 'C1', 'C2'];
var synth = window.speechSynthesis; // used by the Hören placement phase below
// ---------------------------------------------------------------
// Lesen & Hören data for the placement test — one representative item
// per level, reused directly from lesen.html / hoeren.html (same
// original, copyright-safe content — not copied from any real Goethe/
// telc exam). Only ONE item per skill per level here (rather than the
// full set from those standalone pages) to keep the combined placement
// test a reasonable length — vocab + a reading + a listening sample
// per level, not the full practice-length battery.
// ---------------------------------------------------------------
var LESEN_DATA = {
A1: {
title: 'Nachricht von Peter', tag: 'Kurze Mitteilung',
passage: ['Liebe Susanne, ich komme morgen um 15:30 Uhr am Hauptbahnhof an. Kannst du mich abholen? Mein Zug kommt auf Gleis 7. Viele Grüße, Peter'],
questions: [
{ text: 'Wann kommt Peter an?', options: ['Um 15:30 Uhr', 'Um 13:30 Uhr', 'Um 17:30 Uhr', 'Um 15:00 Uhr'], answerIndex: 0, explanation: 'Im Text steht: „ich komme morgen um 15:30 Uhr am Hauptbahnhof an.“' },
{ text: 'Wo kommt er an?', options: ['Am Hauptbahnhof, Gleis 7', 'Am Flughafen', 'Am Busbahnhof', 'Am Hauptbahnhof, Gleis 3'], answerIndex: 0, explanation: 'Peter schreibt: „Mein Zug kommt auf Gleis 7“ — also am Hauptbahnhof, Gleis 7.' },
{ text: 'Was soll Susanne machen?', options: ['Peter abholen', 'Peter anrufen', 'Eine SMS schreiben', 'Zum Flughafen fahren'], answerIndex: 0, explanation: 'Peter fragt direkt: „Kannst du mich abholen?“' }
]
},
A2: {
title: 'Stadtfest Heidelberg', tag: 'Informationstext',
passage: ['Stadtfest Heidelberg. Samstag, 15. Juli — Sonntag, 16. Juli. Altstadt, rund um den Marktplatz. Samstag: 11:00–23:00 Uhr | Sonntag: 11:00–20:00 Uhr. Eintritt frei! Programm: Live-Musik, Kinderprogramm, internationales Essen, Kunsthandwerk.'],
questions: [
{ text: 'Das Stadtfest dauert drei Tage.', options: ['Richtig', 'Falsch'], answerIndex: 1, explanation: 'Das Fest dauert nur zwei Tage — Samstag und Sonntag —, nicht drei.' },
{ text: 'Am Sonntag endet das Fest früher als am Samstag.', options: ['Richtig', 'Falsch'], answerIndex: 0, explanation: 'Samstag endet das Fest um 23:00 Uhr, Sonntag schon um 20:00 Uhr — also früher.' },
{ text: 'Man muss Eintritt bezahlen.', options: ['Richtig', 'Falsch'], answerIndex: 1, explanation: 'Im Text steht ausdrücklich: „Eintritt frei!“' }
]
},
B1: {
title: 'Homeoffice in Deutschland', tag: 'Zeitungsbericht',
passage: ['Immer mehr Deutsche arbeiten im Homeoffice. 40 Prozent der Beschäftigten arbeiten regelmäßig von zu Hause. Die Vorteile: Man spart Zeit, kann sich die Zeit flexibler einteilen und hat oft eine bessere Work-Life-Balance. Allerdings gibt es auch Nachteile: Einsamkeit und fehlender Kontakt zu Kollegen. Experten empfehlen feste Arbeitszeiten und regelmäßige Pausen.'],
questions: [
{ text: 'Wie viel Prozent arbeiten im Homeoffice?', options: ['40%', '25%', '60%', '15%'], answerIndex: 0, explanation: 'Der Text nennt die Zahl direkt: „40 Prozent der Beschäftigten arbeiten regelmäßig von zu Hause.“' },
{ text: 'Was ist ein Vorteil?', options: ['Man spart Zeit und hat mehr Flexibilität', 'Höheres Gehalt', 'Mehr Kollegenkontakt', 'Kürzere Arbeitszeiten'], answerIndex: 0, explanation: 'Der Text nennt als Vorteile: „Man spart Zeit, kann sich die Zeit flexibler einteilen.“' },
{ text: 'Was empfehlen Experten?', options: ['Feste Arbeitszeiten einhalten', 'Nachts arbeiten', 'Keine Pausen machen', 'Immer erreichbar sein'], answerIndex: 0, explanation: 'Der letzte Satz lautet: „Experten empfehlen feste Arbeitszeiten und regelmäßige Pausen.“' }
]
},
B2: {
title: 'Kommentar: Tempolimit auf Autobahnen', tag: 'Meinungstext',
passage: ['Deutschland ist eines der wenigen Länder weltweit, in denen es auf Autobahnen kein generelles Tempolimit gibt. Befürworter argumentieren mit der Verkehrssicherheit: Bei niedrigerer Geschwindigkeit seien Unfälle weniger schwer. Ein Tempolimit von 130 km/h würde den CO2-Ausstoß reduzieren. Gegner sehen in der freien Fahrt ein Stück deutsche Identität und befürchten negative Auswirkungen auf die Autoindustrie. Ich persönlich bin der Meinung, dass ein Tempolimit längst überfällig ist.'],
questions: [
{ text: 'Was argumentieren Befürworter?', options: ['Verkehrssicherheit und CO2-Reduktion', 'Höhere Steuereinnahmen', 'Bessere Straßen', 'Weniger Staus'], answerIndex: 0, explanation: 'Befürworter nennen zwei Argumente: geringere Unfallschwere bei niedrigerer Geschwindigkeit und CO2-Reduktion durch ein Tempolimit von 130 km/h.' },
{ text: 'Was befürchten Gegner?', options: ['Negative Auswirkungen auf die Autoindustrie', 'Höhere Unfallzahlen', 'Weniger Tourismus', 'Höhere Benzinpreise'], answerIndex: 0, explanation: 'Der Text sagt: Gegner „…befürchten negative Auswirkungen auf die Autoindustrie.“' },
{ text: 'Welche Position vertritt der Autor?', options: ['Er ist für ein Tempolimit', 'Er ist dagegen', 'Er ist neutral', 'Er äußert keine Meinung'], answerIndex: 0, explanation: 'Der Autor schreibt direkt: „Ich persönlich bin der Meinung, dass ein Tempolimit längst überfällig ist.“' }
]
},
C1: {
title: 'Die Grenzen der künstlichen Intelligenz', tag: 'Sachtext',
passage: ['Die Fortschritte im Bereich der künstlichen Intelligenz haben in den letzten Jahren für erhebliches Aufsehen gesorgt. Dennoch wäre es verfehlt, daraus zu schließen, dass Maschinen in absehbarer Zeit das menschliche Denken ersetzen könnten. Was KI-Systeme leisten, ist eine hocheffiziente Mustererkennung auf der Grundlage großer Datenmengen. Was ihnen fehlt, ist ein genuines Verständnis dessen, was sie tun. Hinzu kommt das Problem der sogenannten Halluzinationen: KI-Systeme generieren mitunter Inhalte, die plausibel klingen, aber faktisch falsch sind. Dies ist ein fundamentales Defizit.'],
questions: [
{ text: 'Was können KI-Systeme laut Text besonders gut?', options: ['Mustererkennung auf Basis großer Datenmengen', 'Eigenständig neue Ideen entwickeln', 'Menschliche Gefühle verstehen', 'Ethische Entscheidungen treffen'], answerIndex: 0, explanation: 'Der Text sagt: KI-Systeme leisten „eine hocheffiziente Mustererkennung auf der Grundlage großer Datenmengen.“' },
{ text: 'Was fehlt KI-Systemen laut Autor?', options: ['Echtes Verständnis dessen, was sie tun', 'Ausreichend Rechenleistung', 'Genug Trainingsdaten', 'Schnelligkeit'], answerIndex: 0, explanation: 'Der Autor schreibt: KI-Systemen fehlt „ein genuines Verständnis dessen, was sie tun.“' },
{ text: 'Wie bewertet der Autor das Problem der Halluzinationen?', options: ['Als fundamentales Defizit', 'Als marginales technisches Problem', 'Als bereits gelöst', 'Als übertrieben dargestellt'], answerIndex: 0, explanation: 'Der letzte Satz des Textes lautet: „Dies ist ein fundamentales Defizit.“' }
]
},
C2: {
title: 'Die Paradoxie des Fortschritts', tag: 'Komplexer Sachtext',
passage: ['Es gehört zu den bemerkenswerten Paradoxien unserer Zeit, dass technologischer Fortschritt zunehmend zum Gegenstand fundamentaler Skepsis geworden ist. Die Verheißungen der Digitalisierung haben sich zwar in mancherlei Hinsicht erfüllt, doch gleichzeitig haben sie neue Probleme hervorgebracht. Während der Zugang zu Wissen nie einfacher war, fällt es den Menschen paradoxerweise immer schwerer, zwischen gesicherten Erkenntnissen und Desinformation zu unterscheiden. Die Algorithmen der sozialen Medien haben sich als mächtige Instrumente der Manipulation erwiesen, die zur Entstehung sogenannter Filterblasen beitragen.'],
questions: [
{ text: 'Worin besteht die "Paradoxie des Fortschritts" laut Autor?', options: ['Fortschritt löst Probleme, schafft aber gleichzeitig neue', 'Fortschritt war schon immer problematisch', 'Fortschritt hat nie Verheißungen erfüllt', 'Menschen lehnen Fortschritt ab'], answerIndex: 0, explanation: 'Der Text sagt, die Verheißungen der Digitalisierung hätten sich zwar erfüllt, „doch gleichzeitig haben sie neue Probleme hervorgebracht.“' },
{ text: 'Was kritisiert der Autor an den Algorithmen sozialer Medien?', options: ['Sie tragen zur Polarisierung bei und schaffen Filterblasen', 'Sie funktionieren nicht', 'Sie sind zu langsam', 'Sie verhindern den Zugang zu Information'], answerIndex: 0, explanation: 'Der Text sagt, die Algorithmen seien „mächtige Instrumente der Manipulation…, die zur Entstehung sogenannter Filterblasen beitragen.“' }
]
}
};
var HOEREN_DATA = {
A1: {
title: 'Dialog: Am Telefon',
script: 'Praxis Doktor Klein, guten Tag! Guten Tag, hier ist Frau Yilmaz. Ich möchte einen Termin machen. Ja, gerne. Wie wäre es am Donnerstag um 10 Uhr? Donnerstag geht leider nicht. Geht es auch am Freitag? Am Freitag um 11 Uhr? Ja, das passt. Vielen Dank!',
questions: [
{ text: 'Frau Yilmaz ruft beim Arzt an.', options: ['Richtig', 'Falsch'], answerIndex: 0, explanation: 'Der Anruf beginnt mit „Praxis Doktor Klein“ — Frau Yilmaz spricht also mit einer Arztpraxis.' },
{ text: 'Sie bekommt einen Termin am Donnerstag.', options: ['Richtig', 'Falsch'], answerIndex: 1, explanation: 'Donnerstag wird zuerst vorgeschlagen, aber sie sagt: „Donnerstag geht leider nicht.“ Der Termin wird auf Freitag verlegt.' },
{ text: 'Der Termin ist am Freitag um 11 Uhr.', options: ['Richtig', 'Falsch'], answerIndex: 0, explanation: 'Am Ende bestätigt sie: „Am Freitag um 11 Uhr? – Ja, das passt.“' }
]
},
A2: {
title: 'Zahnarzt (Anrufbeantworter)',
script: 'Guten Tag, hier ist die Zahnarztpraxis Doktor Hoffmann. Leider müssen wir Ihren Termin am Dienstag um 14 Uhr absagen, weil Herr Doktor Hoffmann erkrankt ist. Wir bieten Ihnen als neuen Termin Donnerstag um 10 Uhr an.',
questions: [
{ text: 'Warum wird der Termin abgesagt?', options: ['Dr. Hoffmann ist krank', 'Die Praxis ist geschlossen', 'Der Patient hat abgesagt', 'Es gibt einen Notfall'], answerIndex: 0, explanation: 'Die Nachricht sagt: „…weil Herr Doktor Hoffmann erkrankt ist.“' },
{ text: 'Wann ist der neue Termin?', options: ['Donnerstag um 10 Uhr', 'Dienstag um 14 Uhr', 'Freitag um 10 Uhr', 'Donnerstag um 14 Uhr'], answerIndex: 0, explanation: 'Die Praxis bietet an: „…Donnerstag um 10 Uhr an.“ Dienstag 14 Uhr war der ALTE, abgesagte Termin.' }
]
},
B1: {
title: 'Dialog: Berufliche Veränderung',
script: 'Ich habe mich entschieden, meinen Job zu kündigen. Was? Aber du arbeitest erst seit zwei Jahren dort! Die Arbeit ist langweilig und mein Chef ist schwierig. Ich mache eine Weiterbildung in Webdesign. Hast du genug gespart? Ja, und die Weiterbildung dauert nur sechs Monate.',
questions: [
{ text: 'Warum kündigt die Person?', options: ['Langweilige Arbeit und schwieriger Chef', 'Zu wenig Gehalt', 'Zu weiter Arbeitsweg', 'Gesundheitliche Probleme'], answerIndex: 0, explanation: 'Sie sagt: „Die Arbeit ist langweilig und mein Chef ist schwierig.“' },
{ text: 'Was hat die Person vor?', options: ['Weiterbildung in Webdesign', 'Studium beginnen', 'Ins Ausland gehen', 'Ein eigenes Geschäft eröffnen'], answerIndex: 0, explanation: 'Sie sagt: „Ich mache eine Weiterbildung in Webdesign.“' },
{ text: 'Wie lange dauert die Weiterbildung?', options: ['Sechs Monate', 'Drei Monate', 'Ein Jahr', 'Zwölf Monate'], answerIndex: 0, explanation: 'Am Ende heißt es: „die Weiterbildung dauert nur sechs Monate.“' }
]
},
B2: {
title: 'Interview: Ehrenamt',
script: 'Frau Doktor Becker, was hat sich beim ehrenamtlichen Engagement verändert? Die Art des Engagements hat sich stark gewandelt. Früher haben sich Menschen langfristig an einen Verein gebunden. Heute sehen wir einen Trend zum projektbezogenen Engagement. Ein Problem für Organisationen: die fehlende Planungssicherheit.',
questions: [
{ text: 'Was hat sich verändert?', options: ['Vom langfristigen zum projektbezogenen Engagement', 'Ehrenamt ist komplett verschwunden', 'Nur ältere Menschen engagieren sich noch', 'Es gibt keine Vereine mehr'], answerIndex: 0, explanation: 'Frau Dr. Becker sagt: früher langfristige Vereinsbindung, heute „ein Trend zum projektbezogenen Engagement.“' },
{ text: 'Was ist ein Problem für Organisationen?', options: ['Fehlende Planungssicherheit', 'Zu viele Freiwillige', 'Zu hohe Kosten', 'Mangelnde staatliche Unterstützung'], answerIndex: 0, explanation: 'Sie nennt direkt: „Ein Problem für Organisationen: die fehlende Planungssicherheit.“' }
]
},
C1: {
title: 'Dialog: Karrierewechsel',
script: 'Sag mal, stimmt es, dass du deinen Job an der Uni aufgibst? Ja, die akademische Laufbahn hat mich zunehmend frustriert. Der Druck, ständig zu publizieren, die befristeten Verträge, die Unsicherheit — das will ich mir nicht mehr antun. Ich fange nächsten Monat bei einer Unternehmensberatung an.',
questions: [
{ text: 'Warum gibt die Person die akademische Karriere auf?', options: ['Frustration über Publikationsdruck, befristete Verträge, Unsicherheit', 'Zu niedriges Gehalt', 'Konflikt mit dem Professor', 'Umzug in eine andere Stadt'], answerIndex: 0, explanation: 'Genannt werden: „Der Druck, ständig zu publizieren, die befristeten Verträge, die Unsicherheit.“' },
{ text: 'Was beginnt die Person nächsten Monat?', options: ['Stelle bei einer Unternehmensberatung', 'Ein neues Studium', 'Eine eigene Firma', 'Eine Stelle an einer anderen Uni'], answerIndex: 0, explanation: 'Sie sagt: „Ich fange nächsten Monat bei einer Unternehmensberatung an.“' }
]
},
C2: {
title: 'Vortrag: Spracherwerb und kognitive Entwicklung',
script: 'Ich möchte heute über den Zusammenhang zwischen Spracherwerb und kognitiver Entwicklung sprechen. Es ist ein weit verbreiteter Irrtum, dass Sprache lediglich ein Kommunikationsinstrument ist. Sprache formt unser Denken — diese als Sapir-Whorf-Hypothese bekannte These gilt in ihrer radikalen, deterministischen Form heute als überholt. Bilinguale Menschen zeigen in zahlreichen Studien eine erhöhte kognitive Flexibilität. Allerdings handelt es sich um Korrelationen, nicht um nachgewiesene Kausalitäten.',
questions: [
{ text: 'Die Sapir-Whorf-Hypothese gilt in ihrer radikalen Form als bestätigt.', options: ['Richtig', 'Falsch'], answerIndex: 1, explanation: 'Der Vortrag sagt das Gegenteil: die These „gilt in ihrer radikalen, deterministischen Form heute als überholt.“' },
{ text: 'Bilingualismus zeigt Zusammenhänge mit kognitiver Flexibilität.', options: ['Richtig', 'Falsch'], answerIndex: 0, explanation: 'Der Vortrag sagt: „Bilinguale Menschen zeigen in zahlreichen Studien eine erhöhte kognitive Flexibilität.“' },
{ text: 'Der Sprecher warnt vor voreiligen Kausalschlüssen.', options: ['Richtig', 'Falsch'], answerIndex: 0, explanation: 'Der letzte Satz lautet: „Allerdings handelt es sich um Korrelationen, nicht um nachgewiesene Kausalitäten.“' }
]
}
};
// ---------------------------------------------------------------
// Full Hören & Lesen PRACTICE datasets (all items per level, not just
// the single placement-sample above) — reused verbatim from the
// standalone hoeren.html / lesen.html pages, now folded into Quiz as
// two additional practice tabs so there's one single practice hub
// instead of scattering skills across separate top-level pages.
// ---------------------------------------------------------------
function tf(text, answer, explanation) {
return { type: 'mc', text: text, options: ['Richtig', 'Falsch'], answerIndex: answer ? 0 : 1, explanation: explanation };
}
function mc(text, options, answerIndex, explanation) {
return { type: 'mc', text: text, options: options, answerIndex: answerIndex, explanation: explanation };
}
var HOEREN_PRACTICE_DATA = {
A1: [
{
title: 'Dialog 1: Am Telefon', part: 'Teil 1',
script: 'Praxis Doktor Klein, guten Tag! Guten Tag, hier ist Frau Yilmaz. Ich möchte einen Termin machen. Ja, gerne. Wie wäre es am Donnerstag um 10 Uhr? Donnerstag geht leider nicht. Geht es auch am Freitag? Am Freitag um 11 Uhr? Ja, das passt. Vielen Dank!',
questions: [
tf('Frau Yilmaz ruft beim Arzt an.', true, 'Der Anruf beginnt mit „Praxis Doktor Klein“ — Frau Yilmaz ruft also bei einer Arztpraxis an.'),
tf('Sie bekommt einen Termin am Donnerstag.', false, 'Donnerstag wird vorgeschlagen, aber sie sagt: „Donnerstag geht leider nicht.“'),
tf('Der Termin ist am Freitag um 11 Uhr.', true, 'Am Ende bestätigt sie: „Am Freitag um 11 Uhr? – Ja, das passt.“')
]
},
{
title: 'Dialog 2: Am Bahnhof', part: 'Teil 1',
script: 'Entschuldigung, wann fährt der nächste Zug nach Hamburg? Der nächste Zug fährt um 14:35 Uhr von Gleis 8. Und wann kommt er in Hamburg an? Um 16:50 Uhr. Was kostet eine Fahrkarte? Einfach oder hin und zurück? Einfach, bitte. Das macht 45 Euro.',
questions: [
mc('Wohin will die Person fahren?', ['Nach Hamburg', 'Nach Berlin', 'Nach München', 'Nach Köln'], 0, 'Die Frage lautet direkt: „wann fährt der nächste Zug nach Hamburg?“'),
mc('Um wie viel Uhr fährt der Zug?', ['14:35 Uhr', '13:35 Uhr', '15:35 Uhr', '16:50 Uhr'], 0, 'Die Antwort ist: „Der nächste Zug fährt um 14:35 Uhr.“'),
mc('Von welchem Gleis?', ['Gleis 8', 'Gleis 3', 'Gleis 5', 'Gleis 10'], 0, 'Der Zug fährt „…von Gleis 8.“'),
mc('Wie viel kostet die Fahrkarte?', ['45 Euro', '35 Euro', '55 Euro', '40 Euro'], 0, 'Am Ende heißt es: „Das macht 45 Euro.“')
]
},
{
title: 'Hörtext 1: Telefonansage', part: 'Teil 2',
script: 'Sie haben die Arztpraxis Doktor Müller erreicht. Die Praxis ist von Montag bis Freitag von 8 bis 12 Uhr und von 14 bis 17 Uhr geöffnet. Am Mittwochnachmittag ist die Praxis geschlossen. In dringenden Fällen rufen Sie bitte die Notfallnummer 112 an.',
questions: [
mc('Wann ist die Praxis morgens geöffnet?', ['Von 8 bis 12 Uhr', 'Von 9 bis 13 Uhr', 'Von 7 bis 11 Uhr', 'Von 8 bis 13 Uhr'], 0, 'Die Ansage sagt: „von 8 bis 12 Uhr und von 14 bis 17 Uhr geöffnet.“'),
mc('Wann ist die Praxis nachmittags geschlossen?', ['Am Mittwochnachmittag', 'Am Montagnachmittag', 'Am Freitagnachmittag', 'Am Dienstagnachmittag'], 0, 'Die Ansage sagt: „Am Mittwochnachmittag ist die Praxis geschlossen.“'),
mc('Welche Nummer ruft man im Notfall an?', ['112', '110', '911', '115'], 0, 'Die Ansage nennt: „die Notfallnummer 112.“')
]
},
{
title: 'Hörtext 2: Wetterbericht', part: 'Teil 2',
script: 'Der Wetterbericht für heute: Am Vormittag scheint die Sonne bei Temperaturen um 15 Grad. Am Nachmittag wird es bewölkt und am Abend kann es regnen. Morgen wird es den ganzen Tag sonnig und warm.',
questions: [
tf('Am Vormittag scheint die Sonne.', true, 'Der Bericht sagt: „Am Vormittag scheint die Sonne.“'),
tf('Es wird den ganzen Tag sonnig.', false, 'Nur am Vormittag ist es sonnig; am Nachmittag wird es bewölkt, am Abend kann es regnen.'),
tf('Morgen regnet es.', false, 'Der Bericht sagt: „Morgen wird es den ganzen Tag sonnig und warm“ — kein Regen.')
]
},
{
title: 'Durchsage 1: Am Bahnhof', part: 'Teil 3',
script: 'Achtung auf Gleis 3: Der ICE 574 nach München über Nürnberg hat eine Verspätung von 15 Minuten. Voraussichtliche Abfahrt: 10:45 Uhr.',
questions: [
mc('Welcher Zug hat Verspätung?', ['ICE 574', 'ICE 475', 'ICE 754', 'RE 574'], 0, 'Die Durchsage nennt: „Der ICE 574 nach München.“'),
mc('Wie viel Verspätung hat er?', ['15 Minuten', '5 Minuten', '30 Minuten', '45 Minuten'], 0, 'Die Durchsage sagt: „eine Verspätung von 15 Minuten.“'),
mc('Von welchem Gleis fährt der Zug?', ['Gleis 3', 'Gleis 8', 'Gleis 1', 'Gleis 5'], 0, 'Die Durchsage beginnt: „Achtung auf Gleis 3.“')
]
},
{
title: 'Durchsage 2: Im Kaufhaus', part: 'Teil 3',
script: 'Liebe Kunden, heute haben wir ein Sonderangebot: Alle Winterjacken sind um 30 Prozent reduziert. Sie finden die Winterjacken in der 2. Etage. Das Angebot gilt nur heute.',
questions: [
mc('Was ist im Sonderangebot?', ['Winterjacken', 'Sommerkleider', 'Schuhe', 'Handschuhe'], 0, 'Die Durchsage sagt: „Alle Winterjacken sind um 30 Prozent reduziert.“'),
mc('Wie viel Prozent Rabatt gibt es?', ['30%', '20%', '50%', '15%'], 0, 'Die Durchsage nennt: „um 30 Prozent reduziert.“'),
mc('In welcher Etage?', ['2. Etage', '1. Etage', '3. Etage', 'Erdgeschoss'], 0, 'Die Durchsage sagt: „Sie finden die Winterjacken in der 2. Etage.“'),
mc('Wie lange gilt das Angebot?', ['Nur heute', 'Diese Woche', 'Bis Samstag', 'Den ganzen Monat'], 0, 'Die Durchsage sagt: „Das Angebot gilt nur heute.“')
]
}
],
A2: [
{
title: 'Hörtext 1: Zahnarzt (Anrufbeantworter)', part: 'Teil 1',
script: 'Guten Tag, hier ist die Zahnarztpraxis Doktor Hoffmann. Leider müssen wir Ihren Termin am Dienstag um 14 Uhr absagen, weil Herr Doktor Hoffmann erkrankt ist. Wir bieten Ihnen als neuen Termin Donnerstag um 10 Uhr an. Bitte rufen Sie zurück.',
questions: [
mc('Warum wird der Termin abgesagt?', ['Dr. Hoffmann ist krank', 'Die Praxis ist geschlossen', 'Der Patient hat abgesagt', 'Es gibt einen Notfall'], 0, 'Die Nachricht sagt: „…weil Herr Doktor Hoffmann erkrankt ist.“'),
mc('Wann ist der neue Termin?', ['Donnerstag um 10 Uhr', 'Dienstag um 14 Uhr', 'Freitag um 10 Uhr', 'Donnerstag um 14 Uhr'], 0, 'Die Praxis bietet an: „Donnerstag um 10 Uhr.“')
]
},
{
title: 'Hörtext 3: Supermarkt (Durchsage)', part: 'Teil 2',
script: 'Liebe Kunden, heute haben wir besondere Angebote: Frische Erdbeeren, 500 Gramm nur 1,99 Euro. Außerdem alle Joghurts 20 Prozent günstiger. Die Angebote gelten bis Samstag.',
questions: [
tf('Die Erdbeeren kosten 1,99 Euro pro Kilo.', false, 'Die Durchsage sagt „500 Gramm nur 1,99 Euro“ — das ist ein halbes Kilo, nicht ein ganzes.'),
tf('Joghurts sind diese Woche billiger.', true, 'Die Durchsage sagt: „alle Joghurts 20 Prozent günstiger.“'),
tf('Die Angebote gelten nur heute.', false, 'Die Durchsage sagt: „Die Angebote gelten bis Samstag“ — nicht nur heute.')
]
},
{
title: 'Dialog 1: Wohnung mieten', part: 'Teil 3',
script: 'Guten Tag, ich rufe wegen der Wohnungsanzeige an. Ja, die Wohnung ist noch frei. 2 Zimmer mit Balkon, 55 Quadratmeter im 3. Stock mit Einbauküche. Was kostet sie? 520 Euro kalt plus 150 Euro Nebenkosten. Kann ich besichtigen? Mittwoch um 16 Uhr? Ja, gerne. Bis dann!',
questions: [
mc('Wie viele Zimmer?', ['2 Zimmer', '1 Zimmer', '3 Zimmer', '4 Zimmer'], 0, 'Die Antwort ist: „2 Zimmer mit Balkon.“'),
mc('Gesamtkosten?', ['670 Euro', '520 Euro', '150 Euro', '700 Euro'], 0, '520 Euro kalt plus 150 Euro Nebenkosten ergibt 670 Euro.'),
mc('Wann ist die Besichtigung?', ['Mittwoch um 16 Uhr', 'Dienstag um 16 Uhr', 'Mittwoch um 14 Uhr', 'Donnerstag um 16 Uhr'], 0, 'Am Ende wird vereinbart: „Mittwoch um 16 Uhr? – Ja, gerne.“')
]
}
],
B1: [
{
title: 'Dialog: Ernährung', part: 'Teil 1',
script: 'Seit ich mich vegetarisch ernähre, fühle ich mich viel besser. Wie lange machst du das schon? Seit ungefähr drei Monaten. Am Anfang war es schwer. Und jetzt vermisst du nichts? Nein, gar nicht. Und ich habe sogar abgenommen.',
questions: [
tf('Sie ernährt sich seit einem Jahr vegetarisch.', false, 'Sie sagt: „Seit ungefähr drei Monaten“ — nicht seit einem Jahr.'),
tf('Am Anfang war es einfach.', false, 'Sie sagt: „Am Anfang war es schwer“ — nicht einfach.'),
tf('Sie fühlt sich jetzt besser.', true, 'Sie sagt zu Beginn: „fühle ich mich viel besser.“')
]
},
{
title: 'Dialog: Berufliche Veränderung', part: 'Teil 3',
script: 'Ich habe mich entschieden, meinen Job zu kündigen. Was? Aber du arbeitest erst seit zwei Jahren dort! Die Arbeit ist langweilig und mein Chef ist schwierig. Ich mache eine Weiterbildung in Webdesign. Hast du genug gespart? Ja, und die Weiterbildung dauert nur sechs Monate. Viel Erfolg! Ich drücke dir die Daumen.',
questions: [
mc('Warum kündigt die Person?', ['Langweilige Arbeit und schwieriger Chef', 'Zu wenig Gehalt', 'Zu weiter Arbeitsweg', 'Gesundheitliche Probleme'], 0, 'Sie sagt: „Die Arbeit ist langweilig und mein Chef ist schwierig.“'),
mc('Was hat die Person vor?', ['Weiterbildung in Webdesign', 'Studium beginnen', 'Ins Ausland gehen', 'Ein eigenes Geschäft eröffnen'], 0, 'Sie sagt: „Ich mache eine Weiterbildung in Webdesign.“'),
mc('Wie lange dauert die Weiterbildung?', ['Sechs Monate', 'Drei Monate', 'Ein Jahr', 'Zwölf Monate'], 0, 'Sie sagt: „die Weiterbildung dauert nur sechs Monate.“')
]
},
{
title: 'Vortrag: Ehrenamtliches Engagement', part: 'Teil 4',
script: 'In Deutschland engagieren sich rund 30 Millionen Menschen ehrenamtlich — etwa 40 Prozent der Bevölkerung über 14 Jahre. Die meisten sind im Sportbereich aktiv. Gründe: etwas für die Gesellschaft tun, neue Leute kennenlernen, Erfahrungen sammeln. Problem: Es wird schwieriger, Freiwillige zu finden.',
questions: [
tf('40 Prozent der Deutschen über 14 sind ehrenamtlich aktiv.', true, 'Der Vortrag sagt: „30 Millionen Menschen ehrenamtlich — etwa 40 Prozent der Bevölkerung über 14 Jahre.“'),
tf('Am meisten engagieren sich Menschen im Bereich Musik.', false, 'Der Vortrag sagt: „Die meisten sind im Sportbereich aktiv“ — nicht Musik.'),
tf('Es wird leichter, Freiwillige zu finden.', false, 'Der Vortrag sagt das Gegenteil: „Es wird schwieriger, Freiwillige zu finden.“')
]
}
],
B2: [
{
title: 'Interview: Ehrenamt (Dr. Becker)', part: 'Teil 1',
script: 'Frau Doktor Becker, Sie forschen seit Jahren zum Thema ehrenamtliches Engagement. Was hat sich in den letzten Jahren verändert? Die Art des Engagements hat sich stark gewandelt. Früher haben sich Menschen langfristig an einen Verein gebunden. Heute sehen wir einen Trend zum projektbezogenen Engagement. Junge Menschen möchten sich zwar einbringen, aber nicht jahrelang an eine Organisation gebunden sein. Welche Folgen hat das? Einerseits ist die Flexibilität ein Vorteil — mehr Menschen beteiligen sich. Andererseits fehlt den Organisationen die Planungssicherheit. Was müsste sich ändern? Organisationen müssen sich anpassen. Sie sollten flexiblere Möglichkeiten anbieten, sich zu engagieren. Auch digitale Formate könnten helfen.',
questions: [
mc('Was hat sich verändert?', ['Vom langfristigen zum projektbezogenen Engagement', 'Ehrenamt ist komplett verschwunden', 'Nur ältere Menschen engagieren sich noch', 'Es gibt keine Vereine mehr'], 0, 'Dr. Becker sagt: früher langfristige Vereinsbindung, heute „ein Trend zum projektbezogenen Engagement.“'),
mc('Was ist ein Problem für Organisationen?', ['Fehlende Planungssicherheit', 'Zu viele Freiwillige', 'Zu hohe Kosten', 'Mangelnde staatliche Unterstützung'], 0, 'Sie sagt: „…fehlt den Organisationen die Planungssicherheit.“'),
mc('Was empfiehlt Dr. Becker?', ['Flexiblere Möglichkeiten und digitale Formate', 'Höhere Mitgliedsbeiträge', 'Strengere Regeln für Freiwillige', 'Weniger Vereine gründen'], 0, 'Sie sagt: „Sie sollten flexiblere Möglichkeiten anbieten… Auch digitale Formate könnten helfen.“')
]
},
{
title: 'Diskussion: Bedingungsloses Grundeinkommen', part: 'Teil 4',
script: 'Person A sagt: Ich bin fest davon überzeugt, dass ein bedingungsloses Grundeinkommen die richtige Antwort auf die Herausforderungen der Digitalisierung ist. Wenn Maschinen immer mehr Arbeit übernehmen, brauchen die Menschen ein Sicherheitsnetz. Person B sagt: Das klingt ja schön, aber wer soll das bezahlen? Die Steuerlast wäre enorm. Außerdem befürchte ich, dass viele Menschen dann gar nicht mehr arbeiten würden. Person C sagt: Ich sehe das differenzierter. Ein Grundeinkommen für alle halte ich für unrealistisch, aber ein Modell, das besonders gefährdete Gruppen unterstützt, könnte sinnvoll sein.',
questions: [
mc('Wie steht Person A zum Grundeinkommen?', ['Eindeutig dafür', 'Eindeutig dagegen', 'Neutral', 'Unentschieden'], 0, 'Person A sagt: „Ich bin fest davon überzeugt, dass ein bedingungsloses Grundeinkommen die richtige Antwort ist.“'),
mc('Wie steht Person B?', ['Eindeutig dagegen', 'Eindeutig dafür', 'Neutral', 'Unentschieden'], 0, 'Person B fragt kritisch „wer soll das bezahlen?“ und äußert nur Bedenken, keine Zustimmung.'),
mc('Wie steht Person C?', ['Teilweise dafür, differenziert', 'Eindeutig dagegen', 'Komplett neutral', 'Eindeutig dafür ohne Einschränkung'], 0, 'Person C sagt: „Ich sehe das differenzierter… könnte sinnvoll sein“ — weder klare Zustimmung noch Ablehnung.')
]
}
],
C1: [
{
title: 'Dialog: Karrierewechsel', part: 'Teil 1',
script: 'Sag mal, stimmt es, dass du deinen Job an der Uni aufgibst? Ja, ich habe lange darüber nachgedacht. Die akademische Laufbahn hat mich zunehmend frustriert. Der Druck, ständig zu publizieren, die befristeten Verträge, die Unsicherheit — das will ich mir nicht mehr antun. Aber du hast doch gerade erst deine Habilitation abgeschlossen! Wirfst du das nicht alles weg? So sehe ich das nicht. Die Kompetenzen, die ich mir angeeignet habe, sind auch außerhalb der Universität gefragt. Ich fange nächsten Monat bei einer Unternehmensberatung an. Und du hast kein schlechtes Gewissen? Anfangs schon. Aber letztlich muss jeder für sich selbst entscheiden, wo er seine Stärken am besten einsetzen kann.',
questions: [
mc('Warum gibt die Person die akademische Karriere auf?', ['Frustration über Publikationsdruck, befristete Verträge, Unsicherheit', 'Zu niedriges Gehalt', 'Konflikt mit dem Professor', 'Umzug in eine andere Stadt'], 0, 'Sie nennt: „Der Druck, ständig zu publizieren, die befristeten Verträge, die Unsicherheit.“'),
mc('Was beginnt die Person nächsten Monat?', ['Stelle bei einer Unternehmensberatung', 'Ein neues Studium', 'Eine eigene Firma', 'Eine Stelle an einer anderen Uni'], 0, 'Sie sagt: „Ich fange nächsten Monat bei einer Unternehmensberatung an.“'),
mc('Hatte die Person anfangs Bedenken?', ['Ja, ein schlechtes Gewissen', 'Nein, gar keine', 'Ja, finanzielle Sorgen', 'Ja, Angst vor dem Scheitern'], 0, 'Auf die Frage nach dem Gewissen antwortet sie: „Anfangs schon.“')
]
},
{
title: 'Podiumsdiskussion: Grundeinkommen', part: 'Teil 3',
script: 'Person A sagt: Es gibt keinerlei empirische Evidenz für die Finanzierbarkeit. Person B sagt: Unter bestimmten Bedingungen könnte ein modifiziertes Modell funktionieren. Person C sagt: Die Würde des Menschen erfordert materielle Absicherung.',
questions: [
mc('Wer sagt: "Die Würde des Menschen erfordert materielle Absicherung"?', ['Person C', 'Person A', 'Person B', 'Der Moderator'], 0, 'Nur Person C argumentiert moralisch-philosophisch über Menschenwürde; Person A argumentiert empirisch (fehlende Evidenz), Person B pragmatisch-bedingt (mögliches Modell).'),
mc('Wer sagt: "Es gibt keinerlei empirische Evidenz für die Finanzierbarkeit"?', ['Person A', 'Person B', 'Person C', 'Der Moderator'], 0, 'Nur Person A bezweifelt die Finanzierbarkeit mit einem empirischen Argument; Person B und C äußern sich nicht zu diesem spezifischen Punkt.'),
mc('Wer vertritt eine differenzierte, bedingte Position?', ['Person B', 'Person A', 'Person C', 'Keiner'], 0, 'Person B sagt: „Unter bestimmten Bedingungen könnte ein modifiziertes Modell funktionieren“ — eine bedingte, abgestufte Position.')
]
}
],
C2: [
{
title: 'Vortrag: Spracherwerb und kognitive Entwicklung', part: 'Teil 1',
script: 'Meine sehr verehrten Damen und Herren, ich möchte heute über den Zusammenhang zwischen Spracherwerb und kognitiver Entwicklung sprechen. Es ist ein weit verbreiteter Irrtum, dass Sprache lediglich ein Kommunikationsinstrument ist. Sprache formt unser Denken — diese These, bekannt als Sapir-Whorf-Hypothese, mag in ihrer deterministischen Variante überholt sein, doch in ihrer relativistischen Ausprägung wird sie durch zahlreiche Studien gestützt. Sprecher von Sprachen mit einem differenzierten Farbvokabular können feine Farbunterschiede nachweislich schneller identifizieren. Das Russische etwa unterscheidet lexikalisch zwischen Hellblau und Dunkelblau. Bilinguale Menschen zeigen in zahlreichen Studien eine erhöhte kognitive Flexibilität und eine verzögerte Manifestation altersbedingter kognitiver Einschränkungen. Allerdings handelt es sich um Korrelationen, nicht um nachgewiesene Kausalitäten. Es wäre unwissenschaftlich, daraus voreilige Schlüsse zu ziehen.',
questions: [
tf('Die Sapir-Whorf-Hypothese gilt in ihrer radikalen Form als bestätigt.', false, 'Der Vortrag sagt das Gegenteil: die deterministische Variante „mag… überholt sein.“'),
tf('Russische Muttersprachler unterscheiden Blautöne schneller.', true, 'Der Vortrag sagt: „Das Russische… unterscheidet lexikalisch zwischen Hellblau und Dunkelblau“, und Sprecher mit differenziertem Farbvokabular identifizieren Farbunterschiede nachweislich schneller.'),
tf('Bilingualismus kann altersbedingte kognitive Einschränkungen komplett verhindern.', false, 'Der Vortrag spricht nur von einer „verzögerten Manifestation“, nicht von vollständiger Verhinderung.'),
tf('Der Sprecher warnt vor voreiligen Kausalschlüssen.', true, 'Der Vortrag endet: „Es wäre unwissenschaftlich, daraus voreilige Schlüsse zu ziehen.“')
]
},
{
title: 'Podiumsdiskussion: Staatliche Kunstförderung', part: 'Teil 2',
script: 'Unser Thema heute: Staatliche Kunstförderung — notwendige Investition oder Verschwendung von Steuergeldern? Professor Richter sagt: Die Frage müsste lauten: Können wir es uns leisten, Kunst nicht zu fördern? Kunst ist ein Grundpfeiler einer offenen Gesellschaft. Frau Becker sagt: Grundsätzlich stimme ich zu, allerdings muss man auch fragen, was gefördert wird und wessen Kunst. Die staatliche Förderung bevorzugt etablierte Institutionen und vernachlässigt innovative Projekte. Herr Wagner sagt: Ich sehe das pragmatischer. Warum sollte der Steuerzahler für eine Oper bezahlen, die nur von einer kleinen Elite besucht wird? Wenn Kunst relevant ist, wird sie ihren Markt finden. Professor Richter antwortet: Das ist ein gefährlicher Trugschluss. Der Markt ist kein geeignetes Instrument, um den Wert von Kunst zu bemessen.',
questions: [
mc('Wer sagt "Kunstförderung ist unverzichtbar für die Demokratie"?', ['Prof. Richter', 'Frau Becker', 'Herr Wagner', 'Der Moderator'], 0, 'Er fragt: „Können wir es uns leisten, Kunst nicht zu fördern?“ und nennt Kunst einen „Grundpfeiler einer offenen Gesellschaft.“'),
mc('Wer sagt "Die Förderung muss gerechter verteilt werden"?', ['Frau Becker', 'Prof. Richter', 'Herr Wagner', 'Der Moderator'], 0, 'Sie sagt: „die staatliche Förderung bevorzugt etablierte Institutionen und vernachlässigt innovative Projekte.“'),
mc('Wer meint "Der Markt sollte über den Wert von Kunst entscheiden"?', ['Herr Wagner', 'Prof. Richter', 'Frau Becker', 'Der Moderator'], 0, 'Er sagt: „Wenn Kunst relevant ist, wird sie ihren Markt finden.“'),
mc('Wer hält Marktlogik für Kunst ungeeignet?', ['Prof. Richter', 'Herr Wagner', 'Frau Becker', 'Der Moderator'], 0, 'Er antwortet: „Der Markt ist kein geeignetes Instrument, um den Wert von Kunst zu bemessen.“')
]
}
]
}
var LESEN_PRACTICE_DATA = {
A1: [
{
title: 'Schild: Bibliothek', part: 'Teil 1', tag: 'Schild (Sign)',
passage: ['Bibliothek\nMo–Fr: 9:00–18:00\nSa: 10:00–14:00\nSo: geschlossen'],
questions: [
tf('Die Bibliothek ist am Sonntag geöffnet.', false, 'Das Schild sagt: „So: geschlossen“ — am Sonntag ist geschlossen.'),
tf('Am Samstag ist die Bibliothek von 10 bis 14 Uhr offen.', true, 'Das Schild sagt: „Sa: 10:00–14:00.“'),