faultmesh 1.0.0

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 (37) hide show
  1. package/README.md +98 -0
  2. package/dist/cli.d.ts +2 -0
  3. package/dist/cli.js +105 -0
  4. package/dist/dashboard/app.js +998 -0
  5. package/dist/dashboard/index.html +291 -0
  6. package/dist/dashboard/styles.css +1120 -0
  7. package/dist/engine/ControlApi.d.ts +24 -0
  8. package/dist/engine/ControlApi.js +269 -0
  9. package/dist/engine/FaultMeshProxy.d.ts +16 -0
  10. package/dist/engine/FaultMeshProxy.js +167 -0
  11. package/dist/engine/TelemetryHub.d.ts +16 -0
  12. package/dist/engine/TelemetryHub.js +67 -0
  13. package/dist/engine/ToxicPipeline.d.ts +22 -0
  14. package/dist/engine/ToxicPipeline.js +67 -0
  15. package/dist/scorer/ResilienceScorer.d.ts +13 -0
  16. package/dist/scorer/ResilienceScorer.js +330 -0
  17. package/dist/scorer/SecurityAuditor.d.ts +13 -0
  18. package/dist/scorer/SecurityAuditor.js +428 -0
  19. package/dist/scorer/TrafficStormAuditor.d.ts +10 -0
  20. package/dist/scorer/TrafficStormAuditor.js +261 -0
  21. package/dist/server.d.ts +21 -0
  22. package/dist/server.js +169 -0
  23. package/dist/toxics/BandwidthToxic.d.ts +11 -0
  24. package/dist/toxics/BandwidthToxic.js +36 -0
  25. package/dist/toxics/BaseToxic.d.ts +11 -0
  26. package/dist/toxics/BaseToxic.js +19 -0
  27. package/dist/toxics/CorruptToxic.d.ts +11 -0
  28. package/dist/toxics/CorruptToxic.js +53 -0
  29. package/dist/toxics/CutToxic.d.ts +9 -0
  30. package/dist/toxics/CutToxic.js +31 -0
  31. package/dist/toxics/LatencyToxic.d.ts +13 -0
  32. package/dist/toxics/LatencyToxic.js +40 -0
  33. package/dist/toxics/StatusToxic.d.ts +9 -0
  34. package/dist/toxics/StatusToxic.js +22 -0
  35. package/dist/types.d.ts +123 -0
  36. package/dist/types.js +4 -0
  37. package/package.json +35 -0
