@oh-my-pi/omp-stats 16.0.3 → 16.0.5

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 (107) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/build.ts +11 -0
  3. package/dist/client/index.css +1 -1
  4. package/dist/client/index.html +11 -0
  5. package/dist/client/index.js +108 -108
  6. package/dist/client/styles.css +1070 -631
  7. package/dist/types/client/api.d.ts +19 -10
  8. package/dist/types/client/app/AppLayout.d.ts +16 -0
  9. package/dist/types/client/app/NavRail.d.ts +7 -0
  10. package/dist/types/client/app/RangeControl.d.ts +7 -0
  11. package/dist/types/client/app/SyncButton.d.ts +14 -0
  12. package/dist/types/client/app/ThemeToggle.d.ts +1 -0
  13. package/dist/types/client/app/TopBar.d.ts +15 -0
  14. package/dist/types/client/app/routes.d.ts +12 -0
  15. package/dist/types/client/components/chart-shared.d.ts +26 -40
  16. package/dist/types/client/components/models-table-shared.d.ts +20 -40
  17. package/dist/types/client/data/charts.d.ts +1 -0
  18. package/dist/types/client/data/formatters.d.ts +7 -0
  19. package/dist/types/client/data/useHashRoute.d.ts +8 -0
  20. package/dist/types/client/data/useResource.d.ts +13 -0
  21. package/dist/types/client/data/view-models.d.ts +37 -0
  22. package/dist/types/client/index.d.ts +1 -0
  23. package/dist/types/client/routes/BehaviorRoute.d.ts +7 -0
  24. package/dist/types/client/routes/CostsRoute.d.ts +7 -0
  25. package/dist/types/client/routes/ErrorsRoute.d.ts +8 -0
  26. package/dist/types/client/routes/ModelsRoute.d.ts +7 -0
  27. package/dist/types/client/routes/OverviewRoute.d.ts +8 -0
  28. package/dist/types/client/routes/ProjectsRoute.d.ts +7 -0
  29. package/dist/types/client/routes/RequestsRoute.d.ts +8 -0
  30. package/dist/types/client/routes/index.d.ts +7 -0
  31. package/dist/types/client/ui/AsyncBoundary.d.ts +12 -0
  32. package/dist/types/client/ui/DataTable.d.ts +17 -0
  33. package/dist/types/client/ui/EmptyState.d.ts +7 -0
  34. package/dist/types/client/ui/ErrorState.d.ts +6 -0
  35. package/dist/types/client/ui/JsonBlock.d.ts +7 -0
  36. package/dist/types/client/ui/MetricCluster.d.ts +5 -0
  37. package/dist/types/client/ui/Panel.d.ts +7 -0
  38. package/dist/types/client/ui/RequestDrawer.d.ts +5 -0
  39. package/dist/types/client/ui/SegmentedControl.d.ts +12 -0
  40. package/dist/types/client/ui/Skeleton.d.ts +8 -0
  41. package/dist/types/client/ui/StatusPill.d.ts +7 -0
  42. package/dist/types/client/ui/index.d.ts +11 -0
  43. package/dist/types/client/useSystemTheme.d.ts +9 -0
  44. package/package.json +4 -4
  45. package/src/aggregator.ts +4 -3
  46. package/src/client/App.tsx +89 -207
  47. package/src/client/api.ts +55 -37
  48. package/src/client/app/AppLayout.tsx +93 -0
  49. package/src/client/app/NavRail.tsx +44 -0
  50. package/src/client/app/RangeControl.tsx +39 -0
  51. package/src/client/app/SyncButton.tsx +75 -0
  52. package/src/client/app/ThemeToggle.tsx +37 -0
  53. package/src/client/app/TopBar.tsx +73 -0
  54. package/src/client/app/routes.ts +50 -0
  55. package/src/client/components/chart-shared.tsx +28 -91
  56. package/src/client/components/models-table-shared.tsx +9 -29
  57. package/src/client/components/range-meta.ts +3 -2
  58. package/src/client/data/charts.ts +14 -0
  59. package/src/client/data/formatters.ts +38 -0
  60. package/src/client/data/useHashRoute.ts +85 -0
  61. package/src/client/data/useResource.ts +154 -0
  62. package/src/client/data/view-models.ts +178 -0
  63. package/src/client/index.tsx +4 -0
  64. package/src/client/routes/BehaviorRoute.tsx +623 -0
  65. package/src/client/routes/CostsRoute.tsx +234 -0
  66. package/src/client/routes/ErrorsRoute.tsx +118 -0
  67. package/src/client/routes/ModelsRoute.tsx +430 -0
  68. package/src/client/routes/OverviewRoute.tsx +332 -0
  69. package/src/client/routes/ProjectsRoute.tsx +163 -0
  70. package/src/client/routes/RequestsRoute.tsx +123 -0
  71. package/src/client/routes/index.ts +7 -0
  72. package/src/client/styles.css +1242 -225
  73. package/src/client/ui/AsyncBoundary.tsx +54 -0
  74. package/src/client/ui/DataTable.tsx +122 -0
  75. package/src/client/ui/EmptyState.tsx +16 -0
  76. package/src/client/ui/ErrorState.tsx +25 -0
  77. package/src/client/ui/JsonBlock.tsx +75 -0
  78. package/src/client/ui/MetricCluster.tsx +67 -0
  79. package/src/client/ui/Panel.tsx +24 -0
  80. package/src/client/ui/RequestDrawer.tsx +208 -0
  81. package/src/client/ui/SegmentedControl.tsx +36 -0
  82. package/src/client/ui/Skeleton.tsx +17 -0
  83. package/src/client/ui/StatusPill.tsx +15 -0
  84. package/src/client/ui/index.ts +11 -0
  85. package/src/client/useSystemTheme.ts +73 -17
  86. package/dist/types/client/components/BehaviorChart.d.ts +0 -6
  87. package/dist/types/client/components/BehaviorModelsTable.d.ts +0 -7
  88. package/dist/types/client/components/BehaviorSummary.d.ts +0 -7
  89. package/dist/types/client/components/ChartsContainer.d.ts +0 -7
  90. package/dist/types/client/components/CostChart.d.ts +0 -6
  91. package/dist/types/client/components/CostSummary.d.ts +0 -6
  92. package/dist/types/client/components/Header.d.ts +0 -12
  93. package/dist/types/client/components/ModelsTable.d.ts +0 -8
  94. package/dist/types/client/components/RequestDetail.d.ts +0 -6
  95. package/dist/types/client/components/RequestList.d.ts +0 -8
  96. package/dist/types/client/components/StatsGrid.d.ts +0 -6
  97. package/src/client/components/BehaviorChart.tsx +0 -189
  98. package/src/client/components/BehaviorModelsTable.tsx +0 -342
  99. package/src/client/components/BehaviorSummary.tsx +0 -95
  100. package/src/client/components/ChartsContainer.tsx +0 -221
  101. package/src/client/components/CostChart.tsx +0 -171
  102. package/src/client/components/CostSummary.tsx +0 -53
  103. package/src/client/components/Header.tsx +0 -72
  104. package/src/client/components/ModelsTable.tsx +0 -265
  105. package/src/client/components/RequestDetail.tsx +0 -172
  106. package/src/client/components/RequestList.tsx +0 -73
  107. package/src/client/components/StatsGrid.tsx +0 -135
