File size: 42,357 Bytes
31f2a28
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
<!DOCTYPE html>
<html lang="en" class="dark">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Agent DAG Inspector — Trajectory Debug</title>
<script src="https://cdn.tailwindcss.com?plugins=typography"></script>
<script src="https://unpkg.com/vis-network/standalone/umd/vis-network.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<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=Inter:wght@300;400;500;600;700;800&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<script>
  tailwind.config = {
    darkMode: 'class',
    theme: {
      extend: {
        fontFamily: {
          sans: ['Inter', 'system-ui', 'sans-serif'],
          mono: ['JetBrains Mono', 'monospace']
        }
      }
    }
  }
</script>
<style>
  :root {
    --bg-base: #09090b;
    --bg-elevated: #131316;
    --bg-card: #1a1a1e;
    --border: #27272a;
    --border-strong: #3f3f46;
    --text-primary: #fafafa;
    --text-secondary: #a1a1aa;
    --text-muted: #71717a;
    --accent-emerald: #10b981;
    --accent-red: #ef4444;
    --accent-amber: #f59e0b;
    --accent-blue: #3b82f6;
  }
  * { box-sizing: border-box; }
  html, body { height: 100%; }
  body {
    background: var(--bg-base);
    color: var(--text-primary);
    font-family: 'Inter', system-ui, sans-serif;
    overflow: hidden;
    -webkit-font-smoothing: antialiased;
  }
  body::before {
    content: '';
    position: fixed;
    inset: 0;
    background-image:
      radial-gradient(circle at 18% 8%, rgba(59, 130, 246, 0.05), transparent 42%),
      radial-gradient(circle at 82% 92%, rgba(16, 185, 129, 0.04), transparent 42%);
    pointer-events: none;
    z-index: 0;
  }
  ::-webkit-scrollbar { width: 8px; height: 8px; }
  ::-webkit-scrollbar-track { background: transparent; }
  ::-webkit-scrollbar-thumb { background: #27272a; border-radius: 4px; }
  ::-webkit-scrollbar-thumb:hover { background: #3f3f46; }

  #graph-container { width: 100%; height: 100%; }
  .vis-network { outline: none; }
  .vis-network canvas { cursor: grab; }

  .drawer {
    transform: translateX(100%);
    transition: transform 340ms cubic-bezier(0.32, 0.72, 0, 1);
    box-shadow: -20px 0 60px -20px rgba(0,0,0,0.6);
  }
  .drawer.open { transform: translateX(0); }
  .drawer-backdrop {
    opacity: 0;
    pointer-events: none;
    transition: opacity 320ms ease;
  }
  .drawer-backdrop.open { opacity: 1; pointer-events: auto; }

  @keyframes pulse-dot {
    0%, 100% { opacity: 1; transform: scale(1); }
    50% { opacity: 0.55; transform: scale(0.85); }
  }
  .pulse-dot { animation: pulse-dot 2s ease-in-out infinite; }
  .health-ring circle { transition: stroke-dashoffset 1.1s cubic-bezier(0.16, 1, 0.3, 1), stroke 400ms ease; }
  .stat-card { transition: border-color 200ms ease, background-color 200ms ease; }
  .stat-card:hover { border-color: var(--border-strong); background-color: rgba(255,255,255,0.015); }

  .badge-healthy { background: rgba(16, 185, 129, 0.1); color: #34d399; border: 1px solid rgba(16, 185, 129, 0.25); }
  .badge-error    { background: rgba(239, 68, 68, 0.1);  color: #f87171; border: 1px solid rgba(239, 68, 68, 0.25); }
  .badge-warning  { background: rgba(245, 158, 11, 0.1); color: #fbbf24; border: 1px solid rgba(245, 158, 11, 0.25); }

  .bar-track { background: rgba(255, 255, 255, 0.05); }
  .bar-fill  { transition: width 1s cubic-bezier(0.16, 1, 0.3, 1), background 400ms ease; }

  .btn-icon { transition: background-color 150ms ease, color 150ms ease; }
  .btn-icon:hover { background: rgba(255, 255, 255, 0.06); color: var(--text-primary); }

  @keyframes fade-in-up {
    from { opacity: 0; transform: translateY(8px); }
    to   { opacity: 1; transform: translateY(0); }
  }
  .drawer.open .drawer-content > * {
    animation: fade-in-up 340ms ease-out backwards;
  }
  .drawer.open .drawer-content > *:nth-child(1) { animation-delay: 60ms; }
  .drawer.open .drawer-content > *:nth-child(2) { animation-delay: 110ms; }
  .drawer.open .drawer-content > *:nth-child(3) { animation-delay: 160ms; }
  .drawer.open .drawer-content > *:nth-child(4) { animation-delay: 210ms; }
  .drawer.open .drawer-content > *:nth-child(5) { animation-delay: 260ms; }

  .empty-state {
    display: flex; align-items: center; justify-content: center;
    flex-direction: column; height: 100%; color: var(--text-muted);
  }
  .line-clamp-2 {
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
    overflow: hidden;
  }
  .modal-enter { animation: modal-in 220ms cubic-bezier(0.16, 1, 0.3, 1); }
  @keyframes modal-in {
    from { opacity: 0; transform: scale(0.97) translateY(8px); }
    to   { opacity: 1; transform: scale(1) translateY(0); }
  }
</style>
</head>
<body class="text-zinc-100">
  <div class="relative z-10 h-screen flex flex-col">

    <!-- ============ TOP BAR / EXECUTIVE SUMMARY ============ -->
    <header class="border-b border-zinc-800/80 bg-zinc-950/80 backdrop-blur-xl flex-shrink-0">
      <div class="flex items-center justify-between px-6 py-3 border-b border-zinc-800/50">
        <div class="flex items-center gap-3">
          <div class="w-8 h-8 rounded-lg bg-gradient-to-br from-emerald-500 to-blue-600 flex items-center justify-center shadow-lg shadow-emerald-500/20">
            <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
              <circle cx="6" cy="6" r="2"/><circle cx="18" cy="6" r="2"/>
              <circle cx="6" cy="18" r="2"/><circle cx="18" cy="18" r="2"/>
              <path d="M8 6h8M6 8v8M18 8v8M8 18h8"/>
            </svg>
          </div>
          <div>
            <h1 class="text-sm font-semibold tracking-tight">Limina AI — Agent DAG Inspector</h1>
            <p class="text-[11px] text-zinc-500 font-mono">trajectory_debug_session_4821</p>
          </div>
        </div>
        <div class="flex items-center gap-4">
          <div class="flex items-center gap-2 text-xs">
            <span class="w-1.5 h-1.5 rounded-full bg-emerald-500 pulse-dot"></span>
            <span class="text-zinc-400">Live session</span>
          </div>
          <div class="text-xs text-zinc-500 font-mono"><span id="timestamp"></span></div>
        </div>
      </div>

      <!-- UPGRADE: 4-Column Grid, adaugat cardul strategic Session Cost deasupra -->
      <div class="grid grid-cols-4 divide-x divide-zinc-800/60">
        <!-- Health Rating -->
        <div class="stat-card px-6 py-4">
          <div class="flex items-center justify-between mb-2">
            <span class="text-[11px] uppercase tracking-wider text-zinc-500 font-medium">Health Rating</span>
            <span class="text-[10px] font-mono text-zinc-600">/100</span>
          </div>
          <div class="flex items-center gap-4">
            <div class="relative w-12 h-12">
              <svg class="health-ring w-12 h-12 -rotate-90" viewBox="0 0 48 48">
                <circle cx="24" cy="24" r="20" fill="none" stroke="rgba(255,255,255,0.06)" stroke-width="4"/>
                <circle id="health-circle" cx="24" cy="24" r="20" fill="none" stroke="#10b981" stroke-width="4" stroke-linecap="round" stroke-dasharray="125.6" stroke-dashoffset="125.6"/>
              </svg>
              <div class="absolute inset-0 flex items-center justify-center">
                <span id="health-value" class="text-sm font-semibold text-emerald-400 tabular-nums">0</span>
              </div>
            </div>
            <div class="flex-1 min-w-0">
              <div id="health-label" class="text-sm font-semibold text-zinc-100"></div>
              <div id="health-sub" class="text-xs text-zinc-500 truncate">Analyzing...</div>
            </div>
          </div>
        </div>

        <!-- Success Rate -->
        <div class="stat-card px-6 py-4">
          <div class="flex items-center justify-between mb-2">
            <span class="text-[11px] uppercase tracking-wider text-zinc-500 font-medium">Success Rate</span>
            <span id="success-total" class="text-[10px] font-mono text-zinc-600">— nodes</span>
          </div>
          <div class="flex items-baseline gap-2 mb-2">
            <span id="success-value" class="text-2xl font-bold tabular-nums">0%</span>
          </div>
          <div class="bar-track h-1.5 rounded-full overflow-hidden">
            <div id="success-bar" class="bar-fill h-full bg-gradient-to-r from-emerald-500 to-emerald-400 rounded-full" style="width: 0%"></div>
          </div>
        </div>

        <!-- UPGRADE: Session Cost Card (Amplasament strategic de business) -->
        <div class="stat-card px-6 py-4">
          <div class="flex items-center justify-between mb-2">
            <span class="text-[11px] uppercase tracking-wider text-zinc-500 font-medium">Session Cost</span>
            <span id="session-tokens" class="text-[10px] font-mono text-zinc-400">0 tokens</span>
          </div>
          <div class="flex items-baseline gap-2 mb-1">
            <span id="session-cost-value" class="text-2xl font-bold text-emerald-400 tabular-nums">$0.00000</span>
            <span class="text-[10px] text-zinc-500">simulated USD</span>
          </div>
          <div class="text-[10px] text-zinc-500 font-mono">Based on standard B2B rates</div>
        </div>

        <!-- Actionable Advice -->
        <div class="stat-card px-6 py-4">
          <div class="flex items-center justify-between mb-2">
            <span class="text-[11px] uppercase tracking-wider text-zinc-500 font-medium">Actionable Advice</span>
            <span class="badge-warning text-[10px] px-1.5 py-0.5 rounded font-medium">PRIORITY</span>
          </div>
          <p id="advice-text" class="text-xs text-zinc-300 leading-relaxed line-clamp-2">No advice available.</p>
          <button id="advice-expand" class="mt-1.5 text-[11px] text-blue-400 hover:text-blue-300 transition-colors">View full analysis →</button>
        </div>
      </div>
    </header>

    <!-- ============ MAIN AREA ============ -->
    <main class="flex-1 flex relative overflow-hidden">

      <!-- Graph panel -->
      <section class="flex-1 flex flex-col relative">
        <!-- Toolbar -->
        <div class="flex items-center justify-between px-4 py-2 border-b border-zinc-800/60 bg-zinc-950/40">
          <div class="flex items-center gap-3">
            <span class="text-xs text-zinc-400 font-medium pl-2">Trajectory Graph</span>
            <span class="text-zinc-700">·</span>
            <!-- Dropdown dinamic pentru selectarea sesiunilor -->
            <select id="session-select" class="bg-zinc-900 border border-zinc-800 text-xs text-zinc-300 rounded-md px-2.5 py-1 focus:outline-none focus:border-zinc-700 cursor-pointer font-mono"></select>
            <span class="text-zinc-700">·</span>
            <span id="node-count" class="text-xs text-zinc-500 font-mono">0 nodes</span>
            <span class="text-zinc-700">·</span>
            <span id="edge-count" class="text-xs text-zinc-500 font-mono">0 edges</span>
          </div>
          <div class="flex items-center gap-1">
            <button id="zoom-fit" class="btn-icon text-zinc-400 p-1.5 rounded-md" title="Fit to view">
              <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                <path d="M3 7V5a2 2 0 0 1 2-2h2M17 3h2a2 2 0 0 1 2 2v2M21 17v2a2 2 0 0 1-2 2h-2M7 21H5a2 2 0 0 1-2-2v-2"/>
              </svg>
            </button>
            <button id="zoom-in" class="btn-icon text-zinc-400 p-1.5 rounded-md" title="Zoom in">
              <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                <circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/><line x1="11" y1="8" x2="11" y2="14"/><line x1="8" y1="11" x2="14" y2="11"/>
              </svg>
            </button>
            <button id="zoom-out" class="btn-icon text-zinc-400 p-1.5 rounded-md" title="Zoom out">
              <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                <circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/><line x1="8" y1="11" x2="14" y2="11"/>
              </svg>
            </button>
            <div class="w-px h-5 bg-zinc-800 mx-1"></div>
            <button id="layout-toggle" class="btn-icon text-zinc-400 p-1.5 rounded-md" title="Toggle layout direction">
              <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                <path d="M3 6h18M3 12h18M3 18h18"/>
              </svg>
            </button>
          </div>
        </div>

        <!-- Graph canvas -->
        <div class="flex-1 relative">
          <div id="graph-container"></div>

          <!-- Empty state -->
          <div id="empty-state" class="empty-state absolute inset-0 pointer-events-none" style="display:none">
            <svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" class="text-zinc-700 mb-3">
              <circle cx="6" cy="6" r="2"/><circle cx="18" cy="6" r="2"/>
              <circle cx="6" cy="18" r="2"/><circle cx="18" cy="18" r="2"/>
              <path d="M8 6h8M6 8v8M18 8v8M8 18h8"/>
            </svg>
            <p class="text-sm text-zinc-500">No trajectory data loaded</p>
            <p class="text-xs text-zinc-600 mt-1">Waiting for <code class="font-mono text-zinc-400">reportData</code></p>
          </div>

          <!-- Legend -->
          <div class="absolute bottom-4 left-4 bg-zinc-950/80 backdrop-blur-md border border-zinc-800 rounded-lg p-3 text-xs">
            <div class="text-[10px] uppercase tracking-wider text-zinc-500 font-medium mb-2">Legend</div>
            <div class="space-y-1.5">
              <div class="flex items-center gap-2">
                <span class="w-2.5 h-2.5 rounded-full bg-emerald-500 ring-2 ring-emerald-500/30"></span>
                <span class="text-zinc-300">Healthy</span>
                <span class="text-zinc-600 text-[10px] font-mono">stable &amp; secure</span>
              </div>
              <div class="flex items-center gap-2">
                <span class="w-2.5 h-2.5 rounded-full bg-amber-500 ring-2 ring-amber-500/30"></span>
                <span class="text-zinc-300">Unstable / Warn</span>
                <span class="text-zinc-600 text-[10px] font-mono">instability / low robustness</span>
              </div>
              <div class="flex items-center gap-2">
                <span class="w-2.5 h-2.5 rounded-full bg-red-500 ring-2 ring-red-500/30"></span>
                <span class="text-zinc-300">Error / Breach</span>
                <span class="text-zinc-600 text-[10px] font-mono">contradiction / format fail / leak</span>
              </div>
            </div>
          </div>

          <!-- Hint -->
          <div id="graph-hint" class="absolute top-4 left-1/2 -translate-x-1/2 bg-zinc-950/80 backdrop-blur-md border border-zinc-800 rounded-full px-3 py-1.5 text-xs text-zinc-400 flex items-center gap-2 transition-opacity duration-500" style="display:none">
            <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
              <path d="M9 11.24V7.5a2.5 2.5 0 0 1 5 0v3.74M7 11h10v8a2 2 0 0 1-2 2H9a2 2 0 0 1-2-2v-8z"/>
            </svg>
            <span>Click any node to inspect diagnostics</span>
          </div>
        </div>
      </section>

      <!-- Drawer backdrop -->
      <div id="drawer-backdrop" class="drawer-backdrop absolute inset-0 bg-black/40 z-20"></div>

      <!-- ============ DIAGNOSTIC DRAWER ============ -->
      <aside id="drawer" class="drawer absolute right-0 top-0 bottom-0 w-[420px] bg-zinc-950 border-l border-zinc-800 z-30 flex flex-col">
        <div class="flex items-center justify-between px-5 py-4 border-b border-zinc-800">
          <div class="flex items-center gap-2">
            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="text-zinc-400">
              <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/>
            </svg>
            <h2 class="text-sm font-semibold tracking-tight">Node Diagnostics</h2>
          </div>
          <button id="drawer-close" class="btn-icon text-zinc-400 p-1.5 rounded-md" title="Close (Esc)">
            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
              <line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/>
            </svg>
          </button>
        </div>

        <div class="drawer-content flex-1 overflow-y-auto p-5 space-y-5">
          <!-- Identity -->
          <div>
            <div class="flex items-center gap-2 mb-2">
              <span id="drawer-status-badge" class="badge-healthy text-[10px] px-2 py-0.5 rounded-full font-medium uppercase tracking-wider">Healthy</span>
              <span id="drawer-type" class="text-[11px] text-zinc-500 font-mono">type</span>
            </div>
            <h3 id="drawer-label" class="text-lg font-semibold text-zinc-100"></h3>
            <div class="flex items-center gap-2 mt-1">
              <span class="text-[11px] text-zinc-600 font-mono">id:</span>
              <code id="drawer-id" class="text-[11px] text-zinc-400 font-mono"></code>
            </div>
          </div>

          <!-- UPGRADE: 3-Column Metrics (Exec Time, Instability, Cost/Tokens) -->
          <div class="grid grid-cols-3 gap-1.5">
            <div class="bg-zinc-900/50 border border-zinc-800 rounded-lg p-2.5">
              <div class="text-[9px] uppercase tracking-wider text-zinc-500 font-medium mb-1">Exec Time</div>
              <div class="flex items-baseline gap-0.5">
                <span id="drawer-exec-time" class="text-sm font-semibold tabular-nums text-zinc-100"></span>
                <span class="text-[9px] text-zinc-500">ms</span>
              </div>
            </div>
            <div class="bg-zinc-900/50 border border-zinc-800 rounded-lg p-2.5">
              <div class="text-[9px] uppercase tracking-wider text-zinc-500 font-medium mb-1">Instability</div>
              <div class="flex items-baseline gap-0.5">
                <span id="drawer-instability" class="text-sm font-semibold tabular-nums text-zinc-100"></span>
                <span class="text-[9px] text-zinc-500">idx</span>
              </div>
              <div class="mt-2 bar-track h-1 rounded-full overflow-hidden">
                <div id="drawer-instability-bar" class="bar-fill h-full rounded-full" style="width: 0%"></div>
              </div>
            </div>
            <div class="bg-zinc-900/50 border border-zinc-800 rounded-lg p-2.5">
              <div class="text-[9px] uppercase tracking-wider text-zinc-500 font-medium mb-1">Session Cost</div>
              <div class="flex flex-col">
                <span id="drawer-cost" class="text-sm font-semibold text-emerald-400 tabular-nums">$0.00</span>
                <span id="drawer-tokens" class="text-[9px] text-zinc-500 font-mono">0 tokens</span>
              </div>
            </div>
          </div>

          <!-- Validation errors list -->
          <div id="drawer-error-section" class="hidden">
            <div class="text-[10px] uppercase tracking-wider text-zinc-500 font-medium mb-2">Validation Errors</div>
            <div id="drawer-error" class="space-y-2"></div>
          </div>

          <!-- Node text with 1-Click Copy -->
          <div>
            <div class="flex items-center justify-between mb-2">
              <span class="text-[10px] uppercase tracking-wider text-zinc-500 font-medium">Node Output / Text</span>
              <!-- UPGRADE: 1-Click Copy Button -->
              <button id="copy-payload" class="flex items-center gap-1.5 text-[11px] text-blue-400 hover:text-blue-300 transition-colors">
                <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                  <rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/>
                </svg>
                <span id="copy-text">Copy</span>
              </button>
            </div>
            <div class="bg-zinc-900/50 border border-zinc-800 rounded-lg p-3">
              <p id="drawer-text" class="text-xs text-zinc-300 leading-relaxed font-mono break-words select-all"></p>
            </div>
          </div>

          <!-- Connected edges -->
          <div>
            <div class="flex items-center justify-between mb-2">
              <span class="text-[10px] uppercase tracking-wider text-zinc-500 font-medium">Connected Edges</span>
              <span id="drawer-edges-count" class="text-[10px] text-zinc-600 font-mono">0</span>
            </div>
            <div id="drawer-edges" class="space-y-2"></div>
          </div>
        </div>
      </aside>
    </main>
  </div>

  <!-- Advice modal -->
  <div id="advice-modal" class="fixed inset-0 z-50 hidden items-center justify-center p-6 bg-black/60 backdrop-blur-sm">
    <div class="modal-enter bg-zinc-950 border border-zinc-800 rounded-xl max-w-xl w-full max-h-[85vh] flex flex-col p-6 shadow-2xl">
      <div class="flex items-start justify-between mb-4">
        <div>
          <h3 class="text-base font-semibold">Diagnostic Analysis</h3>
          <p class="text-xs text-zinc-500 mt-0.5">Generated locally by Limina Cognitive Engine</p>
        </div>
        <button id="advice-close" class="btn-icon text-zinc-400 p-1.5 rounded-md">
          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
            <line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/>
          </svg>
        </button>
      </div>
      <!-- UPGRADE: Clasa prose si prose-invert pentru formatarea corecta a Markdown-ului -->
      <div id="advice-full" class="text-sm text-zinc-300 leading-relaxed prose prose-invert max-w-none overflow-y-auto flex-1 pr-2 prose-p:text-sm prose-li:text-sm prose-code:text-xs prose-code:bg-zinc-900 prose-code:px-1 prose-code:py-0.5 prose-code:rounded"></div>
    </div>
  </div>

  <script>
    // =====================================================================
    //  PLACEHOLDER — populated externally by the report generator.
    //  Expected shape:
    //    reportData = {
    //      executive_summary: { health_rating, success_rate, actionable_advice, total_nodes, errors_detected },
    //      enriched_graph: { nodes: [...], edges: [...] }
    //    }
    // =====================================================================
    const reportData = /* INSERT_REPORT_DATA_HERE */;

    // ---- Demo payload (ONLY runs if reportData is empty) ----
    if (!reportData || Object.keys(reportData).length === 0) {
      Object.assign(reportData, {
        executive_summary: {
          health_rating: 72,
          success_rate: 71.4,
          actionable_advice: "Node 'validator' shows critical instability (24.8)...",
          total_nodes: 7,
          errors_detected: 2
        },
        enriched_graph: {
          nodes: [
            { id: "plan",       type: "planner",    label: "Planner",     text: "Decomposed user query...", execution_time_ms: 142,  instability_index: 4.2,  validation_error: null },
            { id: "validate",   type: "validator",  label: "Validator",   text: "NLI consistency check...", execution_time_ms: 95,   instability_index: 24.8, validation_error: "ContradictionDetected" }
          ],
          edges: [
            { from: "plan",       to: "validate",   drift_score: 0.67, nli_label: "contradiction" }
          ]
        }
      });
    }

    // =================== Application ===================
    let network = null;
    let nodesDataset = null;
    let edgesDataset = null;
    let layoutVertical = true;
    let hintDismissed = false;
    let currentSessionIdx = 0;

    const $ = (sel) => document.querySelector(sel);
    const drawer = $('#drawer');
    const drawerBackdrop = $('#drawer-backdrop');
    const emptyState = $('#empty-state');
    const graphHint = $('#graph-hint');

    // UPGRADE: Evaluam starea nodului pe baza listei complete de failures din sesiune (SOTA)
    function getNodeStatus(node) {
      const session = reportData.results[currentSessionIdx];
      if (!session) return 'healthy';

      // 1. Daca are o eroare critica de conformitate, formatare, securitate sau contradictie
      const hasCriticalFailure = session.failures.some(f => 
        f.to_node === node.id && 
        f.failure_type !== "SEMANTIC_INSTABILITY" && 
        f.failure_type !== "LOW_ROBUSTNESS"
      );
      if (hasCriticalFailure || node.validation_error) {
        return 'error';
      }

      // 2. Daca are o eroare de instabilitate sau robustete scazuta (atribuita acum nodului corect USER sau AGENT)
      const hasWarningFailure = session.failures.some(f => 
        (f.to_node === node.id || f.from_node === node.id) && 
        (f.failure_type === "SEMANTIC_INSTABILITY" || f.failure_type === "LOW_ROBUSTNESS")
      );
      if (hasWarningFailure || (node.instability_index != null && node.instability_index >= 15)) {
        return 'warning';
      }

      return 'healthy';
    }

    function statusColor(s) {
      return ({ healthy: '#10b981', error: '#ef4444', warning: '#f59e0b' })[s];
    }
    function nliColor(label) {
      return ({ entailment: '#10b981', neutral: '#a1a1aa', contradiction: '#ef4444' })[label] || '#a1a1aa';
    }
    function driftColor(score) {
      if (score < 0.15) return '#10b981';
      if (score < 0.25) return '#fbbf24';
      if (score < 0.40) return '#f59e0b';
      return '#ef4444';
    }
    function escapeHtml(s) {
      const div = document.createElement('div');
      div.textContent = String(s ?? '');
      return div.innerHTML;
    }

    // ===== Executive summary render =====
    function renderSummary() {
      const s = reportData.executive_summary;
      if (!s) return;

      const health = Math.max(0, Math.min(100, s.health_rating || 0));
      const circumference = 2 * Math.PI * 20;
      const offset = circumference * (1 - health / 100);
      const ring = $('#health-circle');
      ring.setAttribute('stroke-dasharray', circumference);
      ring.setAttribute('stroke-dashoffset', offset);

      let color = '#10b981', label = 'Excellent';
      if (health < 50)      { color = '#ef4444'; label = 'Critical'; }
      else if (health < 75) { color = '#f59e0b'; label = 'Degraded'; }
      else if (health < 90) { color = '#10b981'; label = 'Good'; }
      ring.setAttribute('stroke', color);

      const hv = $('#health-value');
      hv.textContent = health;
      hv.style.color = color;
      $('#health-label').textContent = label;
      $('#health-sub').textContent = `${s.errors_detected || 0} validation issues detected`;

      const sr = s.success_rate_percentage != null ? s.success_rate_percentage : s.success_rate || 0;
      $('#success-value').textContent = sr.toFixed(1) + '%';
      $('#success-bar').style.width = sr + '%';
      $('#success-total').textContent = `${s.total_nodes || 0} nodes`;

      let barColor = 'from-emerald-500 to-emerald-400';
      if (sr < 50)      barColor = 'from-red-500 to-red-400';
      else if (sr < 75) barColor = 'from-amber-500 to-amber-400';
      $('#success-bar').className = `bar-fill h-full bg-gradient-to-r ${barColor} rounded-full`;

      $('#advice-text').textContent = s.actionable_advice || 'No advice available.';
    }

    // ===== Dropdown session population =====
    function populateSessionSelect() {
      const select = $('#session-select');
      if (!select || !reportData.results) return;
      select.innerHTML = '';
      
      reportData.results.forEach((r, idx) => {
        const opt = document.createElement('option');
        opt.value = idx;
        // UPGRADE: "Red Dot Indicator" - Adaugam automat emoji 🔴 sau 🟢 in functie de statusul sesiunii!
        const statusEmoji = r.status === "FAILED" ? "🔴" : "🟢";
        opt.textContent = `${statusEmoji} ${r.session_id} (${r.status})`;
        select.appendChild(opt);
      });
      
      select.addEventListener('change', (e) => {
        currentSessionIdx = parseInt(e.target.value);
        closeDrawer();
        renderGraph();
      });
    }

    // ===== Graph render =====
    function renderGraph() {
      const session = reportData.results[currentSessionIdx];
      const g = session ? session.enriched_graph : null;
      
      if (!g || !g.nodes || g.nodes.length === 0) {
        emptyState.style.display = 'flex';
        graphHint.style.display = 'none';
        return;
      }
      emptyState.style.display = 'none';
      if (!hintDismissed) graphHint.style.display = 'flex';

      const visNodes = g.nodes.map(n => {
        const status = getNodeStatus(n);
        const color = statusColor(status);
        return {
          id: n.id,
          label: n.label || n.id,
          shape: 'dot',
          size: 18,
          color: {
            background: color,
            border: color,
            highlight: { background: color, border: '#ffffff' },
            hover: { background: color, border: '#ffffff' }
          },
          font: { color: '#e4e4e7', size: 13, face: 'Inter', strokeWidth: 0 },
          borderWidth: 2,
          shadow: { enabled: true, color: color + '55', size: 14, x: 0, y: 0 },
          _data: n
        };
      });

      const visEdges = g.edges.map((e, i) => {
        const drift = e.drift_score != null ? e.drift_score : 0;
        return {
          id: 'e' + i,
          from: e.from, to: e.to,
          color: { color: driftColor(drift), highlight: '#ffffff', hover: '#ffffff' },
          width: 1.5,
          smooth: { enabled: true, type: 'cubicBezier', roundness: 0.5 },
          arrows: { to: { enabled: true, scaleFactor: 0.6 } },
          _data: e
        };
      });

      nodesDataset = new vis.DataSet(visNodes);
      edgesDataset = new vis.DataSet(visEdges);

      const container = document.getElementById('graph-container');
      const options = {
        layout: {
          hierarchical: {
            enabled: true,
            direction: layoutVertical ? 'UD' : 'LR',
            sortMethod: 'directed',
            levelSeparation: 120,
            nodeSpacing: 110,
            treeSpacing: 160
          }
        },
        physics: { enabled: false },
        interaction: { hover: true, dragNodes: true, dragView: true, zoomView: true, tooltipDelay: 100 }
      };

      if (network) network.destroy();
      network = new vis.Network(container, { nodes: nodesDataset, edges: edgesDataset }, options);

      network.on('click', (params) => {
        if (params.nodes.length > 0) {
          const node = g.nodes.find(n => n.id === params.nodes[0]);
          if (node) {
            openDrawer(node);
            dismissHint();
          }
        } else {
          closeDrawer();
        }
      });
      network.on('hoverNode', () => { if (network.canvas.frame) network.canvas.frame.canvas.style.cursor = 'pointer'; });
      network.on('blurNode',  () => { if (network.canvas.frame) network.canvas.frame.canvas.style.cursor = 'default'; });

      $('#node-count').textContent = `${g.nodes.length} nodes`;
      $('#edge-count').textContent = `${g.edges.length} edges`;

      // Upgradam datele generale de cost din top-bar pentru sesiunea curenta
      $('#session-cost-value').textContent = session.estimated_cost_usd != null ? ('$' + session.estimated_cost_usd.toFixed(5)) : '$0.00000';
      $('#session-tokens').textContent = `${session.total_tokens || 0} tokens`;

      setTimeout(() => network && network.fit({ animation: { duration: 500, easingFunction: 'easeInOutQuad' } }), 80);
    }

    function dismissHint() {
      if (hintDismissed) return;
      hintDismissed = true;
      graphHint.style.opacity = '0';
      setTimeout(() => { graphHint.style.display = 'none'; }, 500);
    }

    // ===== Drawer =====
    function openDrawer(node) {
      const session = reportData.results[currentSessionIdx];
      const g = session ? session.enriched_graph : null;
      if (!g) return;

      const status = getNodeStatus(node);
      const badge = $('#drawer-status-badge');
      const badgeClass = status === 'healthy' ? 'badge-healthy' : status === 'error' ? 'badge-error' : 'badge-warning';
      badge.className = `${badgeClass} text-[10px] px-2 py-0.5 rounded-full font-medium uppercase tracking-wider`;
      badge.textContent = status === 'healthy' ? 'Healthy' : status === 'error' ? 'Error' : 'Unstable';

      $('#drawer-type').textContent = node.type || 'unknown';
      $('#drawer-label').textContent = node.label || node.id;
      $('#drawer-id').textContent = node.id;
      $('#drawer-exec-time').textContent = (node.execution_time_ms != null ? node.execution_time_ms : '—');

      const instability = node.instability_index != null ? node.instability_index : 0;
      $('#drawer-instability').textContent = instability.toFixed(1);
      const instBar = $('#drawer-instability-bar');
      instBar.style.width = Math.min(100, (instability / 30) * 100) + '%';
      instBar.style.background = statusColor(status);

      // Upgradam datele specifice de cost ale acestei sesiuni in drawer
      $('#drawer-cost').textContent = session.estimated_cost_usd != null ? ('$' + session.estimated_cost_usd.toFixed(5)) : '$0.00';
      $('#drawer-tokens').textContent = session.total_tokens != null ? (session.total_tokens + ' tokens') : '0 tokens';

      // UPGRADE: Randeram o LISTA de erori pe nod (nu doar pe prima) si adaugam "Oglinda Minciunii" (Side-by-Side)
      const errorSection = $('#drawer-error-section');
      const errorContainer = $('#drawer-error');
      
      const nodeFailures = session.failures.filter(f => 
        f.to_node === node.id || 
        (f.from_node === node.id && f.failure_type === "LOW_ROBUSTNESS")
      );

      if (nodeFailures.length > 0 || node.validation_error) {
        errorSection.classList.remove('hidden');
        let errorsHtml = '';

        if (node.validation_error) {
          errorsHtml += `
            <div class="bg-red-950/20 border border-red-500/30 rounded-lg p-3">
              <code class="text-xs text-red-200 font-mono leading-relaxed break-words">
                <strong class="text-red-400">AST_FORMAT_ERROR:</strong> ${escapeHtml(node.validation_error)}
              </code>
            </div>
          `;
        }

        nodeFailures.forEach(f => {
          const detailText = f.details ? ` (${f.details})` : '';
          
          // UPGRADE: "Oglinda Minciunii" (Side-by-Side comparison) pentru contradictii si scurgeri de date
          let diffHtml = '';
          if (f.failure_type === "GENERATION_CONTRADICTION" || f.failure_type === "SECURITY_LEAK" || f.failure_type === "RELEVANCE_VIOLATION") {
  // Creăm o etichetă dinamică în funcție de tipul de eroare
  const sourceLabel = f.failure_type === "RELEVANCE_VIOLATION" ? "🔵 Initial User Input (Prompt)" : "🔵 Source Database / Context (Premise)";
  diffHtml = `
    <div class="mt-3 space-y-2 border-t border-zinc-800/80 pt-2.5">
      <div class="bg-red-950/20 border border-red-500/30 rounded-lg p-2.5">
        <div class="text-[9px] uppercase tracking-wider text-red-400 font-medium mb-1">🔴 Agent Generated (Target)</div>
        <p class="text-xs font-mono text-zinc-300 leading-relaxed">${escapeHtml(f.error_node_text)}</p>
      </div>
      <div class="bg-blue-950/20 border border-blue-500/30 rounded-lg p-2.5">
        <div class="text-[9px] uppercase tracking-wider text-blue-400 font-medium mb-1">${escapeHtml(sourceLabel)}</div>
        <p class="text-xs font-mono text-zinc-300 leading-relaxed">${escapeHtml(f.source_node_text || node.text || '—')}</p>
      </div>
    </div>
  `;
}

          errorsHtml += `
            <div class="bg-red-950/20 border border-red-500/30 rounded-lg p-3">
              <code class="text-xs text-red-200 font-mono leading-relaxed break-words">
                <strong class="text-red-400">${escapeHtml(f.failure_type)}:</strong> ${escapeHtml(f.reason)}${escapeHtml(detailText)}
              </code>
              ${diffHtml}
            </div>
          `;
        });

        errorContainer.innerHTML = errorsHtml;
      } else {
        errorSection.classList.add('hidden');
        errorContainer.innerHTML = '';
      }

      $('#drawer-text').textContent = node.text || '(no output captured)';

      // Connected edges
      const connected = g.edges.filter(e => e.from === node.id || e.to === node.id);
      const connContainer = $('#drawer-edges');
      connContainer.innerHTML = '';
      $('#drawer-edges-count').textContent = connected.length;

      if (connected.length === 0) {
        connContainer.innerHTML = '<div class="text-xs text-zinc-600 italic py-2">No connected edges</div>';
      } else {
        connected.forEach(edge => {
          const isIncoming = edge.to === node.id;
          const otherId = isIncoming ? edge.from : edge.to;
          const otherNode = g.nodes.find(n => n.id === otherId);
          const otherLabel = otherNode ? (otherNode.label || otherNode.id) : otherId;
          const drift = edge.drift_score != null ? edge.drift_score : 0;
          const nli = edge.nli_label || 'unknown';

          const el = document.createElement('div');
          el.className = 'bg-zinc-900/50 border border-zinc-800 rounded-lg p-3 hover:border-zinc-700 transition-colors cursor-pointer';
          el.innerHTML = `
            <div class="flex items-center justify-between mb-2">
              <div class="flex items-center gap-1.5 text-[11px]">
                <span class="text-zinc-500">${isIncoming ? 'from' : 'to'}</span>
                <span class="text-zinc-300 font-medium">${escapeHtml(otherLabel)}</span>
              </div>
            </div>
            <div class="flex items-center justify-between text-[11px] mb-1">
              <span class="text-zinc-500">Relative Drift</span>
              <span class="font-mono font-medium tabular-nums" style="color:${driftColor(drift)}">${(drift * 100).toFixed(2)}%</span>
            </div>
            <div class="bar-track h-1 rounded-full overflow-hidden">
              <div class="h-full rounded-full" style="width:${(drift * 100)}%;background:${driftColor(drift)}"></div>
            </div>
          `;
          el.addEventListener('click', () => {
            if (otherNode) openDrawer(otherNode);
            if (network) {
              network.selectNodes([otherId]);
              network.focus(otherId, { scale: 1.2, animation: { duration: 400, easingFunction: 'easeInOutQuad' } });
            }
          });
          connContainer.appendChild(el);
        });
      }

      drawer.classList.add('open');
      drawerBackdrop.classList.add('open');
    }

    function closeDrawer() {
      drawer.classList.remove('open');
      drawerBackdrop.classList.remove('open');
      if (network) network.unselectAll();
    }

    // ===== Toolbar / global handlers =====
    $('#zoom-fit').addEventListener('click', () => network && network.fit({ animation: { duration: 400, easingFunction: 'easeInOutQuad' } }));
    $('#zoom-in').addEventListener('click',  () => network && network.moveTo({ scale: network.getScale() * 1.3, animation: { duration: 200 } }));
    $('#zoom-out').addEventListener('click', () => network && network.moveTo({ scale: network.getScale() / 1.3, animation: { duration: 200 } }));
    $('#layout-toggle').addEventListener('click', () => { layoutVertical = !layoutVertical; renderGraph(); });
    $('#drawer-close').addEventListener('click', closeDrawer);
    drawerBackdrop.addEventListener('click', closeDrawer);

    // UPGRADE: 1-Click Copy function with visual feedback
    $('#copy-payload').addEventListener('click', () => {
      const textToCopy = $('#drawer-text').textContent;
      navigator.clipboard.writeText(textToCopy).then(() => {
        const copyText = $('#copy-text');
        copyText.textContent = 'Copied!';
        copyText.className = 'text-emerald-400 transition-colors font-medium';
        setTimeout(() => {
          copyText.textContent = 'Copy';
          copyText.className = 'text-blue-400 transition-colors';
        }, 1500);
      });
    });

    $('#advice-expand').addEventListener('click', () => {
      const m = $('#advice-modal');
      m.classList.remove('hidden');
      m.classList.add('flex');
      
      // UPGRADE: Renderam raportul generativ local complex (Markdown) utilizand marked.js
      const markdownReport = reportData.narrative_report || reportData.executive_summary.actionable_advice;
      $('#advice-full').innerHTML = marked.parse(markdownReport);
    });
    
    function closeAdvice() {
      const m = $('#advice-modal');
      m.classList.add('hidden');
      m.classList.remove('flex');
    }
    $('#advice-close').addEventListener('click', closeAdvice);
    $('#advice-modal').addEventListener('click', (e) => { if (e.target.id === 'advice-modal') closeAdvice(); });

    document.addEventListener('keydown', (e) => {
      if (e.key === 'Escape') { closeDrawer(); closeAdvice(); }
    });

    // ===== Init =====
    function init() {
      if (!reportData || !reportData.executive_summary) {
        emptyState.style.display = 'flex';
        return;
      }
      renderSummary();
      populateSessionSelect();
      renderGraph();
    }
    window.addEventListener('load', () => setTimeout(init, 60));
  </script>
</body>
</html>