File size: 47,152 Bytes
2ee54cd
 
 
 
3f3206d
 
 
 
 
 
 
 
 
 
 
 
 
2ee54cd
 
 
3f3206d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65784c0
 
3f3206d
 
 
 
 
 
 
 
 
65784c0
3f3206d
 
 
 
 
2ee54cd
3f3206d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2ee54cd
 
 
 
3f3206d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2ee54cd
 
3f3206d
 
 
65784c0
3f3206d
 
 
 
 
 
 
2ee54cd
 
3f3206d
2ee54cd
3f3206d
 
 
 
 
 
 
 
2ee54cd
3f3206d
 
 
 
 
 
 
 
 
 
 
 
2ee54cd
3f3206d
 
 
2ee54cd
 
3f3206d
 
 
 
 
 
 
65784c0
3f3206d
2ee54cd
 
3f3206d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2ee54cd
3f3206d
 
 
 
 
2ee54cd
3f3206d
 
 
 
 
2ee54cd
3f3206d
 
 
 
 
 
2ee54cd
 
65784c0
2ee54cd
 
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
<!DOCTYPE html>
<html lang="fr">
<head>
  <meta charset="UTF-8">
  <!-- **Optimisation Mobile: Assure un bon affichage et désactive le zoom manuel** -->
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
  <title>Mariam AI - Analyse Littéraire</title>

  <!-- Bibliothèque marked pour l'AFFICHAGE UTILISATEUR SEULEMENT -->
  <script src="https://cdnjs.cloudflare.com/ajax/libs/marked/9.1.6/marked.min.js"></script>

  <!-- Bibliothèque jsPDF pour la génération PDF directe -->
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
  <!-- Plugin jsPDF-AutoTable pour les tableaux -->
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf-autotable/3.5.28/jspdf.plugin.autotable.min.js"></script>


  <style>
    @import url('https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;700&family=Inter:wght@300;400;500;600;700&display=swap');

    :root {
      --primary: #4361ee;
      --primary-dark: #3a56d4;
      --secondary: #2b2d42;
      --secondary-light: #8d99ae; /* For secondary button */
      --accent: #ef476f;
      --light: #f8f9fa;
      --gray-100: #f1f3f5;
      --gray-200: #e9ecef;
      --gray-300: #dee2e6;
      --gray-400: #ced4da;
      --gray-700: #495057;
      --shadow-sm: 0 1px 2px rgba(0,0,0,0.05);
      --shadow-md: 0 4px 6px -1px rgba(0,0,0,0.1), 0 2px 4px -1px rgba(0,0,0,0.06);
      --shadow-lg: 0 10px 15px -3px rgba(0,0,0,0.1), 0 4px 6px -2px rgba(0,0,0,0.05);
      --radius-sm: 0.375rem; /* 6px */
      --radius-md: 0.5rem;  /* 8px */
      --radius-lg: 0.75rem; /* 12px */
    }

    * { margin: 0; padding: 0; box-sizing: border-box; }
    html { /* Améliore le défilement sur mobile */ -webkit-overflow-scrolling: touch; }
    body {
      font-family: 'Inter', sans-serif;
      background: linear-gradient(135deg, #f6f8fb 0%, #f1f3f5 100%);
      color: var(--secondary);
      line-height: 1.6;
      padding-bottom: 2rem;
      min-height: 100vh; /* Assure que le dégradé couvre tout l'écran */
    }
    header {
      background-color: white;
      padding: 1.5rem 1rem; /* Padding par défaut */
      text-align: center;
      box-shadow: var(--shadow-sm);
      position: sticky; /* **Mobile: Rend l'en-tête collant en haut** */
      top: 0;
      z-index: 10;
      width: 100%; /* Nécessaire avec sticky */
    }
    .logo {
      font-family: 'Playfair Display', serif;
      font-size: 2rem; /* Taille par défaut */
      color: var(--secondary);
      margin-bottom: 0.25rem;
    }
    .tagline {
      font-size: 0.9rem; /* Taille par défaut */
      color: var(--gray-700);
      font-weight: 500;
    }
    .card {
      background: white;
      border-radius: var(--radius-lg);
      box-shadow: var(--shadow-md);
      padding: 1.5rem; /* Padding par défaut */
      margin: 1rem; /* Marge par défaut */
      transition: transform 0.2s ease, box-shadow 0.2s ease;
    }
    .upload-area {
      border: 2px dashed var(--gray-300);
      border-radius: var(--radius-md);
      padding: 1.5rem 1rem; /* Padding par défaut */
      text-align: center;
      cursor: pointer;
      transition: all 0.2s ease;
      margin: 1.5rem 0;
    }
    .upload-area:hover, .upload-area.active {
      border-color: var(--primary);
      background-color: rgba(67, 97, 238, 0.05);
    }
    .upload-icon {
      width: 3.5rem; height: 3.5rem; /* Taille par défaut */
      margin: 0 auto 1rem;
      color: var(--gray-400);
    }
    .upload-area:hover .upload-icon, .upload-area.active .upload-icon {
      color: var(--primary);
    }
    .input-group { margin-bottom: 1.5rem; }
    .label {
      display: block;
      margin-bottom: 0.5rem;
      font-weight: 600;
      font-size: 0.9rem; /* Taille par défaut */
    }
    .input {
      width: 100%;
      padding: 0.75rem; /* Padding par défaut */
      border: 1px solid var(--gray-300);
      border-radius: var(--radius-md);
      font-family: 'Inter', sans-serif;
      font-size: 1rem; /* Taille par défaut */
      transition: border-color 0.2s ease;
      /* **Mobile: Assure que le zoom n'est pas activé sur focus input sous iOS** */
      -webkit-appearance: none;
       appearance: none;
    }
    .input:focus {
      outline: none;
      border-color: var(--primary);
      box-shadow: 0 0 0 3px rgba(67, 97, 238, 0.1);
    }
    .preview-container { margin: 1.5rem 0; }
    .preview-title {
      font-weight: 600;
      margin-bottom: 0.5rem;
      font-size: 0.9rem; /* Taille par défaut */
    }
    .preview-image-container {
      background-color: var(--gray-100);
      border-radius: var(--radius-md);
      overflow: hidden;
      position: relative;
    }
    .preview-image {
      max-width: 100%;
      max-height: 15rem; /* Limite hauteur aperçu */
      height: auto;
      margin: 0 auto;
      display: block;
    }
    .btn {
      display: block;
      width: 100%;
      padding: 0.875rem; /* Padding par défaut */
      font-weight: 600;
      text-align: center;
      border: none;
      border-radius: var(--radius-md);
      cursor: pointer;
      transition: all 0.2s ease;
      font-size: 1rem; /* Taille par défaut */
      /* **Mobile: Empêche la sélection de texte sur appui long** */
      -webkit-user-select: none; user-select: none;
    }
    .btn:disabled {
      background-color: var(--gray-300) !important;
      color: var(--gray-700) !important;
      cursor: not-allowed;
      opacity: 0.7;
      transform: none !important;
      box-shadow: none !important;
    }
    .btn-primary { background-color: var(--primary); color: white; }
    .btn-primary:not(:disabled):hover, .btn-primary:not(:disabled):focus { background-color: var(--primary-dark); transform: translateY(-1px); box-shadow: var(--shadow-md); }
    .btn-primary:not(:disabled):active { transform: translateY(0); }
    .btn-secondary { background-color: var(--secondary-light); color: var(--secondary); margin-top: 0.75rem; } /* Style for DeepThink */
    .btn-secondary:not(:disabled):hover, .btn-secondary:not(:disabled):focus { background-color: var(--secondary); color: white; transform: translateY(-1px); box-shadow: var(--shadow-md); }
    .btn-secondary:not(:disabled):active { transform: translateY(0); }

    .loading-overlay { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background-color: rgba(0, 0, 0, 0.5); display: flex; justify-content: center; align-items: center; z-index: 100; padding: 1rem; /* Ajout padding pour mobile */ }
    .loading-card { background-color: white; padding: 2rem; border-radius: var(--radius-lg); box-shadow: var(--shadow-lg); text-align: center; max-width: 90%; /* Légère augmentation pour petits écrans */ }
    .spinner { width: 3rem; height: 3rem; border: 4px solid var(--gray-200); border-radius: 50%; border-top-color: var(--primary); animation: spin 1s linear infinite; margin: 0 auto 1rem; }
    @keyframes spin { to { transform: rotate(360deg); } }

    .result-card { padding: 0; overflow: hidden; }
    .tabs { display: flex; border-bottom: 1px solid var(--gray-200); background-color: var(--gray-100); width: 100%; /* Assure pleine largeur */ }
    .tab {
      flex: 1; /* Prend espace égal */
      text-align: center;
      padding: 1rem 0.5rem; /* Padding par défaut */
      font-weight: 600;
      font-size: 0.9rem; /* Taille par défaut */
      color: var(--gray-700);
      background-color: transparent;
      border: none;
      border-bottom: 3px solid transparent;
      cursor: pointer;
      transition: color 0.2s ease, border-color 0.2s ease;
      margin-bottom: -1px;
      /* **Mobile: Empêche la sélection de texte** */
      -webkit-user-select: none; user-select: none;
      white-space: nowrap; /* Empêche le retour à la ligne si texte long */
      overflow: hidden; /* Cache le texte qui dépasse */
      text-overflow: ellipsis; /* Ajoute ... si texte dépasse */
    }
    .tab:hover { color: var(--primary); }
    .tab.active { color: var(--primary); border-bottom-color: var(--primary); }
    .tab-content { padding: 1.5rem; /* Padding par défaut */ }

    /* Styles pour le contenu généré (prose/texte) */
    .custom-prose { font-size: 1rem; line-height: 1.8; } /* Taille/interligne par défaut */
    .custom-prose h1, .custom-prose h2, .custom-prose h3 { font-family: 'Playfair Display', serif; margin-top: 1.5em; margin-bottom: 0.75em; line-height: 1.3; color: var(--primary-dark); }
    .custom-prose h1 { font-size: 1.75rem; } .custom-prose h2 { font-size: 1.5rem; } .custom-prose h3 { font-size: 1.25rem; } /* Tailles titres par défaut */
    .custom-prose p { margin-bottom: 1.25em; } .custom-prose ul, .custom-prose ol { margin-top: 1em; margin-bottom: 1em; padding-left: 1.5em; } .custom-prose li { margin-bottom: 0.5em; }

    /* Styles pour les tableaux générés */
    .markdown-table {
      overflow-x: auto; /* ESSENTIEL pour mobile */
      -webkit-overflow-scrolling: touch; /* Défilement fluide sur iOS */
      border: 1px solid var(--gray-200);
      border-radius: var(--radius-sm);
      margin-top: 1em;
      margin-left: -1.5rem; /* Compense le padding du parent pour utiliser toute la largeur */
      margin-right: -1.5rem; /* Compense le padding du parent */
      padding-left: 0.5rem; /* Petit padding interne pour ne pas coller au bord */
      padding-right: 0.5rem;
    }
    /* Cache l'overflow quand on imprime ou génère PDF */
    #pdfContentWrapper .markdown-table, @media print { overflow-x: visible; margin-left: 0; margin-right: 0; padding-left: 0; padding-right: 0;}
    .markdown-table table { width: 100%; border-collapse: collapse; border-spacing: 0; table-layout: auto; }
    .markdown-table th { background: var(--primary); color: white; font-weight: 600; padding: 0.75rem 1rem; text-align: left; font-size: 0.9rem; border-bottom: 2px solid var(--primary-dark); white-space: nowrap; /* Empêche retour à la ligne des titres */ }
    .markdown-table td { padding: 0.75rem 1rem; border-bottom: 1px solid var(--gray-200); font-size: 0.9rem; vertical-align: top; word-break: break-word; /* Permet au texte long de passer à la ligne */ }
    .markdown-table tr:nth-child(even) td { background-color: var(--gray-100); }
    .markdown-table tr:hover td { background-color: rgba(67, 97, 238, 0.1); }

    .upload-instructions { font-size: 0.85rem; color: var(--gray-700); margin-top: 0.5rem; }
    .file-input { display: none; }
    .slide-up { animation: slide-up 0.4s ease forwards; }
    @keyframes slide-up { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } }
    .streaming-cursor { display: inline-block; width: 2px; height: 1.2em; background-color: var(--primary); margin-left: 1px; animation: blink 1s infinite; vertical-align: text-bottom; opacity: 1; }
    @keyframes blink { 0%, 100% { opacity: 1; } 50% { opacity: 0; } }
    .final-cursor { display: none !important; }
    .button-container { margin-top: 1.5rem; } /* Container for buttons */


    /* ============================================ */
    /* == OPTIMISATIONS POUR SMARTPHONES (<= 600px) == */
    /* ============================================ */
    @media (max-width: 600px) {
      body {
        padding-bottom: 1rem; /* Moins de padding en bas */
        -webkit-text-size-adjust: 100%; /* Empêche l'ajustement auto de la taille du texte sur iOS */
      }
      header {
        padding: 1rem; /* Header plus compact */
      }
      .logo {
        font-size: 1.75rem; /* Logo légèrement plus petit */
      }
      .tagline {
        font-size: 0.85rem; /* Slogan légèrement plus petit */
      }
      .card {
        margin: 0.75rem; /* Moins de marge horizontale */
        padding: 1.25rem; /* Moins de padding interne */
        border-radius: var(--radius-md); /* Coins un peu moins arrondis si désiré */
      }
       main .card:first-of-type {
           margin-top: 1rem; /* Espace après le header sticky */
       }
      .upload-area {
        padding: 1.25rem 1rem; /* Ajustement padding */
      }
      .upload-icon {
        width: 3rem; height: 3rem; /* Icône légèrement plus petite */
      }
      .upload-instructions {
        font-size: 0.8rem; /* Texte instructions plus petit */
      }
      .label {
        font-size: 0.85rem; /* Label légèrement plus petit */
      }
      .input {
        padding: 0.8rem; /* Padding input ajusté pour le toucher */
        font-size: 1rem; /* Garder 1rem évite le zoom auto sur iOS */
      }
      .preview-title {
         font-size: 0.85rem;
      }
      .btn {
        padding: 0.9rem; /* Boutons un peu plus grands pour le toucher */
        font-size: 0.95rem; /* Texte bouton légèrement plus petit */
        border-radius: var(--radius-sm); /* Rayon plus petit pour boutons */
      }
      .btn-secondary {
          margin-top: 1rem; /* Un peu plus d'espace entre les boutons */
      }
      .tab {
        padding: 0.9rem 0.25rem; /* Padding vertical augmenté pour toucher, horizontal réduit */
        font-size: 0.8rem; /* Texte onglet plus petit */
      }
      .tab-content {
        padding: 1.25rem; /* Padding contenu onglet réduit */
      }
      /* Ajustements taille texte contenu généré */
      .custom-prose {
        font-size: 0.95rem; /* Taille texte principal légèrement réduite */
        line-height: 1.7; /* Interligne confortable */
      }
      .custom-prose h1 { font-size: 1.5rem; }
      .custom-prose h2 { font-size: 1.3rem; }
      .custom-prose h3 { font-size: 1.1rem; }

      /* Ajustements tableau pour mobile */
      .markdown-table {
          margin-left: -1.25rem; /* Ajuster pour le nouveau padding du parent */
          margin-right: -1.25rem; /* Ajuster pour le nouveau padding du parent */
          padding-left: 0.4rem;
          padding-right: 0.4rem;
      }
       .markdown-table th, .markdown-table td {
          padding: 0.6rem 0.75rem; /* Cellules tableau plus compactes */
          font-size: 0.85rem; /* Texte tableau plus petit */
       }
       /* Optionnel: Rendre le texte des cellules un peu plus petit si nécessaire */
       /* .markdown-table td { font-size: 0.8rem; } */

       .loading-card {
           padding: 1.5rem; /* Padding chargement réduit */
       }
       .spinner {
           width: 2.5rem; height: 2.5rem; /* Spinner légèrement plus petit */
           margin-bottom: 0.8rem;
       }
       .loading-card p {
           font-size: 0.9rem; /* Texte chargement plus petit */
       }
    }

  </style>