@@ -1,64 +1,92 @@
1
1
  @import "tailwindcss/index.css";
2
+
3
+ /* ==========================================================================
4
+ OMP Theme Variables & Color Scheme
5
+ ========================================================================== */
2
6
  :root {
3
- color-scheme: light;
4
- --bg-page: #f8fafc;
5
- --bg-surface: #ffffff;
6
- --bg-elevated: #f1f5f9;
7
- --bg-hover: rgba(15, 23, 42, 0.04);
8
- --bg-active: rgba(15, 23, 42, 0.08);
9
-
10
- --border-subtle: rgba(15, 23, 42, 0.08);
11
- --border-default: rgba(15, 23, 42, 0.14);
12
-
13
- --text-primary: #0f172a;
14
- --text-secondary: #334155;
15
- --text-muted: #64748b;
16
-
17
- --accent-pink: #ec4899;
18
- --accent-pink-glow: rgba(236, 72, 153, 0.26);
19
- --accent-cyan: #0891b2;
20
- --accent-cyan-glow: rgba(8, 145, 178, 0.24);
21
- --accent-violet: #8b5cf6;
22
- --accent-green: #16a34a;
23
- --accent-amber: #d97706;
24
- --accent-red: #dc2626;
25
-
26
- --tab-active-highlight: inset 0 1px 0 rgba(15, 23, 42, 0.08);
27
-
28
- --radius-sm: 6px;
29
- --radius-md: 10px;
30
- --radius-lg: 14px;
31
- }
32
-
33
- @media (prefers-color-scheme: dark) {
34
- :root {
35
- color-scheme: dark;
36
- --bg-page: #0a0a0f;
37
- --bg-surface: #111118;
38
- --bg-elevated: #16161e;
39
- --bg-hover: rgba(255, 255, 255, 0.03);
40
- --bg-active: rgba(255, 255, 255, 0.06);
41
-
42
- --border-subtle: rgba(255, 255, 255, 0.06);
43
- --border-default: rgba(255, 255, 255, 0.1);
44
-
45
- --text-primary: #f8fafc;
46
- --text-secondary: #94a3b8;
47
- --text-muted: #64748b;
48
-
49
- --accent-pink: #ec4899;
50
- --accent-pink-glow: rgba(236, 72, 153, 0.3);
51
- --accent-cyan: #22d3ee;
52
- --accent-cyan-glow: rgba(34, 211, 238, 0.3);
53
- --accent-violet: #a78bfa;
54
- --accent-green: #4ade80;
55
- --accent-amber: #fbbf24;
56
- --accent-red: #f87171;
57
-
58
- --tab-active-highlight: inset 0 1px 0 rgba(255, 255, 255, 0.05);
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);
59
64
  }
