ragaudit-cli 0.3.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. ragaudit/__init__.py +1 -0
  2. ragaudit/adapters/__init__.py +0 -0
  3. ragaudit/adapters/base.py +109 -0
  4. ragaudit/adapters/callable_adapter.py +15 -0
  5. ragaudit/cli.py +540 -0
  6. ragaudit/cli_easy.py +458 -0
  7. ragaudit/cli_v2.py +507 -0
  8. ragaudit/env.py +46 -0
  9. ragaudit/generate/__init__.py +0 -0
  10. ragaudit/generate/pipeline.py +486 -0
  11. ragaudit/generate/prompts.py +116 -0
  12. ragaudit/generate/testset_generator.py +146 -0
  13. ragaudit/generate/text.py +75 -0
  14. ragaudit/ingest/__init__.py +0 -0
  15. ragaudit/ingest/chunker.py +53 -0
  16. ragaudit/ingest/corpus.py +120 -0
  17. ragaudit/ingest/loader.py +49 -0
  18. ragaudit/ingest/versioning.py +92 -0
  19. ragaudit/llm/__init__.py +0 -0
  20. ragaudit/llm/client.py +86 -0
  21. ragaudit/llm/factory.py +70 -0
  22. ragaudit/llm/json_output.py +72 -0
  23. ragaudit/llm/mock.py +552 -0
  24. ragaudit/models/__init__.py +0 -0
  25. ragaudit/models/adapter.py +39 -0
  26. ragaudit/models/document.py +28 -0
  27. ragaudit/models/evaluation.py +70 -0
  28. ragaudit/models/question.py +152 -0
  29. ragaudit/models/run.py +44 -0
  30. ragaudit/models/scoring.py +82 -0
  31. ragaudit/models/testset.py +30 -0
  32. ragaudit/models/tune.py +56 -0
  33. ragaudit/report/__init__.py +0 -0
  34. ragaudit/report/generator.py +155 -0
  35. ragaudit/report/plain_summary.py +122 -0
  36. ragaudit/report/templates/_v2_tooltip.jinja +43 -0
  37. ragaudit/report/templates/generate_report.html.jinja +175 -0
  38. ragaudit/report/templates/report.html.jinja +252 -0
  39. ragaudit/report/templates/style.css +1095 -0
  40. ragaudit/report/templates/tune_report.html.jinja +158 -0
  41. ragaudit/report/templates/v2.css +286 -0
  42. ragaudit/report/v2.py +380 -0
  43. ragaudit/runner/__init__.py +0 -0
  44. ragaudit/runner/ablation.py +46 -0
  45. ragaudit/runner/evaluate.py +325 -0
  46. ragaudit/runner/executor.py +98 -0
  47. ragaudit/runner/locked.py +37 -0
  48. ragaudit/runner/summary.py +45 -0
  49. ragaudit/scaffold.py +252 -0
  50. ragaudit/scoring/__init__.py +0 -0
  51. ragaudit/scoring/correctness.py +94 -0
  52. ragaudit/scoring/groundedness.py +86 -0
  53. ragaudit/scoring/retrieval.py +42 -0
  54. ragaudit/scoring/text_match.py +51 -0
  55. ragaudit/scoring/verdict.py +14 -0
  56. ragaudit/storage/__init__.py +0 -0
  57. ragaudit/storage/db.py +81 -0
  58. ragaudit/storage/lock.py +36 -0
  59. ragaudit/storage/repository.py +216 -0
  60. ragaudit/storage/store.py +536 -0
  61. ragaudit/tune/__init__.py +7 -0
  62. ragaudit/tune/devset.py +16 -0
  63. ragaudit/tune/loop.py +208 -0
  64. ragaudit/tune/search_space.py +140 -0
  65. ragaudit/tune/strategies.py +197 -0
  66. ragaudit/yaml_io.py +199 -0
  67. ragaudit_cli-0.3.0.dist-info/METADATA +429 -0
  68. ragaudit_cli-0.3.0.dist-info/RECORD +71 -0
  69. ragaudit_cli-0.3.0.dist-info/WHEEL +4 -0
  70. ragaudit_cli-0.3.0.dist-info/entry_points.txt +2 -0
  71. ragaudit_cli-0.3.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,1095 @@