</head>
<body>
   <header>
    <h1 class="logo">Mariam AI</h1>
    <p class="tagline">Assistant d'Analyse Littéraire</p>
  </header>

  <main>
    <div class="card">
      <form id="uploadForm">
         <div class="input-group">
          <label for="imageInput" class="label">Votre document</label>
          <div id="uploadArea" class="upload-area">
            <svg class="upload-icon" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12" /></svg>
            <p>Touchez pour télécharger</p>
            <p class="upload-instructions">PNG, JPG jusqu'à 10MB</p>
            <input id="imageInput" type="file" class="file-input" accept="image/*" required>
          </div>
        </div>
        <div class="input-group">
          <label for="consignesInput" class="label">Consignes (optionnel)</label>
          <input id="consignesInput" type="text" class="input" placeholder="Entrez vos consignes ici">
        </div>
        <div id="previewContainer" class="preview-container" style="display: none;">
          <p class="preview-title">Aperçu du document</p>
          <div class="preview-image-container"><img id="previewImage" class="preview-image" src="#" alt="Aperçu"></div>
        </div>
        <div class="button-container">
            <button type="submit" class="btn btn-primary">Lancer l'analyse standard</button>
            <button type="button" id="deepThinkBtn" class="btn btn-secondary">DeepThink (1/jour)</button>
        </div>
      </form>
    </div>

    <div id="result" class="card result-card" style="display: none;">
      <div class="tabs">
        <button id="dissertationTab" class="tab active">Dissertation</button>
        <button id="tableauTab" class="tab">Tableau</button>
      </div>
      <div id="displayContentWrapper">
        <div id="dissertationContentWrapper" class="tab-content">
          <div id="dissertationContent" class="custom-prose"></div>
        </div>
        <div id="tableauContentWrapper" class="tab-content" style="display: none;">
           <!-- **Mobile: Conteneur spécifique pour le style 'markdown-table' qui gère l'overflow** -->
          <div id="tableauContent" class="markdown-table">
              <!-- Le contenu HTML du tableau sera injecté ici par Marked.js -->
          </div>
        </div>
      </div>
      <div style="padding: 0 1.25rem 1.25rem;"> <!-- Padding ajusté pour mobile -->
        <button id="downloadPdf" class="btn btn-primary" style="margin-top: 1rem;" disabled>Télécharger en PDF</button>
      </div>
    </div>
  </main>

  <div id="loading" class="loading-overlay" style="display: none;">
       <div class="loading-card"><div class="spinner"></div><p>Préparation de l'analyse...</p></div>
  </div>

  <script>
    // Vérification bibliothèques
    if (typeof window.jspdf === 'undefined') { console.error("Erreur: jsPDF non chargée."); }
    else { console.log("jsPDF chargée:", window.jspdf.jsPDF.version);
           if (typeof window.jspdf.jsPDF.API?.autoTable === 'undefined') { console.error("Erreur: Plugin jsPDF-AutoTable non chargé."); }
           else { console.log("Plugin jsPDF-AutoTable détecté."); }
    }
    if (typeof window.marked === 'undefined') { console.error("Erreur: Marked.js non chargée."); }

    // DOM Elements
    const uploadForm = document.getElementById('uploadForm');
    const imageInput = document.getElementById('imageInput');
    const consignesInput = document.getElementById('consignesInput');
    const uploadArea = document.getElementById('uploadArea');
    const previewContainer = document.getElementById('previewContainer');
    const previewImage = document.getElementById('previewImage');
    const loadingIndicator = document.getElementById('loading');
    const resultDiv = document.getElementById('result');
    const dissertationTab = document.getElementById('dissertationTab');
    const tableauTab = document.getElementById('tableauTab');
    const dissertationContentWrapper = document.getElementById('dissertationContentWrapper');
    const tableauContentWrapper = document.getElementById('tableauContentWrapper');
    const dissertationContent = document.getElementById('dissertationContent');
    const tableauContent = document.getElementById('tableauContent'); // Référence au conteneur du tableau
    const downloadPdfBtn = document.getElementById('downloadPdf');
    const deepThinkBtn = document.getElementById('deepThinkBtn'); // DeepThink Button

    // Config marked
    if (typeof window.marked !== 'undefined') {
        marked.setOptions({ breaks: true, gfm: true, mangle: false, headerIds: false });
    }

    // --- Global state & Constants ---
    let tableauMarkdownRaw = '';
    let dissertationMarkdownRaw = '';
    let currentlyStreaming = null;
    let streamComplete = false;
    const dissertationCursorId = 'dissertationCursor';
    const tableauCursorId = 'tableauCursor';
    const DEEPTHINK_STORAGE_KEY = 'deepThinkLastUsedDate'; // Key for Local Storage

    // --- Helper Functions ---
    function getCursorElement(type) { return document.getElementById(type === 'dissertation' ? dissertationCursorId : tableauCursorId); }
    function removeCursor(type) { const cursor = getCursorElement(type); if (cursor) { cursor.style.display = 'none'; cursor.classList.add('final-cursor'); } }
    function ensureCursor(type, container) {
        let cursor = getCursorElement(type);
        // Try to append cursor after the table if it exists, otherwise just append to the container.
        // This helps visibility in the scrollable table container.
        const tableElement = container.querySelector('table');
        const targetContainer = (type === 'tableau' && tableElement) ? tableElement.parentElement : container;
        if (!cursor) {
            cursor = document.createElement('span');
            cursor.id = type === 'dissertation' ? dissertationCursorId : tableauCursorId;
            cursor.className = 'streaming-cursor';
            targetContainer.appendChild(cursor);
        }
        cursor.style.display = 'inline-block';
        cursor.classList.remove('final-cursor');
        targetContainer.appendChild(cursor); // Ensure it's the last element in the target container
    }


    // --- UI Management ---
    // Standard click for desktop compatibility
    uploadArea.addEventListener('click', () => {
        // Prevent click if triggered immediately after touch end on mobile
        if (uploadArea.dataset.touched) {
            delete uploadArea.dataset.touched;
            return;
        }
        imageInput.click();
    });
    // Utilisation de touchstart/touchend pour réactivité immédiate sur mobile
    uploadArea.addEventListener('touchstart', function(e) {
        e.preventDefault(); // Prevent default touch behavior like scrolling or double-tap zoom
        this.classList.add('active');
        this.dataset.touched = true; // Flag that touch happened
    }, { passive: false });
    uploadArea.addEventListener('touchend', function(e) {
        this.classList.remove('active');
        // Only trigger click if the touch didn't move significantly (optional check, simple version here)
        e.preventDefault(); // Prevent ghost click on some devices
        imageInput.click();
        // Set a flag or timeout to potentially ignore the subsequent 'click' event
        setTimeout(() => { delete uploadArea.dataset.touched; }, 300); // Remove flag after a delay
    });


    imageInput.addEventListener('change', function() { const file = this.files[0]; if (file) { const reader = new FileReader(); reader.onload = function(e) { previewImage.src = e.target.result; previewContainer.style.display = 'block'; previewContainer.classList.add('slide-up'); uploadArea.classList.add('active'); }; reader.readAsDataURL(file); } else { previewContainer.style.display = 'none'; uploadArea.classList.remove('active'); } });
    dissertationTab.addEventListener('click', () => switchTab('dissertation'));
    tableauTab.addEventListener('click', () => switchTab('tableau'));
    function switchTab(tabName) { const isDissertation = tabName === 'dissertation'; dissertationTab.classList.toggle('active', isDissertation); tableauTab.classList.toggle('active', !isDissertation); dissertationContentWrapper.style.display = isDissertation ? 'block' : 'none'; tableauContentWrapper.style.display = !isDissertation ? 'block' : 'none'; }

    // --- DeepThink Daily Limit Logic ---
    function checkDeepThinkLimit() {
        const lastUsedDate = localStorage.getItem(DEEPTHINK_STORAGE_KEY);
        const todayDate = new Date().toDateString(); // Gets "Mon Apr 15 2024" format

        if (lastUsedDate === todayDate) {
            deepThinkBtn.disabled = true;
            deepThinkBtn.textContent = "DeepThink (Utilisé)"; // Texte plus court pour mobile
            console.log("DeepThink limit reached for today.");
        } else {
            deepThinkBtn.disabled = false;
            deepThinkBtn.textContent = "DeepThink (1/jour)";
            console.log("DeepThink available.");
        }
    }

    function recordDeepThinkUsage() {
        const todayDate = new Date().toDateString();
        localStorage.setItem(DEEPTHINK_STORAGE_KEY, todayDate);
        deepThinkBtn.disabled = true;
        deepThinkBtn.textContent = "DeepThink (Utilisé)"; // Texte plus court pour mobile
        console.log("DeepThink usage recorded for today.");
    }

    // --- Streaming Logic ---
    function updateDisplayContent(type) {
        if (typeof window.marked === 'undefined') return;
        if (type === 'tableau') {
            // Injecte le HTML généré par Marked DANS le div 'tableauContent'.
            // Le div 'tableauContent' a déjà la classe 'markdown-table' pour l'overflow.
            tableauContent.innerHTML = marked.parse(tableauMarkdownRaw);
            ensureCursor('tableau', tableauContent); // Place cursor within the container
        } else if (type === 'dissertation') {
            dissertationContent.innerHTML = marked.parse(dissertationMarkdownRaw);
            ensureCursor('dissertation', dissertationContent);
        }
    }
    function processStreamChunk(jsonData, isDeepThink) { // Pass deepthink flag
        try {
            const parsedData = JSON.parse(jsonData);
            if (parsedData.error) { console.error("Erreur serveur:", parsedData.error); alert("Erreur serveur: " + parsedData.error); loadingIndicator.style.display = 'none'; downloadPdfBtn.disabled = true; if (currentlyStreaming) removeCursor(currentlyStreaming); streamComplete = true; return; }

            // First chunk received successfully
            if (resultDiv.style.display === 'none') {
                 resultDiv.style.display = 'block';
                 resultDiv.classList.add('slide-up');
                 loadingIndicator.style.display = 'none';
                 switchTab('dissertation'); // Default to dissertation tab
                 // Record usage ONLY if it was a DeepThink request and this is the first chunk
                 if (isDeepThink) {
                     recordDeepThinkUsage();
                 }
            }

            if (parsedData.type === 'tableau') { tableauMarkdownRaw += parsedData.chunk; }
            else if (parsedData.type === 'dissertation') { dissertationMarkdownRaw += parsedData.chunk; }
            else { console.warn("Type de chunk inconnu reçu:", parsedData.type); return; }

            if (currentlyStreaming !== parsedData.type) { if (currentlyStreaming) { removeCursor(currentlyStreaming); } currentlyStreaming = parsedData.type; }
            updateDisplayContent(parsedData.type);

        } catch (e) { if (e instanceof SyntaxError) { console.warn("Chunk JSON invalide:", jsonData, e); } else { console.error("Erreur traitement chunk:", e, jsonData); } }
    }
    function handleStreamEnd() { console.log("Fin du stream."); streamComplete = true; if (currentlyStreaming) { removeCursor(currentlyStreaming); } loadingIndicator.style.display = 'none'; downloadPdfBtn.disabled = false; currentlyStreaming = null; }

    // --- Analysis Request Logic (Reusable) ---
    function startAnalysis(formData) {
        // Reset state before starting
        tableauMarkdownRaw = ''; dissertationMarkdownRaw = ''; currentlyStreaming = null; streamComplete = false;
        dissertationContent.innerHTML = ''; tableauContent.innerHTML = ''; // Clear previous content
        resultDiv.style.display = 'none'; loadingIndicator.style.display = 'flex'; downloadPdfBtn.disabled = true; switchTab('dissertation');

        const isDeepThinkRequest = formData.get('use_deepthink') === 'true';
        console.log(`Lancement de l'analyse ${isDeepThinkRequest ? 'DeepThink' : 'standard'}...`);

        fetch('/analyze', { method: 'POST', body: formData })
        .then(response => {
            if (!response.ok) {
                return response.text().then(text => {
                    let errorMsg = `Erreur HTTP ${response.status}: ${response.statusText}`;
                    try { const errData = JSON.parse(text); errorMsg += `. Détail: ${errData.error || text}`; } catch (e) { errorMsg += `. Détail: ${text}`; }
                    throw new Error(errorMsg);
                });
            }
            if (!response.body) { throw new Error("Réponse serveur sans corps."); }
            const reader = response.body.getReader();
            const decoder = new TextDecoder();
            function read() {
                reader.read().then(({done, value}) => {
                    if (done) { handleStreamEnd(); return; }
                    const text = decoder.decode(value, {stream: true});
                    const lines = text.split('\n').filter(line => line.trim() !== '');
                    // Pass the isDeepThinkRequest flag to processStreamChunk
                    lines.forEach(line => { processStreamChunk(line, isDeepThinkRequest); });
                    read();
                }).catch(error => { console.error('Erreur lecture stream:', error); alert('Erreur réception analyse: ' + error.message); loadingIndicator.style.display = 'none'; downloadPdfBtn.disabled = true; if (currentlyStreaming) removeCursor(currentlyStreaming); streamComplete = true; });
            }
            read();
        })
        .catch(error => { console.error('Erreur Fetch:', error); loadingIndicator.style.display = 'none'; alert(`Erreur connexion/analyse: ${error.message}`); downloadPdfBtn.disabled = true; streamComplete = true; });
    }

    // --- Form Submission Handlers ---
    uploadForm.addEventListener('submit', function(e) {
        e.preventDefault(); // Prevent default form submission
        if (imageInput.files.length === 0) { alert("Veuillez sélectionner un fichier image."); return; }

        const formData = new FormData();
        formData.append('image', imageInput.files[0]);
        formData.append('consignes', consignesInput.value);
        // NO use_deepthink flag here for standard analysis

        startAnalysis(formData); // Call the reusable analysis function
     });

    deepThinkBtn.addEventListener('click', function() {
        if (this.disabled) {
            alert("La fonctionnalité DeepThink est limitée à une utilisation par jour.");
            return;
        }
        if (imageInput.files.length === 0) { alert("Veuillez sélectionner un fichier image avant de lancer DeepThink."); return; }

        // Double check limit just before sending
        const lastUsedDate = localStorage.getItem(DEEPTHINK_STORAGE_KEY);
        const todayDate = new Date().toDateString();
        if(lastUsedDate === todayDate) {
             alert("DeepThink a déjà été utilisé aujourd'hui.");
             checkDeepThinkLimit(); // Update button state if needed
             return;
        }

        const formData = new FormData();
        formData.append('image', imageInput.files[0]);
        formData.append('consignes', consignesInput.value);
        formData.append('use_deepthink', 'true'); // ADD THE FLAG FOR DEEPTHINK

        startAnalysis(formData); // Call the reusable analysis function
    });


    // --- PDF Download Logic (Unchanged logic, should still work) ---
    downloadPdfBtn.addEventListener('click', () => {
        if (!streamComplete || (!dissertationMarkdownRaw && !tableauMarkdownRaw)) {
            alert("Analyse non terminée ou contenu vide.");
            return;
        }
        if (typeof window.jspdf === 'undefined' || typeof window.jspdf.jsPDF === 'undefined' || typeof window.jspdf.jsPDF.API.autoTable === 'undefined') {
             alert("Erreur critique : jsPDF ou le plugin AutoTable ne sont pas disponibles.");
             return;
         }
        const { jsPDF } = window.jspdf;

        console.log("Préparation du PDF avec détection de blocs...");
        downloadPdfBtn.disabled = true;
        downloadPdfBtn.textContent = "Génération PDF...";

        try {
            const pdf = new jsPDF({ orientation: 'p', unit: 'pt', format: 'letter' });
            const pageHeight = pdf.internal.pageSize.getHeight();
            const pageWidth = pdf.internal.pageSize.getWidth();
            const margin = 40;
            const maxLineWidth = pageWidth - margin * 2;
            const fontSize = 10; // Base font size for PDF
            const lineHeightFactor = 1.3;
            const lineHeight = fontSize * lineHeightFactor;
            let cursorY = margin;

            pdf.setFontSize(fontSize);
            // Utiliser une police standard comme Helvetica pour une meilleure compatibilité PDF embarquée
            pdf.setFont("Helvetica", "normal");

            function addTextToPage(text) {
                if (!text) return;
                // Basic cleaning: remove markdown markers for simplicity in PDF text blocks
                const simplifiedText = text.trim()
                    .replace(/^#+\s+/gm, '')        // Remove heading markers
                    .replace(/^[\*\-]\s+/gm, '  '); // Replace list markers with indent
                const lines = pdf.splitTextToSize(simplifiedText, maxLineWidth);
                lines.forEach(line => {
                    if (cursorY + lineHeight > pageHeight - margin) { pdf.addPage(); cursorY = margin; }
                    pdf.text(line, margin, cursorY); cursorY += lineHeight;
                });
                 cursorY += lineHeight * 0.5; // Add some space after paragraph
            }
             function addTitleToPage(titleText, level = 1) {
                 if (!titleText) return;
                 const titleSize = level === 1 ? 16 : (level === 2 ? 14 : 12);
                 const titleLineHeight = titleSize * lineHeightFactor;
                 if (cursorY + titleLineHeight > pageHeight - margin) { pdf.addPage(); cursorY = margin; }
                 pdf.setFontSize(titleSize); pdf.setFont("Helvetica", "bold");
                 pdf.text(titleText.trim(), margin, cursorY);
                 pdf.setFontSize(fontSize); pdf.setFont("Helvetica", "normal"); // Reset to normal
                 cursorY += titleLineHeight + 6; // Space after title
            }
            function parseMarkdownTable(mdTableBlock) {
                 if (!mdTableBlock || typeof mdTableBlock !== 'string') return { head: [], body: [] };
                 const lines = mdTableBlock.trim().split('\n');
                 const cleanCell = (cell) => cell ? cell.trim() : ''; // Function to trim cell content

                 let headerLineIndex = -1, separatorLineIndex = -1;

                 // Find header and separator lines more robustly
                 for(let i = 0; i < lines.length; i++) {
                     const trimmedLine = lines[i].trim();
                     if (trimmedLine.startsWith('|') && trimmedLine.endsWith('|')) {
                          // Check for separator line (allows alignment colons)
                         if (trimmedLine.includes('-') && trimmedLine.replace(/\|/g, '').replace(/-/g, '').replace(/:/g, '').trim() === '') {
                             separatorLineIndex = i;
                             // Check if the previous line looks like a header
                             if (i > 0 && lines[i-1].trim().startsWith('|') && lines[i-1].trim().endsWith('|')) {
                                 headerLineIndex = i - 1;
                                 break; // Found both, exit loop
                             }
                         } else if (headerLineIndex === -1 && separatorLineIndex === -1) {
                            // Potential header line if we haven't found one yet and not passed separator
                            headerLineIndex = i;
                         }
                     }
                 }

                 // Validate findings
                 if (headerLineIndex === -1 || separatorLineIndex === -1 || separatorLineIndex !== headerLineIndex + 1) {
                     console.warn("Structure de tableau Markdown non standard ou incomplète:", mdTableBlock.substring(0, 100));
                      // Fallback attempt if structure is simple (Header \n Separator \n ...)
                     if (lines.length >= 2 && lines[0].includes('|') && lines[1].includes('|') && lines[1].includes('-')) {
                         headerLineIndex = 0; separatorLineIndex = 1;
                         console.log("Fallback: Utilisation des deux premières lignes comme header/separator.");
                     } else {
                         return { head: [], body: [] }; // Cannot parse reliably
                     }
                 }

                 const headerLine = lines[headerLineIndex];
                 // Extract header cells, removing empty strings from start/end splits
                 const head = headerLine.split('|').map(cleanCell).filter((cell, i, arr) => i > 0 && i < arr.length - 1);

                 const body = lines.slice(separatorLineIndex + 1)
                     .map(line => {
                         const trimmedLine = line.trim();
                         // Ensure it's a valid table row line
                         if (!trimmedLine.startsWith('|') || !trimmedLine.endsWith('|')) return null;
                         // Extract row cells, removing empty strings from start/end splits
                         return trimmedLine.split('|').map(cleanCell).filter((cell, i, arr) => i > 0 && i < arr.length - 1);
                     })
                     // Keep only valid rows (not null) with the correct number of cells matching the header
                     .filter(row => row && row.length === head.length);

                 return { head: [head], body: body }; // Return jspdf-autotable compatible format
             }


            // Combine dissertation and table markdown for sequential processing
            const fullMarkdownText = dissertationMarkdownRaw + "\n\n" + tableauMarkdownRaw;
            const lines = fullMarkdownText.split('\n');
            let currentBlock = ''; // Accumulates lines of text or a table
            let isInsideTable = false; // Flag to track if we are processing table lines

            for (let i = 0; i < lines.length; i++) {
                const line = lines[i];
                const trimmedLine = line.trim();
                const isTableLine = trimmedLine.startsWith('|') && trimmedLine.endsWith('|');
                // More robust separator check (allows for alignment colons like |:---|:--|)
                const isSeparatorLine = isTableLine && trimmedLine.includes('-') && trimmedLine.replace(/\|/g, '').replace(/-/g, '').replace(/:/g, '').trim() === '';

                if (isTableLine && !isSeparatorLine) { // Potential header or data row
                    if (!isInsideTable) {
                        // Check if the *next* line is a separator to confirm start of a table
                        const nextLineIndex = i + 1;
                        const nextLine = (nextLineIndex < lines.length) ? lines[nextLineIndex].trim() : null;
                        const nextLineIsSeparator = nextLine && nextLine.startsWith('|') && nextLine.endsWith('|') && nextLine.includes('-') && nextLine.replace(/\|/g, '').replace(/-/g, '').replace(/:/g, '').trim() === '';

                        if (nextLineIsSeparator) {
                            // Start of a table detected
                            if (currentBlock.trim()) { // Add any preceding text first
                                addTextToPage(currentBlock.trim());
                            }
                            currentBlock = line + '\n'; // Start accumulating table block
                            isInsideTable = true;
                        } else {
                            // Just a regular line containing pipes, treat as text
                            currentBlock += line + '\n';
                        }
                    } else {
                        // Already inside a table, accumulate the line
                        currentBlock += line + '\n';
                    }
                } else if (isSeparatorLine) { // Separator line
                    if (isInsideTable) {
                        // Part of the current table block
                        currentBlock += line + '\n';
                    } else {
                         // Separator outside a table context? Treat as text.
                         // This might happen with badly formatted markdown.
                         currentBlock += line + '\n';
                    }
                 } else { // Not a table line (or separator)
                    if (isInsideTable) {
                        // End of the table block detected (current line is non-table)
                        console.log("Traitement bloc tableau détecté.");
                        const tableData = parseMarkdownTable(currentBlock.trim());
                        if (tableData.head.length > 0 && tableData.head[0].length > 0) {
                             if (cursorY + 30 > pageHeight - margin) { pdf.addPage(); cursorY = margin; } // Check space before adding table
                             pdf.autoTable({
                                head: tableData.head, body: tableData.body, startY: cursorY,
                                theme: 'grid', // 'striped', 'grid', 'plain'
                                styles: { fontSize: 9, cellPadding: 5, overflow: 'linebreak', font: "Helvetica" }, // Use standard font
                                headStyles: { fillColor: [67, 97, 238], textColor: [255, 255, 255], fontStyle: 'bold', halign: 'center' },
                                didParseCell: function (data) { data.cell.styles.valign = 'middle'; }, // Vertically align cell content
                                margin: { left: margin, right: margin }
                             });
                             cursorY = pdf.previousAutoTable.finalY + lineHeight; // Update cursor position
                        } else {
                             console.warn("Échec parsing bloc tableau ou tableau vide.");
                             addTextToPage("(Erreur: Bloc tableau non formaté ou vide)\n" + currentBlock.trim());
                        }
                        currentBlock = line + '\n'; // Start new text block with the current line
                        isInsideTable = false;
                    } else {
                        // Regular text line processing
                        if (trimmedLine.startsWith('#')) { // Handle headings
                            if (currentBlock.trim()) { addTextToPage(currentBlock.trim()); } // Add preceding text
                            const level = (trimmedLine.match(/^#+/) || [''])[0].length;
                            const titleText = trimmedLine.replace(/^#+\s*/, '');
                            addTitleToPage(titleText, level);
                            currentBlock = ''; // Reset block after title
                        } else {
                            // Accumulate regular text line
                            currentBlock += line + '\n';
                        }
                    }
                }
            }

            // Process any remaining block after the loop finishes
            if (currentBlock.trim()) {
                if (isInsideTable) {
                    // The document ended while inside a table block
                    console.log("Traitement dernier bloc (tableau).");
                    const tableData = parseMarkdownTable(currentBlock.trim());
                     if (tableData.head.length > 0 && tableData.head[0].length > 0) {
                         if (cursorY + 30 > pageHeight - margin) { pdf.addPage(); cursorY = margin; }
                         pdf.autoTable({
                            head: tableData.head, body: tableData.body, startY: cursorY,
                            theme: 'grid', styles: { fontSize: 9, cellPadding: 5, overflow: 'linebreak', font: "Helvetica" },
                            headStyles: { fillColor: [67, 97, 238], textColor: [255, 255, 255], fontStyle: 'bold', halign: 'center' },
                            didParseCell: function (data) { data.cell.styles.valign = 'middle'; },
                            margin: { left: margin, right: margin }
                         });
                     } else {
                          console.warn("Échec parsing dernier bloc tableau ou tableau vide.");
                          addTextToPage("(Erreur: Dernier bloc tableau non formaté ou vide)\n" + currentBlock.trim());
                     }
                } else {
                    // Last block was text
                    console.log("Ajout dernier bloc texte.");
                    addTextToPage(currentBlock.trim());
                }
            }

            console.log("Contenu ajouté, sauvegarde du PDF...");
            pdf.save('MariamAI-Analyse-Resultat.pdf');

        } catch (error) {
            console.error("Erreur lors de la génération du PDF mixte:", error);
            alert("Une erreur s'est produite lors de la création du PDF mixte.");
        } finally {
             downloadPdfBtn.disabled = false;
             downloadPdfBtn.textContent = "Télécharger en PDF";
        }
    });

    // --- Initialisation ---
    document.addEventListener('DOMContentLoaded', () => {
        switchTab('dissertation');
        checkDeepThinkLimit(); // Check limit on page load

        // Améliorations tactiles génériques (peuvent rester pour les boutons/tabs)
        const interactiveElements = document.querySelectorAll('.btn, .tab'); // Upload area has specific handlers now
        interactiveElements.forEach(el => {
            let touchMoved = false;
            // Use passive: true where possible to improve scrolling performance
            el.addEventListener('touchstart', function() {
                 touchMoved = false;
                 if (!this.disabled) {
                     // Apply visual feedback instantly on touch
                     this.style.transition = 'transform 0.1s ease, background-color 0.1s ease';
                     this.style.transform = 'scale(0.97)';
                     // Maybe slightly change background for immediate feedback
                     // Example: this.style.backgroundColor = 'rgba(0,0,0,0.05)';
                 }
             }, { passive: true });

            el.addEventListener('touchmove', function() {
                 touchMoved = true; // User is likely scrolling
                 this.style.transform = 'scale(1)'; // Reset visual feedback if touch moves
                 // Reset background if changed on touchstart
             }, { passive: true });

            el.addEventListener('touchend', function() {
                 // Reset transform only on touchend, giving the 'pressed' effect
                 this.style.transform = 'scale(1)';
                 // Reset background if changed on touchstart
             }); // Not passive, might be needed for subsequent logic

            // Keep mouse events for desktop compatibility
            el.addEventListener('mousedown', function() { if (!this.disabled) { this.style.transform = 'scale(0.97)'; } });
            el.addEventListener('mouseup', function() { this.style.transform = 'scale(1)'; });
            el.addEventListener('mouseleave', function() { this.style.transform = 'scale(1)'; }); // Reset if mouse leaves while pressed
        });
     });

  </script>

</body>
</html>