@oh-my-pi-zen/omp-stats 16.3.6-zen.1

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 (120) hide show
  1. package/CHANGELOG.md +197 -0
  2. package/README.md +82 -0
  3. package/build.ts +95 -0
  4. package/dist/client/index.css +1 -0
  5. package/dist/client/index.html +24 -0
  6. package/dist/client/index.js +257 -0
  7. package/dist/client/styles.css +1656 -0
  8. package/dist/types/aggregator.d.ts +87 -0
  9. package/dist/types/client/App.d.ts +1 -0
  10. package/dist/types/client/api.d.ts +21 -0
  11. package/dist/types/client/app/AppLayout.d.ts +16 -0
  12. package/dist/types/client/app/NavRail.d.ts +7 -0
  13. package/dist/types/client/app/RangeControl.d.ts +7 -0
  14. package/dist/types/client/app/SyncButton.d.ts +14 -0
  15. package/dist/types/client/app/ThemeToggle.d.ts +1 -0
  16. package/dist/types/client/app/TopBar.d.ts +15 -0
  17. package/dist/types/client/app/routes.d.ts +12 -0
  18. package/dist/types/client/components/AgentTokenShare.d.ts +5 -0
  19. package/dist/types/client/components/chart-shared.d.ts +173 -0
  20. package/dist/types/client/components/models-table-shared.d.ts +175 -0
  21. package/dist/types/client/components/range-meta.d.ts +21 -0
  22. package/dist/types/client/data/charts.d.ts +1 -0
  23. package/dist/types/client/data/formatters.d.ts +8 -0
  24. package/dist/types/client/data/useHashRoute.d.ts +8 -0
  25. package/dist/types/client/data/useResource.d.ts +13 -0
  26. package/dist/types/client/data/view-models.d.ts +67 -0
  27. package/dist/types/client/index.d.ts +2 -0
  28. package/dist/types/client/routes/BehaviorRoute.d.ts +7 -0
  29. package/dist/types/client/routes/CostsRoute.d.ts +7 -0
  30. package/dist/types/client/routes/ErrorsRoute.d.ts +8 -0
  31. package/dist/types/client/routes/GainRoute.d.ts +7 -0
  32. package/dist/types/client/routes/ModelsRoute.d.ts +7 -0
  33. package/dist/types/client/routes/OverviewRoute.d.ts +8 -0
  34. package/dist/types/client/routes/ProjectsRoute.d.ts +7 -0
  35. package/dist/types/client/routes/RequestsRoute.d.ts +8 -0
  36. package/dist/types/client/routes/ToolsRoute.d.ts +7 -0
  37. package/dist/types/client/routes/index.d.ts +9 -0
  38. package/dist/types/client/types.d.ts +63 -0
  39. package/dist/types/client/ui/AsyncBoundary.d.ts +12 -0
  40. package/dist/types/client/ui/DataTable.d.ts +17 -0
  41. package/dist/types/client/ui/EmptyState.d.ts +7 -0
  42. package/dist/types/client/ui/ErrorState.d.ts +6 -0
  43. package/dist/types/client/ui/JsonBlock.d.ts +7 -0
  44. package/dist/types/client/ui/MetricCluster.d.ts +5 -0
  45. package/dist/types/client/ui/Panel.d.ts +7 -0
  46. package/dist/types/client/ui/RequestDrawer.d.ts +5 -0
  47. package/dist/types/client/ui/SegmentedControl.d.ts +12 -0
  48. package/dist/types/client/ui/Skeleton.d.ts +8 -0
  49. package/dist/types/client/ui/StatusPill.d.ts +7 -0
  50. package/dist/types/client/ui/index.d.ts +11 -0
  51. package/dist/types/client/useSystemTheme.d.ts +11 -0
  52. package/dist/types/db.d.ts +144 -0
  53. package/dist/types/embedded-client.d.ts +18 -0
  54. package/dist/types/gain-aggregator.d.ts +26 -0
  55. package/dist/types/index.d.ts +7 -0
  56. package/dist/types/parser.d.ts +53 -0
  57. package/dist/types/server.d.ts +7 -0
  58. package/dist/types/shared-types.d.ts +301 -0
  59. package/dist/types/sync-worker.d.ts +31 -0
  60. package/dist/types/types.d.ts +164 -0
  61. package/dist/types/user-metrics.d.ts +72 -0
  62. package/package.json +95 -0
  63. package/src/aggregator.ts +501 -0
  64. package/src/client/App.tsx +109 -0
  65. package/src/client/api.ts +102 -0
  66. package/src/client/app/AppLayout.tsx +93 -0
  67. package/src/client/app/NavRail.tsx +44 -0
  68. package/src/client/app/RangeControl.tsx +39 -0
  69. package/src/client/app/SyncButton.tsx +75 -0
  70. package/src/client/app/ThemeToggle.tsx +37 -0
  71. package/src/client/app/TopBar.tsx +73 -0
  72. package/src/client/app/routes.ts +69 -0
  73. package/src/client/components/AgentTokenShare.tsx +68 -0
  74. package/src/client/components/chart-shared.tsx +257 -0
  75. package/src/client/components/models-table-shared.tsx +255 -0
  76. package/src/client/components/range-meta.ts +73 -0
  77. package/src/client/css.d.ts +1 -0
  78. package/src/client/data/charts.ts +14 -0
  79. package/src/client/data/formatters.ts +45 -0
  80. package/src/client/data/useHashRoute.ts +87 -0
  81. package/src/client/data/useResource.ts +154 -0
  82. package/src/client/data/view-models.ts +251 -0
  83. package/src/client/index.tsx +10 -0
  84. package/src/client/routes/BehaviorRoute.tsx +623 -0
  85. package/src/client/routes/CostsRoute.tsx +234 -0
  86. package/src/client/routes/ErrorsRoute.tsx +118 -0
  87. package/src/client/routes/GainRoute.tsx +226 -0
  88. package/src/client/routes/ModelsRoute.tsx +430 -0
  89. package/src/client/routes/OverviewRoute.tsx +342 -0
  90. package/src/client/routes/ProjectsRoute.tsx +163 -0
  91. package/src/client/routes/RequestsRoute.tsx +123 -0
  92. package/src/client/routes/ToolsRoute.tsx +463 -0
  93. package/src/client/routes/index.ts +9 -0
  94. package/src/client/styles.css +1330 -0
  95. package/src/client/types.ts +80 -0
  96. package/src/client/ui/AsyncBoundary.tsx +54 -0
  97. package/src/client/ui/DataTable.tsx +122 -0
  98. package/src/client/ui/EmptyState.tsx +16 -0
  99. package/src/client/ui/ErrorState.tsx +25 -0
  100. package/src/client/ui/JsonBlock.tsx +75 -0
  101. package/src/client/ui/MetricCluster.tsx +67 -0
  102. package/src/client/ui/Panel.tsx +24 -0
  103. package/src/client/ui/RequestDrawer.tsx +208 -0
  104. package/src/client/ui/SegmentedControl.tsx +36 -0
  105. package/src/client/ui/Skeleton.tsx +17 -0
  106. package/src/client/ui/StatusPill.tsx +15 -0
  107. package/src/client/ui/index.ts +11 -0
  108. package/src/client/useSystemTheme.ts +87 -0
  109. package/src/db.ts +1530 -0
  110. package/src/embedded-client.generated.txt +0 -0
  111. package/src/embedded-client.ts +26 -0
  112. package/src/gain-aggregator.ts +281 -0
  113. package/src/index.ts +194 -0
  114. package/src/parser.ts +450 -0
  115. package/src/server.ts +352 -0
  116. package/src/shared-types.ts +323 -0
  117. package/src/sync-worker.ts +40 -0
  118. package/src/types.ts +171 -0
  119. package/src/user-metrics.ts +685 -0
  120. package/tailwind.config.js +40 -0