1
+ /* Shared stylesheet for the ragaudit HTML report and the docs/ landing page.
2
+ Dark theme, system font stack, no external fonts or frameworks. */
3
+
4
+ :root {
5
+ --bg: #0f1115;
6
+ --surface: #171a21;
7
+ --surface-raised: #1f232c;
8
+ --border: #2a2f3a;
9
+ --text: #e6e6e6;
10
+ --text-muted: #9aa0a6;
11
+ --accent: #5b9dff;
12
+
13
+ --true-pass: #2ecc71;
14
+ --lucky-pass: #f5a623;
15
+ --generation-failure: #e74c3c;
16
+ --retrieval-failure: #8a94a6;
17
+
18
+ --true-pass-bg: rgba(46, 204, 113, 0.12);
19
+ --lucky-pass-bg: rgba(245, 166, 35, 0.16);
20
+ --generation-failure-bg: rgba(231, 76, 60, 0.12);
21
+ --retrieval-failure-bg: rgba(138, 148, 166, 0.12);
22
+ }
23
+
24
+ * {
25
+ box-sizing: border-box;
26
+ }
27
+
28
+ body {
29
+ margin: 0;
30
+ padding: 0;
31
+ background: var(--bg);
32
+ color: var(--text);
33
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
34
+ line-height: 1.5;
35
+ }
36
+
37
+ .container {
38
+ max-width: 1080px;
39
+ margin: 0 auto;
40
+ padding: 2rem 1.5rem 4rem;
41
+ }
42
+
43
+ header.report-header {
44
+ margin-bottom: 2rem;
45
+ padding-bottom: 1.5rem;
46
+ border-bottom: 1px solid var(--border);
47
+ }
48
+
49
+ header.report-header h1 {
50
+ margin: 0 0 0.5rem;
51
+ font-size: 1.75rem;
52
+ }
53
+
54
+ .meta {
55
+ color: var(--text-muted);
56
+ font-size: 0.9rem;
57
+ }
58
+
59
+ .meta code {
60
+ background: var(--surface);
61
+ padding: 0.1rem 0.4rem;
62
+ border-radius: 4px;
63
+ }
64
+
65
+ section {
66
+ background: var(--surface);
67
+ border: 1px solid var(--border);
68
+ border-radius: 10px;
69
+ padding: 1.5rem;
70
+ margin-bottom: 1.5rem;
71
+ }
72
+
73
+ section h2 {
74
+ margin-top: 0;
75
+ font-size: 1.15rem;
76
+ }
77
+
78
+ .report-header .meta code {
79
+ overflow-wrap: anywhere;
80
+ }
81
+
82
+ .summary-box {
83
+ border-left: 4px solid var(--accent);
84
+ }
85
+
86
+ .summary-box.summary-healthy {
87
+ border-left-color: var(--true-pass);
88
+ }
89
+
90
+ .summary-box.summary-needs_work {
91
+ border-left-color: var(--lucky-pass);
92
+ }
93
+
94
+ .summary-box.summary-empty {
95
+ border-left-color: var(--retrieval-failure);
96
+ }
97
+
98
+ .summary-lines {
99
+ margin: 0;
100
+ padding: 0;
101
+ list-style: none;
102
+ }
103
+
104
+ .summary-lines li {
105
+ padding: 0.35rem 0;
106
+ line-height: 1.5;
107
+ }
108
+
109
+ .summary-lines li:first-child {
110
+ font-size: 1.1rem;
111
+ }
112
+
113
+ .summary-lines strong {
114
+ color: var(--text);
115
+ }
116
+
117
+ .headline-sentence {
118
+ font-size: 1.15rem;
119
+ line-height: 1.6;
120
+ }
121
+
122
+ .stats-grid {
123
+ display: grid;
124
+ grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
125
+ gap: 1rem;
126
+ }
127
+
128
+ .stat {
129
+ background: var(--surface-raised);
130
+ border: 1px solid var(--border);
131
+ border-radius: 8px;
132
+ padding: 0.75rem 1rem;
133
+ }
134
+
135
+ .stat .value {
136
+ font-size: 1.4rem;
137
+ font-weight: 600;
138
+ display: block;
139
+ }
140
+
141
+ .stat .label {
142
+ color: var(--text-muted);
143
+ font-size: 0.85rem;
144
+ }
145
+
146
+ table.matrix-table {
147
+ border-collapse: collapse;
148
+ width: 100%;
149
+ text-align: center;
150
+ }
151
+
152
+ table.matrix-table th,
153
+ table.matrix-table td {
154
+ border: 1px solid var(--border);
155
+ padding: 1rem;
156
+ }
157
+
158
+ table.matrix-table th {
159
+ color: var(--text-muted);
160
+ font-weight: 500;
161
+ }
162
+
163
+ table.matrix-table td {
164
+ font-size: 1.5rem;
165
+ font-weight: 700;
166
+ }
167
+
168
+ .cell-label {
169
+ display: block;
170
+ font-size: 0.8rem;
171
+ font-weight: 400;
172
+ color: var(--text-muted);
173
+ margin-top: 0.25rem;
174
+ }
175
+
176
+ .cell-true-pass {
177
+ background: var(--true-pass-bg);
178
+ color: var(--true-pass);
179
+ }
180
+
181
+ .cell-lucky-pass {
182
+ background: var(--lucky-pass-bg);
183
+ color: var(--lucky-pass);
184
+ }
185
+
186
+ .cell-generation-failure {
187
+ background: var(--generation-failure-bg);
188
+ color: var(--generation-failure);
189
+ }
190
+
191
+ .cell-retrieval-failure {
192
+ background: var(--retrieval-failure-bg);
193
+ color: var(--retrieval-failure);
194
+ }
195
+
196
+ .warning {
197
+ color: var(--lucky-pass);
198
+ }
199
+
200
+ .filter-bar {
201
+ display: flex;
202
+ flex-wrap: wrap;
203
+ gap: 0.5rem;
204
+ margin-bottom: 1rem;
205
+ }
206
+
207
+ .filter-btn {
208
+ background: var(--surface-raised);
209
+ color: var(--text);
210
+ border: 1px solid var(--border);
211
+ border-radius: 999px;
212
+ padding: 0.4rem 0.9rem;
213
+ font-size: 0.85rem;
214
+ cursor: pointer;
215
+ }
216
+
217
+ .filter-btn:hover {
218
+ border-color: var(--accent);
219
+ }
220
+
221
+ .filter-btn.active {
222
+ background: var(--accent);
223
+ border-color: var(--accent);
224
+ color: #061021;
225
+ font-weight: 600;
226
+ }
227
+
228
+ table#case-table {
229
+ border-collapse: collapse;
230
+ width: 100%;
231
+ }
232
+
233
+ table#case-table th,
234
+ table#case-table td {
235
+ border-bottom: 1px solid var(--border);
236
+ padding: 0.6rem 0.75rem;
237
+ text-align: left;
238
+ vertical-align: top;
239
+ }
240
+
241
+ table#case-table th {
242
+ color: var(--text-muted);
243
+ font-weight: 500;
244
+ user-select: none;
245
+ }
246
+
247
+ table#case-table th[data-sort]::after {
248
+ content: " \2195";
249
+ color: var(--text-muted);
250
+ font-size: 0.75rem;
251
+ }
252
+
253
+ table#case-table td {
254
+ overflow-wrap: anywhere;
255
+ }
256
+
257
+ /* Phones: one card per case instead of four columns, so the page never scrolls sideways. */
258
+ @media (max-width: 600px) {
259
+ table#case-table,
260
+ table#case-table tbody,
261
+ table#case-table tr,
262
+ table#case-table td {
263
+ display: block;
264
+ width: auto;
265
+ }
266
+
267
+ table#case-table thead {
268
+ display: none;
269
+ }
270
+
271
+ table#case-table tr.case-row {
272
+ padding: 0.75rem 0;
273
+ border-bottom: 1px solid var(--border);
274
+ }
275
+
276
+ table#case-table td {
277
+ border-bottom: 0;
278
+ padding: 0.2rem 0;
279
+ }
280
+
281
+ table#case-table td.case-question {
282
+ font-weight: 600;
283
+ }
284
+
285
+ table#case-table td.case-verdict,
286
+ table#case-table td.case-rank {
287
+ display: inline-block;
288
+ margin-right: 0.75rem;
289
+ }
290
+
291
+ table#case-table td.case-rank {
292
+ color: var(--text-muted);
293
+ font-size: 0.85rem;
294
+ }
295
+
296
+ table#case-table td.case-rank::before {
297
+ content: attr(data-label) ": ";
298
+ }
299
+ }
300
+
301
+ .badge {
302
+ display: inline-block;
303
+ padding: 0.15rem 0.6rem;
304
+ border-radius: 999px;
305
+ font-size: 0.8rem;
306
+ font-weight: 600;
307
+ }
308
+
309
+ .badge-true_pass {
310
+ background: var(--true-pass-bg);
311
+ color: var(--true-pass);
312
+ }
313
+
314
+ .badge-lucky_pass {
315
+ background: var(--lucky-pass-bg);
316
+ color: var(--lucky-pass);
317
+ }
318
+
319
+ .badge-generation_failure {
320
+ background: var(--generation-failure-bg);
321
+ color: var(--generation-failure);
322
+ }
323
+
324
+ .badge-retrieval_failure {
325
+ background: var(--retrieval-failure-bg);
326
+ color: var(--retrieval-failure);
327
+ }
328
+
329
+ details summary {
330
+ cursor: pointer;
331
+ color: var(--accent);
332
+ }
333
+
334
+ details dl {
335
+ margin: 0.75rem 0 0;
336
+ }
337
+
338
+ details dt {
339
+ color: var(--text-muted);
340
+ font-size: 0.8rem;
341
+ margin-top: 0.6rem;
342
+ }
343
+
344
+ details dd {
345
+ margin: 0.2rem 0 0;
346
+ white-space: pre-wrap;
347
+ }
348
+
349
+ details ol {
350
+ margin: 0.2rem 0 0;
351
+ padding-left: 1.2rem;
352
+ }
353
+
354
+ /* The contexts list itself is markup: only each passage keeps its line breaks. */
355
+ details dd.contexts {
356
+ white-space: normal;
357
+ }
358
+
359
+ details dd.contexts li {
360
+ white-space: pre-wrap;
361
+ }
362
+
363
+ a {
364
+ color: var(--accent);
365
+ }
366
+
367
+ /* --- Code blocks (shared) --- */
368
+
369
+ pre,
370
+ code {
371
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
372
+ }
373
+
374
+ code {
375
+ font-size: 0.9em;
376
+ }
377
+
378
+ pre {
379
+ background: var(--surface);
380
+ border: 1px solid var(--border);
381
+ border-radius: 8px;
382
+ padding: 1rem 1.25rem;
383
+ margin: 0;
384
+ overflow-x: auto;
385
+ font-size: 0.9rem;
386
+ line-height: 1.6;
387
+ color: var(--text);
388
+ }
389
+
390
+ pre code {
391
+ font-size: inherit;
392
+ }
393
+
394
+ /* --- Landing page (docs/index.html) ---
395
+ Everything below is scoped under html.ln / body.ln-page so the report
396
+ styles above are untouched. The page uses full-width bands with the
397
+ text held in an 1100px column. */
398
+
399
+ :root {
400
+ --accent-hover: #78afff;
401
+ --accent-ink: #061021;
402
+ --nav-h: 60px;
403
+ }
404
+
405
+ html.ln {
406
+ scroll-behavior: smooth;
407
+ scroll-padding-top: calc(var(--nav-h) + 16px);
408
+ }
409
+
410
+ body.ln-page {
411
+ line-height: 1.6;
412
+ }
413
+
414
+ .ln-col {
415
+ max-width: 1100px;
416
+ margin: 0 auto;
417
+ padding: 0 2rem;
418
+ }
419
+
420
+ /* Nav */
421
+
422
+ .ln-nav {
423
+ position: fixed;
424
+ top: 0;
425
+ left: 0;
426
+ right: 0;
427
+ height: var(--nav-h);
428
+ z-index: 10;
429
+ background: rgba(15, 17, 21, 0.78);
430
+ -webkit-backdrop-filter: blur(10px);
431
+ backdrop-filter: blur(10px);
432
+ border-bottom: 1px solid var(--border);
433
+ }
434
+
435
+ .ln-nav .ln-col {
436
+ height: 100%;
437
+ display: flex;
438
+ align-items: center;
439
+ justify-content: space-between;
440
+ }
441
+
442
+ .ln-brand {
443
+ color: var(--text);
444
+ text-decoration: none;
445
+ font-weight: 700;
446
+ letter-spacing: -0.01em;
447
+ }
448
+
449
+ .ln-nav-links {
450
+ display: flex;
451
+ align-items: center;
452
+ gap: 0.25rem;
453
+ list-style: none;
454
+ margin: 0;
455
+ padding: 0;
456
+ }
457
+
458
+ .ln-nav-links a {
459
+ display: inline-block;
460
+ color: var(--text-muted);
461
+ text-decoration: none;
462
+ font-size: 0.95rem;
463
+ padding: 0.4rem 0.75rem;
464
+ border-radius: 6px;
465
+ transition: color 150ms, background-color 150ms;
466
+ }
467
+
468
+ .ln-nav-links a:hover {
469
+ color: var(--text);
470
+ background: var(--surface-raised);
471
+ }
472
+
473
+ .ln-nav-links a.ln-nav-gh {
474
+ color: var(--text);
475
+ border: 1px solid var(--border);
476
+ margin-left: 0.5rem;
477
+ }
478
+
479
+ .ln-nav-links a.ln-nav-gh:hover {
480
+ border-color: var(--accent);
481
+ }
482
+
483
+ /* Focus, shared by every interactive element on the page */
484
+
485
+ .ln-page a:focus-visible,
486
+ .ln-page button:focus-visible {
487
+ outline: 2px solid var(--accent);
488
+ outline-offset: 2px;
489
+ }
490
+
491
+ /* Bands */
492
+
493
+ .ln-band {
494
+ padding: 6rem 0;
495
+ }
496
+
497
+ .ln-band--alt {
498
+ background: var(--surface);
499
+ border-top: 1px solid var(--border);
500
+ border-bottom: 1px solid var(--border);
501
+ }
502
+
503
+ .ln-band--alt pre {
504
+ background: var(--surface-raised);
505
+ }
506
+
507
+ .ln-band h2 {
508
+ font-size: 1.75rem;
509
+ line-height: 1.2;
510
+ letter-spacing: -0.01em;
511
+ margin: 0 0 0.75rem;
512
+ }
513
+
514
+ .ln-band .ln-lead {
515
+ color: var(--text-muted);
516
+ font-size: 1.1rem;
517
+ max-width: 64ch;
518
+ margin: 0 0 2.5rem;
519
+ }
520
+
521
+ .ln-band p {
522
+ max-width: 68ch;
523
+ margin: 0 0 1rem;
524
+ }
525
+
526
+ /* Hero */
527
+
528
+ .ln-hero {
529
+ min-height: 100vh;
530
+ padding-top: calc(var(--nav-h) + 3rem);
531
+ padding-bottom: 4rem;
532
+ display: flex;
533
+ align-items: center;
534
+ }
535
+
536
+ .ln-hero-grid {
537
+ display: grid;
538
+ grid-template-columns: 1.05fr 1fr;
539
+ gap: 4.5rem;
540
+ align-items: center;
541
+ width: 100%;
542
+ }
543
+
544
+ .ln-hero h1 {
545
+ font-size: 3.5rem;
546
+ line-height: 1.05;
547
+ letter-spacing: -0.03em;
548
+ margin: 0 0 1.25rem;
549
+ }
550
+
551
+ .ln-hero .ln-desc {
552
+ font-size: 1.2rem;
553
+ color: var(--text-muted);
554
+ max-width: 34rem;
555
+ margin: 0 0 2.5rem;
556
+ }
557
+
558
+ .ln-stats {
559
+ display: grid;
560
+ grid-template-columns: repeat(2, minmax(0, 1fr));
561
+ gap: 2rem;
562
+ margin: 0 0 1rem;
563
+ }
564
+
565
+ .ln-stat .value {
566
+ display: block;
567
+ font-size: 3.75rem;
568
+ font-weight: 700;
569
+ line-height: 1;
570
+ letter-spacing: -0.03em;
571
+ }
572
+
573
+ .ln-stat .label {
574
+ display: block;
575
+ margin-top: 0.5rem;
576
+ color: var(--text-muted);
577
+ }
578
+
579
+ .ln-stat--lucky .value {
580
+ color: var(--lucky-pass);
581
+ }
582
+
583
+ .ln-stats-note {
584
+ color: var(--text-muted);
585
+ max-width: 34rem;
586
+ margin: 0 0 2.5rem;
587
+ }
588
+
589
+ .ln-actions {
590
+ display: flex;
591
+ gap: 0.75rem;
592
+ flex-wrap: wrap;
593
+ }
594
+
595
+ /* Buttons */
596
+
597
+ .ln-btn {
598
+ display: inline-flex;
599
+ align-items: center;
600
+ padding: 0.7rem 1.25rem;
601
+ border-radius: 8px;
602
+ font: inherit;
603
+ font-weight: 600;
604
+ font-size: 0.95rem;
605
+ text-decoration: none;
606
+ cursor: pointer;
607
+ border: 1px solid transparent;
608
+ transition: background-color 150ms, border-color 150ms, color 150ms;
609
+ }
610
+
611
+ .ln-btn--primary {
612
+ background: var(--accent);
613
+ color: var(--accent-ink);
614
+ border-color: var(--accent);
615
+ }
616
+
617
+ .ln-btn--primary:hover {
618
+ background: var(--accent-hover);
619
+ border-color: var(--accent-hover);
620
+ }
621
+
622
+ .ln-btn--secondary {
623
+ background: transparent;
624
+ color: var(--text);
625
+ border-color: var(--border);
626
+ }
627
+
628
+ .ln-btn--secondary:hover {
629
+ border-color: var(--accent);
630
+ color: var(--accent);
631
+ }
632
+
633
+ /* Interactive 2x2 */
634
+
635
+ .ln-matrix {
636
+ display: grid;
637
+ grid-template-columns: 5.5rem repeat(2, minmax(0, 1fr));
638
+ gap: 0.6rem;
639
+ }
640
+
641
+ .ln-matrix .axis {
642
+ color: var(--text-muted);
643
+ font-size: 0.85rem;
644
+ display: flex;
645
+ align-items: center;
646
+ }
647
+
648
+ .ln-matrix .axis--col {
649
+ padding-left: 0.25rem;
650
+ padding-bottom: 0.25rem;
651
+ }
652
+
653
+ .ln-cell {
654
+ display: block;
655
+ width: 100%;
656
+ text-align: left;
657
+ font: inherit;
658
+ color: var(--text);
659
+ background: var(--surface);
660
+ border: 1px solid var(--border);
661
+ border-radius: 10px;
662
+ padding: 1.25rem 1.1rem;
663
+ cursor: pointer;
664
+ transition: border-color 150ms, background-color 150ms;
665
+ }
666
+
667
+ .ln-cell .verdict {
668
+ display: block;
669
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
670
+ font-size: 0.95rem;
671
+ font-weight: 600;
672
+ color: var(--text-muted);
673
+ margin-bottom: 0.3rem;
674
+ transition: color 150ms;
675
+ }
676
+
677
+ .ln-cell .explain {
678
+ display: block;
679
+ color: var(--text-muted);
680
+ font-size: 0.85rem;
681
+ line-height: 1.45;
682
+ }
683
+
684
+ .ln-cell:hover {
685
+ border-color: var(--text-muted);
686
+ }
687
+
688
+ .ln-cell[aria-pressed="true"] {
689
+ border-color: var(--cell-border);
690
+ background: var(--cell-bg);
691
+ }
692
+
693
+ .ln-cell[aria-pressed="true"] .verdict {
694
+ color: var(--cell);
695
+ }
696
+
697
+ .ln-cell[aria-pressed="true"] .explain {
698
+ color: var(--text);
699
+ }
700
+
701
+ .ln-cell--true { --cell: var(--true-pass); --cell-border: var(--true-pass); --cell-bg: var(--true-pass-bg); }
702
+ .ln-cell--lucky { --cell: var(--lucky-pass); --cell-border: var(--lucky-pass); --cell-bg: var(--lucky-pass-bg); }
703
+ .ln-cell--gen { --cell: var(--generation-failure); --cell-border: var(--generation-failure); --cell-bg: var(--generation-failure-bg); }
704
+ .ln-cell--ret { --cell: var(--retrieval-failure); --cell-border: var(--retrieval-failure); --cell-bg: var(--retrieval-failure-bg); }
705
+
706
+ /* Lucky is always the dominant cell, selected or not. */
707
+ .ln-cell--lucky {
708
+ border-color: var(--lucky-pass);
709
+ padding: 1.5rem 1.25rem;
710
+ }
711
+
712
+ .ln-cell--lucky .verdict {
713
+ font-size: 1.25rem;
714
+ color: var(--lucky-pass);
715
+ }
716
+
717
+ .ln-cell--lucky[aria-pressed="true"] {
718
+ border-width: 2px;
719
+ padding: calc(1.5rem - 1px) calc(1.25rem - 1px);
720
+ }
721
+
722
+ .ln-cell-detail {
723
+ margin-top: 1rem;
724
+ border: 1px solid var(--border);
725
+ border-radius: 10px;
726
+ background: var(--surface);
727
+ padding: 1.25rem 1.5rem;
728
+ min-height: 9.5rem;
729
+ }
730
+
731
+ .ln-cell-detail .ln-detail-title {
732
+ display: block;
733
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
734
+ font-weight: 600;
735
+ margin-bottom: 0.5rem;
736
+ }
737
+
738
+ .ln-cell-detail p {
739
+ margin: 0 0 0.6rem;
740
+ font-size: 0.95rem;
741
+ max-width: none;
742
+ }
743
+
744
+ .ln-cell-detail p:last-child {
745
+ margin-bottom: 0;
746
+ }
747
+
748
+ .ln-cell-detail [data-detail] {
749
+ display: none;
750
+ }
751
+
752
+ .ln-cell-detail [data-detail].is-active {
753
+ display: block;
754
+ }
755
+
756
+ /* How it works */
757
+
758
+ .ln-steps {
759
+ display: grid;
760
+ grid-template-columns: repeat(4, minmax(0, 1fr));
761
+ gap: 1.25rem;
762
+ counter-reset: step;
763
+ }
764
+
765
+ .ln-step {
766
+ border: 1px solid var(--border);
767
+ border-radius: 10px;
768
+ background: var(--surface-raised);
769
+ padding: 1.25rem 1.25rem 1.4rem;
770
+ }
771
+
772
+ .ln-step .k {
773
+ display: block;
774
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
775
+ color: var(--accent);
776
+ font-size: 0.85rem;
777
+ margin-bottom: 0.5rem;
778
+ }
779
+
780
+ .ln-step strong {
781
+ display: block;
782
+ margin-bottom: 0.35rem;
783
+ }
784
+
785
+ .ln-step p {
786
+ margin: 0;
787
+ color: var(--text-muted);
788
+ font-size: 0.92rem;
789
+ }
790
+
791
+ /* Report viewer */
792
+
793
+ .ln-viewer-desc {
794
+ min-height: 1.6em;
795
+ margin: 0 0 1rem;
796
+ color: var(--text-muted);
797
+ }
798
+
799
+ .ln-tabs {
800
+ display: flex;
801
+ gap: 0.5rem;
802
+ margin: 0 0 1rem;
803
+ flex-wrap: wrap;
804
+ }
805
+
806
+ .ln-tab {
807
+ font: inherit;
808
+ font-size: 0.95rem;
809
+ font-weight: 600;
810
+ color: var(--text-muted);
811
+ background: var(--surface);
812
+ border: 1px solid var(--border);
813
+ border-radius: 8px;
814
+ padding: 0.55rem 1rem;
815
+ cursor: pointer;
816
+ transition: color 150ms, border-color 150ms, background-color 150ms;
817
+ }
818
+
819
+ .ln-tab:hover {
820
+ color: var(--text);
821
+ border-color: var(--text-muted);
822
+ }
823
+
824
+ .ln-tab[aria-selected="true"] {
825
+ color: var(--accent-ink);
826
+ background: var(--accent);
827
+ border-color: var(--accent);
828
+ }
829
+
830
+ .ln-frame {
831
+ display: block;
832
+ width: 100%;
833
+ height: 700px;
834
+ border: 1px solid var(--border);
835
+ border-radius: 10px;
836
+ background: var(--bg);
837
+ }
838
+
839
+ .ln-viewer-foot {
840
+ margin-top: 0.75rem;
841
+ font-size: 0.9rem;
842
+ color: var(--text-muted);
843
+ }
844
+
845
+ /* Install: code blocks with copy buttons */
846
+
847
+ .ln-code {
848
+ position: relative;
849
+ margin: 0 0 1.5rem;
850
+ }
851
+
852
+ .ln-code pre {
853
+ padding-right: 5.5rem;
854
+ }
855
+
856
+ .ln-copy {
857
+ position: absolute;
858
+ top: 0.6rem;
859
+ right: 0.6rem;
860
+ font: inherit;
861
+ font-size: 0.8rem;
862
+ font-weight: 600;
863
+ color: var(--text-muted);
864
+ background: var(--surface-raised);
865
+ border: 1px solid var(--border);
866
+ border-radius: 6px;
867
+ padding: 0.3rem 0.65rem;
868
+ cursor: pointer;
869
+ transition: color 150ms, border-color 150ms, background-color 150ms;
870
+ }
871
+
872
+ .ln-copy:hover {
873
+ color: var(--text);
874
+ border-color: var(--accent);
875
+ }
876
+
877
+ .ln-copy.is-done {
878
+ color: var(--true-pass);
879
+ border-color: var(--true-pass);
880
+ }
881
+
882
+ /* 5-minute quickstart */
883
+
884
+ .ln-quick-demo {
885
+ margin: 1.5rem 0 0;
886
+ max-width: 820px;
887
+ min-width: 0;
888
+ padding: 1rem 1.25rem;
889
+ border: 1px solid var(--border);
890
+ border-left: 4px solid var(--accent);
891
+ border-radius: 6px;
892
+ background: var(--surface);
893
+ }
894
+
895
+ .ln-quick-demo > p:first-child {
896
+ margin: 0 0 0.75rem;
897
+ }
898
+
899
+ .ln-quick-demo .ln-code {
900
+ margin-bottom: 0.6rem;
901
+ }
902
+
903
+ .ln-quick {
904
+ margin: 2rem 0 0;
905
+ padding: 0;
906
+ list-style: none;
907
+ counter-reset: quick;
908
+ max-width: 820px;
909
+ }
910
+
911
+ .ln-quick > li {
912
+ counter-increment: quick;
913
+ position: relative;
914
+ padding: 0 0 1.5rem 3rem;
915
+ }
916
+
917
+ .ln-quick > li::before {
918
+ content: counter(quick);
919
+ position: absolute;
920
+ left: 0;
921
+ top: -0.1rem;
922
+ width: 2rem;
923
+ height: 2rem;
924
+ border-radius: 50%;
925
+ border: 1px solid var(--accent);
926
+ color: var(--accent);
927
+ font-weight: 600;
928
+ display: flex;
929
+ align-items: center;
930
+ justify-content: center;
931
+ }
932
+
933
+ .ln-quick > li > strong {
934
+ display: block;
935
+ margin-bottom: 0.6rem;
936
+ font-size: 1.05rem;
937
+ }
938
+
939
+ .ln-quick .ln-code {
940
+ margin-bottom: 0.6rem;
941
+ }
942
+
943
+ .ln-quick-note {
944
+ margin: 0;
945
+ color: var(--text-muted);
946
+ font-size: 0.92rem;
947
+ }
948
+
949
+ .ln-quick-note code {
950
+ overflow-wrap: anywhere;
951
+ }
952
+
953
+ .ln-quick-h {
954
+ margin: 1.5rem 0 1rem;
955
+ }
956
+
957
+ .ln-table-wrap {
958
+ overflow-x: auto;
959
+ }
960
+
961
+ /* Let code blocks scroll inside their column instead of widening the page. */
962
+ .ln-install-grid > *,
963
+ .ln-quick > li {
964
+ min-width: 0;
965
+ }
966
+
967
+ .ln-verdicts {
968
+ width: 100%;
969
+ border-collapse: collapse;
970
+ font-size: 0.92rem;
971
+ }
972
+
973
+ .ln-verdicts th,
974
+ .ln-verdicts td {
975
+ padding: 0.6rem 0.75rem;
976
+ border-bottom: 1px solid var(--border);
977
+ text-align: left;
978
+ vertical-align: top;
979
+ }
980
+
981
+ .ln-verdicts th {
982
+ color: var(--text-muted);
983
+ font-weight: 600;
984
+ }
985
+
986
+ .ln-tag {
987
+ display: inline-block;
988
+ padding: 0.15rem 0.5rem;
989
+ border-radius: 4px;
990
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
991
+ font-size: 0.8rem;
992
+ font-weight: 600;
993
+ }
994
+
995
+ .ln-install-grid {
996
+ display: grid;
997
+ grid-template-columns: 1.15fr 0.85fr;
998
+ gap: 3rem;
999
+ align-items: start;
1000
+ }
1001
+
1002
+ .ln-aside {
1003
+ border-left: 2px solid var(--border);
1004
+ padding-left: 1.25rem;
1005
+ color: var(--text-muted);
1006
+ font-size: 0.95rem;
1007
+ }
1008
+
1009
+ .ln-aside p {
1010
+ max-width: none;
1011
+ }
1012
+
1013
+ /* Footer */
1014
+
1015
+ .ln-footer {
1016
+ border-top: 1px solid var(--border);
1017
+ padding: 2.5rem 0;
1018
+ color: var(--text-muted);
1019
+ font-size: 0.9rem;
1020
+ }
1021
+
1022
+ .ln-footer .ln-col {
1023
+ display: flex;
1024
+ justify-content: space-between;
1025
+ gap: 1rem;
1026
+ flex-wrap: wrap;
1027
+ }
1028
+
1029
+ /* Responsive */
1030
+
1031
+ @media (max-width: 960px) {
1032
+ .ln-hero-grid {
1033
+ grid-template-columns: 1fr;
1034
+ gap: 3rem;
1035
+ }
1036
+
1037
+ .ln-hero {
1038
+ min-height: 0;
1039
+ }
1040
+
1041
+ .ln-steps {
1042
+ grid-template-columns: repeat(2, minmax(0, 1fr));
1043
+ }
1044
+
1045
+ .ln-install-grid {
1046
+ grid-template-columns: 1fr;
1047
+ }
1048
+
1049
+ .ln-aside {
1050
+ border-left: 0;
1051
+ padding-left: 0;
1052
+ }
1053
+ }
1054
+
1055
+ @media (max-width: 720px) {
1056
+ .ln-col {
1057
+ padding: 0 1.25rem;
1058
+ }
1059
+
1060
+ .ln-nav-links a:not(.ln-nav-gh) {
1061
+ display: none;
1062
+ }
1063
+
1064
+ .ln-band {
1065
+ padding: 4rem 0;
1066
+ }
1067
+
1068
+ .ln-hero h1 {
1069
+ font-size: 2.5rem;
1070
+ }
1071
+
1072
+ .ln-stats {
1073
+ gap: 1.25rem;
1074
+ }
1075
+
1076
+ .ln-stat .value {
1077
+ font-size: 2.75rem;
1078
+ }
1079
+
1080
+ .ln-matrix {
1081
+ grid-template-columns: 1fr;
1082
+ }
1083
+
1084
+ .ln-matrix .axis--col {
1085
+ display: none;
1086
+ }
1087
+
1088
+ .ln-steps {
1089
+ grid-template-columns: 1fr;
1090
+ }
1091
+
1092
+ .ln-frame {
1093
+ height: 480px;
1094
+ }
1095
+ }