Repository navigation
Expand file tree
/
Copy pathindex.html
More file actions
1078 lines (1035 loc) · 56.3 KB
/
Copy pathindex.html
File metadata and controls
1078 lines (1035 loc) · 56.3 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="fr">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Corps humain et micro-organismes — je révise</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;500;700;900&display=swap" rel="stylesheet">
<style>
/* ============================ jetons ============================ */
:root{
--nuit:#0B1622; --fond:#0F1D2B; --carte:#16293B; --carte2:#1E3750; --trait:#2B4762;
--texte:#E9F2F8; --doux:#9DB5C6; --faible:#6C879C;
--vert:#4FC38A; --bleu:#4E9BE0; --rose:#F08FB4; --ambre:#F0A742;
--violet:#B58BE0; --turquoise:#5FD0CE; --rouge:#F0655E;
--display:'Outfit', Verdana, Geneva, sans-serif;
--corps:Verdana, Geneva, Tahoma, sans-serif;
--r:18px;
}
*{box-sizing:border-box;}
html,body{margin:0;padding:0;}
body{
background:var(--nuit); color:var(--texte); font-family:var(--corps);
font-size:16px; line-height:1.55; -webkit-font-smoothing:antialiased;
min-height:100vh; overflow-x:hidden;
}
body::before{
content:''; position:fixed; inset:0; pointer-events:none; z-index:0;
background:
radial-gradient(900px 600px at 15% -5%, rgba(79,195,138,.13), transparent 60%),
radial-gradient(800px 700px at 90% 10%, rgba(181,139,224,.13), transparent 60%),
radial-gradient(900px 700px at 50% 110%, rgba(78,155,224,.12), transparent 60%);
}
#fond-microbes{position:fixed; inset:0; z-index:0; pointer-events:none; opacity:.20;}
.wrap{position:relative; z-index:1; max-width:1000px; margin:0 auto; padding:22px 18px 80px;}
/* ============================ en-tête ============================ */
.entete{display:flex; align-items:center; gap:14px; flex-wrap:wrap; margin-bottom:26px;}
.pastille{
width:52px;height:52px;border-radius:16px;flex:none;display:grid;place-items:center;
background:linear-gradient(140deg,var(--vert),var(--bleu)); box-shadow:0 10px 26px rgba(78,155,224,.28);
}
.pastille svg{width:30px;height:30px;}
.entete h1{
font-family:var(--display); font-weight:900; font-size:clamp(21px,3.6vw,30px);
margin:0; letter-spacing:-.02em; line-height:1.1;
}
.entete p{margin:2px 0 0; color:var(--doux); font-size:13px;}
.btn-retour{
margin-left:auto; background:var(--carte); border:1px solid var(--trait); color:var(--texte);
font-family:var(--display); font-weight:500; font-size:14px; padding:10px 16px; border-radius:99px;
cursor:pointer; display:none; transition:.18s;
}
.btn-retour:hover{background:var(--carte2); transform:translateY(-1px);}
/* ============================ boîte de Petri ============================ */
.intro{
font-family:var(--display); font-weight:300; font-size:clamp(17px,2.4vw,21px);
color:var(--doux); max-width:620px; margin:0 0 6px;
}
.intro b{color:var(--texte); font-weight:700;}
.dish-zone{display:flex; justify-content:center; margin:8px 0 10px;}
.dish{
position:relative; width:min(560px,92vw); aspect-ratio:1; border-radius:50%;
background:
radial-gradient(circle at 32% 26%, rgba(255,255,255,.06), transparent 55%),
radial-gradient(circle at 50% 50%, #17334a 0%, #12283b 62%, #0e2032 100%);
border:2px solid rgba(159,182,198,.28);
box-shadow:0 0 0 10px rgba(159,182,198,.05), 0 26px 60px rgba(0,0,0,.55), inset 0 0 60px rgba(0,0,0,.35);
}
.dish::after{
content:''; position:absolute; inset:7%; border-radius:50%;
border:1px dashed rgba(159,182,198,.16);
pointer-events:none; /* le liseré ne doit jamais intercepter les clics */
z-index:0;
}
.colonie{
position:absolute; transform:translate(-50%,-50%);
width:27%; aspect-ratio:1; border-radius:50%; border:0; cursor:pointer;
background:transparent; padding:0; color:var(--texte); font-family:var(--display);
transition:transform .22s cubic-bezier(.34,1.4,.64,1);
z-index:2; /* au-dessus du liseré de la boîte */
}
.colonie:hover,.colonie:focus-visible{transform:translate(-50%,-50%) scale(1.09); outline:none;}
.colonie:focus-visible .bulle{box-shadow:0 0 0 3px var(--texte);}
.bulle{
position:absolute; inset:0; border-radius:47% 53% 51% 49% / 52% 48% 52% 48%;
background:var(--ac); opacity:.92;
box-shadow:0 0 30px -4px var(--ac), inset 0 -10px 22px rgba(0,0,0,.25);
display:grid; place-items:center; text-align:center; padding:8px;
animation:blob 14s ease-in-out infinite;
}
@keyframes blob{
0%,100%{border-radius:47% 53% 51% 49% / 52% 48% 52% 48%;}
50%{border-radius:53% 47% 46% 54% / 47% 55% 45% 53%;}
}
.colonie:nth-child(2n) .bulle{animation-duration:17s; animation-direction:reverse;}
.bulle span{
pointer-events:none; color:#0B1622; font-weight:700; font-size:clamp(11px,1.9vw,14px); line-height:1.15;
text-shadow:0 1px 0 rgba(255,255,255,.25);
}
.jauge{
pointer-events:none; position:absolute; left:50%; bottom:-4px; transform:translateX(-50%);
background:var(--nuit); border:1px solid var(--trait); color:var(--doux);
font-size:11px; font-weight:500; padding:2px 9px; border-radius:99px; white-space:nowrap;
}
.jauge.plein{color:#0B1622; background:var(--vert); border-color:var(--vert); font-weight:700;}
@media(max-width:620px){
.dish{
aspect-ratio:auto; border-radius:22px; padding:14px; display:grid;
grid-template-columns:1fr 1fr; gap:14px; box-shadow:0 18px 40px rgba(0,0,0,.45);
}
.dish::after{display:none;}
.colonie{position:relative; transform:none; width:auto; aspect-ratio:1/.9;}
.colonie:hover,.colonie:focus-visible{transform:scale(1.04);}
.bulle span{font-size:13px;}
.jauge{bottom:2px;}
}
/* ============================ contrôle blanc ============================ */
.bandeau-controle{
margin-top:26px; border-radius:var(--r); padding:20px 22px;
background:linear-gradient(120deg, rgba(240,167,66,.16), rgba(240,101,94,.13));
border:1px solid rgba(240,167,66,.35); display:flex; gap:18px; align-items:center; flex-wrap:wrap;
}
.bandeau-controle h2{font-family:var(--display); font-size:19px; margin:0 0 4px; font-weight:700;}
.bandeau-controle p{margin:0; color:var(--doux); font-size:14px;}
.bandeau-controle .txt{flex:1 1 260px;}
/* ============================ boutons ============================ */
.btn{
font-family:var(--display); font-weight:700; font-size:15px; border:0; cursor:pointer;
padding:13px 22px; border-radius:99px; background:var(--vert); color:#08131c;
transition:transform .16s, filter .16s; white-space:nowrap;
}
.btn:hover{transform:translateY(-2px); filter:brightness(1.08);}
.btn:disabled{opacity:.45; cursor:default; transform:none;}
.btn.secondaire{background:var(--carte2); color:var(--texte); border:1px solid var(--trait);}
.btn.ambre{background:var(--ambre);}
.btn:focus-visible{outline:3px solid var(--texte); outline-offset:2px;}
/* ============================ thème ============================ */
#vue-theme,#vue-controle{display:none;}
.titre-theme{display:flex; align-items:center; gap:14px; margin:0 0 4px;}
.puce{width:16px;height:16px;border-radius:50%; background:var(--ac); flex:none; box-shadow:0 0 16px var(--ac);}
.titre-theme h2{font-family:var(--display); font-weight:900; font-size:clamp(22px,4vw,32px); margin:0; letter-spacing:-.02em;}
.fiche{
background:var(--carte); border:1px solid var(--trait); border-left:5px solid var(--ac);
border-radius:14px; padding:16px 20px; margin:16px 0 26px;
}
.fiche h3{font-family:var(--display); font-size:13px; letter-spacing:.09em; text-transform:uppercase; color:var(--ac); margin:0 0 10px;}
.fiche ul{margin:0; padding-left:20px;}
.fiche li{margin:6px 0; font-size:15px; color:#DCE9F1;}
.fiche b{color:#fff;}
.progression{display:flex; align-items:center; gap:10px; margin:0 0 18px; color:var(--doux); font-size:13px;}
.barre{flex:1; height:7px; background:var(--carte2); border-radius:99px; overflow:hidden;}
.barre i{display:block; height:100%; width:0; background:var(--ac); border-radius:99px; transition:width .5s cubic-bezier(.2,.8,.3,1);}
/* ============================ exercices ============================ */
.exo{
background:var(--carte); border:1px solid var(--trait); border-radius:var(--r);
padding:20px 22px; margin-bottom:16px; animation:apparait .4s both;
}
@keyframes apparait{from{opacity:0; transform:translateY(14px);} to{opacity:1; transform:none;}}
.exo .num{
font-family:var(--display); font-size:12px; letter-spacing:.1em; text-transform:uppercase;
color:var(--faible); display:block; margin-bottom:6px;
}
.exo .enonce{font-family:var(--display); font-weight:500; font-size:clamp(17px,2.3vw,19px); margin:0 0 16px; line-height:1.35;}
.aide{font-size:13px; color:var(--doux); font-style:italic; margin:-8px 0 14px;}
.choix{display:grid; gap:9px;}
.choix.deux{grid-template-columns:1fr 1fr;}
@media(max-width:600px){.choix.deux{grid-template-columns:1fr;}}
.opt{
display:flex; align-items:center; gap:12px; text-align:left; width:100%;
background:var(--carte2); border:1px solid var(--trait); color:var(--texte);
border-radius:13px; padding:13px 15px; font-family:var(--corps); font-size:15px;
cursor:pointer; transition:.15s;
}
.opt:hover:not(:disabled){border-color:var(--ac); background:#24405b;}
.opt .lettre{
flex:none; width:26px; height:26px; border-radius:8px; background:var(--trait);
display:grid; place-items:center; font-family:var(--display); font-weight:700; font-size:13px;
}
.opt.juste{background:rgba(79,195,138,.18); border-color:var(--vert);}
.opt.juste .lettre{background:var(--vert); color:#08131c;}
.opt.faux{background:rgba(240,101,94,.16); border-color:var(--rouge);}
.opt.faux .lettre{background:var(--rouge); color:#1a0b0b;}
.opt:disabled{cursor:default;}
.opt svg{flex:none;}
.retour{
margin-top:14px; padding:12px 15px; border-radius:12px; font-size:14.5px;
display:none; animation:apparait .3s both;
}
.retour.ok{background:rgba(79,195,138,.14); border:1px solid rgba(79,195,138,.45);}
.retour.ko{background:rgba(240,101,94,.13); border:1px solid rgba(240,101,94,.42);}
.retour b{font-family:var(--display);}
/* paires */
.paires{display:grid; grid-template-columns:1fr 1fr; gap:9px;}
@media(max-width:600px){.paires{grid-template-columns:1fr;}}
.paires .col{display:grid; gap:9px; align-content:start;}
.jeton{
background:var(--carte2); border:1px solid var(--trait); color:var(--texte);
border-radius:12px; padding:11px 14px; font-family:var(--corps); font-size:14.5px;
cursor:pointer; text-align:left; transition:.15s;
}
.jeton:hover:not(:disabled){border-color:var(--ac);}
.jeton.actif{border-color:var(--ambre); background:rgba(240,167,66,.16);}
.jeton.trouve{background:rgba(79,195,138,.15); border-color:var(--vert); cursor:default; opacity:.75;}
.jeton.rate{animation:secoue .35s;}
@keyframes secoue{25%{transform:translateX(-6px)}75%{transform:translateX(6px)}}
/* ordre */
.pioche,.serie{display:flex; flex-wrap:wrap; gap:9px; min-height:52px;}
.serie{
border:1.5px dashed var(--trait); border-radius:13px; padding:9px; margin-bottom:11px;
align-items:center;
}
.serie:empty::before{content:'Clique les étapes dans le bon ordre'; color:var(--faible); font-size:13.5px; font-style:italic; padding:6px;}
.etape{
background:var(--carte2); border:1px solid var(--trait); color:var(--texte);
border-radius:11px; padding:10px 14px; font-family:var(--corps); font-size:14.5px; cursor:pointer;
display:flex; align-items:center; gap:9px; transition:.15s;
}
.etape:hover:not(:disabled){border-color:var(--ac);}
.etape .rang{
width:22px;height:22px;border-radius:7px;background:var(--ac);color:#08131c;
display:grid;place-items:center;font-family:var(--display);font-weight:700;font-size:12px;
}
.etape.juste{border-color:var(--vert); background:rgba(79,195,138,.15);}
.etape.faux{border-color:var(--rouge); background:rgba(240,101,94,.14);}
/* texte à trous */
.trous{font-size:16px; line-height:2.5;}
.trous select{
font-family:var(--corps); font-size:15px; background:var(--carte2); color:var(--texte);
border:1px solid var(--trait); border-bottom:2px solid var(--ac); border-radius:9px;
padding:6px 9px; margin:0 3px; cursor:pointer; max-width:min(230px,60vw);
}
.trous select.juste{border-color:var(--vert); background:rgba(79,195,138,.16);}
.trous select.faux{border-color:var(--rouge); background:rgba(240,101,94,.14);}
/* figures */
.figs{display:flex; gap:14px; flex-wrap:wrap; justify-content:center; margin-bottom:16px;}
.fig-cible{
background:#0d1c2a; border:1px solid var(--trait); border-radius:14px; padding:12px 16px; text-align:center;
}
.fig-cible span{display:block; font-size:12px; color:var(--doux); margin-top:4px;}
.opt-fig{
display:flex; flex-direction:column; align-items:center; gap:6px; padding:12px;
background:var(--carte2); border:1px solid var(--trait); border-radius:14px; cursor:pointer; transition:.15s;
}
.opt-fig:hover:not(:disabled){border-color:var(--ac); transform:translateY(-2px);}
.opt-fig.juste{border-color:var(--vert); background:rgba(79,195,138,.16);}
.opt-fig.faux{border-color:var(--rouge); background:rgba(240,101,94,.14);}
.opt-fig .lettre{font-family:var(--display); font-weight:700; font-size:13px; color:var(--doux);}
.grille-fig{display:flex; gap:12px; flex-wrap:wrap; justify-content:center;}
/* résultat */
.bilan-fin{
text-align:center; background:var(--carte); border:1px solid var(--trait);
border-radius:var(--r); padding:30px 22px; animation:apparait .45s both;
}
.bilan-fin .score{
font-family:var(--display); font-weight:900; font-size:clamp(42px,10vw,66px); line-height:1;
background:linear-gradient(120deg,var(--ac),var(--texte)); -webkit-background-clip:text;
background-clip:text; color:transparent;
}
.bilan-fin .sur{color:var(--doux); font-size:15px; margin-bottom:10px;}
.bilan-fin h3{font-family:var(--display); font-size:21px; margin:6px 0 4px;}
.bilan-fin p{color:var(--doux); margin:0 auto 20px; max-width:440px;}
.actions{display:flex; gap:10px; justify-content:center; flex-wrap:wrap;}
.rappel{text-align:left; margin:22px auto 0; max-width:560px;}
.rappel h4{font-family:var(--display); font-size:13px; letter-spacing:.08em; text-transform:uppercase; color:var(--faible); margin:0 0 8px;}
.rappel li{margin:7px 0; font-size:14.5px; color:#D6E5EF;}
.pied{text-align:center; color:var(--faible); font-size:12.5px; margin-top:40px;}
@media (prefers-reduced-motion: reduce){
*{animation:none !important; transition:none !important;}
}
</style>
</head>
<body>
<svg id="fond-microbes" aria-hidden="true"></svg>
<div class="wrap">
<header class="entete">
<div class="pastille">
<svg viewBox="0 0 24 24" fill="none" stroke="#08131c" stroke-width="2" stroke-linecap="round">
<circle cx="12" cy="12" r="8.5"/><path d="M6 8.5 C10 11, 14 6, 18 9"/><circle cx="9.5" cy="14.5" r="1.6"/>
</svg>
</div>
<div>
<h1>Corps humain et micro-organismes</h1>
<p>Chapitre 1 — SVT 3<sup>e</sup> · je révise, je m'entraîne, je me teste</p>
</div>
<button class="btn-retour" id="btn-retour">← Revenir à la boîte</button>
</header>
<!-- ================= ACCUEIL ================= -->
<section id="vue-accueil">
<p class="intro">Six colonies ont poussé dans la boîte. <b>Clique sur l'une d'elles</b> pour t'entraîner. Quand tu as tout juste, la colonie devient verte.</p>
<div class="dish-zone"><div class="dish" id="dish"></div></div>
<div class="bandeau-controle">
<div class="txt">
<h2>Le contrôle blanc</h2>
<p>15 questions tirées au hasard dans tout le chapitre. Pas de correction pendant l'épreuve : tu vois tes réponses à la fin, comme pour un vrai contrôle.</p>
</div>
<button class="btn ambre" id="btn-controle">Lancer le contrôle blanc</button>
</div>
</section>
<!-- ================= THÈME ================= -->
<section id="vue-theme">
<div class="titre-theme"><span class="puce"></span><h2 id="theme-titre"></h2></div>
<div class="fiche" id="theme-fiche"></div>
<div class="progression">
<span id="progression-txt"></span>
<div class="barre"><i id="progression-barre"></i></div>
</div>
<div id="theme-exos"></div>
</section>
<!-- ================= CONTRÔLE ================= -->
<section id="vue-controle">
<div class="titre-theme"><span class="puce"></span><h2>Contrôle blanc</h2></div>
<div class="progression">
<span id="ctrl-txt"></span>
<div class="barre"><i id="ctrl-barre"></i></div>
</div>
<div id="ctrl-zone"></div>
</section>
<p class="pied">Fais-toi confiance : si tu te trompes, relis l'explication et recommence.</p>
</div>
<script>
/* ==========================================================================
1. Figures : anticorps, antigènes, pathogènes, antibiogramme
========================================================================== */
const AC_COL = {T:'#4E9BE0', C:'#F0A742', R:'#B58BE0'};
function siteSVG(tx,ty,deg,forme,col){
const r = deg*Math.PI/180, ux=Math.cos(r), uy=Math.sin(r), px=-uy, py=ux;
const L=(a,b,c,d)=>`<line x1="${a.toFixed(1)}" y1="${b.toFixed(1)}" x2="${c.toFixed(1)}" y2="${d.toFixed(1)}"/>`;
if(forme==='T'){
let s='';
for(const sg of [1,-1]){
const e=(deg+sg*40)*Math.PI/180;
s+=L(tx,ty,tx+11*Math.cos(e),ty+11*Math.sin(e));
}
return s;
}
if(forme==='C'){
const b=6.5;
const a1x=tx+b*px, a1y=ty+b*py, a2x=tx-b*px, a2y=ty-b*py;
return L(a1x,a1y,a2x,a2y)+L(a1x,a1y,a1x+8*ux,a1y+8*uy)+L(a2x,a2y,a2x+8*ux,a2y+8*uy);
}
const rad=7, cx=tx+rad*ux, cy=ty+rad*uy;
const a=(deg+90)*Math.PI/180, b2=(deg+270)*Math.PI/180;
return `<path d="M ${(cx+rad*Math.cos(a)).toFixed(1)} ${(cy+rad*Math.sin(a)).toFixed(1)}
A ${rad} ${rad} 0 0 1 ${(cx+rad*Math.cos(b2)).toFixed(1)} ${(cy+rad*Math.sin(b2)).toFixed(1)}" fill="none"/>`;
}
function anticorpsSVG(forme,taille=96){
const col=AC_COL[forme];
const fx=50,fy=64, lx=26,ly=32, rx=74,ry=32;
const dg=(ax,ay)=>Math.atan2(ay-fy,ax-fx)*180/Math.PI;
return `<svg viewBox="0 0 100 96" width="${taille}" height="${taille*.96}" aria-hidden="true">
<g stroke="${col}" stroke-width="5.5" stroke-linecap="round" fill="none">
<line x1="50" y1="90" x2="${fx}" y2="${fy}"/>
<line x1="${fx}" y1="${fy}" x2="${lx}" y2="${ly}"/>
<line x1="${fx}" y1="${fy}" x2="${rx}" y2="${ry}"/>
${siteSVG(lx,ly,dg(lx,ly),forme,col)}
${siteSVG(rx,ry,dg(rx,ry),forme,col)}
</g></svg>`;
}
function antigeneSVG(forme,x,y,haut){
const s=haut?1:-1;
if(forme==='T') return `<polygon points="${x-8},${y} ${x+8},${y} ${x},${y+s*11}"/>`;
if(forme==='C') return `<rect x="${x-7}" y="${haut?y-10:y}" width="14" height="10"/>`;
return `<path d="M ${x-8} ${y} a 8 8 0 0 ${haut?1:0} 16 0 z"/>`;
}
function pathogeneSVG(forme,taille=170){
let ag='';
for(const dx of [-34,0,34]){ ag+=antigeneSVG(forme,90+dx,34,true); ag+=antigeneSVG(forme,90+dx,86,false); }
return `<svg viewBox="0 0 180 120" width="${taille}" height="${taille*120/180}" aria-hidden="true">
<g fill="#3E7CB8" stroke="#8FC4EE" stroke-width="2">
<rect x="24" y="34" width="132" height="52" rx="26"/>${ag}
</g></svg>`;
}
function lymphoSVG(forme,taille=120){
const col=AC_COL[forme];
let acs='';
[[60,26,-90],[26,52,-150],[94,52,-30]].forEach(([x,y,a])=>{
acs+=`<g transform="translate(${x},${y}) rotate(${a+90}) scale(.42) translate(-50,-90)">
<g stroke="${col}" stroke-width="11" stroke-linecap="round" fill="none">
<line x1="50" y1="90" x2="50" y2="64"/><line x1="50" y1="64" x2="26" y2="32"/><line x1="50" y1="64" x2="74" y2="32"/>
${siteSVG(26,32,Math.atan2(32-64,26-50)*180/Math.PI,forme,col)}
${siteSVG(74,32,Math.atan2(32-64,74-50)*180/Math.PI,forme,col)}
</g></g>`;
});
return `<svg viewBox="0 0 120 120" width="${taille}" height="${taille}" aria-hidden="true">
<circle cx="60" cy="66" r="34" fill="#C9B8E8" stroke="#9E8FC7" stroke-width="2"/>
<circle cx="60" cy="66" r="26" fill="#D9A9C4" stroke="#C08AA8" stroke-width="1.6"/>
${acs}</svg>`;
}
function antibiogrammeSVG(halos){
const pos=[[62,62],[138,62],[138,138],[62,138]], lettres=['A','B','C','D'];
let d='';
halos.forEach((h,i)=>{
const [x,y]=pos[i];
if(h>0) d+=`<circle cx="${x}" cy="${y}" r="${h}" fill="#F3ECF8" opacity=".9"/>`;
d+=`<circle cx="${x}" cy="${y}" r="12" fill="#fff" stroke="#1B3A4B" stroke-width="2"/>`;
d+=`<text x="${x}" y="${y+4.5}" text-anchor="middle" font-size="13" font-weight="700" fill="#1B3A4B" font-family="Verdana">${lettres[i]}</text>`;
});
return `<svg viewBox="0 0 200 200" width="230" height="230" aria-hidden="true">
<circle cx="100" cy="100" r="94" fill="#C9A6D8" stroke="#E9F2F8" stroke-width="3"/>${d}</svg>`;
}
/* ==========================================================================
2. Contenu du chapitre
========================================================================== */
const THEMES = [
{
id:'t1', nom:'Les micro-organismes', couleur:'var(--vert)', hex:'#4FC38A',
fiche:[
'Un <b>micro-organisme</b> est un être vivant trop petit pour être vu à l\'œil nu : moins de <b>0,3 mm</b>.',
'Ils sont <b>partout</b> : air, eau, sol, et jusque dans notre corps (environ <b>1 kg</b>). On dit qu\'ils sont <b>ubiquistes</b>.',
'La <b>grande majorité n\'est pas pathogène</b> : chez les bactéries, moins de 1 % rendent malade.',
'Les <b>virus ne sont pas des cellules</b> : ils ont besoin d\'une cellule vivante pour se multiplier.'
],
exos:[
{t:'qcm', q:'Un micro-organisme, c\'est un être vivant…', o:[
'plus petit qu\'une fourmi',
'trop petit pour être vu à l\'œil nu, moins de 0,3 mm',
'qui vit seulement dans l\'eau',
'qui rend toujours malade'], b:1,
e:'La limite de l\'œil nu se situe autour de 0,3 mm. En dessous, il faut un microscope.'},
{t:'qcm', q:'Dire que les micro-organismes sont <b>ubiquistes</b>, cela signifie qu\'ils…', o:[
'vivent seulement dans l\'eau douce',
'sont présents dans presque tous les milieux',
'ne vivent qu\'au laboratoire',
'vivent seulement chez l\'Homme'], b:1,
e:'Air, eau, sol, surfaces, et notre corps : ils sont partout.'},
{t:'qcm', q:'Quelle part des bactéries connues est pathogène pour l\'Homme ?', o:[
'100 %','50 %','10 %','moins de 1 %'], b:3,
e:'Moins de 1 %. La très grande majorité des bactéries sont inoffensives, et beaucoup nous sont utiles.'},
{t:'qcm', q:'Pourquoi dit-on qu\'un virus n\'est pas un être vivant ?', o:[
'parce qu\'il est trop petit',
'parce qu\'il n\'est pas une cellule et ne peut pas se multiplier seul',
'parce qu\'il ne bouge pas',
'parce qu\'il ne rend pas malade'], b:1,
e:'Un virus n\'est pas composé de cellules. Il lui faut entrer dans une cellule vivante pour se multiplier.'},
{t:'paires', q:'Relie chaque micro-organisme à ce qui le caractérise.', p:[
['Bactérie','une cellule simple, sans noyau'],
['Levure','un champignon microscopique qui bourgeonne'],
['Virus','pas une cellule, se multiplie dans une cellule'],
['Paramécie','couverte de cils, elle nage très vite']],
e:'Ce sont les quatre types que tu peux rencontrer dans l\'eau de la mare.'},
{t:'ordre', q:'Range ces êtres vivants du <b>plus grand au plus petit</b>.',
l:['Paramécie (0,2 mm)','Levure (0,01 mm)','Bactérie (0,002 mm)','Virus (0,0002 mm)'],
e:'Une paramécie est environ 1 000 fois plus longue qu\'un virus.'},
{t:'qcm', q:'Sur une photo, la barre d\'échelle mesure 1 cm et vaut 3 µm. Tu mesures une bactérie : elle fait 0,7 cm. Quelle est sa taille réelle ?', o:[
'0,7 µm','2,1 µm','3,7 µm','21 µm'], b:1,
e:'On multiplie : 0,7 × 3 = 2,1 µm. C\'est la taille habituelle d\'une bactérie.'},
{t:'trous', q:'Complète le bilan.',
s:['Les micro-organismes sont des organismes de petite taille, inférieure à ',
'. Ils sont ',' dans l\'environnement : on dit qu\'ils sont ubiquistes. La plupart ne sont pas ',
'. Les virus ne sont pas composés de ',' et ne sont donc pas considérés comme des êtres vivants.'],
c:[['0,3 mm','3 cm','3 mm'],['partout','au fond de l\'eau','dans le sol seulement'],
['pathogènes','vivants','visibles'],['cellules','noyaux','sang']],
b:[0,0,0,0], e:'C\'est exactement le bilan 1 de ton cahier.'}
]
},
{
id:'t2', nom:'Les barrières du corps', couleur:'var(--bleu)', hex:'#4E9BE0',
fiche:[
'Barrières <b>physiques</b> : la <b>peau</b> et les <b>muqueuses</b> (bouche, tube digestif, voies respiratoires…).',
'Barrières <b>chimiques</b> : sébum, sueur, larmes, salive, mucus, suc gastrique, milieu vaginal acide.',
'<b>Contamination</b> : les pathogènes ont franchi une barrière. <b>Infection</b> : ils se multiplient dans le milieu intérieur.',
'<b>Asepsie</b> = AVANT, j\'empêche d\'entrer. <b>Antisepsie</b> = APRÈS, je détruis ce qui est entré.',
'La <b>réaction inflammatoire</b> est déclenchée par les <b>cellules sentinelles</b> : rougeur, chaleur, gonflement, douleur.'
],
exos:[
{t:'qcm', q:'Parmi ces éléments, lequel est une barrière <b>physique</b> ?', o:[
'la sueur','les larmes','la peau','le suc gastrique'], b:2,
e:'La peau et les muqueuses forment un mur : ce sont les barrières physiques. Les autres agissent par leur composition chimique.'},
{t:'paires', q:'Relie chaque barrière chimique à son rôle.', p:[
['Suc gastrique','très acide, il détruit de nombreux microbes'],
['Larmes','elles contiennent des substances qui découpent les bactéries'],
['Mucus','substance visqueuse qui piège les microbes'],
['Sueur','acide et salée, elle gêne la croissance des microbes']],
e:'Chaque barrière chimique agit là où elle est produite.'},
{t:'qcm', q:'Une écharde traverse la peau et des bactéries entrent. Comment appelle-t-on ce moment ?', o:[
'l\'infection','la contamination','l\'inflammation','l\'asepsie'], b:1,
e:'Franchir la barrière = contamination. On n\'est pas encore malade à ce stade.'},
{t:'qcm', q:'Les bactéries entrées se multiplient par millions dans le sang. C\'est…', o:[
'la contamination','l\'infection','l\'antisepsie','la phagocytose'], b:1,
e:'La contamination vient toujours <b>avant</b> l\'infection.'},
{t:'qcm', q:'Le chirurgien stérilise ses instruments avant d\'opérer. C\'est…', o:[
'de l\'asepsie','de l\'antisepsie'], b:0, deux:true,
e:'On empêche les microbes d\'arriver jusqu\'aux barrières : c\'est de l\'asepsie, elle agit AVANT.'},
{t:'qcm', q:'Tu mets de la Bétadine sur une coupure. C\'est…', o:[
'de l\'asepsie','de l\'antisepsie'], b:1, deux:true,
e:'Les microbes ont déjà franchi la peau : on les détruit. C\'est de l\'antisepsie, elle agit APRÈS.'},
{t:'qcm', q:'Quels sont les quatre signes de la réaction inflammatoire ?', o:[
'fièvre, toux, fatigue, nausée',
'rougeur, chaleur, gonflement, douleur',
'démangeaison, pâleur, froid, frisson',
'rougeur, toux, douleur, fièvre'], b:1,
e:'Rougeur, chaleur, gonflement et douleur : ce sont les quatre signes que tu vois autour d\'une plaie infectée.'},
{t:'qcm', q:'Qui donne l\'alerte et fait venir les phagocytes ?', o:[
'les globules rouges','les cellules sentinelles','les lymphocytes','la peau'], b:1,
e:'Les cellules sentinelles détectent l\'intrus et libèrent des molécules attractives.'},
{t:'trous', q:'Complète le bilan.',
s:['Si les micro-organismes pathogènes passent les barrières, on parle de ',
'. S\'ils se multiplient dans le milieu intérieur, on parle d\'',
'. Pour limiter le contact avec les barrières, on utilise l\'',
', et pour éliminer ceux qui sont entrés, l\'','.'],
c:[['contamination','infection','inflammation'],['infection','contamination','asepsie'],
['asepsie','antisepsie','antibiotique'],['antisepsie','asepsie','anticorps']],
b:[0,0,0,0], e:'Contamination puis infection ; asepsie avant, antisepsie après.'}
]
},
{
id:'t3', nom:'La phagocytose', couleur:'var(--rose)', hex:'#F08FB4',
fiche:[
'Le <b>phagocyte</b> se reconnaît à son <b>noyau plurilobé</b> ; il intervient <b>rapidement</b>.',
'Le <b>lymphocyte</b> se reconnaît à son <b>gros noyau</b> ; il intervient après <b>plusieurs jours</b>.',
'Le <b>globule rouge</b> transporte les gaz et n\'intervient pas dans l\'immunité.',
'La phagocytose se fait en 4 étapes : <b>adhésion → ingestion → digestion → rejet</b>.',
'Les <b>cellules sentinelles</b> libèrent des molécules attractives ; les phagocytes sortent du sang avec le <b>plasma</b>.'
],
exos:[
{t:'qcm', q:'Au microscope, une cellule a un gros noyau qui occupe presque toute la place. C\'est…', o:[
'un globule rouge','un phagocyte','un lymphocyte','une bactérie'], b:2,
e:'Gros noyau rond = lymphocyte. Noyau découpé en plusieurs morceaux = phagocyte.'},
{t:'qcm', q:'Le sang d\'un malade contient beaucoup de lymphocytes. Que peux-tu en déduire ?', o:[
'il vient tout juste d\'être contaminé',
'il est infecté depuis plusieurs jours',
'il n\'est pas malade',
'il a une infection par une bactérie seulement'], b:1,
e:'Les lymphocytes mettent plusieurs jours à se multiplier : leur nombre élevé date l\'infection.'},
{t:'ordre', q:'Remets les quatre étapes de la <b>phagocytose</b> dans l\'ordre.',
l:['Adhésion : le phagocyte reconnaît l\'intrus','Ingestion : il l\'enferme dans une vésicule',
'Digestion : l\'intrus est détruit dans la vésicule','Rejet : les débris sont éjectés'],
e:'Adhésion, ingestion, digestion, rejet : c\'est toujours cet ordre.'},
{t:'qcm', q:'Qu\'est-ce qui sort du sang en même temps que les phagocytes ?', o:[
'les globules rouges','le plasma','les bactéries','les anticorps'], b:1,
e:'Le plasma sort du capillaire avec les phagocytes : c\'est ce qui fait gonfler la zone.'},
{t:'qcm', q:'Par quel moyen les cellules sentinelles font-elles venir les phagocytes ?', o:[
'en les touchant','en libérant des molécules attractives','en changeant de couleur','par les nerfs'], b:1,
e:'Elles libèrent un flux de molécules attractives, une sorte de message chimique.'},
{t:'qcm', q:'À quoi sert le globule rouge ?', o:[
'à digérer les bactéries','à fabriquer des anticorps',
'à transporter le dioxygène et le dioxyde de carbone','à donner l\'alerte'], b:2,
e:'Il transporte les gaz. Il n\'intervient pas du tout dans l\'immunité.'},
{t:'trous', q:'Complète le bilan.',
s:['Les phagocytes sortent des vaisseaux sanguins et réalisent la ',
'. À l\'étape d\'ingestion, le phagocyte enferme l\'intrus dans une ',
'. Ce sont les cellules ',' qui donnent l\'alerte.'],
c:[['phagocytose','sérothérapie','vaccination'],['vésicule','veine','vacuole de réserve'],
['sentinelles','mémoires','rouges']],
b:[0,0,0], e:'Phagocytose, vésicule, cellules sentinelles.'}
]
},
{
id:'t4', nom:'Les antibiotiques', couleur:'var(--ambre)', hex:'#F0A742',
fiche:[
'Les antibiotiques agissent sur les <b>bactéries</b>. Ils sont <b>sans effet sur les virus</b>.',
'Un <b>antibiogramme</b> teste plusieurs antibiotiques sur une bactérie, dans une boîte de Petri.',
'<b>Plus l\'auréole est grande, plus l\'antibiotique est efficace.</b> Pas d\'auréole : la bactérie est résistante.',
'<b>Alexander Fleming</b> découvre la <b>pénicilline</b> en <b>1928</b>.',
'Trop utilisés, les antibiotiques rendent les bactéries <b>résistantes</b>.'
],
exos:[
{t:'qcm', q:'Tu as la grippe, qui est une maladie virale. Un antibiotique va-t-il te soigner ?', o:[
'oui, il tue tous les microbes',
'non, les antibiotiques n\'agissent que sur les bactéries',
'oui, mais seulement à forte dose',
'non, il faut attendre qu\'il fasse effet'], b:1,
e:'L\'expérience des deux milieux le montre : avec ou sans antibiotique, les virus se multiplient pareil.'},
{t:'figure', q:'Voici un antibiogramme après 20 minutes. Quel antibiotique le laborantin doit-il conseiller au médecin ?',
cible:antibiogrammeSVG([40,26,0,16]), sousCible:'La bactérie est teintée en violet.',
o:['A','B','C','D'], b:0, deux:true,
e:'C\'est autour de A que l\'auréole est la plus grande : c\'est là que le plus de bactéries ont été tuées.'},
{t:'qcm', q:'Autour du disque C, il n\'y a aucune auréole. Cela veut dire que…', o:[
'la bactérie est sensible à cet antibiotique',
'la bactérie est résistante à cet antibiotique',
'le disque a été mal posé',
'l\'antibiotique est trop fort'], b:1,
e:'Pas d\'auréole = les bactéries ont survécu tout autour = elles résistent à cet antibiotique.'},
{t:'qcm', q:'Qui a découvert la pénicilline, et en quelle année ?', o:[
'Louis Pasteur, en 1877','Emil von Behring, en 1891',
'Alexander Fleming, en 1928','Marie Curie, en 1903'], b:2,
e:'Fleming, 1928. Avant lui, il avait trouvé le lysozyme, beaucoup moins efficace.'},
{t:'qcm', q:'Pourquoi ne faut-il pas prendre des antibiotiques pour un oui ou pour un non ?', o:[
'parce qu\'ils coûtent cher',
'parce que les bactéries deviennent résistantes',
'parce qu\'ils abîment les virus utiles',
'parce qu\'ils font grossir les auréoles'], b:1,
e:'À force, les bactéries résistantes survivent et se multiplient : les antibiotiques deviennent moins efficaces.'},
{t:'trous', q:'Complète le bilan.',
s:['Les antibiotiques agissent sur les ',', mais sont sans effet sur les ',
'. Plus l\'auréole est grande, plus l\'antibiotique est ',
'. Trop utilisés, ils rendent les bactéries ','.'],
c:[['bactéries','virus','champignons'],['virus','bactéries','levures'],
['efficace','inefficace','dangereux'],['résistantes','sensibles','plus petites']],
b:[0,0,0,0], e:'Bactéries / virus / efficace / résistantes.'}
]
},
{
id:'t5', nom:'Anticorps et sérothérapie', couleur:'var(--violet)', hex:'#B58BE0',
fiche:[
'Après plusieurs <b>jours</b>, le corps fabrique des molécules de défense : les <b>anticorps</b>.',
'Un anticorps a la forme d\'un <b>Y</b>, avec un site de reconnaissance au bout de chacune de ses deux petites branches.',
'Un anticorps est <b>spécifique</b> : il ne reconnaît qu\'un seul antigène, comme une clé pour une seule serrure.',
'La <b>sérothérapie</b> : on injecte au malade les anticorps d\'une personne ou d\'un animal <b>guéri</b>.',
'<b>Emil von Behring</b> sauve le premier enfant la nuit de Noël 1891 ; premier prix Nobel de médecine en 1901.'
],
exos:[
{t:'qcm', q:'Combien de temps le corps met-il à fabriquer ses anticorps contre un nouvel intrus ?', o:[
'quelques secondes','quelques minutes','plusieurs jours','plusieurs mois'], b:2,
e:'Plusieurs jours : c\'est ce délai qui rend l\'infection dangereuse au début.'},
{t:'figure', q:'Voici un pathogène. Quel anticorps peut le neutraliser ?',
cible:pathogeneSVG('C'), sousCible:'Regarde bien la forme de ses antigènes.',
oFig:[anticorpsSVG('T'),anticorpsSVG('C'),anticorpsSVG('R')], b:1,
e:'Les antigènes sont carrés : il faut un anticorps dont les deux sites ont une encoche carrée.'},
{t:'qcm', q:'On injecte à une souris du sérum de cheval guéri du <b>tétanos</b>, puis la toxine de la <b>diphtérie</b>. Que se passe-t-il ?', o:[
'la souris survit, le sérum protège de tout',
'la souris meurt : les anticorps ne correspondent pas à cette toxine',
'la souris survit une semaine puis meurt',
'rien, la toxine n\'agit pas sur les souris'], b:1,
e:'Un anticorps est spécifique. Les anticorps anti-tétanos ne reconnaissent pas la toxine diphtérique.'},
{t:'qcm', q:'En quoi consiste la sérothérapie ?', o:[
'injecter un microbe affaibli pour se protéger plus tard',
'injecter des antibiotiques dans le sang',
'injecter les anticorps d\'un individu déjà guéri',
'transfuser des globules rouges'], b:2,
e:'On emprunte les anticorps de quelqu\'un qui a guéri : la protection est immédiate, mais temporaire.'},
{t:'paires', q:'Relie chaque mot à sa définition.', p:[
['Sérum','le liquide du sang, sans les cellules'],
['Anticorps','la molécule de défense en forme de Y'],
['Spécifique','qui ne reconnaît qu\'un seul intrus'],
['Toxine','le poison fabriqué par la bactérie']],
e:'Ces quatre mots reviennent dans le bilan et dans le contrôle.'},
{t:'trous', q:'Complète le bilan.',
s:['Une fois infecté, notre corps produit, au bout de plusieurs jours, des molécules de défense : les ',
'. Un anticorps est ',' : il n\'agit que contre l\'intrus qui l\'a fait fabriquer. On peut sauver un malade en lui injectant les anticorps d\'une personne guérie : c\'est la ','.'],
c:[['anticorps','antigènes','antibiotiques'],['spécifique','rapide','fragile'],
['sérothérapie','vaccination','phagocytose']],
b:[0,0,0], e:'Anticorps, spécifique, sérothérapie.'}
]
},
{
id:'t6', nom:'Lymphocytes et vaccination', couleur:'var(--turquoise)', hex:'#5FD0CE',
fiche:[
'Chaque <b>lymphocyte B</b> porte sur sa membrane <b>un seul type d\'anticorps</b>.',
'Les <b>antigènes</b> sont les motifs portés par le pathogène, reconnus par l\'anticorps.',
'Quand la clé entre dans la serrure, le lymphocyte <b>se multiplie</b> et libère énormément d\'anticorps.',
'Une partie est gardée en <b>mémoire</b> dans les <b>ganglions</b> : la fois suivante, la réponse est plus <b>rapide</b> et plus <b>forte</b>. C\'est le principe de la <b>vaccination</b>.',
'Les <b>lymphocytes T</b> éliminent les <b>cellules infectées</b> par des virus.'
],
exos:[
{t:'qcm', q:'Combien de types d\'anticorps différents un même lymphocyte B peut-il fabriquer ?', o:[
'un seul','deux','autant qu\'il y a d\'intrus','aucun'], b:0,
e:'Un seul. C\'est pour cela qu\'il faut du temps pour trouver LE bon lymphocyte parmi tous les autres.'},
{t:'figure', q:'Voici un pathogène. Quel lymphocyte B va le reconnaître ?',
cible:pathogeneSVG('R'), sousCible:'Ses antigènes sont arrondis.',
oFig:[lymphoSVG('T'),lymphoSVG('R'),lymphoSVG('C')], b:1,
e:'Seul le lymphocyte dont les anticorps ont une encoche arrondie peut s\'emboîter avec ces antigènes.'},
{t:'qcm', q:'Les antigènes, ce sont…', o:[
'les molécules de défense du corps',
'les motifs portés par le pathogène et reconnus par les anticorps',
'des globules blancs',
'des médicaments'], b:1,
e:'Anticorps = la clé, fabriquée par nous. Antigène = la serrure, portée par l\'intrus.'},
{t:'qcm', q:'Où sont gardés en réserve les lymphocytes mémoire ?', o:[
'dans la peau','dans les ganglions','dans l\'estomac','dans les poumons'], b:1,
e:'Dans les ganglions. C\'est pour cela qu\'ils gonflent quand tu es malade.'},
{t:'ordre', q:'Remets dans l\'ordre ce qui se passe lors d\'un <b>premier</b> contact avec un intrus.',
l:['Le corps cherche le lymphocyte dont l\'anticorps s\'emboîte','Le bon lymphocyte est trouvé et se multiplie',
'Il libère d\'énormes quantités d\'anticorps','Une partie des lymphocytes est gardée en mémoire'],
e:'C\'est la recherche du bon lymphocyte qui prend plusieurs jours.'},
{t:'qcm', q:'Par rapport à la première, comment est la <b>réponse secondaire</b> ?', o:[
'plus lente et plus faible','identique',
'plus rapide et beaucoup plus forte','plus rapide mais plus faible'], b:2,
e:'Le corps n\'a plus besoin de chercher : les lymphocytes mémoire sont déjà là, et nombreux.'},
{t:'qcm', q:'Qu\'est-ce qu\'on injecte, au final, dans un vaccin ?', o:[
'des anticorps','des antibiotiques',
'des antigènes, sans microbe capable de rendre malade','des lymphocytes'], b:2,
e:'Microbe atténué, microbe tué, ou une partie du microbe : dans les trois cas, on apporte des antigènes.'},
{t:'qcm', q:'À quoi servent les lymphocytes <b>T</b> ?', o:[
'à fabriquer les anticorps','à éliminer les cellules infectées par des virus',
'à transporter le dioxygène','à donner l\'alerte'], b:1,
e:'Les lymphocytes B fabriquent les anticorps ; les T détruisent nos cellules déjà infectées.'},
{t:'trous', q:'Complète le bilan.',
s:['Chaque lymphocyte ne produit qu\'un seul type d\'',
'. Les motifs reconnus sur le pathogène sont les ',
'. Une partie des lymphocytes est mise en réserve dans les ',
' : c\'est le principe de la ','.'],
c:[['anticorps','antigènes','antibiotiques'],['antigènes','anticorps','vésicules'],
['ganglions','poumons','muscles'],['vaccination','sérothérapie','antisepsie']],
b:[0,0,0,0], e:'Anticorps, antigènes, ganglions, vaccination.'}
]
}
];
/* ==========================================================================
3. Outils
========================================================================== */
const $ = s => document.querySelector(s);
const melange = a => a.map(v=>[Math.random(),v]).sort((x,y)=>x[0]-y[0]).map(v=>v[1]);
const LETTRES = ['A','B','C','D','E'];
let scores = {};
try{ scores = JSON.parse(localStorage.getItem('svt-ch1')||'{}'); }catch(e){ scores = {}; }
function sauver(){ try{ localStorage.setItem('svt-ch1', JSON.stringify(scores)); }catch(e){} }
/* ==========================================================================
4. Accueil : la boîte de Petri
========================================================================== */
const POS = [[50,19],[77,34],[75,66],[51,81],[23,67],[25,34]];
function dessineDish(){
const dish = $('#dish'); dish.innerHTML='';
THEMES.forEach((th,i)=>{
const s = scores[th.id];
const total = th.exos.length;
const b = document.createElement('button');
b.className='colonie';
b.style.left = POS[i][0]+'%'; b.style.top = POS[i][1]+'%';
b.style.setProperty('--ac', th.hex);
b.setAttribute('aria-label', th.nom);
const fait = s ? s.juste : null;
b.innerHTML = `<span class="bulle"><span>${th.nom}</span></span>
<span class="jauge${fait===total?' plein':''}">${fait==null?'à faire':fait+' / '+total}</span>`;
b.onclick = ()=>ouvrirTheme(i);
dish.appendChild(b);
});
}
/* ==========================================================================
5. Rendu des exercices
========================================================================== */
function bloc(n, total, enonce, aide){
const d = document.createElement('div');
d.className='exo';
d.innerHTML = `<span class="num">Question ${n} sur ${total}</span>
<p class="enonce">${enonce}</p>${aide?`<p class="aide">${aide}</p>`:''}`;
return d;
}
function retour(d, ok, msg){
let r = d.querySelector('.retour');
if(!r){ r = document.createElement('div'); r.className='retour'; d.appendChild(r); }
r.className = 'retour ' + (ok?'ok':'ko');
r.innerHTML = `<b>${ok?'Bien vu.':'Pas encore.'}</b> ${msg}`;
r.style.display='block';
}
/* --- QCM (texte ou figures) --- */
function rendreQCM(ex, d, fini){
const zone = document.createElement('div');
const figs = !!ex.oFig;
zone.className = figs ? 'grille-fig' : ('choix'+(ex.deux?' deux':''));
if(ex.cible){
const c = document.createElement('div'); c.className='figs';
c.innerHTML = `<div class="fig-cible">${ex.cible}${ex.sousCible?`<span>${ex.sousCible}</span>`:''}</div>`;
d.appendChild(c);
}
const liste = figs ? ex.oFig : ex.o;
liste.forEach((txt,i)=>{
const b = document.createElement('button');
if(figs){ b.className='opt-fig'; b.innerHTML = txt + `<span class="lettre">${LETTRES[i]}</span>`; }
else{ b.className='opt'; b.innerHTML = `<span class="lettre">${LETTRES[i]}</span><span>${txt}</span>`; }
b.onclick = ()=>{
zone.querySelectorAll('button').forEach(x=>x.disabled=true);
const ok = i===ex.b;
b.classList.add(ok?'juste':'faux');
if(!ok) zone.querySelectorAll('button')[ex.b].classList.add('juste');
retour(d, ok, ex.e);
fini(ok);
};
zone.appendChild(b);
});
d.appendChild(zone);
}
/* --- paires --- */
function rendrePaires(ex, d, fini){
const g = document.createElement('div'); g.className='paires';
const cg = document.createElement('div'); cg.className='col';
const cd = document.createElement('div'); cd.className='col';
const gauche = melange(ex.p.map((p,i)=>({t:p[0],i})));
const droite = melange(ex.p.map((p,i)=>({t:p[1],i})));
let sel=null, trouves=0, erreurs=0;
const faire = (arr,col)=>arr.forEach(o=>{
const b=document.createElement('button'); b.className='jeton'; b.textContent=o.t; b.dataset.i=o.i; b.dataset.col=col;
b.onclick=()=>{
if(b.classList.contains('trouve')) return;
if(!sel){ sel=b; b.classList.add('actif'); return; }
if(sel===b){ sel=null; b.classList.remove('actif'); return; }
if(sel.dataset.col===b.dataset.col){ sel.classList.remove('actif'); sel=b; b.classList.add('actif'); return; }
if(sel.dataset.i===b.dataset.i){
sel.classList.remove('actif'); sel.classList.add('trouve'); b.classList.add('trouve');
sel=null; trouves++;
if(trouves===ex.p.length){
g.querySelectorAll('.jeton').forEach(x=>x.disabled=true);
retour(d, erreurs===0, ex.e + (erreurs?' Tu as fait '+erreurs+(erreurs>1?' essais ratés.':' essai raté.'):''));
fini(erreurs===0);
}
} else {
erreurs++;
b.classList.add('rate'); sel.classList.remove('actif');
const s=sel; s.classList.add('rate');
setTimeout(()=>{b.classList.remove('rate'); s.classList.remove('rate');},380);
sel=null;
}
};
(col==='g'?cg:cd).appendChild(b);
});
faire(gauche,'g'); faire(droite,'d');
g.appendChild(cg); g.appendChild(cd); d.appendChild(g);
}
/* --- ordre --- */
function rendreOrdre(ex, d, fini){
const serie = document.createElement('div'); serie.className='serie';
const pioche = document.createElement('div'); pioche.className='pioche';
const choix = [];
melange(ex.l.map((t,i)=>({t,i}))).forEach(o=>{
const b=document.createElement('button'); b.className='etape'; b.textContent=o.t; b.dataset.i=o.i;
b.onclick=()=>{
if(b.parentNode===pioche){ choix.push(o.i); serie.appendChild(b);
b.innerHTML=`<span class="rang">${choix.length}</span>${o.t}`; }
else { const k=choix.indexOf(o.i); choix.splice(k,1); pioche.appendChild(b); b.textContent=o.t;
[...serie.children].forEach((c,j)=>c.querySelector('.rang').textContent=j+1); }
valider.disabled = choix.length!==ex.l.length;
};
pioche.appendChild(b);
});
const valider = document.createElement('button');
valider.className='btn'; valider.textContent='Vérifier l\'ordre'; valider.disabled=true;
valider.style.marginTop='12px';
valider.onclick=()=>{
const ok = choix.every((v,j)=>v===j);
[...serie.children].forEach((c,j)=>c.classList.add(choix[j]===j?'juste':'faux'));
serie.querySelectorAll('button').forEach(x=>x.disabled=true);
pioche.querySelectorAll('button').forEach(x=>x.disabled=true);
valider.disabled=true;
retour(d, ok, ok?ex.e:('Le bon ordre est : '+ex.l.map(t=>t.split(' :')[0]).join(' → ')+'. '+ex.e));
fini(ok);
};
d.appendChild(serie); d.appendChild(pioche); d.appendChild(valider);
}
/* --- texte à trous --- */
function rendreTrous(ex, d, fini){
const p = document.createElement('div'); p.className='trous';
const sels=[];
ex.s.forEach((morceau,i)=>{
p.appendChild(document.createTextNode(morceau));
if(i<ex.c.length){
const s=document.createElement('select');
s.innerHTML = '<option value="-1">choisis…</option>' +
melange(ex.c[i].map((t,k)=>({t,k}))).map(o=>`<option value="${o.k}">${o.t}</option>`).join('');
sels.push(s); p.appendChild(s);
s.onchange=()=>{ valider.disabled = sels.some(x=>x.value==='-1'); };
}
});
const valider=document.createElement('button');
valider.className='btn'; valider.textContent='Vérifier'; valider.disabled=true; valider.style.marginTop='14px';
valider.onclick=()=>{
let ok=true;
sels.forEach((s,i)=>{
const bon = Number(s.value)===ex.b[i];
s.classList.add(bon?'juste':'faux'); s.disabled=true;
if(!bon){ ok=false; s.innerHTML=`<option>${ex.c[i][ex.b[i]]}</option>`; }
});
valider.disabled=true;
retour(d, ok, ok?ex.e:('Les bons mots sont maintenant écrits. '+ex.e));
fini(ok);
};
d.appendChild(p); d.appendChild(valider);
}
/* ==========================================================================
6. Vue thème
========================================================================== */
let themeActuel=null, faits=0, justes=0;
function ouvrirTheme(idx){
const th = THEMES[idx]; themeActuel=th;
faits=0; justes=0;
$('#vue-accueil').style.display='none';
$('#vue-controle').style.display='none';
$('#vue-theme').style.display='block';
$('#btn-retour').style.display='inline-block';
document.documentElement.style.setProperty('--ac', th.hex);
$('#vue-theme').style.setProperty('--ac', th.hex);
$('#theme-titre').textContent = th.nom;
$('#theme-fiche').innerHTML = '<h3>Ce qu\'il faut savoir</h3><ul>' +
th.fiche.map(f=>`<li>${f}</li>`).join('') + '</ul>';
const zone = $('#theme-exos'); zone.innerHTML='';
majProgression(0, th.exos.length);
th.exos.forEach((ex,i)=>{
const d = bloc(i+1, th.exos.length, ex.q, ex.aide);
const fini = ok=>{
faits++; if(ok) justes++;
majProgression(faits, th.exos.length);
if(faits===th.exos.length){
const s = scores[th.id];
if(!s || justes>s.juste) scores[th.id]={juste:justes,total:th.exos.length};
sauver();
zone.appendChild(finTheme(th));
zone.lastChild.scrollIntoView({behavior:'smooth', block:'center'});
}
};
if(ex.t==='qcm'||ex.t==='figure') rendreQCM(ex,d,fini);
else if(ex.t==='paires') rendrePaires(ex,d,fini);
else if(ex.t==='ordre') rendreOrdre(ex,d,fini);
else if(ex.t==='trous') rendreTrous(ex,d,fini);
zone.appendChild(d);
});
window.scrollTo({top:0,behavior:'smooth'});
}
function majProgression(f,t){
$('#progression-txt').textContent = f+' / '+t;
$('#progression-barre').style.width = (f/t*100)+'%';
}
function finTheme(th){
const d=document.createElement('div'); d.className='bilan-fin';
const pct = justes/th.exos.length;
const mot = pct===1 ? 'Colonie complète !' : pct>=.7 ? 'Presque au point.' : 'À retravailler.';
const txt = pct===1 ? 'Tu maîtrises cette partie du chapitre. Passe à une autre colonie.'
: pct>=.7 ? 'Relis la fiche en haut de page, puis recommence pour viser le sans-faute.'
: 'Relis calmement la fiche « ce qu\'il faut savoir », puis recommence. C\'est normal de se tromper la première fois.';
d.innerHTML = `<div class="score">${justes}</div><div class="sur">bonnes réponses sur ${th.exos.length}</div>
<h3>${mot}</h3><p>${txt}</p>
<div class="actions">
<button class="btn" id="rejouer">Recommencer ce thème</button>
<button class="btn secondaire" id="retourdish">Choisir un autre thème</button>
</div>`;
setTimeout(()=>{
$('#rejouer').onclick=()=>ouvrirTheme(THEMES.indexOf(th));
$('#retourdish').onclick=accueil;
},0);
return d;
}
/* ==========================================================================
7. Contrôle blanc
========================================================================== */
let ctrlQuestions=[], ctrlRep=[], ctrlIdx=0;
function lancerControle(){
const pool=[];
THEMES.forEach(th=>th.exos.forEach(ex=>{
if(ex.t==='qcm'||ex.t==='figure') pool.push({ex, theme:th.nom});
}));
ctrlQuestions = melange(pool).slice(0,15);
ctrlRep = []; ctrlIdx = 0;
$('#vue-accueil').style.display='none';
$('#vue-theme').style.display='none';
$('#vue-controle').style.display='block';
$('#btn-retour').style.display='inline-block';
$('#vue-controle').style.setProperty('--ac', '#F0A742');
afficheCtrl();
window.scrollTo({top:0,behavior:'smooth'});
}
function afficheCtrl(){
const zone=$('#ctrl-zone'); zone.innerHTML='';
$('#ctrl-txt').textContent = (ctrlIdx+1)+' / '+ctrlQuestions.length;
$('#ctrl-barre').style.width = (ctrlIdx/ctrlQuestions.length*100)+'%';
const {ex} = ctrlQuestions[ctrlIdx];
const d = bloc(ctrlIdx+1, ctrlQuestions.length, ex.q, ex.aide);
if(ex.cible){
const c=document.createElement('div'); c.className='figs';
c.innerHTML=`<div class="fig-cible">${ex.cible}${ex.sousCible?`<span>${ex.sousCible}</span>`:''}</div>`;
d.appendChild(c);
}
const figs = !!ex.oFig;
const g=document.createElement('div');
g.className = figs ? 'grille-fig' : ('choix'+(ex.deux?' deux':''));
(figs?ex.oFig:ex.o).forEach((txt,i)=>{
const b=document.createElement('button');
if(figs){ b.className='opt-fig'; b.innerHTML = txt+`<span class="lettre">${LETTRES[i]}</span>`; }
else{ b.className='opt'; b.innerHTML=`<span class="lettre">${LETTRES[i]}</span><span>${txt}</span>`; }
b.onclick=()=>{
ctrlRep.push(i); ctrlIdx++;
if(ctrlIdx<ctrlQuestions.length) afficheCtrl(); else finControle();