@klars/agentobs 0.1.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.
@@ -0,0 +1,668 @@
1
+ /*
2
+ * AgentObs dashboard styling.
3
+ *
4
+ * Colors come from a validated data-viz palette: the categorical slots and
5
+ * status steps below passed the six-checks validator (lightness band, chroma
6
+ * floor, CVD separation, normal-vision floor, contrast) against both the
7
+ * light (#fcfcfb) and dark (#1a1a19) surfaces. Do not substitute hexes by eye
8
+ * - re-run the validator if these change.
9
+ *
10
+ * Every color is defined on bare :root first, then redefined for dark under
11
+ * both the OS media query and the explicit [data-theme] scope, so the toggle
12
+ * wins in either direction.
13
+ */
14
+
15
+ :root {
16
+ color-scheme: light;
17
+
18
+ --page: #f9f9f7;
19
+ --surface: #fcfcfb;
20
+ --text-primary: #0b0b0b;
21
+ --text-secondary: #52514e;
22
+ --text-muted: #898781;
23
+ --grid: #e1e0d9;
24
+ --axis: #c3c2b7;
25
+ --border: rgba(11, 11, 11, 0.1);
26
+ --raised: rgba(11, 11, 11, 0.04);
27
+
28
+ /* Categorical slots 1-3 (validated all-pairs in both modes). */
29
+ --series-1: #2a78d6; /* calls */
30
+ --series-2: #eb6834; /* secondary */
31
+ --series-3: #1baf7a;
32
+
33
+ /* Status palette - reserved, never reused as a series color. */
34
+ --status-good: #0ca30c;
35
+ --status-warning: #fab219;
36
+ --status-serious: #ec835a;
37
+ --status-critical: #d03b3b;
38
+ --success-text: #006300;
39
+
40
+ --radius: 10px;
41
+ --radius-sm: 6px;
42
+ --shadow: 0 1px 2px rgba(11, 11, 11, 0.05), 0 8px 24px -12px rgba(11, 11, 11, 0.12);
43
+ --font: ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", Inter, Roboto,
44
+ "Helvetica Neue", Arial, sans-serif;
45
+ --mono: ui-monospace, SFMono-Regular, "SF Mono", "JetBrains Mono", Menlo, Consolas, monospace;
46
+ }
47
+
48
+ @media (prefers-color-scheme: dark) {
49
+ :root:not([data-theme="light"]) {
50
+ color-scheme: dark;
51
+ --page: #0d0d0d;
52
+ --surface: #1a1a19;
53
+ --text-primary: #ffffff;
54
+ --text-secondary: #c3c2b7;
55
+ --text-muted: #898781;
56
+ --grid: #2c2c2a;
57
+ --axis: #383835;
58
+ --border: rgba(255, 255, 255, 0.1);
59
+ --raised: rgba(255, 255, 255, 0.05);
60
+ --series-1: #3987e5;
61
+ --series-2: #d95926;
62
+ --series-3: #199e70;
63
+ --success-text: #0ca30c;
64
+ --shadow: 0 1px 2px rgba(0, 0, 0, 0.4), 0 8px 24px -12px rgba(0, 0, 0, 0.6);
65
+ }
66
+ }
67
+
68
+ :root[data-theme="dark"] {
69
+ color-scheme: dark;
70
+ --page: #0d0d0d;
71
+ --surface: #1a1a19;
72
+ --text-primary: #ffffff;
73
+ --text-secondary: #c3c2b7;
74
+ --text-muted: #898781;
75
+ --grid: #2c2c2a;
76
+ --axis: #383835;
77
+ --border: rgba(255, 255, 255, 0.1);
78
+ --raised: rgba(255, 255, 255, 0.05);
79
+ --series-1: #3987e5;
80
+ --series-2: #d95926;
81
+ --series-3: #199e70;
82
+ --success-text: #0ca30c;
83
+ --shadow: 0 1px 2px rgba(0, 0, 0, 0.4), 0 8px 24px -12px rgba(0, 0, 0, 0.6);
84
+ }
85
+
86
+ *,
87
+ *::before,
88
+ *::after {
89
+ box-sizing: border-box;
90
+ }
91
+
92
+ html,
93
+ body {
94
+ margin: 0;
95
+ padding: 0;
96
+ }
97
+
98
+ body {
99
+ background: var(--page);
100
+ color: var(--text-primary);
101
+ font-family: var(--font);
102
+ font-size: 14px;
103
+ line-height: 1.5;
104
+ -webkit-font-smoothing: antialiased;
105
+ }
106
+
107
+ .sr-only {
108
+ position: absolute;
109
+ width: 1px;
110
+ height: 1px;
111
+ padding: 0;
112
+ margin: -1px;
113
+ overflow: hidden;
114
+ clip: rect(0 0 0 0);
115
+ white-space: nowrap;
116
+ border: 0;
117
+ }
118
+
119
+ .skip-link {
120
+ position: absolute;
121
+ left: -9999px;
122
+ top: 0;
123
+ background: var(--surface);
124
+ color: var(--text-primary);
125
+ padding: 10px 16px;
126
+ z-index: 10;
127
+ border-radius: var(--radius-sm);
128
+ }
129
+ .skip-link:focus {
130
+ left: 12px;
131
+ top: 12px;
132
+ }
133
+
134
+ /* ---------- Top bar ---------- */
135
+
136
+ .topbar {
137
+ display: flex;
138
+ align-items: center;
139
+ justify-content: space-between;
140
+ gap: 16px;
141
+ padding: 16px 24px;
142
+ background: var(--surface);
143
+ border-bottom: 1px solid var(--border);
144
+ position: sticky;
145
+ top: 0;
146
+ z-index: 5;
147
+ flex-wrap: wrap;
148
+ }
149
+
150
+ .brand {
151
+ display: flex;
152
+ align-items: center;
153
+ gap: 12px;
154
+ }
155
+
156
+ .brand-mark {
157
+ width: 30px;
158
+ height: 30px;
159
+ border-radius: 8px;
160
+ background: linear-gradient(135deg, var(--series-1), var(--series-3));
161
+ flex: none;
162
+ }
163
+
164
+ .brand h1 {
165
+ margin: 0;
166
+ font-size: 15px;
167
+ font-weight: 650;
168
+ letter-spacing: -0.01em;
169
+ }
170
+
171
+ .brand-sub {
172
+ margin: 0;
173
+ font-size: 12px;
174
+ color: var(--text-muted);
175
+ }
176
+
177
+ .topbar-actions {
178
+ display: flex;
179
+ align-items: center;
180
+ gap: 10px;
181
+ }
182
+
183
+ .rangeset,
184
+ .filterset {
185
+ display: inline-flex;
186
+ background: var(--raised);
187
+ border: 1px solid var(--border);
188
+ border-radius: var(--radius-sm);
189
+ padding: 2px;
190
+ gap: 2px;
191
+ }
192
+
193
+ .rangeset button,
194
+ .filterset button {
195
+ appearance: none;
196
+ border: 0;
197
+ background: transparent;
198
+ color: var(--text-secondary);
199
+ font: inherit;
200
+ font-size: 13px;
201
+ padding: 5px 12px;
202
+ border-radius: 4px;
203
+ cursor: pointer;
204
+ min-height: 30px;
205
+ }
206
+
207
+ .rangeset button:hover,
208
+ .filterset button:hover {
209
+ color: var(--text-primary);
210
+ }
211
+
212
+ .rangeset button[aria-pressed="true"],
213
+ .filterset button[aria-pressed="true"] {
214
+ background: var(--surface);
215
+ color: var(--text-primary);
216
+ font-weight: 600;
217
+ box-shadow: 0 1px 2px rgba(11, 11, 11, 0.08);
218
+ }
219
+
220
+ .icon-btn {
221
+ appearance: none;
222
+ width: 34px;
223
+ height: 34px;
224
+ border-radius: var(--radius-sm);
225
+ border: 1px solid var(--border);
226
+ background: var(--raised);
227
+ color: var(--text-secondary);
228
+ cursor: pointer;
229
+ font-size: 15px;
230
+ line-height: 1;
231
+ }
232
+ .icon-btn:hover {
233
+ color: var(--text-primary);
234
+ }
235
+
236
+ :focus-visible {
237
+ outline: 2px solid var(--series-1);
238
+ outline-offset: 2px;
239
+ }
240
+
241
+ /* ---------- Layout ---------- */
242
+
243
+ main {
244
+ max-width: 1240px;
245
+ margin: 0 auto;
246
+ padding: 24px;
247
+ display: grid;
248
+ gap: 20px;
249
+ }
250
+
251
+ .panel {
252
+ background: var(--surface);
253
+ border: 1px solid var(--border);
254
+ border-radius: var(--radius);
255
+ box-shadow: var(--shadow);
256
+ overflow: hidden;
257
+ }
258
+
259
+ .panel-head {
260
+ display: flex;
261
+ align-items: flex-start;
262
+ justify-content: space-between;
263
+ gap: 16px;
264
+ padding: 16px 18px;
265
+ border-bottom: 1px solid var(--border);
266
+ flex-wrap: wrap;
267
+ }
268
+
269
+ .panel-head h2 {
270
+ margin: 0;
271
+ font-size: 14px;
272
+ font-weight: 650;
273
+ }
274
+
275
+ .panel-sub {
276
+ margin: 2px 0 0;
277
+ font-size: 12px;
278
+ color: var(--text-muted);
279
+ }
280
+
281
+ .split {
282
+ display: grid;
283
+ grid-template-columns: 1fr 1fr;
284
+ gap: 20px;
285
+ /* Start-align so a short table doesn't stretch to match a tall neighbour,
286
+ leaving a block of dead whitespace under its last row. */
287
+ align-items: start;
288
+ }
289
+
290
+ @media (max-width: 900px) {
291
+ .split {
292
+ grid-template-columns: 1fr;
293
+ }
294
+ }
295
+
296
+ /* ---------- Hero ---------- */
297
+
298
+ .hero {
299
+ background: var(--surface);
300
+ border: 1px solid var(--border);
301
+ border-radius: var(--radius);
302
+ box-shadow: var(--shadow);
303
+ padding: 22px 24px;
304
+ display: flex;
305
+ align-items: center;
306
+ justify-content: space-between;
307
+ gap: 24px;
308
+ flex-wrap: wrap;
309
+ }
310
+
311
+ .hero-label {
312
+ margin: 0;
313
+ font-size: 12px;
314
+ text-transform: uppercase;
315
+ letter-spacing: 0.06em;
316
+ color: var(--text-muted);
317
+ font-weight: 600;
318
+ }
319
+
320
+ /* Proportional figures: tabular-nums makes a large value look loose. */
321
+ .hero-figure {
322
+ margin: 4px 0 0;
323
+ font-size: 48px;
324
+ line-height: 1.05;
325
+ font-weight: 680;
326
+ letter-spacing: -0.02em;
327
+ }
328
+
329
+ .hero-note {
330
+ margin: 6px 0 0;
331
+ font-size: 12px;
332
+ color: var(--text-muted);
333
+ }
334
+
335
+ .hero-side {
336
+ display: flex;
337
+ gap: 28px;
338
+ margin: 0;
339
+ flex-wrap: wrap;
340
+ }
341
+
342
+ .hero-side div {
343
+ min-width: 88px;
344
+ }
345
+
346
+ .hero-side dt {
347
+ font-size: 11px;
348
+ text-transform: uppercase;
349
+ letter-spacing: 0.05em;
350
+ color: var(--text-muted);
351
+ font-weight: 600;
352
+ }
353
+
354
+ .hero-side dd {
355
+ margin: 2px 0 0;
356
+ font-size: 18px;
357
+ font-weight: 600;
358
+ font-variant-numeric: tabular-nums;
359
+ }
360
+
361
+ /* ---------- Stat tiles ---------- */
362
+
363
+ .tiles {
364
+ display: grid;
365
+ grid-template-columns: repeat(4, 1fr);
366
+ gap: 16px;
367
+ }
368
+
369
+ @media (max-width: 900px) {
370
+ .tiles {
371
+ grid-template-columns: repeat(2, 1fr);
372
+ }
373
+ }
374
+
375
+ .tile {
376
+ background: var(--surface);
377
+ border: 1px solid var(--border);
378
+ border-radius: var(--radius);
379
+ padding: 16px 18px;
380
+ box-shadow: var(--shadow);
381
+ }
382
+
383
+ .tile-label {
384
+ margin: 0;
385
+ font-size: 12px;
386
+ color: var(--text-muted);
387
+ font-weight: 600;
388
+ text-transform: uppercase;
389
+ letter-spacing: 0.05em;
390
+ }
391
+
392
+ .tile-value {
393
+ margin: 6px 0 0;
394
+ font-size: 28px;
395
+ font-weight: 660;
396
+ letter-spacing: -0.015em;
397
+ }
398
+
399
+ .tile-sub {
400
+ margin: 2px 0 0;
401
+ font-size: 12px;
402
+ color: var(--text-muted);
403
+ }
404
+
405
+ /* ---------- Chart ---------- */
406
+
407
+ .chart-wrap {
408
+ position: relative;
409
+ padding: 16px 18px 8px;
410
+ }
411
+
412
+ #timeline {
413
+ width: 100%;
414
+ display: block;
415
+ }
416
+
417
+ .legend {
418
+ display: flex;
419
+ gap: 14px;
420
+ align-items: center;
421
+ font-size: 12px;
422
+ color: var(--text-secondary);
423
+ }
424
+
425
+ .legend-item {
426
+ display: inline-flex;
427
+ align-items: center;
428
+ gap: 6px;
429
+ }
430
+
431
+ .swatch {
432
+ width: 10px;
433
+ height: 10px;
434
+ border-radius: 3px;
435
+ display: inline-block;
436
+ }
437
+
438
+ .swatch-calls {
439
+ background: var(--series-1);
440
+ }
441
+
442
+ /* Errors use the reserved critical status step, never a categorical slot. */
443
+ .swatch-errors {
444
+ background: var(--status-critical);
445
+ }
446
+
447
+ .tooltip {
448
+ position: absolute;
449
+ pointer-events: none;
450
+ background: var(--text-primary);
451
+ color: var(--surface);
452
+ padding: 7px 10px;
453
+ border-radius: var(--radius-sm);
454
+ font-size: 12px;
455
+ line-height: 1.45;
456
+ white-space: nowrap;
457
+ opacity: 0;
458
+ transition: opacity 0.12s ease;
459
+ z-index: 4;
460
+ font-variant-numeric: tabular-nums;
461
+ }
462
+
463
+ .tooltip.is-visible {
464
+ opacity: 1;
465
+ }
466
+
467
+ .panel-note {
468
+ margin: 0;
469
+ padding: 0 18px 14px;
470
+ }
471
+
472
+ .linklike {
473
+ appearance: none;
474
+ background: none;
475
+ border: 0;
476
+ padding: 0;
477
+ color: var(--text-secondary);
478
+ font: inherit;
479
+ font-size: 12px;
480
+ text-decoration: underline;
481
+ cursor: pointer;
482
+ }
483
+ .linklike:hover {
484
+ color: var(--text-primary);
485
+ }
486
+
487
+ /* ---------- Tables ---------- */
488
+
489
+ .table-wrap {
490
+ overflow-x: auto;
491
+ }
492
+
493
+ .table-wrap.is-hidden {
494
+ display: none;
495
+ }
496
+
497
+ table {
498
+ width: 100%;
499
+ border-collapse: collapse;
500
+ font-size: 13px;
501
+ }
502
+
503
+ thead th {
504
+ text-align: left;
505
+ font-size: 11px;
506
+ text-transform: uppercase;
507
+ letter-spacing: 0.05em;
508
+ color: var(--text-muted);
509
+ font-weight: 600;
510
+ padding: 10px 14px;
511
+ border-bottom: 1px solid var(--border);
512
+ white-space: nowrap;
513
+ background: var(--surface);
514
+ }
515
+
516
+ tbody td {
517
+ padding: 10px 14px;
518
+ border-bottom: 1px solid var(--grid);
519
+ vertical-align: top;
520
+ }
521
+
522
+ tbody tr:last-child td {
523
+ border-bottom: 0;
524
+ }
525
+
526
+ tbody tr:hover td {
527
+ background: var(--raised);
528
+ }
529
+
530
+ .num {
531
+ text-align: right;
532
+ font-variant-numeric: tabular-nums;
533
+ }
534
+
535
+ td.empty {
536
+ color: var(--text-muted);
537
+ text-align: center;
538
+ padding: 28px 14px;
539
+ }
540
+
541
+ .mono {
542
+ font-family: var(--mono);
543
+ font-size: 12px;
544
+ }
545
+
546
+ .truncate {
547
+ max-width: 420px;
548
+ overflow: hidden;
549
+ text-overflow: ellipsis;
550
+ white-space: nowrap;
551
+ display: block;
552
+ }
553
+
554
+ /* ---------- Status pills ---------- */
555
+
556
+ /* Icon + label pairing, never color alone: on the light surface several
557
+ status steps sit below 3:1, and this is the documented mitigation. */
558
+ .pill {
559
+ display: inline-flex;
560
+ align-items: center;
561
+ gap: 5px;
562
+ font-size: 12px;
563
+ font-weight: 600;
564
+ padding: 2px 8px;
565
+ border-radius: 999px;
566
+ border: 1px solid transparent;
567
+ white-space: nowrap;
568
+ }
569
+
570
+ .pill::before {
571
+ font-size: 10px;
572
+ line-height: 1;
573
+ }
574
+
575
+ .pill-success {
576
+ color: var(--success-text);
577
+ background: color-mix(in srgb, var(--status-good) 12%, transparent);
578
+ border-color: color-mix(in srgb, var(--status-good) 34%, transparent);
579
+ }
580
+ .pill-success::before {
581
+ content: "\2713";
582
+ }
583
+
584
+ .pill-error {
585
+ color: var(--status-critical);
586
+ background: color-mix(in srgb, var(--status-critical) 12%, transparent);
587
+ border-color: color-mix(in srgb, var(--status-critical) 34%, transparent);
588
+ }
589
+ .pill-error::before {
590
+ content: "\2717";
591
+ }
592
+
593
+ .pill-blocked {
594
+ color: var(--status-serious);
595
+ background: color-mix(in srgb, var(--status-serious) 14%, transparent);
596
+ border-color: color-mix(in srgb, var(--status-serious) 38%, transparent);
597
+ }
598
+ .pill-blocked::before {
599
+ content: "\26D4";
600
+ }
601
+
602
+ .pill-pending {
603
+ color: var(--text-secondary);
604
+ background: var(--raised);
605
+ border-color: var(--border);
606
+ }
607
+ .pill-pending::before {
608
+ content: "\25CB";
609
+ }
610
+
611
+ .badge {
612
+ display: inline-block;
613
+ font-size: 11px;
614
+ padding: 1px 6px;
615
+ border-radius: 4px;
616
+ background: var(--raised);
617
+ border: 1px solid var(--border);
618
+ color: var(--text-secondary);
619
+ margin-left: 6px;
620
+ }
621
+
622
+ /* ---------- Footer ---------- */
623
+
624
+ .footer {
625
+ max-width: 1240px;
626
+ margin: 0 auto;
627
+ padding: 8px 24px 32px;
628
+ display: flex;
629
+ justify-content: space-between;
630
+ gap: 16px;
631
+ font-size: 12px;
632
+ color: var(--text-muted);
633
+ flex-wrap: wrap;
634
+ }
635
+
636
+ .footer code {
637
+ font-family: var(--mono);
638
+ font-size: 11px;
639
+ }
640
+
641
+ .conn {
642
+ display: inline-flex;
643
+ align-items: center;
644
+ gap: 6px;
645
+ }
646
+
647
+ .conn::before {
648
+ content: "";
649
+ width: 7px;
650
+ height: 7px;
651
+ border-radius: 50%;
652
+ background: var(--text-muted);
653
+ }
654
+
655
+ .conn.is-live::before {
656
+ background: var(--status-good);
657
+ }
658
+
659
+ .conn.is-down::before {
660
+ background: var(--status-critical);
661
+ }
662
+
663
+ @media (prefers-reduced-motion: reduce) {
664
+ * {
665
+ transition-duration: 0.01ms !important;
666
+ animation-duration: 0.01ms !important;
667
+ }
668
+ }