@@ -0,0 +1,1120 @@
1
+ /* ==========================================================================
2
+ FaultMesh — Clean Minimalist Engineering UI
3
+ Zero AI-Slop: Pure Neutral Palette, No Electric Blue, Full Viewport Width
4
+ Zero Emojis: Crisp Plain Text & Monospaced Typography
5
+ ========================================================================== */
6
+
7
+ :root {
8
+ /* Light Theme Default (Crisp, High-Contrast, Minimalist) */
9
+ --bg-app: #fbfbfb;
10
+ --bg-surface: #ffffff;
11
+ --bg-subtle: #f4f4f5;
12
+ --bg-hover: #e4e4e7;
13
+ --bg-input: #ffffff;
14
+
15
+ --border-subtle: #f4f4f5;
16
+ --border-default: #e4e4e7;
17
+ --border-strong: #d4d4d8;
18
+
19
+ --text-main: #09090b;
20
+ --text-muted: #71717a;
21
+ --text-subtle: #a1a1aa;
22
+
23
+ --btn-primary-bg: #18181b;
24
+ --btn-primary-fg: #ffffff;
25
+ --btn-primary-hover: #27272a;
26
+
27
+ --tag-green-bg: #f0fdf4;
28
+ --tag-green-fg: #15803d;
29
+ --tag-green-border: #bbf7d0;
30
+
31
+ --tag-amber-bg: #fffbeb;
32
+ --tag-amber-fg: #b45309;
33
+ --tag-amber-border: #fde68a;
34
+
35
+ --tag-red-bg: #fef2f2;
36
+ --tag-red-fg: #b91c1c;
37
+ --tag-red-border: #fecaca;
38
+
39
+ --font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
40
+ --font-mono: ui-monospace, "SF Mono", Menlo, Monaco, Consolas, monospace;
41
+
42
+ --radius: 6px;
43
+ }
44
+
45
+ [data-theme="dark"] {
46
+ --bg-app: #09090b;
47
+ --bg-surface: #121215;
48
+ --bg-subtle: #18181b;
49
+ --bg-hover: #27272a;
50
+ --bg-input: #18181b;
51
+
52
+ --border-subtle: #1f1f23;
53
+ --border-default: #27272a;
54
+ --border-strong: #3f3f46;
55
+
56
+ --text-main: #f4f4f5;
57
+ --text-muted: #a1a1aa;
58
+ --text-subtle: #71717a;
59
+
60
+ --btn-primary-bg: #f4f4f5;
61
+ --btn-primary-fg: #09090b;
62
+ --btn-primary-hover: #e4e4e7;
63
+
64
+ --tag-green-bg: rgba(22, 163, 74, 0.15);
65
+ --tag-green-fg: #4ade80;
66
+ --tag-green-border: rgba(22, 163, 74, 0.3);
67
+
68
+ --tag-amber-bg: rgba(180, 83, 9, 0.15);
69
+ --tag-amber-fg: #fbbf24;
70
+ --tag-amber-border: rgba(180, 83, 9, 0.3);
71
+
72
+ --tag-red-bg: rgba(185, 28, 28, 0.15);
73
+ --tag-red-fg: #f87171;
74
+ --tag-red-border: rgba(185, 28, 28, 0.3);
75
+ }
76
+
77
+ /* Reset */
78
+ *, *::before, *::after {
79
+ box-sizing: border-box;
80
+ margin: 0;
81
+ padding: 0;
82
+ }
83
+
84
+ body {
85
+ background-color: var(--bg-app);
86
+ color: var(--text-main);
87
+ font-family: var(--font-sans);
88
+ font-size: 13px;
89
+ line-height: 1.5;
90
+ -webkit-font-smoothing: antialiased;
91
+ min-height: 100vh;
92
+ }
93
+
94
+ /* Header: Full Width */
95
+ .app-header {
96
+ background: var(--bg-surface);
97
+ border-bottom: 1px solid var(--border-default);
98
+ padding: 12px 24px;
99
+ width: 100%;
100
+ }
101
+
102
+ .header-content {
103
+ width: 100%;
104
+ display: flex;
105
+ justify-content: space-between;
106
+ align-items: center;
107
+ }
108
+
109
+ .header-left {
110
+ display: flex;
111
+ align-items: center;
112
+ gap: 8px;
113
+ }
114
+
115
+ .app-name {
116
+ font-size: 15px;
117
+ font-weight: 700;
118
+ letter-spacing: -0.3px;
119
+ }
120
+
121
+ .app-divider {
122
+ color: var(--text-subtle);
123
+ }
124
+
125
+ .app-tagline {
126
+ color: var(--text-muted);
127
+ font-size: 13px;
128
+ }
129
+
130
+ .header-right {
131
+ display: flex;
132
+ align-items: center;
133
+ gap: 16px;
134
+ }
135
+
136
+ .proxy-status {
137
+ font-size: 12px;
138
+ color: var(--text-muted);
139
+ }
140
+
141
+ .proxy-status strong {
142
+ color: var(--text-main);
143
+ }
144
+
145
+ /* Main Container: Full Width */
146
+ .container {
147
+ width: 100%;
148
+ padding: 16px 24px 30px;
149
+ }
150
+
151
+ /* Section Box Base */
152
+ .section-box {
153
+ background: var(--bg-surface);
154
+ border: 1px solid var(--border-default);
155
+ border-radius: var(--radius);
156
+ padding: 16px 18px;
157
+ }
158
+
159
+ .section-header {
160
+ margin-bottom: 12px;
161
+ }
162
+
163
+ .section-header h2 {
164
+ font-size: 14px;
165
+ font-weight: 600;
166
+ color: var(--text-main);
167
+ letter-spacing: -0.2px;
168
+ }
169
+
170
+ .section-header p {
171
+ font-size: 12px;
172
+ color: var(--text-muted);
173
+ margin-top: 2px;
174
+ }
175
+
176
+ .header-with-action, .header-with-badge {
177
+ display: flex;
178
+ justify-content: space-between;
179
+ align-items: flex-start;
180
+ }
181
+
182
+ /* ==========================================================================
183
+ PRIMARY HERO FEATURE: AUTOMATED AUDIT & DIAGNOSTICS SUITE
184
+ ========================================================================== */
185
+
186
+ .audit-suite-card {
187
+ margin-bottom: 24px;
188
+ display: flex;
189
+ flex-direction: column;
190
+ gap: 16px;
191
+ border: 1px solid var(--border-strong);
192
+ border-top: 3px solid var(--text-main);
193
+ border-radius: var(--radius);
194
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
195
+ padding: 20px 22px;
196
+ }
197
+
198
+ .audit-header-bar {
199
+ display: flex;
200
+ justify-content: space-between;
201
+ align-items: center;
202
+ flex-wrap: wrap;
203
+ gap: 14px;
204
+ padding-bottom: 14px;
205
+ border-bottom: 1px solid var(--border-default);
206
+ }
207
+
208
+ .audit-title-area {
209
+ display: flex;
210
+ flex-direction: column;
211
+ gap: 4px;
212
+ }
213
+
214
+ .badge-row {
215
+ display: flex;
216
+ align-items: center;
217
+ gap: 6px;
218
+ }
219
+
220
+ .suite-badge {
221
+ font-family: var(--font-mono);
222
+ font-size: 10px;
223
+ font-weight: 700;
224
+ letter-spacing: 0.6px;
225
+ text-transform: uppercase;
226
+ color: var(--text-main);
227
+ background: var(--bg-subtle);
228
+ border: 1px solid var(--border-default);
229
+ padding: 2px 7px;
230
+ border-radius: 4px;
231
+ }
232
+
233
+ .audit-header-bar h2 {
234
+ font-size: 17px;
235
+ font-weight: 700;
236
+ letter-spacing: -0.3px;
237
+ color: var(--text-main);
238
+ }
239
+
240
+ .audit-header-bar p {
241
+ font-size: 12px;
242
+ color: var(--text-muted);
243
+ max-width: 650px;
244
+ }
245
+
246
+ .diag-tabs {
247
+ display: flex;
248
+ gap: 4px;
249
+ background: var(--bg-subtle);
250
+ padding: 3px;
251
+ border-radius: var(--radius);
252
+ border: 1px solid var(--border-default);
253
+ }
254
+
255
+ .diag-tab {
256
+ background: transparent;
257
+ border: none;
258
+ padding: 7px 16px;
259
+ font-size: 12px;
260
+ font-weight: 600;
261
+ color: var(--text-muted);
262
+ border-radius: 4px;
263
+ cursor: pointer;
264
+ transition: all 0.15s ease;
265
+ white-space: nowrap;
266
+ }
267
+
268
+ .diag-tab:hover {
269
+ color: var(--text-main);
270
+ }
271
+
272
+ .diag-tab.active {
273
+ background: var(--bg-surface);
274
+ color: var(--text-main);
275
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
276
+ }
277
+
278
+ /* Banner: Score & Action Runner */
279
+ .audit-banner {
280
+ display: flex;
281
+ justify-content: space-between;
282
+ align-items: center;
283
+ flex-wrap: wrap;
284
+ gap: 16px;
285
+ background: var(--bg-subtle);
286
+ border: 1px solid var(--border-default);
287
+ border-radius: var(--radius);
288
+ padding: 14px 18px;
289
+ }
290
+
291
+ .score-summary {
292
+ display: flex;
293
+ align-items: center;
294
+ gap: 16px;
295
+ }
296
+
297
+ .score-pill {
298
+ display: flex;
299
+ flex-direction: column;
300
+ align-items: center;
301
+ min-width: 72px;
302
+ padding: 6px 10px;
303
+ background: var(--bg-surface);
304
+ border: 1px solid var(--border-default);
305
+ border-radius: var(--radius);
306
+ }
307
+
308
+ .score-number {
309
+ font-size: 26px;
310
+ font-weight: 700;
311
+ font-family: var(--font-mono);
312
+ line-height: 1;
313
+ }
314
+
315
+ .score-label {
316
+ font-size: 9px;
317
+ font-weight: 700;
318
+ color: var(--text-muted);
319
+ margin-top: 3px;
320
+ letter-spacing: 0.5px;
321
+ }
322
+
323
+ .score-text strong {
324
+ font-size: 13px;
325
+ font-weight: 600;
326
+ color: var(--text-main);
327
+ display: block;
328
+ }
329
+
330
+ .score-text p {
331
+ font-size: 11px;
332
+ color: var(--text-muted);
333
+ margin-top: 2px;
334
+ }
335
+
336
+ .diagnostics-actions {
337
+ display: flex;
338
+ align-items: center;
339
+ gap: 10px;
340
+ flex-wrap: wrap;
341
+ }
342
+
343
+ .select-profile {
344
+ padding: 7px 12px;
345
+ font-size: 12px;
346
+ width: auto;
347
+ font-weight: 500;
348
+ }
349
+
350
+ .btn-run-diagnostics {
351
+ min-width: 170px;
352
+ white-space: nowrap;
353
+ flex-shrink: 0;
354
+ padding: 8px 18px;
355
+ font-size: 12px;
356
+ font-weight: 600;
357
+ }
358
+
359
+ /* Checklist & Test Rows */
360
+ .checklist-container {
361
+ display: flex;
362
+ flex-direction: column;
363
+ gap: 8px;
364
+ }
365
+
366
+ .checklist-header {
367
+ display: flex;
368
+ justify-content: space-between;
369
+ align-items: center;
370
+ padding-bottom: 2px;
371
+ }
372
+
373
+ .checklist-title {
374
+ font-size: 11px;
375
+ font-weight: 700;
376
+ text-transform: uppercase;
377
+ letter-spacing: 0.6px;
378
+ color: var(--text-muted);
379
+ }
380
+
381
+ .test-results-list {
382
+ display: flex;
383
+ flex-direction: column;
384
+ gap: 8px;
385
+ }
386
+
387
+ .test-row {
388
+ display: flex;
389
+ justify-content: space-between;
390
+ align-items: flex-start;
391
+ padding: 12px 16px;
392
+ background: var(--bg-surface);
393
+ border: 1px solid var(--border-default);
394
+ border-radius: var(--radius);
395
+ font-size: 12px;
396
+ gap: 16px;
397
+ transition: border-color 0.15s ease, background 0.15s ease;
398
+ }
399
+
400
+ .test-row:hover {
401
+ border-color: var(--border-strong);
402
+ }
403
+
404
+ .test-row.row-passed {
405
+ border-left: 3px solid var(--tag-green-fg);
406
+ }
407
+
408
+ .test-row.row-failed {
409
+ border-left: 3px solid var(--tag-red-fg);
410
+ }
411
+
412
+ .test-row-main {
413
+ display: flex;
414
+ align-items: flex-start;
415
+ gap: 12px;
416
+ flex: 1;
417
+ }
418
+
419
+ .test-num {
420
+ font-family: var(--font-mono);
421
+ font-size: 11px;
422
+ font-weight: 700;
423
+ color: var(--text-subtle);
424
+ min-width: 20px;
425
+ padding-top: 1px;
426
+ }
427
+
428
+ .test-content-col {
429
+ display: flex;
430
+ flex-direction: column;
431
+ gap: 4px;
432
+ flex: 1;
433
+ }
434
+
435
+ .test-name-group {
436
+ display: flex;
437
+ align-items: center;
438
+ gap: 8px;
439
+ flex-wrap: wrap;
440
+ }
441
+
442
+ .test-name {
443
+ font-weight: 600;
444
+ color: var(--text-main);
445
+ font-size: 13px;
446
+ }
447
+
448
+ .test-desc {
449
+ font-size: 12px;
450
+ color: var(--text-muted);
451
+ line-height: 1.45;
452
+ }
453
+
454
+ .test-probe-method {
455
+ font-size: 11px;
456
+ font-family: var(--font-mono);
457
+ color: var(--text-subtle);
458
+ }
459
+
460
+ .test-finding-box {
461
+ margin-top: 4px;
462
+ font-size: 11px;
463
+ font-family: var(--font-mono);
464
+ padding: 4px 8px;
465
+ border-radius: 4px;
466
+ display: inline-block;
467
+ max-width: 100%;
468
+ }
469
+
470
+ .finding-pass {
471
+ color: var(--tag-green-fg);
472
+ background: var(--tag-green-bg);
473
+ border: 1px solid var(--tag-green-border);
474
+ }
475
+
476
+ .finding-fail {
477
+ color: var(--tag-red-fg);
478
+ background: var(--tag-red-bg);
479
+ border: 1px solid var(--tag-red-border);
480
+ }
481
+
482
+ .test-row-aside {
483
+ display: flex;
484
+ flex-direction: column;
485
+ align-items: flex-end;
486
+ gap: 4px;
487
+ min-width: 110px;
488
+ flex-shrink: 0;
489
+ }
490
+
491
+ .test-tag {
492
+ font-family: var(--font-mono);
493
+ font-size: 11px;
494
+ font-weight: 700;
495
+ white-space: nowrap;
496
+ padding: 3px 8px;
497
+ border-radius: 4px;
498
+ }
499
+
500
+ .tag-pass {
501
+ color: var(--tag-green-fg);
502
+ background: var(--tag-green-bg);
503
+ border: 1px solid var(--tag-green-border);
504
+ }
505
+
506
+ .tag-fail {
507
+ color: var(--tag-red-fg);
508
+ background: var(--tag-red-bg);
509
+ border: 1px solid var(--tag-red-border);
510
+ }
511
+
512
+ .status-ready {
513
+ font-family: var(--font-mono);
514
+ font-size: 10px;
515
+ font-weight: 700;
516
+ padding: 3px 8px;
517
+ border-radius: 4px;
518
+ color: var(--text-muted);
519
+ background: var(--bg-subtle);
520
+ border: 1px solid var(--border-default);
521
+ letter-spacing: 0.5px;
522
+ white-space: nowrap;
523
+ }
524
+
525
+ .category-pill {
526
+ font-family: var(--font-mono);
527
+ font-size: 10px;
528
+ font-weight: 700;
529
+ padding: 1px 6px;
530
+ border-radius: 4px;
531
+ text-transform: uppercase;
532
+ letter-spacing: 0.5px;
533
+ white-space: nowrap;
534
+ color: var(--text-muted);
535
+ background: var(--bg-subtle);
536
+ border: 1px solid var(--border-default);
537
+ }
538
+
539
+ /* Severity tags */
540
+ .severity-pill {
541
+ font-family: var(--font-mono);
542
+ font-size: 10px;
543
+ font-weight: 700;
544
+ padding: 1px 6px;
545
+ border-radius: 4px;
546
+ text-transform: uppercase;
547
+ letter-spacing: 0.5px;
548
+ white-space: nowrap;
549
+ }
550
+
551
+ .severity-critical {
552
+ color: var(--tag-red-fg);
553
+ background: var(--tag-red-bg);
554
+ border: 1px solid var(--tag-red-border);
555
+ }
556
+
557
+ .severity-high {
558
+ color: var(--tag-amber-fg);
559
+ background: var(--tag-amber-bg);
560
+ border: 1px solid var(--tag-amber-border);
561
+ }
562
+
563
+ .severity-medium {
564
+ color: var(--text-main);
565
+ background: var(--bg-subtle);
566
+ border: 1px solid var(--border-default);
567
+ }
568
+
569
+ .severity-low {
570
+ color: var(--text-muted);
571
+ background: var(--bg-subtle);
572
+ border: 1px solid var(--border-subtle);
573
+ }
574
+
575
+ .advice-list {
576
+ margin-top: 6px;
577
+ padding: 14px 18px;
578
+ background: var(--bg-subtle);
579
+ border: 1px solid var(--border-default);
580
+ border-radius: var(--radius);
581
+ font-size: 12px;
582
+ }
583
+
584
+ .advice-list strong {
585
+ color: var(--text-main);
586
+ display: block;
587
+ margin-bottom: 8px;
588
+ font-size: 12px;
589
+ font-weight: 600;
590
+ }
591
+
592
+ .advice-list ul {
593
+ padding-left: 18px;
594
+ color: var(--text-muted);
595
+ display: flex;
596
+ flex-direction: column;
597
+ gap: 5px;
598
+ }
599
+
600
+ .advice-list li {
601
+ line-height: 1.4;
602
+ }
603
+
604
+ /* ==========================================================================
605
+ WORKBENCH SECTION HEADER
606
+ ========================================================================== */
607
+
608
+ .workbench-section-header {
609
+ margin-top: 24px;
610
+ margin-bottom: 12px;
611
+ display: flex;
612
+ flex-direction: column;
613
+ gap: 3px;
614
+ }
615
+
616
+ .workbench-title-group {
617
+ display: flex;
618
+ align-items: center;
619
+ gap: 8px;
620
+ }
621
+
622
+ .workbench-badge {
623
+ font-family: var(--font-mono);
624
+ font-size: 10px;
625
+ font-weight: 700;
626
+ letter-spacing: 0.5px;
627
+ text-transform: uppercase;
628
+ color: var(--text-muted);
629
+ background: var(--bg-subtle);
630
+ border: 1px solid var(--border-default);
631
+ padding: 2px 6px;
632
+ border-radius: 4px;
633
+ }
634
+
635
+ .workbench-section-header h3 {
636
+ font-size: 14px;
637
+ font-weight: 700;
638
+ color: var(--text-main);
639
+ letter-spacing: -0.2px;
640
+ }
641
+
642
+ .workbench-section-header p {
643
+ font-size: 12px;
644
+ color: var(--text-muted);
645
+ }
646
+
647
+ /* ==========================================================================
648
+ WORKBENCH: SIMULATION & RESPONSE INSPECTION (2 Columns)
649
+ ========================================================================== */
650
+
651
+ .columns-grid {
652
+ display: grid;
653
+ grid-template-columns: 1fr 1fr;
654
+ gap: 16px;
655
+ align-items: start;
656
+ margin-bottom: 16px;
657
+ }
658
+
659
+ .column {
660
+ display: flex;
661
+ flex-direction: column;
662
+ gap: 16px;
663
+ }
664
+
665
+ .adder-subgroup {
666
+ display: flex;
667
+ flex-direction: column;
668
+ gap: 8px;
669
+ }
670
+
671
+ .custom-rule-section {
672
+ margin-top: 14px;
673
+ padding-top: 14px;
674
+ border-top: 1px solid var(--border-default);
675
+ }
676
+
677
+ .subgroup-label {
678
+ font-size: 11px;
679
+ font-weight: 700;
680
+ text-transform: uppercase;
681
+ letter-spacing: 0.5px;
682
+ color: var(--text-muted);
683
+ }
684
+
685
+ .scenario-table {
686
+ display: flex;
687
+ flex-direction: column;
688
+ border: 1px solid var(--border-default);
689
+ border-radius: var(--radius);
690
+ overflow: hidden;
691
+ }
692
+
693
+ .scenario-row {
694
+ display: flex;
695
+ justify-content: space-between;
696
+ align-items: center;
697
+ padding: 8px 12px;
698
+ border-bottom: 1px solid var(--border-subtle);
699
+ }
700
+
701
+ .scenario-row:last-child {
702
+ border-bottom: none;
703
+ }
704
+
705
+ .scenario-desc {
706
+ display: flex;
707
+ flex-direction: column;
708
+ gap: 1px;
709
+ }
710
+
711
+ .scenario-desc strong {
712
+ font-size: 12px;
713
+ font-weight: 600;
714
+ color: var(--text-main);
715
+ }
716
+
717
+ .scenario-desc span {
718
+ font-size: 11px;
719
+ color: var(--text-muted);
720
+ }
721
+
722
+ /* Active Rules */
723
+ .count-tag {
724
+ font-size: 11px;
725
+ font-weight: 600;
726
+ color: var(--text-muted);
727
+ background: var(--bg-subtle);
728
+ border: 1px solid var(--border-default);
729
+ padding: 2px 8px;
730
+ border-radius: 10px;
731
+ }
732
+
733
+ .rules-list {
734
+ display: flex;
735
+ flex-direction: column;
736
+ gap: 6px;
737
+ }
738
+
739
+ .rule-item {
740
+ display: flex;
741
+ justify-content: space-between;
742
+ align-items: center;
743
+ padding: 8px 12px;
744
+ background: var(--bg-subtle);
745
+ border: 1px solid var(--border-default);
746
+ border-radius: var(--radius);
747
+ }
748
+
749
+ .rule-title {
750
+ font-size: 12px;
751
+ font-weight: 600;
752
+ color: var(--text-main);
753
+ }
754
+
755
+ .rule-subtitle {
756
+ font-size: 11px;
757
+ color: var(--text-muted);
758
+ font-family: var(--font-mono);
759
+ }
760
+
761
+ .empty-state {
762
+ text-align: center;
763
+ padding: 14px;
764
+ color: var(--text-subtle);
765
+ font-size: 12px;
766
+ background: var(--bg-subtle);
767
+ border: 1px dashed var(--border-default);
768
+ border-radius: var(--radius);
769
+ }
770
+
771
+ /* ==========================================================================
772
+ RESPONSE INSPECTOR
773
+ ========================================================================== */
774
+
775
+ .response-inspector-card {
776
+ display: flex;
777
+ flex-direction: column;
778
+ gap: 10px;
779
+ }
780
+
781
+ .inspector-controls {
782
+ display: flex;
783
+ align-items: center;
784
+ gap: 8px;
785
+ flex-wrap: wrap;
786
+ }
787
+
788
+ .inspector-select {
789
+ flex: 1;
790
+ min-width: 200px;
791
+ padding: 6px 10px;
792
+ font-size: 12px;
793
+ }
794
+
795
+ .response-meta-bar {
796
+ display: flex;
797
+ align-items: center;
798
+ gap: 10px;
799
+ flex-wrap: wrap;
800
+ background: var(--bg-subtle);
801
+ border: 1px solid var(--border-default);
802
+ border-radius: var(--radius);
803
+ padding: 7px 12px;
804
+ font-family: var(--font-mono);
805
+ font-size: 11px;
806
+ }
807
+
808
+ .meta-item {
809
+ display: flex;
810
+ align-items: center;
811
+ gap: 5px;
812
+ }
813
+
814
+ .meta-label {
815
+ color: var(--text-muted);
816
+ font-size: 11px;
817
+ }
818
+
819
+ .status-pill {
820
+ padding: 2px 8px;
821
+ border-radius: 4px;
822
+ font-weight: 700;
823
+ font-size: 11px;
824
+ font-family: var(--font-mono);
825
+ background: var(--bg-surface);
826
+ border: 1px solid var(--border-default);
827
+ color: var(--text-main);
828
+ }
829
+
830
+ .response-meta {
831
+ color: var(--text-main);
832
+ font-weight: 600;
833
+ font-variant-numeric: tabular-nums;
834
+ }
835
+
836
+ .response-meta-rule {
837
+ color: var(--tag-amber-fg);
838
+ background: var(--tag-amber-bg);
839
+ border: 1px solid var(--tag-amber-border);
840
+ padding: 2px 8px;
841
+ border-radius: 4px;
842
+ font-size: 11px;
843
+ font-weight: 600;
844
+ }
845
+
846
+ .active-rules-pill {
847
+ font-size: 11px;
848
+ font-family: var(--font-mono);
849
+ padding: 2px 8px;
850
+ border-radius: 12px;
851
+ background: var(--bg-surface);
852
+ color: var(--text-muted);
853
+ border: 1px solid var(--border-default);
854
+ white-space: nowrap;
855
+ }
856
+
857
+ .active-rules-pill.active {
858
+ color: var(--tag-amber-fg);
859
+ background: var(--tag-amber-bg);
860
+ border-color: var(--tag-amber-border);
861
+ font-weight: 600;
862
+ }
863
+
864
+ .test-status-text {
865
+ font-size: 11px;
866
+ font-family: var(--font-mono);
867
+ color: var(--text-muted);
868
+ word-break: break-word;
869
+ }
870
+
871
+ .response-body-wrapper {
872
+ width: 100%;
873
+ }
874
+
875
+ .response-body-pre {
876
+ background: var(--bg-subtle);
877
+ border: 1px solid var(--border-default);
878
+ border-radius: var(--radius);
879
+ padding: 12px 14px;
880
+ font-family: var(--font-mono);
881
+ font-size: 11px;
882
+ min-height: 140px;
883
+ max-height: 220px;
884
+ overflow-y: auto;
885
+ color: var(--text-main);
886
+ white-space: pre-wrap;
887
+ word-break: break-word;
888
+ line-height: 1.45;
889
+ }
890
+
891
+ .inspector-footer {
892
+ display: flex;
893
+ justify-content: space-between;
894
+ align-items: center;
895
+ font-size: 11px;
896
+ color: var(--text-subtle);
897
+ }
898
+
899
+ .inspector-footer code {
900
+ font-family: var(--font-mono);
901
+ color: var(--text-muted);
902
+ background: var(--bg-subtle);
903
+ padding: 2px 6px;
904
+ border-radius: 4px;
905
+ }
906
+
907
+ /* ==========================================================================
908
+ LIVE TRAFFIC LOG (Full Width Across Bottom)
909
+ ========================================================================== */
910
+
911
+ .full-width-log-section {
912
+ margin-top: 0;
913
+ }
914
+
915
+ .full-width-table-container {
916
+ max-height: 200px;
917
+ overflow-y: auto;
918
+ border: 1px solid var(--border-default);
919
+ border-radius: var(--radius);
920
+ }
921
+
922
+ .log-table {
923
+ width: 100%;
924
+ border-collapse: collapse;
925
+ font-size: 11px;
926
+ font-family: var(--font-mono);
927
+ text-align: left;
928
+ }
929
+
930
+ .log-table th {
931
+ background: var(--bg-subtle);
932
+ color: var(--text-muted);
933
+ font-weight: 600;
934
+ padding: 7px 12px;
935
+ border-bottom: 1px solid var(--border-default);
936
+ position: sticky;
937
+ top: 0;
938
+ z-index: 1;
939
+ }
940
+
941
+ .log-table td {
942
+ padding: 6px 12px;
943
+ border-bottom: 1px solid var(--border-subtle);
944
+ color: var(--text-main);
945
+ }
946
+
947
+ .log-table tr:hover td {
948
+ background: var(--bg-subtle);
949
+ }
950
+
951
+ .code-2xx { color: var(--tag-green-fg); font-weight: 600; }
952
+ .code-4xx { color: var(--tag-amber-fg); font-weight: 600; }
953
+ .code-5xx { color: var(--tag-red-fg); font-weight: 600; }
954
+
955
+ .table-empty {
956
+ text-align: center;
957
+ padding: 16px;
958
+ color: var(--text-subtle);
959
+ font-style: italic;
960
+ }
961
+
962
+ /* ==========================================================================
963
+ FORMS & INPUTS
964
+ ========================================================================== */
965
+
966
+ .form-layout {
967
+ display: flex;
968
+ flex-direction: column;
969
+ gap: 10px;
970
+ }
971
+
972
+ .form-row {
973
+ display: grid;
974
+ grid-template-columns: 1fr 1fr;
975
+ gap: 10px;
976
+ }
977
+
978
+ .form-field {
979
+ display: flex;
980
+ flex-direction: column;
981
+ gap: 4px;
982
+ }
983
+
984
+ .form-field label {
985
+ font-size: 11px;
986
+ font-weight: 600;
987
+ color: var(--text-muted);
988
+ }
989
+
990
+ .form-input {
991
+ background: var(--bg-input);
992
+ border: 1px solid var(--border-default);
993
+ border-radius: var(--radius);
994
+ padding: 7px 10px;
995
+ font-size: 12px;
996
+ font-family: var(--font-sans);
997
+ color: var(--text-main);
998
+ outline: none;
999
+ }
1000
+
1001
+ .form-input:focus {
1002
+ border-color: var(--border-strong);
1003
+ }
1004
+
1005
+ .dynamic-row {
1006
+ display: flex;
1007
+ flex-direction: column;
1008
+ gap: 8px;
1009
+ }
1010
+
1011
+ /* ==========================================================================
1012
+ BUTTONS
1013
+ ========================================================================== */
1014
+
1015
+ button {
1016
+ font-family: var(--font-sans);
1017
+ cursor: pointer;
1018
+ border-radius: var(--radius);
1019
+ white-space: nowrap;
1020
+ flex-shrink: 0;
1021
+ transition: background 0.15s ease, border-color 0.15s ease;
1022
+ }
1023
+
1024
+ .btn-primary {
1025
+ background: var(--btn-primary-bg);
1026
+ color: var(--btn-primary-fg);
1027
+ border: 1px solid transparent;
1028
+ padding: 6px 14px;
1029
+ font-size: 12px;
1030
+ font-weight: 600;
1031
+ white-space: nowrap;
1032
+ flex-shrink: 0;
1033
+ display: inline-flex;
1034
+ align-items: center;
1035
+ justify-content: center;
1036
+ }
1037
+
1038
+ .btn-primary:hover {
1039
+ background: var(--btn-primary-hover);
1040
+ }
1041
+
1042
+ .btn-secondary {
1043
+ background: var(--bg-surface);
1044
+ color: var(--text-main);
1045
+ border: 1px solid var(--border-default);
1046
+ padding: 5px 12px;
1047
+ font-size: 12px;
1048
+ font-weight: 500;
1049
+ white-space: nowrap;
1050
+ flex-shrink: 0;
1051
+ display: inline-flex;
1052
+ align-items: center;
1053
+ justify-content: center;
1054
+ }
1055
+
1056
+ .btn-secondary:hover {
1057
+ background: var(--bg-hover);
1058
+ }
1059
+
1060
+ .btn-sm {
1061
+ padding: 3px 8px;
1062
+ font-size: 11px;
1063
+ }
1064
+
1065
+ .btn-full {
1066
+ width: 100%;
1067
+ padding: 7px;
1068
+ margin-top: 4px;
1069
+ }
1070
+
1071
+ .btn-danger-outline {
1072
+ width: 100%;
1073
+ background: transparent;
1074
+ border: 1px solid var(--border-default);
1075
+ color: var(--text-muted);
1076
+ padding: 7px;
1077
+ font-size: 12px;
1078
+ font-weight: 500;
1079
+ }
1080
+
1081
+ .btn-danger-outline:hover {
1082
+ background: var(--tag-red-bg);
1083
+ border-color: var(--tag-red-border);
1084
+ color: var(--tag-red-fg);
1085
+ }
1086
+
1087
+ .btn-text {
1088
+ background: transparent;
1089
+ border: none;
1090
+ color: var(--text-muted);
1091
+ font-size: 12px;
1092
+ padding: 4px 6px;
1093
+ }
1094
+
1095
+ .btn-text:hover {
1096
+ color: var(--text-main);
1097
+ }
1098
+
1099
+ .btn-remove {
1100
+ background: transparent;
1101
+ border: 1px solid var(--border-default);
1102
+ color: var(--text-muted);
1103
+ padding: 3px 8px;
1104
+ font-size: 11px;
1105
+ }
1106
+
1107
+ .btn-remove:hover {
1108
+ border-color: var(--tag-red-border);
1109
+ color: var(--tag-red-fg);
1110
+ }
1111
+
1112
+ /* ==========================================================================
1113
+ RESPONSIVE
1114
+ ========================================================================== */
1115
+
1116
+ @media (max-width: 1024px) {
1117
+ .columns-grid {
1118
+ grid-template-columns: 1fr;
1119
+ }
1120
+ }