@@ -0,0 +1,1330 @@
1
+ @import "tailwindcss/index.css";
2
+
3
+ /* ==========================================================================
4
+ OMP Theme Variables & Color Scheme
5
+ ========================================================================== */
6
+ :root {
7
+ color-scheme: dark;
8
+ /* OMP brand palette — packages/collab-web/src/styles/tokens.css:
9
+ deep-purple surfaces (hue 307), pink accent #ed4abf, cyan focus ring #5ad8e6. */
10
+ --page: oklch(0.16 0.02 307);
11
+ --surface: oklch(0.19 0.022 307);
12
+ --surface-2: oklch(0.235 0.026 307);
13
+ --border: oklch(1 0 0 / 9%);
14
+ --border-strong: oklch(1 0 0 / 13%);
15
+ --text: oklch(0.92 0.01 307);
16
+ --muted: oklch(0.71 0.016 307);
17
+ --dim: oklch(0.53 0.018 307);
18
+ --accent: oklch(0.674 0.23 341); /* brand pink #ed4abf */
19
+ --accent-fg: oklch(0.2 0.07 341); /* ink on accent fills */
20
+ --accent-muted: oklch(0.674 0.23 341 / 18%);
21
+ --link: oklch(0.817 0.112 205); /* brand cyan #5ad8e6 */
22
+ --success: oklch(0.76 0.14 150);
23
+ --danger: oklch(0.66 0.19 25);
24
+ --warning: oklch(0.79 0.14 85);
25
+
26
+ /* Bridge the view components' token vocabulary to the OMP base tokens so
27
+ muted/secondary text and semantic accents resolve instead of silently
28
+ falling back to inherited text color. Re-resolve per theme via var(). */
29
+ --text-primary: var(--text);
30
+ --text-secondary: var(--muted);
31
+ --text-muted: var(--dim);
32
+ --border-subtle: var(--border);
33
+ --accent-red: var(--danger);
34
+ --accent-green: var(--success);
35
+ --accent-cyan: var(--link);
36
+ --bg-hover: var(--surface-2);
37
+ --bg-elevated: var(--surface-2);
38
+
39
+ --radius-sm: 3px;
40
+ --radius-md: 6px;
41
+ --radius-lg: 8px;
42
+ }
43
+
44
+ /* System-default fallback before JS sets data-theme; an explicit data-theme
45
+ (set by the toggle / anti-flash script) opts out so the override wins. */
46
+ @media (prefers-color-scheme: light) {
47
+ :root:not([data-theme]) {
48
+ color-scheme: light;
49
+ --page: oklch(0.985 0.004 307);
50
+ --surface: oklch(1 0 0);
51
+ --surface-2: oklch(0.965 0.006 307);
52
+ --border: oklch(0 0 0 / 10%);
53
+ --border-strong: oklch(0 0 0 / 15%);
54
+ --text: oklch(0.26 0.03 307);
55
+ --muted: oklch(0.46 0.03 307);
56
+ --dim: oklch(0.58 0.025 307);
57
+ --accent: oklch(0.62 0.23 341);
58
+ --accent-fg: oklch(0.99 0.01 341);
59
+ --accent-muted: oklch(0.62 0.23 341 / 14%);
60
+ --link: oklch(0.58 0.13 230);
61
+ --success: oklch(0.55 0.13 150);
62
+ --danger: oklch(0.55 0.19 25);
63
+ --warning: oklch(0.6 0.13 85);
64
+ }
65
+ }
66
+
67
+ /* Explicit theme override (toggle or persisted preference). */
68
+ [data-theme="light"] {
69
+ color-scheme: light;
70
+ --page: oklch(0.985 0.004 307);
71
+ --surface: oklch(1 0 0);
72
+ --surface-2: oklch(0.965 0.006 307);
73
+ --border: oklch(0 0 0 / 10%);
74
+ --border-strong: oklch(0 0 0 / 15%);
75
+ --text: oklch(0.26 0.03 307);
76
+ --muted: oklch(0.46 0.03 307);
77
+ --dim: oklch(0.58 0.025 307);
78
+ --accent: oklch(0.62 0.23 341);
79
+ --accent-fg: oklch(0.99 0.01 341);
80
+ --accent-muted: oklch(0.62 0.23 341 / 14%);
81
+ --link: oklch(0.58 0.13 230);
82
+ --success: oklch(0.55 0.13 150);
83
+ --danger: oklch(0.55 0.19 25);
84
+ --warning: oklch(0.6 0.13 85);
85
+ }
86
+
87
+ /* ==========================================================================
88
+ Base Styles
89
+ ========================================================================== */
90
+ @layer base {
91
+ * {
92
+ box-sizing: border-box;
93
+ }
94
+
95
+ html {
96
+ -webkit-font-smoothing: antialiased;
97
+ -moz-osx-font-smoothing: grayscale;
98
+ }
99
+
100
+ body {
101
+ font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
102
+ background: var(--page);
103
+ color: var(--text);
104
+ margin: 0;
105
+ min-height: 100vh;
106
+ }
107
+
108
+ /* Accessible focus ring style */
109
+ button:focus-visible,
110
+ a:focus-visible,
111
+ [tabindex]:focus-visible {
112
+ outline: 2px solid var(--link);
113
+ outline-offset: 2px;
114
+ }
115
+ }
116
+
117
+ /* ==========================================================================
118
+ Layout Components
119
+ ========================================================================== */
120
+ .stats-app-container {
121
+ display: flex;
122
+ min-height: 100vh;
123
+ background: var(--page);
124
+ color: var(--text);
125
+ }
126
+
127
+ /* Navigation Rail (Sidebar) */
128
+ .stats-nav-rail {
129
+ width: 240px;
130
+ background: var(--surface);
131
+ border-right: 1px solid var(--border);
132
+ display: flex;
133
+ flex-direction: column;
134
+ flex-shrink: 0;
135
+ }
136
+
137
+ .stats-desktop-nav {
138
+ display: flex;
139
+ }
140
+
141
+ @media (max-width: 1023px) {
142
+ .stats-desktop-nav {
143
+ display: none;
144
+ }
145
+ }
146
+
147
+ .stats-nav-rail-header {
148
+ padding: 20px 24px;
149
+ border-bottom: 1px solid var(--border);
150
+ height: 56px;
151
+ display: flex;
152
+ align-items: center;
153
+ }
154
+
155
+ .stats-logo-container {
156
+ display: flex;
157
+ flex-direction: column;
158
+ }
159
+
160
+ .stats-logo-text {
161
+ font-size: 14px;
162
+ font-weight: 700;
163
+ letter-spacing: 0.1em;
164
+ color: var(--text);
165
+ }
166
+
167
+ .stats-logo-subtext {
168
+ font-size: 10px;
169
+ text-transform: uppercase;
170
+ letter-spacing: 0.05em;
171
+ color: var(--muted);
172
+ }
173
+
174
+ .stats-nav-rail-menu {
175
+ flex: 1;
176
+ padding: 16px 12px;
177
+ display: flex;
178
+ flex-direction: column;
179
+ gap: 4px;
180
+ }
181
+
182
+ .stats-nav-rail-item {
183
+ display: flex;
184
+ align-items: center;
185
+ gap: 12px;
186
+ padding: 10px 16px;
187
+ font-size: 13px;
188
+ font-weight: 500;
189
+ color: var(--muted);
190
+ background: transparent;
191
+ border: none;
192
+ border-radius: var(--radius-md);
193
+ cursor: pointer;
194
+ text-align: left;
195
+ transition: all 0.15s ease;
196
+ }
197
+
198
+ .stats-nav-rail-item:hover {
199
+ color: var(--text);
200
+ background: var(--surface-2);
201
+ }
202
+
203
+ .stats-nav-rail-item[data-active="true"] {
204
+ color: var(--accent);
205
+ background: var(--accent-muted);
206
+ position: relative;
207
+ }
208
+
209
+ .stats-nav-rail-item[data-active="true"]::before {
210
+ content: "";
211
+ position: absolute;
212
+ left: 0;
213
+ top: 50%;
214
+ height: 18px;
215
+ width: 3px;
216
+ border-radius: 0 3px 3px 0;
217
+ background: var(--accent);
218
+ transform: translateY(-50%);
219
+ }
220
+
221
+ .stats-nav-rail-item-icon {
222
+ flex-shrink: 0;
223
+ }
224
+
225
+ .stats-nav-rail-footer {
226
+ padding: 16px 24px;
227
+ border-top: 1px solid var(--border);
228
+ }
229
+
230
+ .stats-version-tag {
231
+ font-size: 11px;
232
+ color: var(--dim);
233
+ }
234
+
235
+ /* Main Content Area */
236
+ .stats-main-pane {
237
+ flex: 1;
238
+ display: flex;
239
+ flex-direction: column;
240
+ min-width: 0;
241
+ }
242
+
243
+ .stats-top-bar {
244
+ height: 56px;
245
+ background: var(--surface);
246
+ border-bottom: 1px solid var(--border);
247
+ display: flex;
248
+ align-items: center;
249
+ justify-content: space-between;
250
+ padding: 0 24px;
251
+ }
252
+
253
+ @media (max-width: 767px) {
254
+ .stats-top-bar {
255
+ padding: 0 16px;
256
+ flex-wrap: wrap;
257
+ height: auto;
258
+ min-height: 56px;
259
+ padding-top: 8px;
260
+ padding-bottom: 8px;
261
+ gap: 12px;
262
+ }
263
+ }
264
+
265
+ .stats-top-bar-left {
266
+ display: flex;
267
+ align-items: center;
268
+ gap: 12px;
269
+ }
270
+
271
+ .stats-mobile-menu-btn {
272
+ display: none;
273
+ background: transparent;
274
+ border: none;
275
+ color: var(--text);
276
+ padding: 4px;
277
+ cursor: pointer;
278
+ }
279
+
280
+ @media (max-width: 1023px) {
281
+ .stats-mobile-menu-btn {
282
+ display: inline-flex;
283
+ align-items: center;
284
+ justify-content: center;
285
+ }
286
+ }
287
+
288
+ .stats-page-title {
289
+ font-size: 16px;
290
+ font-weight: 600;
291
+ color: var(--text);
292
+ margin: 0;
293
+ }
294
+
295
+ .stats-top-bar-right {
296
+ display: flex;
297
+ align-items: center;
298
+ gap: 16px;
299
+ }
300
+
301
+ @media (max-width: 767px) {
302
+ .stats-top-bar-right {
303
+ width: 100%;
304
+ justify-content: space-between;
305
+ gap: 8px;
306
+ }
307
+ }
308
+
309
+ .stats-top-bar-meta {
310
+ display: flex;
311
+ align-items: center;
312
+ }
313
+
314
+ .stats-last-updated {
315
+ font-size: 11px;
316
+ color: var(--dim);
317
+ font-variant-numeric: tabular-nums;
318
+ }
319
+
320
+ .stats-content-area {
321
+ flex: 1;
322
+ overflow-y: auto;
323
+ }
324
+
325
+ .stats-content-inner {
326
+ max-width: 1560px;
327
+ margin: 0 auto;
328
+ padding: 24px;
329
+ display: flex;
330
+ flex-direction: column;
331
+ gap: 24px;
332
+ }
333
+
334
+ @media (max-width: 767px) {
335
+ .stats-content-inner {
336
+ padding: 16px;
337
+ gap: 16px;
338
+ }
339
+ }
340
+
341
+ /* Mobile Nav Drawer */
342
+ .stats-mobile-drawer-overlay {
343
+ position: fixed;
344
+ inset: 0;
345
+ background: rgba(0, 0, 0, 0.4);
346
+ backdrop-filter: none; /* No decorative blurs */
347
+ z-index: 100;
348
+ }
349
+
350
+ .stats-mobile-drawer {
351
+ position: absolute;
352
+ left: 0;
353
+ top: 0;
354
+ bottom: 0;
355
+ width: 260px;
356
+ background: var(--surface);
357
+ border-right: 1px solid var(--border);
358
+ display: flex;
359
+ flex-direction: column;
360
+ z-index: 101;
361
+ animation: slideIn 0.2s ease-out;
362
+ }
363
+
364
+ @keyframes slideIn {
365
+ from { transform: translateX(-100%); }
366
+ to { transform: translateX(0); }
367
+ }
368
+
369
+ .stats-mobile-drawer-header {
370
+ height: 56px;
371
+ display: flex;
372
+ align-items: center;
373
+ justify-content: space-between;
374
+ padding: 0 16px 0 24px;
375
+ border-bottom: 1px solid var(--border);
376
+ }
377
+
378
+ .stats-mobile-nav {
379
+ display: flex;
380
+ height: calc(100% - 56px);
381
+ }
382
+
383
+ /* ==========================================================================
384
+ UI Primitives & Styles
385
+ ========================================================================== */
386
+
387
+ /* Button */
388
+ .stats-button {
389
+ display: inline-flex;
390
+ align-items: center;
391
+ justify-content: center;
392
+ gap: 8px;
393
+ padding: 8px 14px;
394
+ font-size: 13px;
395
+ font-weight: 500;
396
+ border-radius: var(--radius-md);
397
+ border: 1px solid transparent;
398
+ cursor: pointer;
399
+ transition: all 0.15s ease;
400
+ font-family: inherit;
401
+ }
402
+
403
+ .stats-button:active:not(:disabled) {
404
+ transform: translateY(1px);
405
+ }
406
+
407
+ .stats-button-primary {
408
+ background: var(--accent);
409
+ color: var(--accent-fg);
410
+ }
411
+
412
+ .stats-button-primary:hover:not(:disabled) {
413
+ opacity: 0.9;
414
+ }
415
+
416
+ .stats-button-primary:disabled {
417
+ opacity: 0.5;
418
+ cursor: not-allowed;
419
+ }
420
+
421
+ .stats-button-secondary {
422
+ background: var(--surface-2);
423
+ color: var(--text);
424
+ border-color: var(--border);
425
+ }
426
+
427
+ .stats-button-secondary:hover:not(:disabled) {
428
+ background: var(--border);
429
+ }
430
+
431
+ .stats-button-secondary:disabled {
432
+ opacity: 0.5;
433
+ cursor: not-allowed;
434
+ }
435
+
436
+ /* RangeControl */
437
+ .stats-range-control {
438
+ display: flex;
439
+ background: var(--surface-2);
440
+ border: 1px solid var(--border);
441
+ border-radius: var(--radius-md);
442
+ padding: 2px;
443
+ }
444
+
445
+ .stats-range-control-btn {
446
+ padding: 4px 10px;
447
+ font-size: 12px;
448
+ font-weight: 500;
449
+ color: var(--muted);
450
+ background: transparent;
451
+ border: none;
452
+ border-radius: var(--radius-sm);
453
+ cursor: pointer;
454
+ transition: all 0.1s ease;
455
+ }
456
+
457
+ .stats-range-control-btn:hover {
458
+ color: var(--text);
459
+ }
460
+
461
+ .stats-range-control-btn[data-active="true"] {
462
+ color: var(--text);
463
+ background: var(--surface);
464
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.18);
465
+ }
466
+
467
+ /* Sync Button & Container */
468
+ .stats-sync-container {
469
+ display: flex;
470
+ align-items: center;
471
+ gap: 12px;
472
+ }
473
+
474
+ .stats-sync-status-msg {
475
+ font-size: 11px;
476
+ font-variant-numeric: tabular-nums;
477
+ max-width: 200px;
478
+ white-space: nowrap;
479
+ overflow: hidden;
480
+ text-overflow: ellipsis;
481
+ }
482
+
483
+ .stats-sync-status-msg[data-type="success"] {
484
+ color: var(--success);
485
+ }
486
+
487
+ .stats-sync-status-msg[data-type="error"] {
488
+ color: var(--danger);
489
+ }
490
+
491
+ .stats-sync-icon {
492
+ flex-shrink: 0;
493
+ }
494
+
495
+ .stats-spin {
496
+ animation: spin 1s linear infinite;
497
+ }
498
+
499
+ @keyframes spin {
500
+ to { transform: rotate(360deg); }
501
+ }
502
+
503
+ /* Panel */
504
+ .stats-panel {
505
+ background: var(--surface);
506
+ border: 1px solid var(--border);
507
+ border-radius: var(--radius-lg);
508
+ display: flex;
509
+ flex-direction: column;
510
+ }
511
+
512
+ .stats-panel-header {
513
+ padding: 16px 20px;
514
+ border-bottom: 1px solid var(--border);
515
+ display: flex;
516
+ align-items: center;
517
+ justify-content: space-between;
518
+ gap: 16px;
519
+ }
520
+
521
+ @media (max-width: 480px) {
522
+ .stats-panel-header {
523
+ flex-direction: column;
524
+ align-items: flex-start;
525
+ gap: 8px;
526
+ }
527
+ }
528
+
529
+ .stats-panel-header-titles {
530
+ display: flex;
531
+ flex-direction: column;
532
+ }
533
+
534
+ .stats-panel-title {
535
+ font-size: 14px;
536
+ font-weight: 600;
537
+ color: var(--text);
538
+ margin: 0;
539
+ }
540
+
541
+ .stats-panel-subtitle {
542
+ font-size: 12px;
543
+ color: var(--muted);
544
+ margin: 2px 0 0 0;
545
+ }
546
+
547
+ .stats-panel-actions {
548
+ display: flex;
549
+ align-items: center;
550
+ gap: 12px;
551
+ }
552
+
553
+ .stats-panel-body {
554
+ padding: 20px;
555
+ }
556
+
557
+ /* Metric Cluster (Overview Dashboard KPI Grid) */
558
+ .stats-metric-cluster {
559
+ display: flex;
560
+ flex-direction: column;
561
+ gap: 16px;
562
+ }
563
+
564
+ .stats-metric-primary-grid {
565
+ display: grid;
566
+ grid-template-columns: repeat(4, 1fr);
567
+ gap: 16px;
568
+ }
569
+
570
+ @media (max-width: 1023px) {
571
+ .stats-metric-primary-grid {
572
+ grid-template-columns: repeat(2, 1fr);
573
+ }
574
+ }
575
+
576
+ @media (max-width: 480px) {
577
+ .stats-metric-primary-grid {
578
+ grid-template-columns: 1fr;
579
+ }
580
+ }
581
+
582
+ .stats-metric-secondary-grid {
583
+ display: grid;
584
+ grid-template-columns: repeat(6, 1fr);
585
+ gap: 12px;
586
+ }
587
+
588
+ @media (max-width: 1023px) {
589
+ .stats-metric-secondary-grid {
590
+ grid-template-columns: repeat(3, 1fr);
591
+ }
592
+ }
593
+
594
+ @media (max-width: 600px) {
595
+ .stats-metric-secondary-grid {
596
+ grid-template-columns: repeat(2, 1fr);
597
+ }
598
+ }
599
+
600
+ .stats-metric-card {
601
+ background: var(--surface);
602
+ border: 1px solid var(--border);
603
+ border-radius: var(--radius-lg);
604
+ padding: 16px;
605
+ display: flex;
606
+ flex-direction: column;
607
+ justify-content: space-between;
608
+ }
609
+
610
+ .stats-metric-card.primary {
611
+ padding: 20px 18px;
612
+ }
613
+
614
+ .stats-metric-card.primary .stats-metric-label {
615
+ color: var(--accent);
616
+ }
617
+
618
+ .stats-metric-card.secondary {
619
+ padding: 12px 14px;
620
+ }
621
+
622
+ .stats-metric-label {
623
+ font-size: 11px;
624
+ font-weight: 600;
625
+ text-transform: uppercase;
626
+ letter-spacing: 0.05em;
627
+ color: var(--muted);
628
+ margin-bottom: 8px;
629
+ }
630
+
631
+ .stats-metric-value {
632
+ font-size: 20px;
633
+ font-weight: 700;
634
+ color: var(--text);
635
+ font-variant-numeric: tabular-nums;
636
+ }
637
+
638
+ .stats-metric-card.secondary .stats-metric-value {
639
+ font-size: 15px;
640
+ font-weight: 600;
641
+ }
642
+
643
+ /* Data Table Component */
644
+ .stats-table-wrapper {
645
+ width: 100%;
646
+ }
647
+
648
+ .stats-table-container {
649
+ width: 100%;
650
+ overflow-x: auto;
651
+ }
652
+
653
+ .stats-table {
654
+ width: 100%;
655
+ border-collapse: collapse;
656
+ font-size: 13px;
657
+ font-variant-numeric: tabular-nums;
658
+ }
659
+
660
+ .stats-table-th {
661
+ font-size: 11px;
662
+ font-weight: 600;
663
+ text-transform: uppercase;
664
+ letter-spacing: 0.05em;
665
+ color: var(--muted);
666
+ padding: 12px 16px;
667
+ border-bottom: 2px solid var(--border);
668
+ }
669
+
670
+ .stats-table-td {
671
+ padding: 10px 16px;
672
+ border-bottom: 1px solid var(--border);
673
+ color: var(--text);
674
+ }
675
+
676
+ .stats-table-tr {
677
+ background: transparent;
678
+ }
679
+
680
+ .stats-table-tr-clickable {
681
+ cursor: pointer;
682
+ transition: background 0.12s ease, box-shadow 0.12s ease;
683
+ }
684
+
685
+ .stats-table-tr-clickable:hover {
686
+ background: var(--surface-2);
687
+ box-shadow: inset 2px 0 0 var(--accent);
688
+ }
689
+
690
+ .stats-text-left {
691
+ text-align: left;
692
+ }
693
+
694
+ .stats-text-right {
695
+ text-align: right;
696
+ }
697
+
698
+ .stats-table-empty {
699
+ padding: 40px;
700
+ text-align: center;
701
+ color: var(--muted);
702
+ font-size: 13px;
703
+ border: 1px dashed var(--border);
704
+ border-radius: var(--radius-lg);
705
+ }
706
+
707
+ /* Project progress bars */
708
+ .stats-progress-bar-track {
709
+ background: var(--surface-2);
710
+ border-radius: 999px;
711
+ overflow: hidden;
712
+ }
713
+
714
+ .stats-progress-bar-fill {
715
+ height: 100%;
716
+ border-radius: inherit;
717
+ transition: width 0.18s ease;
718
+ }
719
+
720
+ .stats-progress-bar-fill[data-variant="link"] {
721
+ background: var(--link);
722
+ }
723
+
724
+ .stats-progress-bar-fill[data-variant="success"] {
725
+ background: var(--success);
726
+ }
727
+
728
+ .stats-table-mobile-only {
729
+ display: none;
730
+ }
731
+
732
+ /* Match .stats-table-container so mobile-card tables also contain horizontal
733
+ overflow instead of spilling the page body on narrow desktops (768-1023px). */
734
+ .stats-table-desktop-only {
735
+ width: 100%;
736
+ overflow-x: auto;
737
+ }
738
+
739
+ @media (max-width: 767px) {
740
+ .stats-table-desktop-only {
741
+ display: none;
742
+ }
743
+ .stats-table-mobile-only {
744
+ display: block;
745
+ }
746
+ }
747
+
748
+ .stats-table-mobile-list {
749
+ display: flex;
750
+ flex-direction: column;
751
+ gap: 12px;
752
+ }
753
+
754
+ .stats-table-mobile-card-wrapper {
755
+ background: var(--surface);
756
+ border: 1px solid var(--border);
757
+ border-radius: var(--radius-lg);
758
+ padding: 14px;
759
+ }
760
+
761
+ /* Status Pill */
762
+ .stats-status-pill {
763
+ display: inline-flex;
764
+ align-items: center;
765
+ justify-content: center;
766
+ padding: 2px 8px;
767
+ font-size: 11px;
768
+ font-weight: 600;
769
+ border-radius: 100px;
770
+ line-height: 1.2;
771
+ }
772
+
773
+ .stats-status-pill[data-variant="success"] {
774
+ background: color-mix(in srgb, var(--success) 18%, transparent);
775
+ color: var(--success);
776
+ }
777
+
778
+ .stats-status-pill[data-variant="danger"] {
779
+ background: color-mix(in srgb, var(--danger) 18%, transparent);
780
+ color: var(--danger);
781
+ }
782
+
783
+ .stats-status-pill[data-variant="warning"] {
784
+ background: color-mix(in srgb, var(--warning) 18%, transparent);
785
+ color: var(--warning);
786
+ }
787
+
788
+ .stats-status-pill[data-variant="info"] {
789
+ background: color-mix(in srgb, var(--link) 18%, transparent);
790
+ color: var(--link);
791
+ }
792
+
793
+ .stats-status-pill[data-variant="default"] {
794
+ background: var(--surface-2);
795
+ color: var(--muted);
796
+ }
797
+
798
+ /* Segmented Control */
799
+ .stats-segmented-control {
800
+ display: flex;
801
+ background: var(--surface-2);
802
+ border: 1px solid var(--border);
803
+ border-radius: var(--radius-md);
804
+ padding: 2px;
805
+ gap: 2px;
806
+ }
807
+
808
+ .stats-segmented-control-btn {
809
+ padding: 6px 12px;
810
+ font-size: 12px;
811
+ font-weight: 500;
812
+ color: var(--muted);
813
+ background: transparent;
814
+ border: none;
815
+ border-radius: var(--radius-sm);
816
+ cursor: pointer;
817
+ transition: all 0.1s ease;
818
+ white-space: nowrap;
819
+ }
820
+
821
+ .stats-segmented-control-btn:hover {
822
+ color: var(--text);
823
+ }
824
+
825
+ .stats-segmented-control-btn[data-active="true"] {
826
+ color: var(--text);
827
+ background: var(--surface);
828
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.18);
829
+ }
830
+
831
+ /* Drawer Detail Component */
832
+ .stats-drawer-overlay {
833
+ position: fixed;
834
+ inset: 0;
835
+ background: rgba(0, 0, 0, 0.5);
836
+ z-index: 100;
837
+ display: flex;
838
+ justify-content: flex-end;
839
+ }
840
+
841
+ .stats-drawer {
842
+ width: 600px;
843
+ max-width: 100%;
844
+ height: 100%;
845
+ background: var(--surface);
846
+ border-left: 1px solid var(--border);
847
+ display: flex;
848
+ flex-direction: column;
849
+ animation: drawerSlide 0.25s cubic-bezier(0.16, 1, 0.3, 1);
850
+ box-shadow: -4px 0 24px rgba(0, 0, 0, 0.25);
851
+ }
852
+
853
+ @keyframes drawerSlide {
854
+ from { transform: translateX(100%); }
855
+ to { transform: translateX(0); }
856
+ }
857
+
858
+ .stats-drawer-header {
859
+ height: 56px;
860
+ border-bottom: 1px solid var(--border);
861
+ padding: 0 24px;
862
+ display: flex;
863
+ align-items: center;
864
+ justify-content: space-between;
865
+ background: var(--surface);
866
+ flex-shrink: 0;
867
+ }
868
+
869
+ .stats-drawer-header-left {
870
+ display: flex;
871
+ align-items: baseline;
872
+ gap: 12px;
873
+ }
874
+
875
+ .stats-drawer-title {
876
+ font-size: 15px;
877
+ font-weight: 600;
878
+ color: var(--text);
879
+ margin: 0;
880
+ }
881
+
882
+ .stats-drawer-id {
883
+ font-size: 11px;
884
+ color: var(--muted);
885
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
886
+ }
887
+
888
+ .stats-drawer-close-btn {
889
+ background: transparent;
890
+ border: none;
891
+ color: var(--muted);
892
+ cursor: pointer;
893
+ padding: 4px;
894
+ display: inline-flex;
895
+ align-items: center;
896
+ justify-content: center;
897
+ border-radius: var(--radius-sm);
898
+ transition: all 0.1s ease;
899
+ }
900
+
901
+ .stats-drawer-close-btn:hover {
902
+ color: var(--text);
903
+ background: var(--surface-2);
904
+ }
905
+
906
+ .stats-drawer-body {
907
+ flex: 1;
908
+ overflow-y: auto;
909
+ padding: 24px;
910
+ }
911
+
912
+ .stats-drawer-content {
913
+ display: flex;
914
+ flex-direction: column;
915
+ gap: 24px;
916
+ }
917
+
918
+ .stats-drawer-status-card {
919
+ background: var(--surface-2);
920
+ border: 1px solid var(--border);
921
+ border-radius: var(--radius-lg);
922
+ padding: 16px;
923
+ }
924
+
925
+ .stats-drawer-status-row {
926
+ display: flex;
927
+ justify-content: space-between;
928
+ align-items: flex-start;
929
+ gap: 16px;
930
+ }
931
+
932
+ .stats-drawer-model {
933
+ font-size: 16px;
934
+ font-weight: 700;
935
+ color: var(--text);
936
+ }
937
+
938
+ .stats-drawer-provider {
939
+ font-size: 12px;
940
+ color: var(--muted);
941
+ margin-top: 2px;
942
+ }
943
+
944
+ .stats-drawer-error-block {
945
+ margin-top: 14px;
946
+ border-top: 1px solid var(--border);
947
+ padding-top: 12px;
948
+ }
949
+
950
+ .stats-drawer-error-label {
951
+ font-size: 11px;
952
+ font-weight: 600;
953
+ text-transform: uppercase;
954
+ letter-spacing: 0.05em;
955
+ color: var(--danger);
956
+ margin-bottom: 4px;
957
+ }
958
+
959
+ .stats-drawer-error-text {
960
+ font-size: 12px;
961
+ color: var(--text);
962
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
963
+ white-space: pre-wrap;
964
+ word-break: break-all;
965
+ }
966
+
967
+ .stats-drawer-metrics-grid {
968
+ display: grid;
969
+ grid-template-columns: repeat(2, 1fr);
970
+ gap: 12px;
971
+ }
972
+
973
+ .stats-drawer-metric-card {
974
+ background: var(--surface);
975
+ border: 1px solid var(--border);
976
+ border-radius: var(--radius-lg);
977
+ padding: 14px;
978
+ display: flex;
979
+ flex-direction: column;
980
+ justify-content: center;
981
+ }
982
+
983
+ .stats-drawer-metric-label {
984
+ display: flex;
985
+ align-items: center;
986
+ gap: 6px;
987
+ font-size: 11px;
988
+ font-weight: 600;
989
+ text-transform: uppercase;
990
+ letter-spacing: 0.05em;
991
+ color: var(--muted);
992
+ margin-bottom: 6px;
993
+ }
994
+
995
+ .stats-drawer-metric-icon {
996
+ color: var(--dim);
997
+ }
998
+
999
+ .stats-drawer-metric-value {
1000
+ font-size: 16px;
1001
+ font-weight: 700;
1002
+ color: var(--text);
1003
+ font-variant-numeric: tabular-nums;
1004
+ }
1005
+
1006
+ .stats-drawer-metric-sub {
1007
+ font-size: 11px;
1008
+ color: var(--muted);
1009
+ margin-top: 2px;
1010
+ font-variant-numeric: tabular-nums;
1011
+ }
1012
+
1013
+ .stats-drawer-json-blocks {
1014
+ display: flex;
1015
+ flex-direction: column;
1016
+ gap: 16px;
1017
+ }
1018
+
1019
+ /* Collapsible JSON Block */
1020
+ .stats-json-block {
1021
+ border: 1px solid var(--border);
1022
+ border-radius: var(--radius-lg);
1023
+ background: var(--surface);
1024
+ overflow: hidden;
1025
+ }
1026
+
1027
+ .stats-json-block-header {
1028
+ padding: 10px 16px;
1029
+ background: var(--surface-2);
1030
+ border-bottom: 1px solid var(--border);
1031
+ display: flex;
1032
+ justify-content: space-between;
1033
+ align-items: center;
1034
+ cursor: pointer;
1035
+ user-select: none;
1036
+ font-size: 12px;
1037
+ font-weight: 600;
1038
+ }
1039
+
1040
+ .stats-json-block-header:hover {
1041
+ background: var(--border);
1042
+ }
1043
+
1044
+ .stats-json-block-title {
1045
+ color: var(--text);
1046
+ }
1047
+
1048
+ .stats-json-block-toggle-indicator {
1049
+ color: var(--muted);
1050
+ }
1051
+
1052
+ .stats-json-block-content-wrapper {
1053
+ padding: 16px;
1054
+ background: var(--page);
1055
+ overflow-x: auto;
1056
+ }
1057
+
1058
+ .stats-json-block-content {
1059
+ margin: 0;
1060
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
1061
+ font-size: 12px;
1062
+ color: var(--text);
1063
+ line-height: 1.5;
1064
+ }
1065
+
1066
+ /* Skeleton Loading Element */
1067
+ .stats-skeleton {
1068
+ background: var(--surface-2);
1069
+ position: relative;
1070
+ overflow: hidden;
1071
+ border-radius: var(--radius-sm);
1072
+ }
1073
+
1074
+ .stats-skeleton[data-variant="text"] {
1075
+ height: 14px;
1076
+ margin-top: 4px;
1077
+ margin-bottom: 4px;
1078
+ }
1079
+
1080
+ .stats-skeleton[data-variant="circle"] {
1081
+ border-radius: 50%;
1082
+ }
1083
+
1084
+ /* Subtle Shimmer effect, respecting media queries for reduced motion */
1085
+ .stats-skeleton::after {
1086
+ content: "";
1087
+ position: absolute;
1088
+ inset: 0;
1089
+ transform: translateX(-100%);
1090
+ background: linear-gradient(
1091
+ 90deg,
1092
+ transparent 0%,
1093
+ rgba(255, 255, 255, 0.05) 50%,
1094
+ transparent 100%
1095
+ );
1096
+ animation: shimmer 1.5s infinite;
1097
+ }
1098
+
1099
+ @media (prefers-color-scheme: light) {
1100
+ .stats-skeleton::after {
1101
+ background: linear-gradient(
1102
+ 90deg,
1103
+ transparent 0%,
1104
+ rgba(0, 0, 0, 0.03) 50%,
1105
+ transparent 100%
1106
+ );
1107
+ }
1108
+ }
1109
+
1110
+ @keyframes shimmer {
1111
+ 100% { transform: translateX(100%); }
1112
+ }
1113
+
1114
+ @media (prefers-reduced-motion: reduce) {
1115
+ .stats-skeleton::after {
1116
+ animation: none;
1117
+ }
1118
+ }
1119
+
1120
+ .stats-boundary-skeleton {
1121
+ padding: 20px;
1122
+ border: 1px solid var(--border);
1123
+ border-radius: var(--radius-lg);
1124
+ background: var(--surface);
1125
+ }
1126
+
1127
+ /* Empty State / Error State */
1128
+ .stats-empty-state,
1129
+ .stats-error-state {
1130
+ padding: 48px 24px;
1131
+ display: flex;
1132
+ flex-direction: column;
1133
+ align-items: center;
1134
+ justify-content: center;
1135
+ text-align: center;
1136
+ background: var(--surface);
1137
+ border: 1px dashed var(--border);
1138
+ border-radius: var(--radius-lg);
1139
+ }
1140
+
1141
+ .stats-empty-state-message {
1142
+ font-size: 13px;
1143
+ color: var(--muted);
1144
+ margin: 0;
1145
+ }
1146
+
1147
+ .stats-error-state-content {
1148
+ max-width: 360px;
1149
+ }
1150
+
1151
+ .stats-error-state-title {
1152
+ font-size: 14px;
1153
+ font-weight: 600;
1154
+ color: var(--text);
1155
+ margin: 0 0 8px 0;
1156
+ }
1157
+
1158
+ .stats-error-state-message {
1159
+ font-size: 12px;
1160
+ color: var(--danger);
1161
+ margin: 0 0 16px 0;
1162
+ word-break: break-word;
1163
+ }
1164
+
1165
+ .stats-error-state-btn {
1166
+ margin: 0 auto;
1167
+ }
1168
+
1169
+ /* ==========================================================================
1170
+ Token-vocabulary bridge utility classes (used across route components)
1171
+ ========================================================================== */
1172
+ .stats-text-primary { color: var(--text); }
1173
+ .stats-text-secondary { color: var(--muted); }
1174
+ .stats-text-muted { color: var(--dim); }
1175
+ .stats-text-xs { font-size: 12px; }
1176
+ .stats-font-medium { font-weight: 500; }
1177
+ .stats-font-semibold { font-weight: 600; }
1178
+
1179
+ /* ==========================================================================
1180
+ Owned scrollbars — thin, brand-tinted, app-wide (ComPress convention)
1181
+ ========================================================================== */
1182
+ * {
1183
+ scrollbar-width: thin;
1184
+ scrollbar-color: var(--border-strong) transparent;
1185
+ }
1186
+
1187
+ *::-webkit-scrollbar {
1188
+ width: 10px;
1189
+ height: 10px;
1190
+ }
1191
+
1192
+ *::-webkit-scrollbar-track {
1193
+ background: transparent;
1194
+ }
1195
+
1196
+ *::-webkit-scrollbar-thumb {
1197
+ background: var(--border-strong);
1198
+ border: 2px solid transparent;
1199
+ background-clip: padding-box;
1200
+ border-radius: 999px;
1201
+ }
1202
+
1203
+ *::-webkit-scrollbar-thumb:hover {
1204
+ background: var(--dim);
1205
+ border: 2px solid transparent;
1206
+ background-clip: padding-box;
1207
+ }
1208
+
1209
+ *::-webkit-scrollbar-corner {
1210
+ background: transparent;
1211
+ }
1212
+
1213
+ /* ==========================================================================
1214
+ Comprehensive reduced-motion fallback for all interaction motion
1215
+ ========================================================================== */
1216
+ @media (prefers-reduced-motion: reduce) {
1217
+ .stats-button,
1218
+ .stats-table-tr-clickable,
1219
+ .stats-nav-rail-item,
1220
+ .stats-range-control-btn,
1221
+ .stats-segmented-control-btn {
1222
+ transition: none;
1223
+ }
1224
+
1225
+ .stats-button:active:not(:disabled) {
1226
+ transform: none;
1227
+ }
1228
+
1229
+ .stats-mobile-drawer,
1230
+ .stats-drawer {
1231
+ animation: none;
1232
+ }
1233
+ }
1234
+
1235
+ /* ==========================================================================
1236
+ Brand mark on the OMP wordmark (both rail + mobile drawer headers)
1237
+ ========================================================================== */
1238
+ .stats-logo-container {
1239
+ display: grid;
1240
+ grid-template-columns: auto 1fr;
1241
+ align-items: center;
1242
+ column-gap: 10px;
1243
+ }
1244
+
1245
+ .stats-logo-container::before {
1246
+ content: "";
1247
+ grid-row: 1 / 3;
1248
+ width: 16px;
1249
+ height: 16px;
1250
+ border-radius: 4px;
1251
+ background: linear-gradient(135deg, #ed4abf 0%, #9b4dff 50%, #5ad8e6 100%); /* OMP brand gradient mark */
1252
+ }
1253
+
1254
+ .stats-logo-text,
1255
+ .stats-logo-subtext {
1256
+ grid-column: 2;
1257
+ }
1258
+
1259
+ /* ==========================================================================
1260
+ JSON block copy affordance
1261
+ ========================================================================== */
1262
+ .stats-json-actions {
1263
+ display: flex;
1264
+ align-items: center;
1265
+ gap: 12px;
1266
+ }
1267
+
1268
+ .stats-json-copy-btn {
1269
+ display: inline-flex;
1270
+ align-items: center;
1271
+ gap: 5px;
1272
+ font-size: 11px;
1273
+ font-weight: 600;
1274
+ color: var(--muted);
1275
+ background: transparent;
1276
+ border: 1px solid var(--border);
1277
+ border-radius: var(--radius-sm);
1278
+ padding: 3px 8px;
1279
+ cursor: pointer;
1280
+ font-family: inherit;
1281
+ transition: color 0.12s ease, background 0.12s ease;
1282
+ }
1283
+
1284
+ .stats-json-copy-btn:hover {
1285
+ color: var(--text);
1286
+ background: var(--surface-2);
1287
+ }
1288
+
1289
+ /* ==========================================================================
1290
+ Empty-state icon
1291
+ ========================================================================== */
1292
+ .stats-empty-state-icon {
1293
+ color: var(--dim);
1294
+ margin-bottom: 12px;
1295
+ }
1296
+
1297
+ @media (prefers-reduced-motion: reduce) {
1298
+ .stats-json-copy-btn {
1299
+ transition: none;
1300
+ }
1301
+ }
1302
+
1303
+ /* ==========================================================================
1304
+ Theme toggle (system / light / dark)
1305
+ ========================================================================== */
1306
+ .stats-theme-toggle {
1307
+ display: inline-flex;
1308
+ align-items: center;
1309
+ justify-content: center;
1310
+ width: 32px;
1311
+ height: 32px;
1312
+ flex-shrink: 0;
1313
+ border: 1px solid var(--border);
1314
+ border-radius: var(--radius-md);
1315
+ background: var(--surface);
1316
+ color: var(--muted);
1317
+ cursor: pointer;
1318
+ transition: color 0.14s ease, background 0.14s ease, border-color 0.14s ease;
1319
+ }
1320
+
1321
+ .stats-theme-toggle:hover {
1322
+ color: var(--text);
1323
+ border-color: var(--border-strong);
1324
+ }
1325
+
1326
+ @media (prefers-reduced-motion: reduce) {
1327
+ .stats-theme-toggle {
1328
+ transition: none;
1329
+ }
1330
+ }