60
65
  }
61
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
+ ========================================================================== */
62
90
  @layer base {
63
91
  * {
64
92
  box-sizing: border-box;
@@ -70,237 +98,1226 @@
70
98
  }
71
99
 
72
100
  body {
73
- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
74
- background: var(--bg-page);
75
- color: var(--text-primary);
101
+ font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
102
+ background: var(--page);
103
+ color: var(--text);
76
104
  margin: 0;
77
105
  min-height: 100vh;
78
106
  }
79
107
 
80
- /* Custom scrollbar */
81
- ::-webkit-scrollbar {
82
- width: 8px;
83
- height: 8px;
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;
84
114
  }
115
+ }
85
116
 
86
- ::-webkit-scrollbar-track {
87
- background: transparent;
88
- }
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
+ }
89
126
 
90
- ::-webkit-scrollbar-thumb {
91
- background: var(--border-default);
92
- border-radius: 4px;
93
- }
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
+ }
94
136
 
95
- ::-webkit-scrollbar-thumb:hover {
96
- background: var(--text-muted);
97
- }
137
+ .stats-desktop-nav {
138
+ display: flex;
98
139
  }
99
140
 
100
- @layer components {
101
- .surface {
102
- background: var(--bg-surface);
103
- border: 1px solid var(--border-subtle);
104
- border-radius: var(--radius-lg);
141
+ @media (max-width: 1023px) {
142
+ .stats-desktop-nav {
143
+ display: none;
105
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
+ }
106
166
 
107
- .surface-elevated {
108
- background: var(--bg-elevated);
109
- border: 1px solid var(--border-default);
110
- border-radius: var(--radius-lg);
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;
111
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
+ }
112
279
 
113
- .btn {
280
+ @media (max-width: 1023px) {
281
+ .stats-mobile-menu-btn {
114
282
  display: inline-flex;
115
283
  align-items: center;
116
284
  justify-content: center;
117
- gap: 8px;
118
- padding: 8px 16px;
119
- font-size: 14px;
120
- font-weight: 500;
121
- border-radius: var(--radius-md);
122
- border: none;
123
- cursor: pointer;
124
- transition: all 0.15s ease;
125
285
  }
286
+ }
126
287
 
127
- .btn-primary {
128
- background: linear-gradient(135deg, var(--accent-pink) 0%, #db2777 100%);
129
- color: white;
130
- box-shadow: 0 0 20px var(--accent-pink-glow);
131
- }
288
+ .stats-page-title {
289
+ font-size: 16px;
290
+ font-weight: 600;
291
+ color: var(--text);
292
+ margin: 0;
293
+ }
132
294
 
133
- .btn-primary:hover {
134
- transform: translateY(-1px);
135
- box-shadow: 0 4px 24px var(--accent-pink-glow);
136
- }
295
+ .stats-top-bar-right {
296
+ display: flex;
297
+ align-items: center;
298
+ gap: 16px;
299
+ }
137
300
 
138
- .btn-primary:disabled {
139
- opacity: 0.6;
140
- cursor: not-allowed;
141
- transform: none;
301
+ @media (max-width: 767px) {
302
+ .stats-top-bar-right {
303
+ width: 100%;
304
+ justify-content: space-between;
305
+ gap: 8px;
142
306
  }
307
+ }
143
308
 
144
- .btn-secondary {
145
- background: var(--bg-elevated);
146
- color: var(--text-primary);
147
- border: 1px solid var(--border-default);
148
- }
309
+ .stats-top-bar-meta {
310
+ display: flex;
311
+ align-items: center;
312
+ }
149
313
 
150
- .btn-secondary:hover {
151
- background: var(--bg-hover);
152
- border-color: var(--border-default);
153
- }
314
+ .stats-last-updated {
315
+ font-size: 11px;
316
+ color: var(--dim);
317
+ font-variant-numeric: tabular-nums;
318
+ }
154
319
 
155
- .tab-btn {
156
- padding: 6px 16px;
157
- font-size: 14px;
158
- font-weight: 500;
159
- color: var(--text-muted);
160
- background: transparent;
161
- border: none;
162
- border-radius: var(--radius-md);
163
- cursor: pointer;
164
- transition: all 0.15s ease;
165
- }
320
+ .stats-content-area {
321
+ flex: 1;
322
+ overflow-y: auto;
323
+ }
166
324
 
167
- .tab-btn:hover {
168
- color: var(--text-primary);
169
- background: var(--bg-hover);
170
- }
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
+ }
171
333
 
172
- .tab-btn.active {
173
- color: var(--text-primary);
174
- background: var(--bg-elevated);
175
- box-shadow: var(--tab-active-highlight);
334
+ @media (max-width: 767px) {
335
+ .stats-content-inner {
336
+ padding: 16px;
337
+ gap: 16px;
176
338
  }
339
+ }
177
340
 
178
- .stat-card {
179
- background: var(--bg-surface);
180
- border: 1px solid var(--border-subtle);
181
- border-radius: var(--radius-lg);
182
- padding: 20px;
183
- transition: all 0.2s ease;
184
- }
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
+ }
185
349
 
186
- .stat-card:hover {
187
- border-color: var(--border-default);
188
- background: var(--bg-elevated);
189
- }
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
+ }
190
363
 
191
- .badge {
192
- display: inline-flex;
193
- align-items: center;
194
- padding: 3px 10px;
195
- font-size: 12px;
196
- font-weight: 500;
197
- border-radius: 100px;
198
- }
364
+ @keyframes slideIn {
365
+ from { transform: translateX(-100%); }
366
+ to { transform: translateX(0); }
367
+ }
199
368
 
200
- .badge-success {
201
- background: rgba(74, 222, 128, 0.15);
202
- color: var(--accent-green);
203
- }
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
+ }
204
377
 
205
- .badge-error {
206
- background: rgba(248, 113, 113, 0.15);
207
- color: var(--accent-red);
208
- }
378
+ .stats-mobile-nav {
379
+ display: flex;
380
+ height: calc(100% - 56px);
381
+ }
209
382
 
210
- .badge-info {
211
- background: rgba(34, 211, 238, 0.15);
212
- color: var(--accent-cyan);
213
- }
383
+ /* ==========================================================================
384
+ UI Primitives & Styles
385
+ ========================================================================== */
214
386
 
215
- .badge-warning {
216
- background: rgba(251, 191, 36, 0.15);
217
- color: var(--accent-amber);
218
- }
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
+ }
219
402
 
220
- .table-header {
221
- font-size: 11px;
222
- font-weight: 600;
223
- text-transform: uppercase;
224
- letter-spacing: 0.05em;
225
- color: var(--text-muted);
226
- }
403
+ .stats-button:active:not(:disabled) {
404
+ transform: translateY(1px);
405
+ }
227
406
 
228
- .table-row {
229
- transition: background 0.15s ease;
230
- }
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
+ }
231
435
 
232
- .table-row:hover {
233
- background: var(--bg-hover);
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;
234
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
+ }
235
540
 
236
- .gradient-text {
237
- background: linear-gradient(135deg, var(--accent-pink) 0%, var(--accent-cyan) 100%);
238
- -webkit-background-clip: text;
239
- -webkit-text-fill-color: transparent;
240
- background-clip: text;
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);
241
573
  }
574
+ }
242
575
 
243
- .gradient-border {
244
- position: relative;
576
+ @media (max-width: 480px) {
577
+ .stats-metric-primary-grid {
578
+ grid-template-columns: 1fr;
245
579
  }
580
+ }
581
+
582
+ .stats-metric-secondary-grid {
583
+ display: grid;
584
+ grid-template-columns: repeat(6, 1fr);
585
+ gap: 12px;
586
+ }
246
587
 
247
- .gradient-border::before {
248
- content: '';
249
- position: absolute;
250
- inset: 0;
251
- padding: 1px;
252
- border-radius: inherit;
253
- background: linear-gradient(135deg, var(--accent-pink), var(--accent-cyan));
254
- -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
255
- mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
256
- -webkit-mask-composite: xor;
257
- mask-composite: exclude;
258
- pointer-events: none;
588
+ @media (max-width: 1023px) {
589
+ .stats-metric-secondary-grid {
590
+ grid-template-columns: repeat(3, 1fr);
259
591
  }
592
+ }
260
593
 
261
- .glow-pink {
262
- box-shadow: 0 0 30px var(--accent-pink-glow);
594
+ @media (max-width: 600px) {
595
+ .stats-metric-secondary-grid {
596
+ grid-template-columns: repeat(2, 1fr);
263
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
+ }
264
679
 
265
- .glow-cyan {
266
- box-shadow: 0 0 30px var(--accent-cyan-glow);
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
+ @media (max-width: 767px) {
733
+ .stats-table-desktop-only {
734
+ display: none;
267
735
  }
736
+ .stats-table-mobile-only {
737
+ display: block;
738
+ }
739
+ }
740
+
741
+ .stats-table-mobile-list {
742
+ display: flex;
743
+ flex-direction: column;
744
+ gap: 12px;
745
+ }
746
+
747
+ .stats-table-mobile-card-wrapper {
748
+ background: var(--surface);
749
+ border: 1px solid var(--border);
750
+ border-radius: var(--radius-lg);
751
+ padding: 14px;
752
+ }
753
+
754
+ /* Status Pill */
755
+ .stats-status-pill {
756
+ display: inline-flex;
757
+ align-items: center;
758
+ justify-content: center;
759
+ padding: 2px 8px;
760
+ font-size: 11px;
761
+ font-weight: 600;
762
+ border-radius: 100px;
763
+ line-height: 1.2;
764
+ }
765
+
766
+ .stats-status-pill[data-variant="success"] {
767
+ background: color-mix(in srgb, var(--success) 18%, transparent);
768
+ color: var(--success);
769
+ }
770
+
771
+ .stats-status-pill[data-variant="danger"] {
772
+ background: color-mix(in srgb, var(--danger) 18%, transparent);
773
+ color: var(--danger);
774
+ }
775
+
776
+ .stats-status-pill[data-variant="warning"] {
777
+ background: color-mix(in srgb, var(--warning) 18%, transparent);
778
+ color: var(--warning);
779
+ }
780
+
781
+ .stats-status-pill[data-variant="info"] {
782
+ background: color-mix(in srgb, var(--link) 18%, transparent);
783
+ color: var(--link);
784
+ }
785
+
786
+ .stats-status-pill[data-variant="default"] {
787
+ background: var(--surface-2);
788
+ color: var(--muted);
789
+ }
790
+
791
+ /* Segmented Control */
792
+ .stats-segmented-control {
793
+ display: flex;
794
+ background: var(--surface-2);
795
+ border: 1px solid var(--border);
796
+ border-radius: var(--radius-md);
797
+ padding: 2px;
798
+ gap: 2px;
799
+ }
800
+
801
+ .stats-segmented-control-btn {
802
+ padding: 6px 12px;
803
+ font-size: 12px;
804
+ font-weight: 500;
805
+ color: var(--muted);
806
+ background: transparent;
807
+ border: none;
808
+ border-radius: var(--radius-sm);
809
+ cursor: pointer;
810
+ transition: all 0.1s ease;
811
+ white-space: nowrap;
812
+ }
813
+
814
+ .stats-segmented-control-btn:hover {
815
+ color: var(--text);
816
+ }
817
+
818
+ .stats-segmented-control-btn[data-active="true"] {
819
+ color: var(--text);
820
+ background: var(--surface);
821
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.18);
822
+ }
823
+
824
+ /* Drawer Detail Component */
825
+ .stats-drawer-overlay {
826
+ position: fixed;
827
+ inset: 0;
828
+ background: rgba(0, 0, 0, 0.5);
829
+ z-index: 100;
830
+ display: flex;
831
+ justify-content: flex-end;
832
+ }
833
+
834
+ .stats-drawer {
835
+ width: 600px;
836
+ max-width: 100%;
837
+ height: 100%;
838
+ background: var(--surface);
839
+ border-left: 1px solid var(--border);
840
+ display: flex;
841
+ flex-direction: column;
842
+ animation: drawerSlide 0.25s cubic-bezier(0.16, 1, 0.3, 1);
843
+ box-shadow: -4px 0 24px rgba(0, 0, 0, 0.25);
844
+ }
845
+
846
+ @keyframes drawerSlide {
847
+ from { transform: translateX(100%); }
848
+ to { transform: translateX(0); }
849
+ }
850
+
851
+ .stats-drawer-header {
852
+ height: 56px;
853
+ border-bottom: 1px solid var(--border);
854
+ padding: 0 24px;
855
+ display: flex;
856
+ align-items: center;
857
+ justify-content: space-between;
858
+ background: var(--surface);
859
+ flex-shrink: 0;
860
+ }
861
+
862
+ .stats-drawer-header-left {
863
+ display: flex;
864
+ align-items: baseline;
865
+ gap: 12px;
866
+ }
867
+
868
+ .stats-drawer-title {
869
+ font-size: 15px;
870
+ font-weight: 600;
871
+ color: var(--text);
872
+ margin: 0;
873
+ }
874
+
875
+ .stats-drawer-id {
876
+ font-size: 11px;
877
+ color: var(--muted);
878
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
879
+ }
880
+
881
+ .stats-drawer-close-btn {
882
+ background: transparent;
883
+ border: none;
884
+ color: var(--muted);
885
+ cursor: pointer;
886
+ padding: 4px;
887
+ display: inline-flex;
888
+ align-items: center;
889
+ justify-content: center;
890
+ border-radius: var(--radius-sm);
891
+ transition: all 0.1s ease;
892
+ }
893
+
894
+ .stats-drawer-close-btn:hover {
895
+ color: var(--text);
896
+ background: var(--surface-2);
897
+ }
898
+
899
+ .stats-drawer-body {
900
+ flex: 1;
901
+ overflow-y: auto;
902
+ padding: 24px;
903
+ }
904
+
905
+ .stats-drawer-content {
906
+ display: flex;
907
+ flex-direction: column;
908
+ gap: 24px;
909
+ }
910
+
911
+ .stats-drawer-status-card {
912
+ background: var(--surface-2);
913
+ border: 1px solid var(--border);
914
+ border-radius: var(--radius-lg);
915
+ padding: 16px;
916
+ }
917
+
918
+ .stats-drawer-status-row {
919
+ display: flex;
920
+ justify-content: space-between;
921
+ align-items: flex-start;
922
+ gap: 16px;
923
+ }
924
+
925
+ .stats-drawer-model {
926
+ font-size: 16px;
927
+ font-weight: 700;
928
+ color: var(--text);
929
+ }
930
+
931
+ .stats-drawer-provider {
932
+ font-size: 12px;
933
+ color: var(--muted);
934
+ margin-top: 2px;
935
+ }
936
+
937
+ .stats-drawer-error-block {
938
+ margin-top: 14px;
939
+ border-top: 1px solid var(--border);
940
+ padding-top: 12px;
941
+ }
942
+
943
+ .stats-drawer-error-label {
944
+ font-size: 11px;
945
+ font-weight: 600;
946
+ text-transform: uppercase;
947
+ letter-spacing: 0.05em;
948
+ color: var(--danger);
949
+ margin-bottom: 4px;
950
+ }
951
+
952
+ .stats-drawer-error-text {
953
+ font-size: 12px;
954
+ color: var(--text);
955
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
956
+ white-space: pre-wrap;
957
+ word-break: break-all;
958
+ }
959
+
960
+ .stats-drawer-metrics-grid {
961
+ display: grid;
962
+ grid-template-columns: repeat(2, 1fr);
963
+ gap: 12px;
964
+ }
965
+
966
+ .stats-drawer-metric-card {
967
+ background: var(--surface);
968
+ border: 1px solid var(--border);
969
+ border-radius: var(--radius-lg);
970
+ padding: 14px;
971
+ display: flex;
972
+ flex-direction: column;
973
+ justify-content: center;
268
974
  }
269
975
 
270
- @layer utilities {
271
- .text-balance {
272
- text-wrap: balance;
976
+ .stats-drawer-metric-label {
977
+ display: flex;
978
+ align-items: center;
979
+ gap: 6px;
980
+ font-size: 11px;
981
+ font-weight: 600;
982
+ text-transform: uppercase;
983
+ letter-spacing: 0.05em;
984
+ color: var(--muted);
985
+ margin-bottom: 6px;
986
+ }
987
+
988
+ .stats-drawer-metric-icon {
989
+ color: var(--dim);
990
+ }
991
+
992
+ .stats-drawer-metric-value {
993
+ font-size: 16px;
994
+ font-weight: 700;
995
+ color: var(--text);
996
+ font-variant-numeric: tabular-nums;
997
+ }
998
+
999
+ .stats-drawer-metric-sub {
1000
+ font-size: 11px;
1001
+ color: var(--muted);
1002
+ margin-top: 2px;
1003
+ font-variant-numeric: tabular-nums;
1004
+ }
1005
+
1006
+ .stats-drawer-json-blocks {
1007
+ display: flex;
1008
+ flex-direction: column;
1009
+ gap: 16px;
1010
+ }
1011
+
1012
+ /* Collapsible JSON Block */
1013
+ .stats-json-block {
1014
+ border: 1px solid var(--border);
1015
+ border-radius: var(--radius-lg);
1016
+ background: var(--surface);
1017
+ overflow: hidden;
1018
+ }
1019
+
1020
+ .stats-json-block-header {
1021
+ padding: 10px 16px;
1022
+ background: var(--surface-2);
1023
+ border-bottom: 1px solid var(--border);
1024
+ display: flex;
1025
+ justify-content: space-between;
1026
+ align-items: center;
1027
+ cursor: pointer;
1028
+ user-select: none;
1029
+ font-size: 12px;
1030
+ font-weight: 600;
1031
+ }
1032
+
1033
+ .stats-json-block-header:hover {
1034
+ background: var(--border);
1035
+ }
1036
+
1037
+ .stats-json-block-title {
1038
+ color: var(--text);
1039
+ }
1040
+
1041
+ .stats-json-block-toggle-indicator {
1042
+ color: var(--muted);
1043
+ }
1044
+
1045
+ .stats-json-block-content-wrapper {
1046
+ padding: 16px;
1047
+ background: var(--page);
1048
+ overflow-x: auto;
1049
+ }
1050
+
1051
+ .stats-json-block-content {
1052
+ margin: 0;
1053
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
1054
+ font-size: 12px;
1055
+ color: var(--text);
1056
+ line-height: 1.5;
1057
+ }
1058
+
1059
+ /* Skeleton Loading Element */
1060
+ .stats-skeleton {
1061
+ background: var(--surface-2);
1062
+ position: relative;
1063
+ overflow: hidden;
1064
+ border-radius: var(--radius-sm);
1065
+ }
1066
+
1067
+ .stats-skeleton[data-variant="text"] {
1068
+ height: 14px;
1069
+ margin-top: 4px;
1070
+ margin-bottom: 4px;
1071
+ }
1072
+
1073
+ .stats-skeleton[data-variant="circle"] {
1074
+ border-radius: 50%;
1075
+ }
1076
+
1077
+ /* Subtle Shimmer effect, respecting media queries for reduced motion */
1078
+ .stats-skeleton::after {
1079
+ content: "";
1080
+ position: absolute;
1081
+ inset: 0;
1082
+ transform: translateX(-100%);
1083
+ background: linear-gradient(
1084
+ 90deg,
1085
+ transparent 0%,
1086
+ rgba(255, 255, 255, 0.05) 50%,
1087
+ transparent 100%
1088
+ );
1089
+ animation: shimmer 1.5s infinite;
1090
+ }
1091
+
1092
+ @media (prefers-color-scheme: light) {
1093
+ .stats-skeleton::after {
1094
+ background: linear-gradient(
1095
+ 90deg,
1096
+ transparent 0%,
1097
+ rgba(0, 0, 0, 0.03) 50%,
1098
+ transparent 100%
1099
+ );
273
1100
  }
1101
+ }
1102
+
1103
+ @keyframes shimmer {
1104
+ 100% { transform: translateX(100%); }
1105
+ }
274
1106
 
275
- .animate-fade-in {
276
- animation: fadeIn 0.3s ease-out;
1107
+ @media (prefers-reduced-motion: reduce) {
1108
+ .stats-skeleton::after {
1109
+ animation: none;
277
1110
  }
1111
+ }
1112
+
1113
+ .stats-boundary-skeleton {
1114
+ padding: 20px;
1115
+ border: 1px solid var(--border);
1116
+ border-radius: var(--radius-lg);
1117
+ background: var(--surface);
1118
+ }
1119
+
1120
+ /* Empty State / Error State */
1121
+ .stats-empty-state,
1122
+ .stats-error-state {
1123
+ padding: 48px 24px;
1124
+ display: flex;
1125
+ flex-direction: column;
1126
+ align-items: center;
1127
+ justify-content: center;
1128
+ text-align: center;
1129
+ background: var(--surface);
1130
+ border: 1px dashed var(--border);
1131
+ border-radius: var(--radius-lg);
1132
+ }
1133
+
1134
+ .stats-empty-state-message {
1135
+ font-size: 13px;
1136
+ color: var(--muted);
1137
+ margin: 0;
1138
+ }
278
1139
 
279
- .animate-slide-up {
280
- animation: slideUp 0.3s ease-out;
1140
+ .stats-error-state-content {
1141
+ max-width: 360px;
1142
+ }
1143
+
1144
+ .stats-error-state-title {
1145
+ font-size: 14px;
1146
+ font-weight: 600;
1147
+ color: var(--text);
1148
+ margin: 0 0 8px 0;
1149
+ }
1150
+
1151
+ .stats-error-state-message {
1152
+ font-size: 12px;
1153
+ color: var(--danger);
1154
+ margin: 0 0 16px 0;
1155
+ word-break: break-word;
1156
+ }
1157
+
1158
+ .stats-error-state-btn {
1159
+ margin: 0 auto;
1160
+ }
1161
+
1162
+ /* ==========================================================================
1163
+ Token-vocabulary bridge utility classes (used across route components)
1164
+ ========================================================================== */
1165
+ .stats-text-primary { color: var(--text); }
1166
+ .stats-text-secondary { color: var(--muted); }
1167
+ .stats-text-muted { color: var(--dim); }
1168
+ .stats-text-xs { font-size: 12px; }
1169
+ .stats-font-medium { font-weight: 500; }
1170
+ .stats-font-semibold { font-weight: 600; }
1171
+
1172
+ /* ==========================================================================
1173
+ Owned scrollbars — thin, brand-tinted, app-wide (ComPress convention)
1174
+ ========================================================================== */
1175
+ * {
1176
+ scrollbar-width: thin;
1177
+ scrollbar-color: var(--border-strong) transparent;
1178
+ }
1179
+
1180
+ *::-webkit-scrollbar {
1181
+ width: 10px;
1182
+ height: 10px;
1183
+ }
1184
+
1185
+ *::-webkit-scrollbar-track {
1186
+ background: transparent;
1187
+ }
1188
+
1189
+ *::-webkit-scrollbar-thumb {
1190
+ background: var(--border-strong);
1191
+ border: 2px solid transparent;
1192
+ background-clip: padding-box;
1193
+ border-radius: 999px;
1194
+ }
1195
+
1196
+ *::-webkit-scrollbar-thumb:hover {
1197
+ background: var(--dim);
1198
+ border: 2px solid transparent;
1199
+ background-clip: padding-box;
1200
+ }
1201
+
1202
+ *::-webkit-scrollbar-corner {
1203
+ background: transparent;
1204
+ }
1205
+
1206
+ /* ==========================================================================
1207
+ Comprehensive reduced-motion fallback for all interaction motion
1208
+ ========================================================================== */
1209
+ @media (prefers-reduced-motion: reduce) {
1210
+ .stats-button,
1211
+ .stats-table-tr-clickable,
1212
+ .stats-nav-rail-item,
1213
+ .stats-range-control-btn,
1214
+ .stats-segmented-control-btn {
1215
+ transition: none;
281
1216
  }
282
1217
 
283
- @keyframes fadeIn {
284
- from { opacity: 0; }
285
- to { opacity: 1; }
1218
+ .stats-button:active:not(:disabled) {
1219
+ transform: none;
286
1220
  }
287
1221
 
288
- @keyframes slideUp {
289
- from {
290
- opacity: 0;
291
- transform: translateY(10px);
292
- }
293
- to {
294
- opacity: 1;
295
- transform: translateY(0);
296
- }
1222
+ .stats-mobile-drawer,
1223
+ .stats-drawer {
1224
+ animation: none;
297
1225
  }
1226
+ }
1227
+
1228
+ /* ==========================================================================
1229
+ Brand mark on the OMP wordmark (both rail + mobile drawer headers)
1230
+ ========================================================================== */
1231
+ .stats-logo-container {
1232
+ display: grid;
1233
+ grid-template-columns: auto 1fr;
1234
+ align-items: center;
1235
+ column-gap: 10px;
1236
+ }
1237
+
1238
+ .stats-logo-container::before {
1239
+ content: "";
1240
+ grid-row: 1 / 3;
1241
+ width: 16px;
1242
+ height: 16px;
1243
+ border-radius: 4px;
1244
+ background: linear-gradient(135deg, #ed4abf 0%, #9b4dff 50%, #5ad8e6 100%); /* OMP brand gradient mark */
1245
+ }
298
1246
 
299
- .spin {
300
- animation: spin 1s linear infinite;
1247
+ .stats-logo-text,
1248
+ .stats-logo-subtext {
1249
+ grid-column: 2;
1250
+ }
1251
+
1252
+ /* ==========================================================================
1253
+ JSON block copy affordance
1254
+ ========================================================================== */
1255
+ .stats-json-actions {
1256
+ display: flex;
1257
+ align-items: center;
1258
+ gap: 12px;
1259
+ }
1260
+
1261
+ .stats-json-copy-btn {
1262
+ display: inline-flex;
1263
+ align-items: center;
1264
+ gap: 5px;
1265
+ font-size: 11px;
1266
+ font-weight: 600;
1267
+ color: var(--muted);
1268
+ background: transparent;
1269
+ border: 1px solid var(--border);
1270
+ border-radius: var(--radius-sm);
1271
+ padding: 3px 8px;
1272
+ cursor: pointer;
1273
+ font-family: inherit;
1274
+ transition: color 0.12s ease, background 0.12s ease;
1275
+ }
1276
+
1277
+ .stats-json-copy-btn:hover {
1278
+ color: var(--text);
1279
+ background: var(--surface-2);
1280
+ }
1281
+
1282
+ /* ==========================================================================
1283
+ Empty-state icon
1284
+ ========================================================================== */
1285
+ .stats-empty-state-icon {
1286
+ color: var(--dim);
1287
+ margin-bottom: 12px;
1288
+ }
1289
+
1290
+ @media (prefers-reduced-motion: reduce) {
1291
+ .stats-json-copy-btn {
1292
+ transition: none;
301
1293
  }
1294
+ }
1295
+
1296
+ /* ==========================================================================
1297
+ Theme toggle (system / light / dark)
1298
+ ========================================================================== */
1299
+ .stats-theme-toggle {
1300
+ display: inline-flex;
1301
+ align-items: center;
1302
+ justify-content: center;
1303
+ width: 32px;
1304
+ height: 32px;
1305
+ flex-shrink: 0;
1306
+ border: 1px solid var(--border);
1307
+ border-radius: var(--radius-md);
1308
+ background: var(--surface);
1309
+ color: var(--muted);
1310
+ cursor: pointer;
1311
+ transition: color 0.14s ease, background 0.14s ease, border-color 0.14s ease;
1312
+ }
1313
+
1314
+ .stats-theme-toggle:hover {
1315
+ color: var(--text);
1316
+ border-color: var(--border-strong);
1317
+ }
302
1318
 
303
- @keyframes spin {
304
- to { transform: rotate(360deg); }
1319
+ @media (prefers-reduced-motion: reduce) {
1320
+ .stats-theme-toggle {
1321
+ transition: none;
305
1322
  }
306
1323
  }