@oh-my-pi/omp-stats 18.3.4 → 18.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (192) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +13 -11
  3. package/build.ts +5 -49
  4. package/dist/client/index.css +1 -1
  5. package/dist/client/index.html +2 -2
  6. package/dist/client/index.js +105 -126
  7. package/dist/types/aggregator.d.ts +25 -22
  8. package/dist/types/client/api.d.ts +11 -7
  9. package/dist/types/client/app/LiveChip.d.ts +2 -0
  10. package/dist/types/client/app/Shell.d.ts +16 -0
  11. package/dist/types/client/app/ThemeToggle.d.ts +1 -0
  12. package/dist/types/client/app/nav.d.ts +18 -0
  13. package/dist/types/client/charts/BarList.d.ts +17 -0
  14. package/dist/types/client/charts/Chart.d.ts +49 -0
  15. package/dist/types/client/charts/Legend.d.ts +16 -0
  16. package/dist/types/client/charts/ShareBar.d.ts +11 -0
  17. package/dist/types/client/charts/Sparkline.d.ts +11 -0
  18. package/dist/types/client/charts/TimeChart.d.ts +9 -0
  19. package/dist/types/client/charts/index.d.ts +7 -0
  20. package/dist/types/client/charts/types.d.ts +25 -0
  21. package/dist/types/client/charts/useWidth.d.ts +3 -0
  22. package/dist/types/client/data/colors.d.ts +25 -0
  23. package/dist/types/client/data/formatters.d.ts +9 -1
  24. package/dist/types/client/data/live.d.ts +29 -0
  25. package/dist/types/client/data/query.d.ts +35 -0
  26. package/dist/types/client/data/range.d.ts +31 -0
  27. package/dist/types/client/data/series.d.ts +28 -0
  28. package/dist/types/client/data/useHashRoute.d.ts +18 -4
  29. package/dist/types/client/data/view-models.d.ts +111 -28
  30. package/dist/types/client/index.d.ts +0 -1
  31. package/dist/types/client/routes/CostsRoute.d.ts +2 -2
  32. package/dist/types/client/routes/ErrorsRoute.d.ts +2 -2
  33. package/dist/types/client/routes/FrustrationRoute.d.ts +7 -0
  34. package/dist/types/client/routes/GainRoute.d.ts +1 -2
  35. package/dist/types/client/routes/ModelsRoute.d.ts +2 -2
  36. package/dist/types/client/routes/OverviewRoute.d.ts +1 -2
  37. package/dist/types/client/routes/ProjectsRoute.d.ts +2 -2
  38. package/dist/types/client/routes/ProvidersRoute.d.ts +2 -2
  39. package/dist/types/client/routes/RequestsRoute.d.ts +1 -2
  40. package/dist/types/client/routes/ToolsRoute.d.ts +2 -2
  41. package/dist/types/client/routes/TracesRoute.d.ts +2 -2
  42. package/dist/types/client/routes/index.d.ts +1 -1
  43. package/dist/types/client/traces/AggregatesPanel.d.ts +4 -3
  44. package/dist/types/client/traces/SummaryStrip.d.ts +2 -2
  45. package/dist/types/client/traces/trace-colors.d.ts +18 -12
  46. package/dist/types/client/ui/Badge.d.ts +19 -0
  47. package/dist/types/client/ui/Card.d.ts +25 -0
  48. package/dist/types/client/ui/Drawer.d.ts +25 -0
  49. package/dist/types/client/ui/JsonBlock.d.ts +2 -2
  50. package/dist/types/client/ui/Modal.d.ts +23 -0
  51. package/dist/types/client/ui/RequestDrawer.d.ts +10 -1
  52. package/dist/types/client/ui/SearchInput.d.ts +8 -0
  53. package/dist/types/client/ui/Segmented.d.ts +15 -0
  54. package/dist/types/client/ui/Stat.d.ts +36 -0
  55. package/dist/types/client/ui/States.d.ts +41 -0
  56. package/dist/types/client/ui/Table.d.ts +48 -0
  57. package/dist/types/client/ui/index.d.ts +9 -10
  58. package/dist/types/db.d.ts +90 -106
  59. package/dist/types/frustration.d.ts +70 -0
  60. package/dist/types/index.d.ts +3 -1
  61. package/dist/types/live.d.ts +30 -0
  62. package/dist/types/rollup.d.ts +115 -0
  63. package/dist/types/server.d.ts +6 -1
  64. package/dist/types/shared-types.d.ts +116 -56
  65. package/dist/types/types.d.ts +4 -0
  66. package/dist/types/user-metrics.d.ts +8 -0
  67. package/package.json +7 -13
  68. package/src/aggregator.ts +276 -211
  69. package/src/client/App.tsx +38 -80
  70. package/src/client/api.ts +65 -7
  71. package/src/client/app/LiveChip.tsx +97 -0
  72. package/src/client/app/Shell.tsx +181 -0
  73. package/src/client/app/ThemeToggle.tsx +5 -2
  74. package/src/client/app/nav.ts +78 -0
  75. package/src/client/charts/BarList.tsx +48 -0
  76. package/src/client/charts/Chart.tsx +388 -0
  77. package/src/client/charts/Legend.tsx +61 -0
  78. package/src/client/charts/ShareBar.tsx +26 -0
  79. package/src/client/charts/Sparkline.tsx +38 -0
  80. package/src/client/charts/TimeChart.tsx +22 -0
  81. package/src/client/charts/index.ts +7 -0
  82. package/src/client/charts/types.ts +27 -0
  83. package/src/client/charts/useWidth.ts +19 -0
  84. package/src/client/data/colors.ts +45 -0
  85. package/src/client/data/formatters.ts +30 -9
  86. package/src/client/data/live.tsx +85 -0
  87. package/src/client/data/query.ts +166 -0
  88. package/src/client/data/range.ts +82 -0
  89. package/src/client/data/series.ts +85 -0
  90. package/src/client/data/useHashRoute.ts +41 -83
  91. package/src/client/data/view-models.ts +347 -140
  92. package/src/client/index.tsx +3 -6
  93. package/src/client/routes/CostsRoute.tsx +394 -222
  94. package/src/client/routes/ErrorsRoute.tsx +401 -98
  95. package/src/client/routes/FrustrationRoute.tsx +924 -0
  96. package/src/client/routes/GainRoute.tsx +209 -206
  97. package/src/client/routes/ModelsRoute.tsx +540 -431
  98. package/src/client/routes/OverviewRoute.tsx +283 -311
  99. package/src/client/routes/ProjectsRoute.tsx +298 -156
  100. package/src/client/routes/ProvidersRoute.tsx +948 -416
  101. package/src/client/routes/RequestsRoute.tsx +295 -107
  102. package/src/client/routes/ToolsRoute.tsx +495 -398
  103. package/src/client/routes/TracesRoute.tsx +136 -117
  104. package/src/client/routes/costs.css +24 -0
  105. package/src/client/routes/errors.css +60 -0
  106. package/src/client/routes/frustration.css +123 -0
  107. package/src/client/routes/index.ts +1 -1
  108. package/src/client/routes/models.css +43 -0
  109. package/src/client/routes/projects.css +6 -0
  110. package/src/client/routes/providers.css +28 -0
  111. package/src/client/routes/tools.css +14 -0
  112. package/src/client/styles.css +1396 -1299
  113. package/src/client/traces/AggregatesPanel.tsx +55 -74
  114. package/src/client/traces/Minimap.tsx +6 -15
  115. package/src/client/traces/SpanDrawer.tsx +128 -194
  116. package/src/client/traces/SummaryStrip.tsx +21 -24
  117. package/src/client/traces/TimelineCanvas.tsx +27 -44
  118. package/src/client/traces/TraceView.tsx +175 -130
  119. package/src/client/traces/TranscriptList.tsx +13 -41
  120. package/src/client/traces/trace-colors.ts +60 -53
  121. package/src/client/traces/traces.css +279 -0
  122. package/src/client/ui/Badge.tsx +29 -0
  123. package/src/client/ui/Card.tsx +61 -0
  124. package/src/client/ui/Drawer.tsx +93 -0
  125. package/src/client/ui/JsonBlock.tsx +26 -44
  126. package/src/client/ui/Modal.tsx +106 -0
  127. package/src/client/ui/RequestDrawer.tsx +163 -188
  128. package/src/client/ui/SearchInput.tsx +25 -0
  129. package/src/client/ui/Segmented.tsx +61 -0
  130. package/src/client/ui/Stat.tsx +104 -0
  131. package/src/client/ui/States.tsx +81 -0
  132. package/src/client/ui/Table.tsx +229 -0
  133. package/src/client/ui/index.ts +9 -10
  134. package/src/client/ui/modal.css +54 -0
  135. package/src/client/ui/request-drawer.css +40 -0
  136. package/src/db.ts +379 -983
  137. package/src/frustration.ts +473 -0
  138. package/src/index.ts +22 -22
  139. package/src/live.ts +259 -0
  140. package/src/parser.ts +55 -66
  141. package/src/rollup.ts +951 -0
  142. package/src/server.ts +123 -40
  143. package/src/shared-types.ts +120 -56
  144. package/src/trace.ts +14 -7
  145. package/src/types.ts +4 -0
  146. package/src/user-metrics.ts +13 -0
  147. package/dist/client/styles.css +0 -1976
  148. package/dist/types/client/app/AppLayout.d.ts +0 -16
  149. package/dist/types/client/app/NavRail.d.ts +0 -7
  150. package/dist/types/client/app/RangeControl.d.ts +0 -7
  151. package/dist/types/client/app/SyncButton.d.ts +0 -14
  152. package/dist/types/client/app/TopBar.d.ts +0 -15
  153. package/dist/types/client/app/routes.d.ts +0 -12
  154. package/dist/types/client/components/AgentTokenShare.d.ts +0 -5
  155. package/dist/types/client/components/chart-shared.d.ts +0 -178
  156. package/dist/types/client/components/models-table-shared.d.ts +0 -175
  157. package/dist/types/client/components/range-meta.d.ts +0 -21
  158. package/dist/types/client/data/charts.d.ts +0 -1
  159. package/dist/types/client/data/useResource.d.ts +0 -13
  160. package/dist/types/client/routes/BehaviorRoute.d.ts +0 -7
  161. package/dist/types/client/ui/AsyncBoundary.d.ts +0 -12
  162. package/dist/types/client/ui/DataTable.d.ts +0 -17
  163. package/dist/types/client/ui/EmptyState.d.ts +0 -7
  164. package/dist/types/client/ui/ErrorState.d.ts +0 -6
  165. package/dist/types/client/ui/MetricCluster.d.ts +0 -5
  166. package/dist/types/client/ui/Panel.d.ts +0 -7
  167. package/dist/types/client/ui/SegmentedControl.d.ts +0 -12
  168. package/dist/types/client/ui/Skeleton.d.ts +0 -8
  169. package/dist/types/client/ui/StatusPill.d.ts +0 -7
  170. package/src/client/app/AppLayout.tsx +0 -93
  171. package/src/client/app/NavRail.tsx +0 -44
  172. package/src/client/app/RangeControl.tsx +0 -39
  173. package/src/client/app/SyncButton.tsx +0 -75
  174. package/src/client/app/TopBar.tsx +0 -73
  175. package/src/client/app/routes.ts +0 -93
  176. package/src/client/components/AgentTokenShare.tsx +0 -68
  177. package/src/client/components/chart-shared.tsx +0 -273
  178. package/src/client/components/models-table-shared.tsx +0 -255
  179. package/src/client/components/range-meta.ts +0 -73
  180. package/src/client/data/charts.ts +0 -14
  181. package/src/client/data/useResource.ts +0 -154
  182. package/src/client/routes/BehaviorRoute.tsx +0 -623
  183. package/src/client/ui/AsyncBoundary.tsx +0 -54
  184. package/src/client/ui/DataTable.tsx +0 -122
  185. package/src/client/ui/EmptyState.tsx +0 -16
  186. package/src/client/ui/ErrorState.tsx +0 -25
  187. package/src/client/ui/MetricCluster.tsx +0 -92
  188. package/src/client/ui/Panel.tsx +0 -24
  189. package/src/client/ui/SegmentedControl.tsx +0 -36
  190. package/src/client/ui/Skeleton.tsx +0 -17
  191. package/src/client/ui/StatusPill.tsx +0 -15
  192. package/tailwind.config.js +0 -40
@@ -1,1736 +1,1833 @@
1
- @import "tailwindcss/index.css";
2
-
3
1
  /* ==========================================================================
4
- OMP Theme Variables & Color Scheme
2
+ omp stats — design system
3
+ Pure-black chassis, one inset panel, hairline edges, one accent gradient.
4
+ Page-specific styles live next to their route (`routes/*.css`).
5
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
- --select-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23999' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
39
-
40
- --radius-sm: 3px;
41
- --radius-md: 6px;
42
- --radius-lg: 8px;
43
- }
44
-
45
- /* System-default fallback before JS sets data-theme; an explicit data-theme
46
- (set by the toggle / anti-flash script) opts out so the override wins. */
47
- @media (prefers-color-scheme: light) {
48
- :root:not([data-theme]) {
49
- color-scheme: light;
50
- --page: oklch(0.985 0.004 307);
51
- --surface: oklch(1 0 0);
52
- --surface-2: oklch(0.965 0.006 307);
53
- --border: oklch(0 0 0 / 10%);
54
- --border-strong: oklch(0 0 0 / 15%);
55
- --text: oklch(0.26 0.03 307);
56
- --muted: oklch(0.46 0.03 307);
57
- --dim: oklch(0.58 0.025 307);
58
- --accent: oklch(0.62 0.23 341);
59
- --accent-fg: oklch(0.99 0.01 341);
60
- --accent-muted: oklch(0.62 0.23 341 / 14%);
61
- --link: oklch(0.58 0.13 230);
62
- --success: oklch(0.55 0.13 150);
63
- --danger: oklch(0.55 0.19 25);
64
- --select-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23555' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
65
- --warning: oklch(0.6 0.13 85);
66
- }
67
- }
68
-
69
- /* Explicit theme override (toggle or persisted preference). */
6
+
7
+ :root,
8
+ [data-theme="dark"] {
9
+ color-scheme: dark;
10
+
11
+ /* Surface ramp: each step rises one notch off the page. */
12
+ --bg: #000;
13
+ --panel: #09090a;
14
+ --card: #0e0e10;
15
+ --raised: #17171a;
16
+ --overlay: rgba(14, 14, 16, 0.78);
17
+ --hover: rgba(255, 255, 255, 0.035);
18
+ --press: rgba(255, 255, 255, 0.06);
19
+ --selected: rgba(255, 255, 255, 0.075);
20
+
21
+ /* Hairlines are alpha so one value reads on every surface step. */
22
+ --line-1: rgba(255, 255, 255, 0.06);
23
+ --line-2: rgba(255, 255, 255, 0.09);
24
+ --line-3: rgba(255, 255, 255, 0.14);
25
+ --line-4: rgba(255, 255, 255, 0.22);
26
+
27
+ --ink-1: #ededef;
28
+ --ink-2: #a0a0a8;
29
+ --ink-3: #6c6c74;
30
+ --ink-4: #46464c;
31
+ --ink-inverse: #0a0a0b;
32
+
33
+ /* Accent: omp cyan → pink. Solid `--accent` for text/strokes, gradient for hero marks. */
34
+ --accent-a: #5ad8e6;
35
+ --accent-b: #ed4abf;
36
+ --accent: #f068c8;
37
+ --accent-soft: rgba(237, 74, 191, 0.14);
38
+ --accent-line: rgba(237, 74, 191, 0.35);
39
+ --accent-gradient: linear-gradient(100deg, var(--accent-a), var(--accent-b));
40
+ --focus: #5ad8e6;
41
+
42
+ /* Status. Live (real-time presence) is reserved for the live indicator. */
43
+ --ok: #3ecf8e;
44
+ --ok-soft: rgba(62, 207, 142, 0.13);
45
+ --warn: #f5a524;
46
+ --warn-soft: rgba(245, 165, 36, 0.13);
47
+ --bad: #ff6166;
48
+ --bad-soft: rgba(255, 97, 102, 0.13);
49
+ --live: #3ecf8e;
50
+
51
+ /* Charts. */
52
+ --chart-grid: rgba(255, 255, 255, 0.055);
53
+ --chart-axis: #5c5c64;
54
+ --chart-cursor: rgba(255, 255, 255, 0.05);
55
+ --chart-primary: #5ad8e6;
56
+ --chart-secondary: #ed4abf;
57
+
58
+ --shadow-1: 0 1px 0 rgba(255, 255, 255, 0.03) inset, 0 1px 2px rgba(0, 0, 0, 0.5);
59
+ --shadow-2: 0 8px 24px rgba(0, 0, 0, 0.55), 0 1px 0 rgba(255, 255, 255, 0.05) inset;
60
+ --shadow-3: 0 24px 64px rgba(0, 0, 0, 0.7), 0 1px 0 rgba(255, 255, 255, 0.06) inset;
61
+ }
62
+
70
63
  [data-theme="light"] {
71
- color-scheme: light;
72
- --page: oklch(0.985 0.004 307);
73
- --surface: oklch(1 0 0);
74
- --surface-2: oklch(0.965 0.006 307);
75
- --border: oklch(0 0 0 / 10%);
76
- --border-strong: oklch(0 0 0 / 15%);
77
- --text: oklch(0.26 0.03 307);
78
- --muted: oklch(0.46 0.03 307);
79
- --dim: oklch(0.58 0.025 307);
80
- --accent: oklch(0.62 0.23 341);
81
- --accent-fg: oklch(0.99 0.01 341);
82
- --accent-muted: oklch(0.62 0.23 341 / 14%);
83
- --link: oklch(0.58 0.13 230);
84
- --success: oklch(0.55 0.13 150);
85
- --danger: oklch(0.55 0.19 25);
86
- --select-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23555' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
87
- --warning: oklch(0.6 0.13 85);
64
+ color-scheme: light;
65
+
66
+ --bg: #f2f2f3;
67
+ --panel: #ffffff;
68
+ --card: #ffffff;
69
+ --raised: #f6f6f7;
70
+ --overlay: rgba(255, 255, 255, 0.8);
71
+ --hover: rgba(0, 0, 0, 0.03);
72
+ --press: rgba(0, 0, 0, 0.05);
73
+ --selected: rgba(0, 0, 0, 0.06);
74
+
75
+ --line-1: rgba(0, 0, 0, 0.06);
76
+ --line-2: rgba(0, 0, 0, 0.09);
77
+ --line-3: rgba(0, 0, 0, 0.14);
78
+ --line-4: rgba(0, 0, 0, 0.22);
79
+
80
+ --ink-1: #151518;
81
+ --ink-2: #5a5a63;
82
+ --ink-3: #8b8b94;
83
+ --ink-4: #b9b9c0;
84
+ --ink-inverse: #ffffff;
85
+
86
+ --accent-a: #1fa9bb;
87
+ --accent-b: #d42ea3;
88
+ --accent: #c42596;
89
+ --accent-soft: rgba(212, 46, 163, 0.1);
90
+ --accent-line: rgba(212, 46, 163, 0.3);
91
+ --focus: #1fa9bb;
92
+
93
+ --ok: #12a36b;
94
+ --ok-soft: rgba(18, 163, 107, 0.11);
95
+ --warn: #c77c02;
96
+ --warn-soft: rgba(199, 124, 2, 0.11);
97
+ --bad: #dc3a40;
98
+ --bad-soft: rgba(220, 58, 64, 0.1);
99
+ --live: #12a36b;
100
+
101
+ --chart-grid: rgba(0, 0, 0, 0.06);
102
+ --chart-axis: #9a9aa2;
103
+ --chart-cursor: rgba(0, 0, 0, 0.04);
104
+ --chart-primary: #1fa9bb;
105
+ --chart-secondary: #d42ea3;
106
+
107
+ --shadow-1: 0 1px 2px rgba(0, 0, 0, 0.04);
108
+ --shadow-2: 0 8px 24px rgba(0, 0, 0, 0.1);
109
+ --shadow-3: 0 24px 64px rgba(0, 0, 0, 0.16);
88
110
  }
89
111
 
90
- /* ==========================================================================
91
- Base Styles
92
- ========================================================================== */
93
- @layer base {
94
- * {
95
- box-sizing: border-box;
96
- }
97
-
98
- html {
99
- -webkit-font-smoothing: antialiased;
100
- -moz-osx-font-smoothing: grayscale;
101
- }
102
-
103
- body {
104
- font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
105
- background: var(--page);
106
- color: var(--text);
107
- margin: 0;
108
- min-height: 100vh;
109
- }
110
-
111
- /* Accessible focus ring style */
112
- button:focus-visible,
113
- a:focus-visible,
114
- [tabindex]:focus-visible {
115
- outline: 2px solid var(--link);
116
- outline-offset: 2px;
117
- }
112
+ :root {
113
+ --font-sans: "Inter var", "Inter", ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
114
+ --font-mono: ui-monospace, "SF Mono", "JetBrains Mono", "Fira Code", Menlo, Consolas, monospace;
115
+
116
+ --r-chip: 6px;
117
+ --r-control: 8px;
118
+ --r-card: 12px;
119
+ --r-panel: 16px;
120
+ --r-pill: 999px;
121
+
122
+ --topbar-h: 52px;
123
+ --sidebar-w: 224px;
124
+ --gutter: 28px;
125
+
126
+ --ease: cubic-bezier(0.2, 0, 0, 1);
127
+ --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
128
+ --dur-1: 120ms;
129
+ --dur-2: 200ms;
130
+ --dur-3: 360ms;
131
+ --stagger: 40ms;
118
132
  }
119
133
 
120
134
  /* ==========================================================================
121
- Layout Components
135
+ Reset & base
122
136
  ========================================================================== */
123
- .stats-app-container {
124
- display: flex;
125
- min-height: 100vh;
126
- background: var(--page);
127
- color: var(--text);
137
+ *,
138
+ *::before,
139
+ *::after {
140
+ box-sizing: border-box;
128
141
  }
129
142
 
130
- /* Navigation Rail (Sidebar) */
131
- .stats-nav-rail {
132
- width: 240px;
133
- background: var(--surface);
134
- border-right: 1px solid var(--border);
135
- display: flex;
136
- flex-direction: column;
137
- flex-shrink: 0;
143
+ html,
144
+ body {
145
+ margin: 0;
146
+ padding: 0;
138
147
  }
139
148
 
140
- .stats-desktop-nav {
141
- display: flex;
149
+ html {
150
+ -webkit-font-smoothing: antialiased;
151
+ -moz-osx-font-smoothing: grayscale;
152
+ text-rendering: optimizeLegibility;
153
+ background: var(--bg);
142
154
  }
143
155
 
144
- @media (max-width: 1023px) {
145
- .stats-desktop-nav {
146
- display: none;
147
- }
156
+ body {
157
+ font-family: var(--font-sans);
158
+ font-size: 13.5px;
159
+ line-height: 1.5;
160
+ color: var(--ink-1);
161
+ background: var(--bg);
162
+ min-height: 100dvh;
163
+ font-feature-settings: "cv11", "ss01";
148
164
  }
149
165
 
150
- .stats-nav-rail-header {
151
- padding: 20px 24px;
152
- border-bottom: 1px solid var(--border);
153
- height: 56px;
154
- display: flex;
155
- align-items: center;
166
+ h1,
167
+ h2,
168
+ h3,
169
+ h4,
170
+ p,
171
+ ul,
172
+ ol,
173
+ figure {
174
+ margin: 0;
175
+ padding: 0;
156
176
  }
157
177
 
158
- .stats-logo-container {
159
- display: flex;
160
- flex-direction: column;
178
+ ul,
179
+ ol {
180
+ list-style: none;
161
181
  }
162
182
 
163
- .stats-logo-text {
164
- font-size: 14px;
165
- font-weight: 700;
166
- letter-spacing: 0.1em;
167
- color: var(--text);
183
+ button,
184
+ input,
185
+ select,
186
+ textarea {
187
+ font: inherit;
188
+ color: inherit;
168
189
  }
169
190
 
170
- .stats-logo-subtext {
171
- font-size: 10px;
172
- text-transform: uppercase;
173
- letter-spacing: 0.05em;
174
- color: var(--muted);
191
+ button {
192
+ cursor: pointer;
193
+ background: none;
194
+ border: 0;
195
+ padding: 0;
175
196
  }
176
197
 
177
- .stats-nav-rail-menu {
178
- flex: 1;
179
- padding: 16px 12px;
180
- display: flex;
181
- flex-direction: column;
182
- gap: 4px;
198
+ button:disabled {
199
+ cursor: default;
183
200
  }
184
201
 
185
- .stats-nav-rail-item {
186
- display: flex;
187
- align-items: center;
188
- gap: 12px;
189
- padding: 10px 16px;
190
- font-size: 13px;
191
- font-weight: 500;
192
- color: var(--muted);
193
- background: transparent;
194
- border: none;
195
- border-radius: var(--radius-md);
196
- cursor: pointer;
197
- text-align: left;
198
- transition: all 0.15s ease;
202
+ a {
203
+ color: inherit;
204
+ text-decoration: none;
199
205
  }
200
206
 
201
- .stats-nav-rail-item:hover {
202
- color: var(--text);
203
- background: var(--surface-2);
207
+ svg {
208
+ display: block;
209
+ flex-shrink: 0;
204
210
  }
205
211
 
206
- .stats-nav-rail-item[data-active="true"] {
207
- color: var(--accent);
208
- background: var(--accent-muted);
209
- position: relative;
212
+ table {
213
+ border-collapse: collapse;
214
+ border-spacing: 0;
210
215
  }
211
216
 
212
- .stats-nav-rail-item[data-active="true"]::before {
213
- content: "";
214
- position: absolute;
215
- left: 0;
216
- top: 50%;
217
- height: 18px;
218
- width: 3px;
219
- border-radius: 0 3px 3px 0;
220
- background: var(--accent);
221
- transform: translateY(-50%);
217
+ code,
218
+ pre,
219
+ kbd {
220
+ font-family: var(--font-mono);
222
221
  }
223
222
 
224
- .stats-nav-rail-item-icon {
225
- flex-shrink: 0;
223
+ ::selection {
224
+ background: var(--accent-soft);
225
+ color: var(--ink-1);
226
226
  }
227
227
 
228
- .stats-nav-rail-footer {
229
- padding: 16px 24px;
230
- border-top: 1px solid var(--border);
228
+ :focus-visible {
229
+ outline: 2px solid var(--focus);
230
+ outline-offset: 2px;
231
+ border-radius: 4px;
231
232
  }
232
233
 
233
- .stats-version-tag {
234
- font-size: 11px;
235
- color: var(--dim);
234
+ [hidden] {
235
+ display: none !important;
236
236
  }
237
237
 
238
- /* Main Content Area */
239
- .stats-main-pane {
240
- flex: 1;
241
- display: flex;
242
- flex-direction: column;
243
- min-width: 0;
238
+ /* Thin, quiet scrollbars. */
239
+ * {
240
+ scrollbar-width: thin;
241
+ scrollbar-color: var(--line-3) transparent;
244
242
  }
245
243
 
246
- .stats-top-bar {
247
- height: 56px;
248
- background: var(--surface);
249
- border-bottom: 1px solid var(--border);
250
- display: flex;
251
- align-items: center;
252
- justify-content: space-between;
253
- padding: 0 24px;
244
+ /* ==========================================================================
245
+ Type utilities
246
+ ========================================================================== */
247
+ .mono {
248
+ font-family: var(--font-mono);
249
+ font-size: 0.93em;
254
250
  }
255
251
 
256
- @media (max-width: 767px) {
257
- .stats-top-bar {
258
- padding: 0 16px;
259
- flex-wrap: wrap;
260
- height: auto;
261
- min-height: 56px;
262
- padding-top: 8px;
263
- padding-bottom: 8px;
264
- gap: 12px;
265
- }
252
+ .num {
253
+ font-family: var(--font-mono);
254
+ font-variant-numeric: tabular-nums;
255
+ font-size: 0.93em;
256
+ letter-spacing: -0.01em;
266
257
  }
267
258
 
268
- .stats-top-bar-left {
269
- display: flex;
270
- align-items: center;
271
- gap: 12px;
259
+ .muted {
260
+ color: var(--ink-2);
272
261
  }
273
262
 
274
- .stats-mobile-menu-btn {
275
- display: none;
276
- background: transparent;
277
- border: none;
278
- color: var(--text);
279
- padding: 4px;
280
- cursor: pointer;
263
+ .dim {
264
+ color: var(--ink-3);
281
265
  }
282
266
 
283
- @media (max-width: 1023px) {
284
- .stats-mobile-menu-btn {
285
- display: inline-flex;
286
- align-items: center;
287
- justify-content: center;
288
- }
267
+ .micro {
268
+ font-size: 12px;
269
+ font-weight: 500;
270
+ color: var(--ink-3);
271
+ line-height: 1.4;
289
272
  }
290
273
 
291
- .stats-page-title {
292
- font-size: 16px;
293
- font-weight: 600;
294
- color: var(--text);
295
- margin: 0;
274
+ .truncate {
275
+ overflow: hidden;
276
+ text-overflow: ellipsis;
277
+ white-space: nowrap;
278
+ min-width: 0;
296
279
  }
297
280
 
298
- .stats-top-bar-right {
299
- display: flex;
300
- align-items: center;
301
- gap: 16px;
281
+ .tone-ok {
282
+ color: var(--ok);
302
283
  }
303
284
 
304
- @media (max-width: 767px) {
305
- .stats-top-bar-right {
306
- width: 100%;
307
- justify-content: space-between;
308
- gap: 8px;
309
- }
285
+ .tone-warn {
286
+ color: var(--warn);
310
287
  }
311
288
 
312
- .stats-top-bar-meta {
313
- display: flex;
314
- align-items: center;
289
+ .tone-bad {
290
+ color: var(--bad);
315
291
  }
316
292
 
317
- .stats-last-updated {
318
- font-size: 11px;
319
- color: var(--dim);
320
- font-variant-numeric: tabular-nums;
293
+ .tone-accent {
294
+ color: var(--accent);
321
295
  }
322
296
 
323
- .stats-content-area {
324
- flex: 1;
325
- overflow-y: auto;
297
+ .gradient-text {
298
+ background: var(--accent-gradient);
299
+ -webkit-background-clip: text;
300
+ background-clip: text;
301
+ color: transparent;
326
302
  }
327
303
 
328
- .stats-content-inner {
329
- max-width: 1560px;
330
- margin: 0 auto;
331
- padding: 24px;
332
- display: flex;
333
- flex-direction: column;
334
- gap: 24px;
304
+ /* ==========================================================================
305
+ Motion
306
+ ========================================================================== */
307
+ @keyframes rise {
308
+ from {
309
+ opacity: 0;
310
+ transform: translateY(6px);
311
+ }
312
+ to {
313
+ opacity: 1;
314
+ transform: none;
315
+ }
316
+ }
317
+
318
+ @keyframes fade {
319
+ from {
320
+ opacity: 0;
321
+ }
322
+ to {
323
+ opacity: 1;
324
+ }
325
+ }
326
+
327
+ @keyframes ping {
328
+ 0% {
329
+ transform: scale(1);
330
+ opacity: 0.7;
331
+ }
332
+ 80%,
333
+ 100% {
334
+ transform: scale(2.6);
335
+ opacity: 0;
336
+ }
335
337
  }
336
338
 
337
- @media (max-width: 767px) {
338
- .stats-content-inner {
339
- padding: 16px;
340
- gap: 16px;
341
- }
339
+ @keyframes shimmer {
340
+ from {
341
+ background-position: 200% 0;
342
+ }
343
+ to {
344
+ background-position: -200% 0;
345
+ }
342
346
  }
343
347
 
344
- /* Mobile Nav Drawer */
345
- .stats-mobile-drawer-overlay {
346
- position: fixed;
347
- inset: 0;
348
- background: rgba(0, 0, 0, 0.4);
349
- backdrop-filter: none; /* No decorative blurs */
350
- z-index: 100;
348
+ @keyframes indeterminate {
349
+ from {
350
+ transform: translateX(-100%);
351
+ }
352
+ to {
353
+ transform: translateX(250%);
354
+ }
351
355
  }
352
356
 
353
- .stats-mobile-drawer {
354
- position: absolute;
355
- left: 0;
356
- top: 0;
357
- bottom: 0;
358
- width: 260px;
359
- background: var(--surface);
360
- border-right: 1px solid var(--border);
361
- display: flex;
362
- flex-direction: column;
363
- z-index: 101;
364
- animation: slideIn 0.2s ease-out;
357
+ @keyframes spin {
358
+ to {
359
+ transform: rotate(360deg);
360
+ }
365
361
  }
366
362
 
367
- @keyframes slideIn {
368
- from { transform: translateX(-100%); }
369
- to { transform: translateX(0); }
363
+ @keyframes flash {
364
+ 0% {
365
+ color: var(--accent-a);
366
+ }
367
+ 100% {
368
+ color: inherit;
369
+ }
370
370
  }
371
371
 
372
- .stats-mobile-drawer-header {
373
- height: 56px;
374
- display: flex;
375
- align-items: center;
376
- justify-content: space-between;
377
- padding: 0 16px 0 24px;
378
- border-bottom: 1px solid var(--border);
372
+ .rise {
373
+ animation: rise var(--dur-3) var(--ease-out) backwards;
374
+ animation-delay: calc(var(--i, 0) * var(--stagger));
379
375
  }
380
376
 
381
- .stats-mobile-nav {
382
- display: flex;
383
- height: calc(100% - 56px);
377
+ .spin {
378
+ animation: spin 0.9s linear infinite;
384
379
  }
385
380
 
386
- /* ==========================================================================
387
- UI Primitives & Styles
388
- ========================================================================== */
389
-
390
- /* Button */
391
- .stats-button {
392
- display: inline-flex;
393
- align-items: center;
394
- justify-content: center;
395
- gap: 8px;
396
- padding: 8px 14px;
397
- font-size: 13px;
398
- font-weight: 500;
399
- border-radius: var(--radius-md);
400
- border: 1px solid transparent;
401
- cursor: pointer;
402
- transition: all 0.15s ease;
403
- font-family: inherit;
381
+ @media (prefers-reduced-motion: reduce) {
382
+ *,
383
+ *::before,
384
+ *::after {
385
+ animation-duration: 1ms !important;
386
+ animation-delay: 0ms !important;
387
+ transition-duration: 1ms !important;
388
+ }
404
389
  }
405
390
 
406
- .stats-button:active:not(:disabled) {
407
- transform: translateY(1px);
391
+ /* ==========================================================================
392
+ Shell: fixed glass topbar + naked sidebar framing one inset panel.
393
+ The document scrolls; the panel is not a scroll container.
394
+ ========================================================================== */
395
+ .shell-ambient {
396
+ position: fixed;
397
+ inset: 0;
398
+ pointer-events: none;
399
+ z-index: 0;
400
+ background:
401
+ radial-gradient(60rem 28rem at 12% -10%, color-mix(in srgb, var(--accent-a) 7%, transparent), transparent 70%),
402
+ radial-gradient(50rem 26rem at 95% -12%, color-mix(in srgb, var(--accent-b) 6%, transparent), transparent 70%);
408
403
  }
409
404
 
410
- .stats-button-primary {
411
- background: var(--accent);
412
- color: var(--accent-fg);
405
+ .topbar {
406
+ position: fixed;
407
+ top: 0;
408
+ left: 0;
409
+ right: 0;
410
+ height: var(--topbar-h);
411
+ z-index: 40;
412
+ display: flex;
413
+ align-items: center;
414
+ gap: 12px;
415
+ padding: 0 14px 0 18px;
416
+ background: color-mix(in srgb, var(--bg) 72%, transparent);
417
+ backdrop-filter: blur(14px) saturate(160%);
418
+ -webkit-backdrop-filter: blur(14px) saturate(160%);
419
+ border-bottom: 1px solid transparent;
420
+ transition: border-color var(--dur-2) var(--ease);
413
421
  }
414
422
 
415
- .stats-button-primary:hover:not(:disabled) {
416
- opacity: 0.9;
423
+ .topbar[data-scrolled="true"] {
424
+ border-bottom-color: var(--line-1);
417
425
  }
418
426
 
419
- .stats-button-primary:disabled {
420
- opacity: 0.5;
421
- cursor: not-allowed;
427
+ .topbar-brand {
428
+ display: flex;
429
+ align-items: center;
430
+ gap: 10px;
431
+ min-width: calc(var(--sidebar-w) - 18px);
432
+ font-weight: 600;
433
+ letter-spacing: -0.01em;
434
+ }
435
+
436
+ .topbar-mark {
437
+ flex: none;
438
+ display: block;
422
439
  }
423
440
 
424
- .stats-button-secondary {
425
- background: var(--surface-2);
426
- color: var(--text);
427
- border-color: var(--border);
441
+ .topbar-slash {
442
+ color: var(--ink-4);
443
+ font-weight: 300;
444
+ font-size: 18px;
428
445
  }
429
446
 
430
- .stats-button-secondary:hover:not(:disabled) {
431
- background: var(--border);
447
+ .topbar-title {
448
+ font-weight: 500;
449
+ color: var(--ink-1);
450
+ white-space: nowrap;
432
451
  }
433
452
 
434
- .stats-button-secondary:disabled {
435
- opacity: 0.5;
436
- cursor: not-allowed;
453
+ .topbar-spacer {
454
+ flex: 1;
437
455
  }
438
456
 
439
- /* RangeControl */
440
- .stats-range-control {
441
- display: flex;
442
- background: var(--surface-2);
443
- border: 1px solid var(--border);
444
- border-radius: var(--radius-md);
445
- padding: 2px;
457
+ .topbar-actions {
458
+ display: flex;
459
+ align-items: center;
460
+ gap: 8px;
446
461
  }
447
462
 
448
- .stats-range-control-btn {
449
- padding: 4px 10px;
450
- font-size: 12px;
451
- font-weight: 500;
452
- color: var(--muted);
453
- background: transparent;
454
- border: none;
455
- border-radius: var(--radius-sm);
456
- cursor: pointer;
457
- transition: all 0.1s ease;
463
+ .topbar-menu {
464
+ display: none;
458
465
  }
459
466
 
460
- .stats-range-control-btn:hover {
461
- color: var(--text);
467
+ /* Sync progress hairline along the bottom edge of the topbar. */
468
+ .topbar-progress {
469
+ position: absolute;
470
+ left: 0;
471
+ right: 0;
472
+ bottom: -1px;
473
+ height: 2px;
474
+ overflow: hidden;
475
+ pointer-events: none;
462
476
  }
463
477
 
464
- .stats-range-control-btn[data-active="true"] {
465
- color: var(--text);
466
- background: var(--surface);
467
- box-shadow: 0 1px 2px rgba(0, 0, 0, 0.18);
478
+ .topbar-progress-fill {
479
+ height: 100%;
480
+ background: var(--accent-gradient);
481
+ transition: width var(--dur-3) var(--ease);
482
+ box-shadow: 0 0 12px var(--accent-b);
468
483
  }
469
484
 
470
- /* Select (native <select>, themed to match RangeControl/Buttons) */
471
- .stats-select {
472
- appearance: none;
473
- padding: 6px 28px 6px 12px;
474
- font-size: 13px;
475
- font-weight: 500;
476
- font-family: inherit;
477
- color: var(--text);
478
- background-color: var(--surface-2);
479
- /* Chevron follows theme: light stroke on dark, dark stroke on light. */
480
- background-image: var(--select-chevron);
481
- background-repeat: no-repeat;
482
- background-position: right 10px center;
483
- border: 1px solid var(--border);
484
- border-radius: var(--radius-md);
485
- cursor: pointer;
486
- transition: border-color 0.15s ease, background-color 0.15s ease;
487
- max-width: 100%;
488
- text-overflow: ellipsis;
485
+ .topbar-progress-fill[data-indeterminate="true"] {
486
+ width: 40% !important;
487
+ animation: indeterminate 1.2s var(--ease) infinite;
489
488
  }
490
489
 
491
- .stats-select:hover:not(:disabled) {
492
- border-color: var(--border-strong);
493
- background-color: var(--bg-hover);
490
+ .sidebar {
491
+ position: fixed;
492
+ top: var(--topbar-h);
493
+ left: 0;
494
+ bottom: 0;
495
+ width: var(--sidebar-w);
496
+ padding: 8px 10px 14px;
497
+ overflow-y: auto;
498
+ scrollbar-width: none;
499
+ display: flex;
500
+ flex-direction: column;
501
+ gap: 18px;
502
+ z-index: 30;
494
503
  }
495
504
 
496
- .stats-select:focus-visible {
497
- outline: 2px solid var(--link);
498
- outline-offset: 1px;
505
+ .sidebar::-webkit-scrollbar {
506
+ display: none;
499
507
  }
500
508
 
501
- .stats-select:disabled {
502
- opacity: 0.5;
503
- cursor: not-allowed;
509
+ .nav-group {
510
+ display: flex;
511
+ flex-direction: column;
512
+ gap: 1px;
504
513
  }
505
514
 
506
- /* Prevent iOS from zooming the viewport when a select receives focus. */
507
- @media (pointer: coarse) {
508
- .stats-select {
509
- font-size: 16px;
510
- }
515
+ .nav-heading {
516
+ font-size: 12px;
517
+ font-weight: 500;
518
+ color: var(--ink-3);
519
+ padding: 0 10px 6px;
511
520
  }
512
521
 
513
- /* Dropdown list itself follows the page theme via color-scheme. */
514
- .stats-select option {
515
- background-color: var(--surface);
516
- color: var(--text);
517
- }
518
- /* Forced-colors (Windows High Contrast) suppresses background images, so the
519
- custom chevron vanishes; restore the native indicator instead. */
520
- @media (forced-colors: active) {
521
- .stats-select {
522
- appearance: auto;
523
- }
522
+ .nav-row {
523
+ display: flex;
524
+ align-items: center;
525
+ gap: 10px;
526
+ height: 32px;
527
+ padding: 0 10px;
528
+ border-radius: var(--r-control);
529
+ color: var(--ink-2);
530
+ font-weight: 450;
531
+ text-align: left;
532
+ width: 100%;
533
+ transition:
534
+ background var(--dur-1) var(--ease),
535
+ color var(--dur-1) var(--ease);
524
536
  }
525
537
 
526
- /* Sync Button & Container */
527
- .stats-sync-container {
528
- display: flex;
529
- align-items: center;
530
- gap: 12px;
538
+ .nav-row:hover {
539
+ background: var(--hover);
540
+ color: var(--ink-1);
531
541
  }
532
542
 
533
- .stats-sync-status-msg {
534
- font-size: 11px;
535
- font-variant-numeric: tabular-nums;
536
- max-width: 200px;
537
- white-space: nowrap;
538
- overflow: hidden;
539
- text-overflow: ellipsis;
543
+ .nav-row:active {
544
+ transform: scale(0.99);
540
545
  }
541
546
 
542
- .stats-sync-status-msg[data-type="success"] {
543
- color: var(--success);
547
+ .nav-row[data-active="true"] {
548
+ background: var(--selected);
549
+ color: var(--ink-1);
544
550
  }
545
551
 
546
- .stats-sync-status-msg[data-type="error"] {
547
- color: var(--danger);
552
+ .nav-row svg {
553
+ color: var(--ink-3);
554
+ transition: color var(--dur-1) var(--ease);
548
555
  }
549
556
 
550
- .stats-sync-icon {
551
- flex-shrink: 0;
557
+ .nav-row[data-active="true"] svg {
558
+ color: var(--accent);
552
559
  }
553
560
 
554
- .stats-spin {
555
- animation: spin 1s linear infinite;
561
+ .nav-row-label {
562
+ flex: 1;
556
563
  }
557
564
 
558
- @keyframes spin {
559
- to { transform: rotate(360deg); }
565
+ .nav-row kbd {
566
+ font-size: 10.5px;
567
+ color: var(--ink-4);
568
+ opacity: 0;
569
+ transition: opacity var(--dur-1) var(--ease);
560
570
  }
561
571
 
562
- /* Panel */
563
- .stats-panel {
564
- background: var(--surface);
565
- border: 1px solid var(--border);
566
- border-radius: var(--radius-lg);
567
- display: flex;
568
- flex-direction: column;
572
+ .nav-row:hover kbd {
573
+ opacity: 1;
569
574
  }
570
575
 
571
- .stats-panel-header {
572
- padding: 16px 20px;
573
- border-bottom: 1px solid var(--border);
574
- display: flex;
575
- align-items: center;
576
- justify-content: space-between;
577
- gap: 16px;
576
+ .sidebar-foot {
577
+ margin-top: auto;
578
+ padding: 10px;
579
+ border-radius: var(--r-card);
580
+ border: 1px solid var(--line-1);
581
+ background: var(--card);
582
+ display: flex;
583
+ flex-direction: column;
584
+ gap: 6px;
578
585
  }
579
586
 
580
- @media (max-width: 480px) {
581
- .stats-panel-header {
582
- flex-direction: column;
583
- align-items: flex-start;
584
- gap: 8px;
585
- }
587
+ .shell-panel {
588
+ position: relative;
589
+ z-index: 1;
590
+ margin: var(--topbar-h) 8px 8px var(--sidebar-w);
591
+ min-height: calc(100dvh - var(--topbar-h) - 8px);
592
+ background: var(--panel);
593
+ border-radius: var(--r-panel);
594
+ border: 1px solid var(--line-1);
595
+ box-shadow: var(--shadow-1);
596
+ overflow: clip;
586
597
  }
587
598
 
588
- .stats-panel-header-titles {
589
- display: flex;
590
- flex-direction: column;
599
+ .shell-content {
600
+ padding: 26px var(--gutter) 48px;
601
+ max-width: 1560px;
602
+ margin: 0 auto;
591
603
  }
592
604
 
593
- .stats-panel-title {
594
- font-size: 14px;
595
- font-weight: 600;
596
- color: var(--text);
597
- margin: 0;
605
+ .drawer-scrim {
606
+ position: fixed;
607
+ inset: 0;
608
+ background: rgba(0, 0, 0, 0.5);
609
+ z-index: 60;
610
+ animation: fade var(--dur-2) var(--ease) both;
598
611
  }
599
612
 
600
- .stats-panel-subtitle {
601
- font-size: 12px;
602
- color: var(--muted);
603
- margin: 2px 0 0 0;
613
+ @media (max-width: 1360px) {
614
+ :root {
615
+ --sidebar-w: 204px;
616
+ --gutter: 22px;
617
+ }
604
618
  }
605
619
 
606
- .stats-panel-actions {
607
- display: flex;
608
- align-items: center;
609
- gap: 12px;
610
- }
620
+ @media (max-width: 900px) {
621
+ :root {
622
+ --gutter: 16px;
623
+ }
611
624
 
612
- .stats-panel-body {
613
- padding: 20px;
614
- }
625
+ .topbar-brand {
626
+ min-width: 0;
627
+ }
615
628
 
616
- /* Metric Cluster (Overview Dashboard KPI Grid) */
617
- .stats-metric-cluster {
618
- display: flex;
619
- flex-direction: column;
620
- gap: 16px;
621
- }
629
+ .topbar-menu {
630
+ display: inline-flex;
631
+ }
622
632
 
623
- .stats-metric-primary-grid {
624
- display: grid;
625
- grid-template-columns: repeat(5, minmax(0, 1fr));
626
- gap: 16px;
627
- }
633
+ .sidebar {
634
+ top: 0;
635
+ width: 260px;
636
+ z-index: 70;
637
+ padding-top: 16px;
638
+ background: var(--overlay);
639
+ backdrop-filter: blur(18px) saturate(160%);
640
+ -webkit-backdrop-filter: blur(18px) saturate(160%);
641
+ border-right: 1px solid var(--line-2);
642
+ transform: translateX(-102%);
643
+ transition: transform var(--dur-3) var(--ease-out);
644
+ }
628
645
 
629
- @media (max-width: 1023px) {
630
- .stats-metric-primary-grid {
631
- grid-template-columns: repeat(2, 1fr);
632
- }
633
- }
646
+ .sidebar[data-open="true"] {
647
+ transform: none;
648
+ box-shadow: var(--shadow-3);
649
+ }
634
650
 
635
- @media (max-width: 480px) {
636
- .stats-metric-primary-grid {
637
- grid-template-columns: 1fr;
638
- }
639
- }
651
+ .shell-panel {
652
+ margin-left: 8px;
653
+ }
640
654
 
641
- .stats-metric-secondary-grid {
642
- display: grid;
643
- grid-template-columns: repeat(8, 1fr);
644
- gap: 12px;
655
+ .topbar-hide-narrow {
656
+ display: none !important;
657
+ }
645
658
  }
646
659
 
647
- @media (max-width: 1279px) {
648
- .stats-metric-secondary-grid {
649
- grid-template-columns: repeat(4, 1fr);
650
- }
660
+ /* ==========================================================================
661
+ Page header
662
+ ========================================================================== */
663
+ .page {
664
+ display: flex;
665
+ flex-direction: column;
666
+ gap: 20px;
651
667
  }
652
668
 
653
- @media (max-width: 767px) {
654
- .stats-metric-secondary-grid {
655
- grid-template-columns: repeat(2, 1fr);
656
- }
669
+ .page-header {
670
+ display: flex;
671
+ align-items: flex-end;
672
+ justify-content: space-between;
673
+ gap: 16px;
674
+ flex-wrap: wrap;
675
+ padding-bottom: 4px;
657
676
  }
658
677
 
659
- .stats-metric-card {
660
- background: var(--surface);
661
- border: 1px solid var(--border);
662
- border-radius: var(--radius-lg);
663
- padding: 16px;
664
- display: flex;
665
- flex-direction: column;
666
- justify-content: space-between;
678
+ .page-title {
679
+ font-size: 22px;
680
+ font-weight: 600;
681
+ letter-spacing: -0.02em;
682
+ line-height: 1.2;
667
683
  }
668
684
 
669
- .stats-metric-card.primary {
670
- padding: 20px 18px;
685
+ .page-description {
686
+ margin-top: 4px;
687
+ color: var(--ink-2);
688
+ max-width: 72ch;
671
689
  }
672
690
 
673
- .stats-metric-card.primary .stats-metric-label {
674
- color: var(--accent);
691
+ .page-actions {
692
+ display: flex;
693
+ align-items: center;
694
+ gap: 8px;
695
+ flex-wrap: wrap;
675
696
  }
676
697
 
677
- .stats-metric-card.secondary {
678
- padding: 12px 14px;
698
+ /* Grid helpers for page layouts. */
699
+ .grid {
700
+ display: grid;
701
+ gap: 16px;
679
702
  }
680
703
 
681
- .stats-metric-label {
682
- font-size: 11px;
683
- font-weight: 600;
684
- text-transform: uppercase;
685
- letter-spacing: 0.05em;
686
- color: var(--muted);
687
- margin-bottom: 8px;
704
+ .grid-2 {
705
+ grid-template-columns: repeat(2, minmax(0, 1fr));
688
706
  }
689
707
 
690
- .stats-metric-value {
691
- font-size: 20px;
692
- font-weight: 700;
693
- color: var(--text);
694
- font-variant-numeric: tabular-nums;
708
+ .grid-3 {
709
+ grid-template-columns: repeat(3, minmax(0, 1fr));
695
710
  }
696
711
 
697
- .stats-metric-card.secondary .stats-metric-value {
698
- font-size: 15px;
699
- font-weight: 600;
712
+ .grid-main-side {
713
+ grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
700
714
  }
701
715
 
702
- /* Data Table Component */
703
- .stats-table-wrapper {
704
- width: 100%;
716
+ @media (max-width: 1100px) {
717
+ .grid-2,
718
+ .grid-3,
719
+ .grid-main-side {
720
+ grid-template-columns: minmax(0, 1fr);
721
+ }
705
722
  }
706
723
 
707
- .stats-table-container {
708
- width: 100%;
709
- overflow-x: auto;
724
+ .row {
725
+ display: flex;
726
+ align-items: center;
727
+ gap: 8px;
728
+ min-width: 0;
710
729
  }
711
730
 
712
- .stats-table {
713
- width: 100%;
714
- border-collapse: collapse;
715
- font-size: 13px;
716
- font-variant-numeric: tabular-nums;
731
+ .stack {
732
+ display: flex;
733
+ flex-direction: column;
734
+ gap: 4px;
735
+ min-width: 0;
717
736
  }
718
737
 
719
- .stats-table-th {
720
- font-size: 11px;
721
- font-weight: 600;
722
- text-transform: uppercase;
723
- letter-spacing: 0.05em;
724
- color: var(--muted);
725
- padding: 12px 16px;
726
- border-bottom: 2px solid var(--border);
738
+ /* ==========================================================================
739
+ Card: top-lit gradient hairline over one surface step.
740
+ ========================================================================== */
741
+ .card {
742
+ position: relative;
743
+ border-radius: var(--r-card);
744
+ border: 1px solid transparent;
745
+ background:
746
+ linear-gradient(var(--card), var(--card)) padding-box,
747
+ linear-gradient(180deg, var(--line-3), var(--line-1) 40%) border-box;
748
+ box-shadow: var(--shadow-1);
749
+ min-width: 0;
750
+ display: flex;
751
+ flex-direction: column;
727
752
  }
728
753
 
729
- .stats-table-td {
730
- padding: 10px 16px;
731
- border-bottom: 1px solid var(--border);
732
- color: var(--text);
754
+ .card-header {
755
+ display: flex;
756
+ align-items: flex-start;
757
+ justify-content: space-between;
758
+ gap: 12px;
759
+ padding: 14px 16px 0;
760
+ flex-wrap: wrap;
733
761
  }
734
762
 
735
- .stats-table-tr {
736
- background: transparent;
763
+ .card-titles {
764
+ min-width: 0;
765
+ display: flex;
766
+ flex-direction: column;
767
+ gap: 2px;
737
768
  }
738
769
 
739
- .stats-table-tr-clickable {
740
- cursor: pointer;
741
- transition: background 0.12s ease, box-shadow 0.12s ease;
770
+ .card-title {
771
+ font-size: 14px;
772
+ font-weight: 550;
773
+ letter-spacing: -0.005em;
774
+ display: flex;
775
+ align-items: center;
776
+ gap: 8px;
742
777
  }
743
778
 
744
- .stats-table-tr-clickable:hover {
745
- background: var(--surface-2);
746
- box-shadow: inset 2px 0 0 var(--accent);
779
+ .card-description {
780
+ font-size: 12.5px;
781
+ color: var(--ink-3);
747
782
  }
748
783
 
749
- .stats-text-left {
750
- text-align: left;
784
+ .card-actions {
785
+ display: flex;
786
+ align-items: center;
787
+ gap: 6px;
788
+ flex-wrap: wrap;
751
789
  }
752
790
 
753
- .stats-text-right {
754
- text-align: right;
791
+ .card-body {
792
+ padding: 14px 16px 16px;
793
+ min-width: 0;
794
+ flex: 1;
755
795
  }
756
796
 
757
- .stats-table-empty {
758
- padding: 40px;
759
- text-align: center;
760
- color: var(--muted);
761
- font-size: 13px;
762
- border: 1px dashed var(--border);
763
- border-radius: var(--radius-lg);
797
+ .card-body[data-flush="true"] {
798
+ padding: 10px 0 0;
764
799
  }
765
800
 
766
- /* Project progress bars */
767
- .stats-progress-bar-track {
768
- background: var(--surface-2);
769
- border-radius: 999px;
770
- overflow: hidden;
801
+ .card-footer {
802
+ border-top: 1px solid var(--line-1);
803
+ padding: 10px 16px;
804
+ font-size: 12.5px;
805
+ color: var(--ink-3);
806
+ display: flex;
807
+ align-items: center;
808
+ justify-content: space-between;
809
+ gap: 8px;
771
810
  }
772
811
 
773
- .stats-progress-bar-fill {
774
- height: 100%;
775
- border-radius: inherit;
776
- transition: width 0.18s ease;
812
+ /* ==========================================================================
813
+ Stat
814
+ ========================================================================== */
815
+ .stat-grid {
816
+ display: grid;
817
+ grid-template-columns: repeat(auto-fit, minmax(var(--stat-min, 170px), 1fr));
818
+ border-radius: var(--r-card);
819
+ border: 1px solid transparent;
820
+ background:
821
+ linear-gradient(var(--card), var(--card)) padding-box,
822
+ linear-gradient(180deg, var(--line-3), var(--line-1) 40%) border-box;
823
+ box-shadow: var(--shadow-1);
824
+ overflow: hidden;
777
825
  }
778
826
 
779
- .stats-progress-bar-fill[data-variant="link"] {
780
- background: var(--link);
827
+ .stat {
828
+ position: relative;
829
+ padding: 14px 16px 12px;
830
+ display: flex;
831
+ flex-direction: column;
832
+ gap: 6px;
833
+ min-width: 0;
834
+ box-shadow:
835
+ 1px 0 0 var(--line-1),
836
+ 0 1px 0 var(--line-1);
781
837
  }
782
838
 
783
- .stats-progress-bar-fill[data-variant="success"] {
784
- background: var(--success);
839
+ .stat-label {
840
+ font-size: 12.5px;
841
+ font-weight: 500;
842
+ color: var(--ink-2);
843
+ display: flex;
844
+ align-items: center;
845
+ gap: 6px;
785
846
  }
786
847
 
787
- .stats-table-mobile-only {
788
- display: none;
848
+ .stat-value {
849
+ font-size: 24px;
850
+ font-weight: 550;
851
+ letter-spacing: -0.025em;
852
+ font-variant-numeric: tabular-nums;
853
+ line-height: 1.15;
854
+ white-space: nowrap;
855
+ overflow: hidden;
856
+ text-overflow: ellipsis;
789
857
  }
790
858
 
791
- /* Match .stats-table-container so mobile-card tables also contain horizontal
792
- overflow instead of spilling the page body on narrow desktops (768-1023px). */
793
- .stats-table-desktop-only {
794
- width: 100%;
795
- overflow-x: auto;
859
+ .stat[data-size="sm"] .stat-value {
860
+ font-size: 18px;
796
861
  }
797
862
 
798
- @media (max-width: 767px) {
799
- .stats-table-desktop-only {
800
- display: none;
801
- }
802
- .stats-table-mobile-only {
803
- display: block;
804
- }
863
+ .stat-value[data-flash="true"] {
864
+ animation: flash 900ms var(--ease) both;
805
865
  }
806
866
 
807
- .stats-table-mobile-list {
808
- display: flex;
809
- flex-direction: column;
810
- gap: 12px;
867
+ .stat-foot {
868
+ display: flex;
869
+ align-items: center;
870
+ gap: 8px;
871
+ font-size: 12px;
872
+ color: var(--ink-3);
873
+ min-height: 18px;
811
874
  }
812
875
 
813
- .stats-table-mobile-card-wrapper {
814
- background: var(--surface);
815
- border: 1px solid var(--border);
816
- border-radius: var(--radius-lg);
817
- padding: 14px;
876
+ .stat-spark {
877
+ margin-top: 2px;
878
+ height: 28px;
818
879
  }
819
880
 
820
- /* Status Pill */
821
- .stats-status-pill {
822
- display: inline-flex;
823
- align-items: center;
824
- justify-content: center;
825
- padding: 2px 8px;
826
- font-size: 11px;
827
- font-weight: 600;
828
- border-radius: 100px;
829
- line-height: 1.2;
881
+ .delta {
882
+ display: inline-flex;
883
+ align-items: center;
884
+ gap: 2px;
885
+ font-family: var(--font-mono);
886
+ font-size: 11.5px;
887
+ font-weight: 500;
888
+ padding: 1px 6px;
889
+ border-radius: var(--r-pill);
890
+ background: var(--raised);
891
+ color: var(--ink-2);
830
892
  }
831
893
 
832
- .stats-status-pill[data-variant="success"] {
833
- background: color-mix(in srgb, var(--success) 18%, transparent);
834
- color: var(--success);
894
+ .delta[data-tone="good"] {
895
+ color: var(--ok);
896
+ background: var(--ok-soft);
835
897
  }
836
898
 
837
- .stats-status-pill[data-variant="danger"] {
838
- background: color-mix(in srgb, var(--danger) 18%, transparent);
839
- color: var(--danger);
899
+ .delta[data-tone="bad"] {
900
+ color: var(--bad);
901
+ background: var(--bad-soft);
840
902
  }
841
903
 
842
- .stats-status-pill[data-variant="warning"] {
843
- background: color-mix(in srgb, var(--warning) 18%, transparent);
844
- color: var(--warning);
904
+ /* ==========================================================================
905
+ Controls
906
+ ========================================================================== */
907
+ .btn {
908
+ display: inline-flex;
909
+ align-items: center;
910
+ justify-content: center;
911
+ gap: 6px;
912
+ height: 30px;
913
+ padding: 0 12px;
914
+ border-radius: var(--r-control);
915
+ font-size: 13px;
916
+ font-weight: 500;
917
+ white-space: nowrap;
918
+ border: 1px solid var(--line-2);
919
+ background: var(--raised);
920
+ color: var(--ink-1);
921
+ transition:
922
+ background var(--dur-1) var(--ease),
923
+ border-color var(--dur-1) var(--ease),
924
+ transform var(--dur-1) var(--ease);
845
925
  }
846
926
 
847
- .stats-status-pill[data-variant="info"] {
848
- background: color-mix(in srgb, var(--link) 18%, transparent);
849
- color: var(--link);
927
+ .btn:hover:not(:disabled) {
928
+ border-color: var(--line-3);
929
+ background: color-mix(in srgb, var(--raised) 80%, var(--ink-1) 6%);
850
930
  }
851
931
 
852
- .stats-status-pill[data-variant="default"] {
853
- background: var(--surface-2);
854
- color: var(--muted);
932
+ .btn:active:not(:disabled) {
933
+ transform: scale(0.97);
855
934
  }
856
935
 
857
- /* Segmented Control */
858
- .stats-segmented-control {
859
- display: flex;
860
- background: var(--surface-2);
861
- border: 1px solid var(--border);
862
- border-radius: var(--radius-md);
863
- padding: 2px;
864
- gap: 2px;
936
+ .btn:disabled {
937
+ opacity: 0.5;
865
938
  }
866
939
 
867
- .stats-segmented-control-btn {
868
- padding: 6px 12px;
869
- font-size: 12px;
870
- font-weight: 500;
871
- color: var(--muted);
872
- background: transparent;
873
- border: none;
874
- border-radius: var(--radius-sm);
875
- cursor: pointer;
876
- transition: all 0.1s ease;
877
- white-space: nowrap;
940
+ .btn[data-variant="primary"] {
941
+ background: var(--ink-1);
942
+ color: var(--ink-inverse);
943
+ border-color: transparent;
878
944
  }
879
945
 
880
- .stats-segmented-control-btn:hover {
881
- color: var(--text);
946
+ .btn[data-variant="primary"]:hover:not(:disabled) {
947
+ background: color-mix(in srgb, var(--ink-1) 88%, transparent);
882
948
  }
883
949
 
884
- .stats-segmented-control-btn[data-active="true"] {
885
- color: var(--text);
886
- background: var(--surface);
887
- box-shadow: 0 1px 2px rgba(0, 0, 0, 0.18);
950
+ .btn[data-variant="accent"] {
951
+ background: var(--accent-gradient);
952
+ color: #fff;
953
+ border-color: transparent;
888
954
  }
889
955
 
890
- /* Drawer Detail Component */
891
- .stats-drawer-overlay {
892
- position: fixed;
893
- inset: 0;
894
- background: rgba(0, 0, 0, 0.5);
895
- z-index: 100;
896
- display: flex;
897
- justify-content: flex-end;
956
+ .btn[data-variant="ghost"] {
957
+ background: transparent;
958
+ border-color: transparent;
959
+ color: var(--ink-2);
898
960
  }
899
961
 
900
- .stats-drawer {
901
- width: 600px;
902
- max-width: 100%;
903
- height: 100%;
904
- background: var(--surface);
905
- border-left: 1px solid var(--border);
906
- display: flex;
907
- flex-direction: column;
908
- animation: drawerSlide 0.25s cubic-bezier(0.16, 1, 0.3, 1);
909
- box-shadow: -4px 0 24px rgba(0, 0, 0, 0.25);
962
+ .btn[data-variant="ghost"]:hover:not(:disabled) {
963
+ background: var(--hover);
964
+ color: var(--ink-1);
910
965
  }
911
966
 
912
- @keyframes drawerSlide {
913
- from { transform: translateX(100%); }
914
- to { transform: translateX(0); }
967
+ .btn[data-variant="danger"] {
968
+ background: var(--bad-soft);
969
+ color: var(--bad);
970
+ border-color: color-mix(in srgb, var(--bad) 30%, transparent);
915
971
  }
916
972
 
917
- .stats-drawer-header {
918
- height: 56px;
919
- border-bottom: 1px solid var(--border);
920
- padding: 0 24px;
921
- display: flex;
922
- align-items: center;
923
- justify-content: space-between;
924
- background: var(--surface);
925
- flex-shrink: 0;
973
+ .btn[data-size="sm"] {
974
+ height: 26px;
975
+ padding: 0 9px;
976
+ font-size: 12.5px;
926
977
  }
927
978
 
928
- .stats-drawer-header-left {
929
- display: flex;
930
- align-items: baseline;
931
- gap: 12px;
979
+ .btn[data-icon="true"] {
980
+ width: 30px;
981
+ padding: 0;
932
982
  }
933
983
 
934
- .stats-drawer-title {
935
- font-size: 15px;
936
- font-weight: 600;
937
- color: var(--text);
938
- margin: 0;
984
+ .btn[data-icon="true"][data-size="sm"] {
985
+ width: 26px;
939
986
  }
940
987
 
941
- .stats-drawer-id {
942
- font-size: 11px;
943
- color: var(--muted);
944
- font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
988
+ .input {
989
+ height: 30px;
990
+ padding: 0 10px;
991
+ border-radius: var(--r-control);
992
+ border: 1px solid var(--line-2);
993
+ background: var(--card);
994
+ color: var(--ink-1);
995
+ font-size: 13px;
996
+ min-width: 0;
997
+ transition: border-color var(--dur-1) var(--ease);
945
998
  }
946
999
 
947
- .stats-drawer-close-btn {
948
- background: transparent;
949
- border: none;
950
- color: var(--muted);
951
- cursor: pointer;
952
- padding: 4px;
953
- display: inline-flex;
954
- align-items: center;
955
- justify-content: center;
956
- border-radius: var(--radius-sm);
957
- transition: all 0.1s ease;
1000
+ .input::placeholder {
1001
+ color: var(--ink-3);
958
1002
  }
959
1003
 
960
- .stats-drawer-close-btn:hover {
961
- color: var(--text);
962
- background: var(--surface-2);
1004
+ .input:hover {
1005
+ border-color: var(--line-3);
963
1006
  }
964
1007
 
965
- .stats-drawer-body {
966
- flex: 1;
967
- overflow-y: auto;
968
- padding: 24px;
1008
+ .input:focus {
1009
+ outline: none;
1010
+ border-color: var(--focus);
1011
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--focus) 18%, transparent);
969
1012
  }
970
1013
 
971
- .stats-drawer-content {
972
- display: flex;
973
- flex-direction: column;
974
- gap: 24px;
1014
+ .search {
1015
+ position: relative;
1016
+ display: inline-flex;
1017
+ align-items: center;
975
1018
  }
976
1019
 
977
- .stats-drawer-status-card {
978
- background: var(--surface-2);
979
- border: 1px solid var(--border);
980
- border-radius: var(--radius-lg);
981
- padding: 16px;
1020
+ .search svg {
1021
+ position: absolute;
1022
+ left: 9px;
1023
+ color: var(--ink-3);
1024
+ pointer-events: none;
982
1025
  }
983
1026
 
984
- .stats-drawer-status-row {
985
- display: flex;
986
- justify-content: space-between;
987
- align-items: flex-start;
988
- gap: 16px;
1027
+ .search .input {
1028
+ padding-left: 30px;
1029
+ width: 240px;
989
1030
  }
990
1031
 
991
- .stats-drawer-model {
992
- font-size: 16px;
993
- font-weight: 700;
994
- color: var(--text);
1032
+ select.input {
1033
+ appearance: none;
1034
+ padding-right: 28px;
1035
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23888' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
1036
+ background-repeat: no-repeat;
1037
+ background-position: right 9px center;
1038
+ cursor: pointer;
995
1039
  }
996
1040
 
997
- .stats-drawer-provider {
998
- font-size: 12px;
999
- color: var(--muted);
1000
- margin-top: 2px;
1041
+ .check {
1042
+ display: inline-flex;
1043
+ align-items: center;
1044
+ gap: 6px;
1045
+ font-size: 12.5px;
1046
+ color: var(--ink-2);
1047
+ cursor: pointer;
1048
+ user-select: none;
1001
1049
  }
1002
1050
 
1003
- .stats-drawer-error-block {
1004
- margin-top: 14px;
1005
- border-top: 1px solid var(--border);
1006
- padding-top: 12px;
1051
+ .check input {
1052
+ accent-color: var(--accent);
1007
1053
  }
1008
1054
 
1009
- .stats-drawer-error-label {
1010
- font-size: 11px;
1011
- font-weight: 600;
1012
- text-transform: uppercase;
1013
- letter-spacing: 0.05em;
1014
- color: var(--danger);
1015
- margin-bottom: 4px;
1055
+ /* Segmented control with a measured sliding thumb. */
1056
+ .segmented {
1057
+ position: relative;
1058
+ display: inline-flex;
1059
+ align-items: center;
1060
+ padding: 2px;
1061
+ gap: 0;
1062
+ border-radius: var(--r-control);
1063
+ background: var(--card);
1064
+ border: 1px solid var(--line-2);
1065
+ isolation: isolate;
1016
1066
  }
1017
1067
 
1018
- .stats-drawer-error-text {
1019
- font-size: 12px;
1020
- color: var(--text);
1021
- font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
1022
- white-space: pre-wrap;
1023
- word-break: break-all;
1068
+ .segmented-thumb {
1069
+ position: absolute;
1070
+ top: 2px;
1071
+ bottom: 2px;
1072
+ border-radius: 6px;
1073
+ background: var(--raised);
1074
+ border: 1px solid var(--line-3);
1075
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);
1076
+ transition:
1077
+ left var(--dur-2) var(--ease-out),
1078
+ width var(--dur-2) var(--ease-out);
1079
+ z-index: -1;
1024
1080
  }
1025
1081
 
1026
- .stats-drawer-metrics-grid {
1027
- display: grid;
1028
- grid-template-columns: repeat(2, 1fr);
1029
- gap: 12px;
1082
+ .segmented-option {
1083
+ height: 24px;
1084
+ padding: 0 10px;
1085
+ border-radius: 6px;
1086
+ font-size: 12.5px;
1087
+ font-weight: 500;
1088
+ color: var(--ink-3);
1089
+ white-space: nowrap;
1090
+ display: inline-flex;
1091
+ align-items: center;
1092
+ gap: 6px;
1093
+ transition: color var(--dur-1) var(--ease);
1030
1094
  }
1031
1095
 
1032
- .stats-drawer-metric-card {
1033
- background: var(--surface);
1034
- border: 1px solid var(--border);
1035
- border-radius: var(--radius-lg);
1036
- padding: 14px;
1037
- display: flex;
1038
- flex-direction: column;
1039
- justify-content: center;
1096
+ .segmented-option:hover {
1097
+ color: var(--ink-1);
1040
1098
  }
1041
1099
 
1042
- .stats-drawer-metric-label {
1043
- display: flex;
1044
- align-items: center;
1045
- gap: 6px;
1046
- font-size: 11px;
1047
- font-weight: 600;
1048
- text-transform: uppercase;
1049
- letter-spacing: 0.05em;
1050
- color: var(--muted);
1051
- margin-bottom: 6px;
1100
+ .segmented-option[data-active="true"] {
1101
+ color: var(--ink-1);
1052
1102
  }
1053
1103
 
1054
- .stats-drawer-metric-icon {
1055
- color: var(--dim);
1056
- }
1104
+ .segmented[data-size="sm"] .segmented-option {
1105
+ height: 22px;
1106
+ padding: 0 8px;
1107
+ font-size: 12px;
1108
+ }
1057
1109
 
1058
- .stats-drawer-metric-value {
1059
- font-size: 16px;
1060
- font-weight: 700;
1061
- color: var(--text);
1062
- font-variant-numeric: tabular-nums;
1110
+ /* Tabs: underline style for in-card view switches. */
1111
+ .tabs {
1112
+ display: flex;
1113
+ align-items: center;
1114
+ gap: 16px;
1115
+ border-bottom: 1px solid var(--line-1);
1116
+ padding: 0 16px;
1063
1117
  }
1064
1118
 
1065
- .stats-drawer-metric-sub {
1066
- font-size: 11px;
1067
- color: var(--muted);
1068
- margin-top: 2px;
1069
- font-variant-numeric: tabular-nums;
1119
+ .tab {
1120
+ position: relative;
1121
+ height: 36px;
1122
+ font-size: 13px;
1123
+ font-weight: 500;
1124
+ color: var(--ink-3);
1125
+ display: inline-flex;
1126
+ align-items: center;
1127
+ gap: 6px;
1128
+ }
1129
+
1130
+ .tab:hover {
1131
+ color: var(--ink-1);
1132
+ }
1133
+
1134
+ .tab[data-active="true"] {
1135
+ color: var(--ink-1);
1136
+ }
1137
+
1138
+ .tab[data-active="true"]::after {
1139
+ content: "";
1140
+ position: absolute;
1141
+ left: 0;
1142
+ right: 0;
1143
+ bottom: -1px;
1144
+ height: 2px;
1145
+ border-radius: 2px;
1146
+ background: var(--accent-gradient);
1147
+ }
1148
+
1149
+ .kbd {
1150
+ display: inline-flex;
1151
+ align-items: center;
1152
+ justify-content: center;
1153
+ min-width: 18px;
1154
+ height: 18px;
1155
+ padding: 0 4px;
1156
+ border-radius: 5px;
1157
+ border: 1px solid var(--line-2);
1158
+ background: var(--card);
1159
+ font-family: var(--font-mono);
1160
+ font-size: 10.5px;
1161
+ color: var(--ink-3);
1070
1162
  }
1071
1163
 
1072
- .stats-drawer-json-blocks {
1073
- display: flex;
1074
- flex-direction: column;
1075
- gap: 16px;
1164
+ /* ==========================================================================
1165
+ Badge & dot
1166
+ ========================================================================== */
1167
+ .badge {
1168
+ display: inline-flex;
1169
+ align-items: center;
1170
+ gap: 5px;
1171
+ height: 20px;
1172
+ padding: 0 8px;
1173
+ border-radius: var(--r-pill);
1174
+ font-size: 11.5px;
1175
+ font-weight: 500;
1176
+ white-space: nowrap;
1177
+ background: var(--raised);
1178
+ color: var(--ink-2);
1179
+ border: 1px solid var(--line-1);
1076
1180
  }
1077
1181
 
1078
- /* Collapsible JSON Block */
1079
- .stats-json-block {
1080
- border: 1px solid var(--border);
1081
- border-radius: var(--radius-lg);
1082
- background: var(--surface);
1083
- overflow: hidden;
1182
+ .badge[data-tone="ok"] {
1183
+ background: var(--ok-soft);
1184
+ color: var(--ok);
1185
+ border-color: transparent;
1084
1186
  }
1085
1187
 
1086
- .stats-json-block-header {
1087
- padding: 10px 16px;
1088
- background: var(--surface-2);
1089
- border-bottom: 1px solid var(--border);
1090
- display: flex;
1091
- justify-content: space-between;
1092
- align-items: center;
1093
- cursor: pointer;
1094
- user-select: none;
1095
- font-size: 12px;
1096
- font-weight: 600;
1188
+ .badge[data-tone="warn"] {
1189
+ background: var(--warn-soft);
1190
+ color: var(--warn);
1191
+ border-color: transparent;
1097
1192
  }
1098
1193
 
1099
- .stats-json-block-header:hover {
1100
- background: var(--border);
1194
+ .badge[data-tone="bad"] {
1195
+ background: var(--bad-soft);
1196
+ color: var(--bad);
1197
+ border-color: transparent;
1101
1198
  }
1102
1199
 
1103
- .stats-json-block-title {
1104
- color: var(--text);
1200
+ .badge[data-tone="accent"] {
1201
+ background: var(--accent-soft);
1202
+ color: var(--accent);
1203
+ border-color: transparent;
1105
1204
  }
1106
1205
 
1107
- .stats-json-block-toggle-indicator {
1108
- color: var(--muted);
1206
+ .badge[data-mono="true"] {
1207
+ font-family: var(--font-mono);
1208
+ font-size: 11px;
1109
1209
  }
1110
1210
 
1111
- .stats-json-block-content-wrapper {
1112
- padding: 16px;
1113
- background: var(--page);
1114
- overflow-x: auto;
1211
+ .dot {
1212
+ position: relative;
1213
+ display: inline-block;
1214
+ width: 8px;
1215
+ height: 8px;
1216
+ border-radius: 50%;
1217
+ background: var(--ink-3);
1218
+ flex-shrink: 0;
1115
1219
  }
1116
1220
 
1117
- .stats-json-block-content {
1118
- margin: 0;
1119
- font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
1120
- font-size: 12px;
1121
- color: var(--text);
1122
- line-height: 1.5;
1221
+ .dot[data-tone="ok"],
1222
+ .dot[data-tone="live"] {
1223
+ background: var(--live);
1123
1224
  }
1124
1225
 
1125
- /* Skeleton Loading Element */
1126
- .stats-skeleton {
1127
- background: var(--surface-2);
1128
- position: relative;
1129
- overflow: hidden;
1130
- border-radius: var(--radius-sm);
1226
+ .dot[data-tone="warn"] {
1227
+ background: var(--warn);
1131
1228
  }
1132
1229
 
1133
- .stats-skeleton[data-variant="text"] {
1134
- height: 14px;
1135
- margin-top: 4px;
1136
- margin-bottom: 4px;
1230
+ .dot[data-tone="bad"] {
1231
+ background: var(--bad);
1137
1232
  }
1138
1233
 
1139
- .stats-skeleton[data-variant="circle"] {
1140
- border-radius: 50%;
1234
+ .dot[data-tone="accent"] {
1235
+ background: var(--accent);
1141
1236
  }
1142
1237
 
1143
- /* Subtle Shimmer effect, respecting media queries for reduced motion */
1144
- .stats-skeleton::after {
1145
- content: "";
1146
- position: absolute;
1147
- inset: 0;
1148
- transform: translateX(-100%);
1149
- background: linear-gradient(
1150
- 90deg,
1151
- transparent 0%,
1152
- rgba(255, 255, 255, 0.05) 50%,
1153
- transparent 100%
1154
- );
1155
- animation: shimmer 1.5s infinite;
1238
+ .dot[data-pulse="true"]::after {
1239
+ content: "";
1240
+ position: absolute;
1241
+ inset: 0;
1242
+ border-radius: 50%;
1243
+ background: inherit;
1244
+ animation: ping 1.6s var(--ease-out) infinite;
1156
1245
  }
1157
1246
 
1158
- @media (prefers-color-scheme: light) {
1159
- .stats-skeleton::after {
1160
- background: linear-gradient(
1161
- 90deg,
1162
- transparent 0%,
1163
- rgba(0, 0, 0, 0.03) 50%,
1164
- transparent 100%
1165
- );
1166
- }
1247
+ .swatch {
1248
+ display: inline-block;
1249
+ width: 8px;
1250
+ height: 8px;
1251
+ border-radius: 2px;
1252
+ flex-shrink: 0;
1167
1253
  }
1168
1254
 
1169
- @keyframes shimmer {
1170
- 100% { transform: translateX(100%); }
1255
+ /* ==========================================================================
1256
+ Table
1257
+ ========================================================================== */
1258
+ .table-wrap {
1259
+ overflow-x: auto;
1260
+ min-width: 0;
1171
1261
  }
1172
1262
 
1173
- @media (prefers-reduced-motion: reduce) {
1174
- .stats-skeleton::after {
1175
- animation: none;
1176
- }
1263
+ .table {
1264
+ width: 100%;
1265
+ font-size: 13px;
1177
1266
  }
1178
1267
 
1179
- .stats-boundary-skeleton {
1180
- padding: 20px;
1181
- border: 1px solid var(--border);
1182
- border-radius: var(--radius-lg);
1183
- background: var(--surface);
1268
+ .table th {
1269
+ position: sticky;
1270
+ top: 0;
1271
+ z-index: 1;
1272
+ text-align: left;
1273
+ font-size: 12px;
1274
+ font-weight: 500;
1275
+ color: var(--ink-3);
1276
+ padding: 8px 12px;
1277
+ white-space: nowrap;
1278
+ background: var(--card);
1279
+ border-bottom: 1px solid var(--line-1);
1280
+ user-select: none;
1184
1281
  }
1185
1282
 
1186
- /* Empty State / Error State */
1187
- .stats-empty-state,
1188
- .stats-error-state {
1189
- padding: 48px 24px;
1190
- display: flex;
1191
- flex-direction: column;
1192
- align-items: center;
1193
- justify-content: center;
1194
- text-align: center;
1195
- background: var(--surface);
1196
- border: 1px dashed var(--border);
1197
- border-radius: var(--radius-lg);
1283
+ .table th:first-child,
1284
+ .table td:first-child {
1285
+ padding-left: 16px;
1198
1286
  }
1199
1287
 
1200
- .stats-empty-state-message {
1201
- font-size: 13px;
1202
- color: var(--muted);
1203
- margin: 0;
1288
+ .table th:last-child,
1289
+ .table td:last-child {
1290
+ padding-right: 16px;
1204
1291
  }
1205
1292
 
1206
- .stats-error-state-content {
1207
- max-width: 360px;
1293
+ .table th[data-sortable="true"] {
1294
+ cursor: pointer;
1208
1295
  }
1209
1296
 
1210
- .stats-error-state-title {
1211
- font-size: 14px;
1212
- font-weight: 600;
1213
- color: var(--text);
1214
- margin: 0 0 8px 0;
1297
+ .table th[data-sortable="true"]:hover {
1298
+ color: var(--ink-1);
1215
1299
  }
1216
1300
 
1217
- .stats-error-state-message {
1218
- font-size: 12px;
1219
- color: var(--danger);
1220
- margin: 0 0 16px 0;
1221
- word-break: break-word;
1301
+ .table th[data-sorted] {
1302
+ color: var(--ink-1);
1222
1303
  }
1223
1304
 
1224
- .stats-error-state-btn {
1225
- margin: 0 auto;
1305
+ .table th .sort-arrow {
1306
+ display: inline-block;
1307
+ margin-left: 4px;
1308
+ opacity: 0.8;
1309
+ vertical-align: -1px;
1226
1310
  }
1227
1311
 
1228
- /* ==========================================================================
1229
- Token-vocabulary bridge utility classes (used across route components)
1230
- ========================================================================== */
1231
- .stats-text-primary { color: var(--text); }
1232
- .stats-text-secondary { color: var(--muted); }
1233
- .stats-text-muted { color: var(--dim); }
1234
- .stats-text-warning { color: var(--warning); }
1235
- .stats-text-xs { font-size: 12px; }
1236
- .stats-font-medium { font-weight: 500; }
1237
- .stats-font-semibold { font-weight: 600; }
1238
-
1239
- /* ==========================================================================
1240
- Owned scrollbars — thin, brand-tinted, app-wide (ComPress convention)
1241
- ========================================================================== */
1242
- * {
1243
- scrollbar-width: thin;
1244
- scrollbar-color: var(--border-strong) transparent;
1312
+ .table td {
1313
+ padding: 9px 12px;
1314
+ border-bottom: 1px solid var(--line-1);
1315
+ vertical-align: middle;
1316
+ white-space: nowrap;
1245
1317
  }
1246
1318
 
1247
- *::-webkit-scrollbar {
1248
- width: 10px;
1249
- height: 10px;
1319
+ .table tbody tr:last-child td {
1320
+ border-bottom: 0;
1250
1321
  }
1251
1322
 
1252
- *::-webkit-scrollbar-track {
1253
- background: transparent;
1323
+ .table tbody tr {
1324
+ transition: background var(--dur-1) var(--ease);
1254
1325
  }
1255
1326
 
1256
- *::-webkit-scrollbar-thumb {
1257
- background: var(--border-strong);
1258
- border: 2px solid transparent;
1259
- background-clip: padding-box;
1260
- border-radius: 999px;
1327
+ .table tbody tr:hover {
1328
+ background: var(--hover);
1261
1329
  }
1262
1330
 
1263
- *::-webkit-scrollbar-thumb:hover {
1264
- background: var(--dim);
1265
- border: 2px solid transparent;
1266
- background-clip: padding-box;
1331
+ .table tbody tr[data-clickable="true"] {
1332
+ cursor: pointer;
1267
1333
  }
1268
1334
 
1269
- *::-webkit-scrollbar-corner {
1270
- background: transparent;
1335
+ .table tbody tr[data-selected="true"] {
1336
+ background: var(--selected);
1271
1337
  }
1272
1338
 
1273
- /* ==========================================================================
1274
- Comprehensive reduced-motion fallback for all interaction motion
1275
- ========================================================================== */
1276
- @media (prefers-reduced-motion: reduce) {
1277
- .stats-button,
1278
- .stats-table-tr-clickable,
1279
- .stats-nav-rail-item,
1280
- .stats-range-control-btn,
1281
- .stats-segmented-control-btn {
1282
- transition: none;
1283
- }
1284
-
1285
- .stats-button:active:not(:disabled) {
1286
- transform: none;
1287
- }
1288
-
1289
- .stats-mobile-drawer,
1290
- .stats-drawer {
1291
- animation: none;
1292
- }
1339
+ .table [data-align="right"] {
1340
+ text-align: right;
1293
1341
  }
1294
1342
 
1295
- /* ==========================================================================
1296
- Brand mark on the OMP wordmark (both rail + mobile drawer headers)
1297
- ========================================================================== */
1298
- .stats-logo-container {
1299
- display: grid;
1300
- grid-template-columns: auto 1fr;
1301
- align-items: center;
1302
- column-gap: 10px;
1343
+ .table [data-align="center"] {
1344
+ text-align: center;
1303
1345
  }
1304
1346
 
1305
- .stats-logo-container::before {
1306
- content: "";
1307
- grid-row: 1 / 3;
1308
- width: 16px;
1309
- height: 16px;
1310
- border-radius: 4px;
1311
- background: linear-gradient(135deg, #ed4abf 0%, #9b4dff 50%, #5ad8e6 100%); /* OMP brand gradient mark */
1347
+ .table td[data-wrap="true"] {
1348
+ white-space: normal;
1312
1349
  }
1313
1350
 
1314
- .stats-logo-text,
1315
- .stats-logo-subtext {
1316
- grid-column: 2;
1351
+ .table[data-dense="true"] td {
1352
+ padding-top: 6px;
1353
+ padding-bottom: 6px;
1317
1354
  }
1318
1355
 
1319
- /* ==========================================================================
1320
- JSON block copy affordance
1321
- ========================================================================== */
1322
- .stats-json-actions {
1323
- display: flex;
1324
- align-items: center;
1325
- gap: 12px;
1356
+ .table-more {
1357
+ display: flex;
1358
+ justify-content: center;
1359
+ align-items: center;
1360
+ gap: 8px;
1361
+ padding: 10px;
1362
+ border-top: 1px solid var(--line-1);
1326
1363
  }
1327
1364
 
1328
- .stats-json-copy-btn {
1329
- display: inline-flex;
1330
- align-items: center;
1331
- gap: 5px;
1332
- font-size: 11px;
1333
- font-weight: 600;
1334
- color: var(--muted);
1335
- background: transparent;
1336
- border: 1px solid var(--border);
1337
- border-radius: var(--radius-sm);
1338
- padding: 3px 8px;
1339
- cursor: pointer;
1340
- font-family: inherit;
1341
- transition: color 0.12s ease, background 0.12s ease;
1365
+ .cell-primary {
1366
+ font-weight: 500;
1367
+ color: var(--ink-1);
1342
1368
  }
1343
1369
 
1344
- .stats-json-copy-btn:hover {
1345
- color: var(--text);
1346
- background: var(--surface-2);
1370
+ .cell-secondary {
1371
+ font-size: 12px;
1372
+ color: var(--ink-3);
1347
1373
  }
1348
1374
 
1349
- /* ==========================================================================
1350
- Empty-state icon
1351
- ========================================================================== */
1352
- .stats-empty-state-icon {
1353
- color: var(--dim);
1354
- margin-bottom: 12px;
1375
+ /* Inline proportional bar used inside table cells. */
1376
+ .meter {
1377
+ position: relative;
1378
+ height: 4px;
1379
+ border-radius: 2px;
1380
+ background: var(--line-1);
1381
+ overflow: hidden;
1382
+ min-width: 48px;
1355
1383
  }
1356
1384
 
1357
- @media (prefers-reduced-motion: reduce) {
1358
- .stats-json-copy-btn {
1359
- transition: none;
1360
- }
1385
+ .meter-fill {
1386
+ position: absolute;
1387
+ inset: 0 auto 0 0;
1388
+ border-radius: 2px;
1389
+ background: var(--chart-primary);
1390
+ transition: width var(--dur-3) var(--ease-out);
1361
1391
  }
1362
1392
 
1363
- /* ==========================================================================
1364
- Theme toggle (system / light / dark)
1365
- ========================================================================== */
1366
- .stats-theme-toggle {
1367
- display: inline-flex;
1368
- align-items: center;
1369
- justify-content: center;
1370
- width: 32px;
1371
- height: 32px;
1372
- flex-shrink: 0;
1373
- border: 1px solid var(--border);
1374
- border-radius: var(--radius-md);
1375
- background: var(--surface);
1376
- color: var(--muted);
1377
- cursor: pointer;
1378
- transition: color 0.14s ease, background 0.14s ease, border-color 0.14s ease;
1379
- }
1380
-
1381
- .stats-theme-toggle:hover {
1382
- color: var(--text);
1383
- border-color: var(--border-strong);
1393
+ .meter-cell {
1394
+ display: flex;
1395
+ align-items: center;
1396
+ gap: 10px;
1397
+ justify-content: flex-end;
1384
1398
  }
1385
1399
 
1386
- @media (prefers-reduced-motion: reduce) {
1387
- .stats-theme-toggle {
1388
- transition: none;
1389
- }
1400
+ .meter-cell .meter {
1401
+ width: 64px;
1390
1402
  }
1391
1403
 
1392
1404
  /* ==========================================================================
1393
- Traces (session flamegraph)
1405
+ States: empty, error, skeleton, stale overlay
1394
1406
  ========================================================================== */
1395
- .stats-trace-view {
1396
- display: flex;
1397
- flex-direction: column;
1398
- gap: 14px;
1399
- }
1400
-
1401
- .stats-trace-header {
1402
- display: flex;
1403
- align-items: center;
1404
- gap: 12px;
1405
- flex-wrap: wrap;
1406
- min-width: 0;
1407
- }
1408
-
1409
- .stats-trace-back {
1410
- display: inline-flex;
1411
- align-items: center;
1412
- gap: 6px;
1413
- padding: 6px 12px;
1414
- font-size: 12px;
1415
- color: var(--muted);
1416
- background: var(--surface);
1417
- border: 1px solid var(--border);
1418
- border-radius: var(--radius-md);
1419
- cursor: pointer;
1420
- transition: color 0.14s ease, border-color 0.14s ease;
1421
- }
1422
-
1423
- .stats-trace-back:hover {
1424
- color: var(--text);
1425
- border-color: var(--border-strong);
1426
- }
1427
-
1428
- .stats-trace-back:focus-visible {
1429
- outline: 2px solid var(--link);
1430
- outline-offset: 2px;
1431
- }
1432
-
1433
- .stats-trace-title {
1434
- font-size: 15px;
1435
- font-weight: 600;
1436
- color: var(--text);
1437
- margin: 0;
1438
- min-width: 0;
1439
- overflow: hidden;
1440
- text-overflow: ellipsis;
1441
- white-space: nowrap;
1407
+ .empty {
1408
+ display: flex;
1409
+ flex-direction: column;
1410
+ align-items: center;
1411
+ justify-content: center;
1412
+ gap: 6px;
1413
+ padding: 40px 16px;
1414
+ text-align: center;
1415
+ color: var(--ink-3);
1416
+ min-height: 140px;
1442
1417
  }
1443
1418
 
1444
- .stats-trace-cwd {
1445
- font-size: 11px;
1446
- color: var(--dim);
1447
- border: 1px solid var(--border);
1448
- border-radius: 999px;
1449
- padding: 3px 10px;
1450
- max-width: 280px;
1451
- overflow: hidden;
1452
- text-overflow: ellipsis;
1453
- white-space: nowrap;
1419
+ .empty svg {
1420
+ color: var(--ink-4);
1421
+ margin-bottom: 4px;
1454
1422
  }
1455
1423
 
1456
- /* Summary strip: one bordered card, hairline-divided stat columns. */
1457
- .stats-trace-summary {
1458
- display: flex;
1459
- flex-wrap: wrap;
1460
- background: var(--surface);
1461
- border: 1px solid var(--border);
1462
- border-radius: var(--radius-lg);
1463
- overflow: hidden;
1424
+ .empty-title {
1425
+ color: var(--ink-2);
1426
+ font-weight: 500;
1464
1427
  }
1465
1428
 
1466
- .stats-trace-summary-cell {
1467
- display: flex;
1468
- flex-direction: column;
1469
- gap: 3px;
1470
- padding: 10px 16px;
1471
- border-right: 1px solid var(--border);
1472
- min-width: 76px;
1429
+ .empty-hint {
1430
+ font-size: 12.5px;
1431
+ max-width: 44ch;
1473
1432
  }
1474
1433
 
1475
- .stats-trace-summary-cell:last-child {
1476
- border-right: none;
1434
+ .error-state {
1435
+ display: flex;
1436
+ align-items: center;
1437
+ gap: 12px;
1438
+ padding: 12px 14px;
1439
+ margin: 12px 16px;
1440
+ border-radius: var(--r-control);
1441
+ background: var(--bad-soft);
1442
+ color: var(--bad);
1443
+ font-size: 13px;
1477
1444
  }
1478
1445
 
1479
- .stats-trace-summary-label {
1480
- font-size: 9px;
1481
- text-transform: uppercase;
1482
- letter-spacing: 0.07em;
1483
- color: var(--dim);
1446
+ .error-state-message {
1447
+ flex: 1;
1448
+ min-width: 0;
1449
+ overflow-wrap: anywhere;
1484
1450
  }
1485
1451
 
1486
- .stats-trace-summary-value {
1487
- font-size: 13px;
1488
- font-weight: 500;
1489
- color: var(--text);
1490
- font-variant-numeric: tabular-nums;
1452
+ .skeleton {
1453
+ border-radius: 6px;
1454
+ background: linear-gradient(90deg, var(--line-1) 0%, var(--line-2) 50%, var(--line-1) 100%);
1455
+ background-size: 200% 100%;
1456
+ animation: shimmer 1.6s linear infinite;
1491
1457
  }
1492
1458
 
1493
- /* Toolbar row above the timeline. */
1494
- .stats-trace-toolbar {
1495
- display: flex;
1496
- align-items: center;
1497
- gap: 12px;
1498
- flex-wrap: wrap;
1459
+ /* Previous data kept on screen while a new key loads. */
1460
+ [data-stale="true"] {
1461
+ opacity: 0.55;
1462
+ transition: opacity var(--dur-2) var(--ease);
1499
1463
  }
1500
1464
 
1501
- .stats-trace-toolbar-hint {
1502
- font-size: 10px;
1503
- color: var(--dim);
1504
- margin-left: auto;
1465
+ [data-stale="false"] {
1466
+ transition: opacity var(--dur-2) var(--ease);
1505
1467
  }
1506
1468
 
1507
- .stats-trace-input {
1508
- background: var(--surface);
1509
- border: 1px solid var(--border);
1510
- border-radius: var(--radius-md);
1511
- color: var(--text);
1512
- font-family: inherit;
1513
- font-size: 12px;
1514
- padding: 6px 10px;
1469
+ /* ==========================================================================
1470
+ Drawer (right-side sheet)
1471
+ ========================================================================== */
1472
+ .drawer {
1473
+ position: fixed;
1474
+ top: 8px;
1475
+ right: 8px;
1476
+ bottom: 8px;
1477
+ width: min(var(--drawer-w, 560px), calc(100vw - 16px));
1478
+ z-index: 61;
1479
+ display: flex;
1480
+ flex-direction: column;
1481
+ border-radius: var(--r-panel);
1482
+ border: 1px solid var(--line-2);
1483
+ background: var(--overlay);
1484
+ backdrop-filter: blur(20px) saturate(170%);
1485
+ -webkit-backdrop-filter: blur(20px) saturate(170%);
1486
+ box-shadow: var(--shadow-3);
1487
+ animation: drawer-in var(--dur-3) var(--ease-out) both;
1488
+ overflow: hidden;
1489
+ }
1490
+
1491
+ @keyframes drawer-in {
1492
+ from {
1493
+ transform: translateX(24px);
1494
+ opacity: 0;
1495
+ }
1496
+ to {
1497
+ transform: none;
1498
+ opacity: 1;
1499
+ }
1500
+ }
1501
+
1502
+ .drawer-header {
1503
+ display: flex;
1504
+ align-items: flex-start;
1505
+ gap: 12px;
1506
+ padding: 16px 16px 12px 20px;
1507
+ border-bottom: 1px solid var(--line-1);
1508
+ }
1509
+
1510
+ .drawer-titles {
1511
+ flex: 1;
1512
+ min-width: 0;
1513
+ overflow-wrap: anywhere;
1514
+ }
1515
+
1516
+ .drawer-title {
1517
+ font-size: 15px;
1518
+ font-weight: 600;
1519
+ letter-spacing: -0.01em;
1520
+ }
1521
+
1522
+ .drawer-subtitle {
1523
+ font-size: 12.5px;
1524
+ color: var(--ink-3);
1525
+ margin-top: 2px;
1526
+ }
1527
+
1528
+ .drawer-body {
1529
+ flex: 1;
1530
+ overflow-y: auto;
1531
+ padding: 16px 20px 24px;
1532
+ display: flex;
1533
+ flex-direction: column;
1534
+ gap: 18px;
1535
+ }
1536
+
1537
+ /* Key/value definition grid used in drawers and detail panels. */
1538
+ .kv {
1539
+ display: grid;
1540
+ grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
1541
+ gap: 12px 16px;
1542
+ }
1543
+
1544
+ .kv-item {
1545
+ display: flex;
1546
+ flex-direction: column;
1547
+ gap: 2px;
1548
+ min-width: 0;
1549
+ }
1550
+
1551
+ .kv-key {
1552
+ font-size: 12px;
1553
+ color: var(--ink-3);
1554
+ }
1555
+
1556
+ .kv-value {
1557
+ font-family: var(--font-mono);
1558
+ font-size: 12.5px;
1559
+ color: var(--ink-1);
1560
+ overflow-wrap: anywhere;
1561
+ }
1562
+
1563
+ .section-label {
1564
+ font-size: 12px;
1565
+ font-weight: 500;
1566
+ color: var(--ink-3);
1567
+ margin-bottom: 8px;
1568
+ }
1569
+
1570
+ .code-block {
1571
+ margin: 0;
1572
+ padding: 12px 14px;
1573
+ border-radius: var(--r-control);
1574
+ border: 1px solid var(--line-1);
1575
+ background: var(--card);
1576
+ font-family: var(--font-mono);
1577
+ font-size: 12px;
1578
+ line-height: 1.55;
1579
+ color: var(--ink-2);
1580
+ overflow: auto;
1581
+ max-height: 480px;
1582
+ white-space: pre-wrap;
1583
+ overflow-wrap: anywhere;
1515
1584
  }
1516
1585
 
1517
- /* Prevent iOS from zooming the viewport when a search input receives focus
1518
- (mirrors the .stats-select coarse-pointer treatment). */
1519
- @media (pointer: coarse) {
1520
- .stats-trace-input {
1521
- font-size: 16px;
1522
- }
1586
+ /* ==========================================================================
1587
+ Live status chip (topbar)
1588
+ ========================================================================== */
1589
+ .live-chip {
1590
+ display: inline-flex;
1591
+ align-items: center;
1592
+ gap: 8px;
1593
+ height: 30px;
1594
+ padding: 0 10px 0 11px;
1595
+ border-radius: var(--r-pill);
1596
+ border: 1px solid var(--line-2);
1597
+ background: var(--card);
1598
+ font-size: 12.5px;
1599
+ color: var(--ink-2);
1600
+ white-space: nowrap;
1601
+ transition: border-color var(--dur-1) var(--ease);
1523
1602
  }
1524
1603
 
1525
- /* Native clear button is a dark glyph in WebKit; keep it visible in the dark
1526
- theme by inverting it (no-op in light). */
1527
- .stats-trace-input::-webkit-search-cancel-button {
1528
- filter: invert(1);
1604
+ .live-chip:hover {
1605
+ border-color: var(--line-3);
1606
+ color: var(--ink-1);
1529
1607
  }
1530
1608
 
1531
- @media (prefers-color-scheme: light) {
1532
- :root:not([data-theme]) .stats-trace-input::-webkit-search-cancel-button {
1533
- filter: none;
1534
- }
1609
+ .live-chip-count {
1610
+ font-family: var(--font-mono);
1611
+ font-size: 11.5px;
1612
+ color: var(--ink-3);
1535
1613
  }
1536
1614
 
1537
- [data-theme="light"] .stats-trace-input::-webkit-search-cancel-button {
1538
- filter: none;
1615
+ /* ==========================================================================
1616
+ Charts
1617
+ ========================================================================== */
1618
+ .chart {
1619
+ position: relative;
1620
+ width: 100%;
1621
+ min-width: 0;
1622
+ user-select: none;
1539
1623
  }
1540
1624
 
1541
- .stats-trace-input:focus-visible {
1542
- outline: 2px solid var(--link);
1543
- outline-offset: 1px;
1625
+ .chart svg {
1626
+ overflow: visible;
1544
1627
  }
1545
1628
 
1546
- .stats-trace-input::placeholder {
1547
- color: var(--dim);
1629
+ .chart-axis text {
1630
+ fill: var(--chart-axis);
1631
+ font-family: var(--font-mono);
1632
+ font-size: 10.5px;
1548
1633
  }
1549
1634
 
1550
- .stats-trace-check {
1551
- display: inline-flex;
1552
- align-items: center;
1553
- gap: 6px;
1554
- font-size: 12px;
1555
- color: var(--muted);
1556
- cursor: pointer;
1557
- user-select: none;
1635
+ .chart-grid line {
1636
+ stroke: var(--chart-grid);
1637
+ shape-rendering: crispEdges;
1558
1638
  }
1559
1639
 
1560
- /* Brand-tint the native checkbox instead of leaving the browser default. */
1561
- .stats-trace-check input[type="checkbox"] {
1562
- accent-color: var(--accent);
1640
+ .chart-baseline {
1641
+ stroke: var(--line-3);
1642
+ shape-rendering: crispEdges;
1563
1643
  }
1564
1644
 
1565
- .stats-trace-icon-btn {
1566
- display: inline-flex;
1567
- align-items: center;
1568
- justify-content: center;
1569
- width: 26px;
1570
- height: 26px;
1571
- background: transparent;
1572
- border: 1px solid var(--border);
1573
- border-radius: var(--radius-md);
1574
- color: var(--muted);
1575
- cursor: pointer;
1576
- transition: color 0.14s ease, border-color 0.14s ease;
1645
+ .chart-cursor {
1646
+ fill: var(--chart-cursor);
1577
1647
  }
1578
1648
 
1579
- .stats-trace-icon-btn:hover:not(:disabled) {
1580
- color: var(--text);
1581
- border-color: var(--border-strong);
1649
+ .chart-bar {
1650
+ shape-rendering: crispEdges;
1651
+ transition: opacity var(--dur-1) var(--ease);
1582
1652
  }
1583
1653
 
1584
- .stats-trace-icon-btn:focus-visible {
1585
- outline: 2px solid var(--link);
1586
- outline-offset: 2px;
1654
+ .chart[data-hovering="true"] .chart-bar[data-hover="false"] {
1655
+ opacity: 0.45;
1587
1656
  }
1588
1657
 
1589
- .stats-trace-icon-btn:disabled {
1590
- opacity: 0.4;
1591
- cursor: default;
1658
+ .chart-line {
1659
+ fill: none;
1660
+ stroke-width: 1.5;
1661
+ stroke-linejoin: round;
1662
+ stroke-linecap: round;
1663
+ vector-effect: non-scaling-stroke;
1592
1664
  }
1593
1665
 
1594
- /* Timeline card: minimap + canvas share one bordered surface. */
1595
- .stats-trace-timeline-card {
1596
- background: var(--surface);
1597
- border: 1px solid var(--border);
1598
- border-radius: var(--radius-lg);
1599
- padding: 12px;
1600
- display: flex;
1601
- flex-direction: column;
1602
- gap: 10px;
1666
+ .chart-empty {
1667
+ position: absolute;
1668
+ inset: 0;
1669
+ display: flex;
1670
+ align-items: center;
1671
+ justify-content: center;
1672
+ color: var(--ink-3);
1673
+ font-size: 12.5px;
1603
1674
  }
1604
1675
 
1605
- .stats-trace-timeline {
1606
- position: relative;
1607
- display: flex;
1608
- max-height: 560px;
1609
- overflow-y: auto;
1610
- overflow-x: hidden;
1676
+ .chart-tooltip {
1677
+ position: absolute;
1678
+ top: 0;
1679
+ z-index: 20;
1680
+ pointer-events: none;
1681
+ min-width: 160px;
1682
+ max-width: 280px;
1683
+ padding: 8px 10px;
1684
+ border-radius: var(--r-control);
1685
+ border: 1px solid var(--line-2);
1686
+ background: var(--overlay);
1687
+ backdrop-filter: blur(14px) saturate(160%);
1688
+ -webkit-backdrop-filter: blur(14px) saturate(160%);
1689
+ box-shadow: var(--shadow-2);
1690
+ font-size: 12px;
1691
+ transition:
1692
+ left 60ms linear,
1693
+ top 60ms linear;
1611
1694
  }
1612
1695
 
1613
- .stats-trace-canvas {
1614
- cursor: grab;
1615
- outline: none;
1616
- touch-action: none;
1617
- border-radius: var(--radius-sm);
1696
+ .chart-tooltip-title {
1697
+ font-family: var(--font-mono);
1698
+ font-size: 11px;
1699
+ color: var(--ink-3);
1700
+ margin-bottom: 6px;
1618
1701
  }
1619
1702
 
1620
- .stats-trace-canvas:focus-visible {
1621
- outline: 2px solid var(--link);
1622
- outline-offset: 2px;
1703
+ .chart-tooltip-row {
1704
+ display: flex;
1705
+ align-items: center;
1706
+ gap: 8px;
1707
+ line-height: 1.7;
1623
1708
  }
1624
1709
 
1625
- .stats-trace-canvas:active {
1626
- cursor: grabbing;
1710
+ .chart-tooltip-label {
1711
+ flex: 1;
1712
+ min-width: 0;
1713
+ overflow: hidden;
1714
+ text-overflow: ellipsis;
1715
+ white-space: nowrap;
1716
+ color: var(--ink-2);
1627
1717
  }
1628
1718
 
1629
- .stats-trace-chevron {
1630
- display: inline-flex;
1631
- background: none;
1632
- border: none;
1633
- padding: 0;
1634
- cursor: pointer;
1635
- color: var(--muted);
1719
+ .chart-tooltip-value {
1720
+ font-family: var(--font-mono);
1721
+ font-variant-numeric: tabular-nums;
1722
+ color: var(--ink-1);
1636
1723
  }
1637
1724
 
1638
- .stats-trace-chevron:hover {
1639
- color: var(--text);
1725
+ .chart-tooltip-total {
1726
+ border-top: 1px solid var(--line-1);
1727
+ margin-top: 4px;
1728
+ padding-top: 4px;
1640
1729
  }
1641
1730
 
1642
- .stats-trace-gutter-track {
1643
- font-size: 11px;
1644
- font-weight: 500;
1645
- color: var(--text);
1731
+ .legend {
1732
+ display: flex;
1733
+ flex-wrap: wrap;
1734
+ gap: 4px 14px;
1735
+ font-size: 12px;
1736
+ color: var(--ink-2);
1646
1737
  }
1647
1738
 
1648
- .stats-trace-gutter-model {
1649
- font-size: 9px;
1650
- color: var(--dim);
1739
+ .legend-item {
1740
+ display: inline-flex;
1741
+ align-items: center;
1742
+ gap: 6px;
1743
+ max-width: 240px;
1744
+ transition: opacity var(--dur-1) var(--ease);
1651
1745
  }
1652
1746
 
1653
- .stats-trace-gutter-lane {
1654
- position: absolute;
1655
- font-size: 8px;
1656
- color: var(--dim);
1657
- text-transform: uppercase;
1658
- letter-spacing: 0.08em;
1747
+ button.legend-item:hover {
1748
+ color: var(--ink-1);
1659
1749
  }
1660
1750
 
1661
- /* Transcript list under the timeline. */
1662
- .stats-trace-list {
1663
- background: var(--surface);
1664
- border: 1px solid var(--border);
1665
- border-radius: var(--radius-lg);
1666
- height: 340px;
1667
- overflow-y: auto;
1751
+ .legend-item[data-off="true"] {
1752
+ opacity: 0.38;
1668
1753
  }
1669
1754
 
1670
- .stats-trace-row {
1671
- display: flex;
1672
- align-items: center;
1673
- gap: 10px;
1674
- height: 28px;
1675
- width: 100%;
1676
- padding: 0 12px;
1677
- background: transparent;
1678
- border: none;
1679
- border-bottom: 1px solid var(--border);
1680
- text-align: left;
1681
- cursor: pointer;
1682
- transition: background 0.1s ease;
1755
+ .legend-value {
1756
+ font-family: var(--font-mono);
1757
+ font-size: 11.5px;
1758
+ color: var(--ink-3);
1759
+ }
1760
+
1761
+ .sparkline path.area {
1762
+ opacity: 0.16;
1683
1763
  }
1684
1764
 
1685
- .stats-trace-row:hover {
1686
- background: var(--bg-hover);
1765
+ /* Horizontal share bar. */
1766
+ .share-bar {
1767
+ display: flex;
1768
+ width: 100%;
1769
+ height: 8px;
1770
+ border-radius: 3px;
1771
+ overflow: hidden;
1772
+ gap: 2px;
1773
+ background: var(--line-1);
1687
1774
  }
1688
1775
 
1689
- .stats-trace-row:focus-visible {
1690
- outline: 2px solid var(--link);
1691
- outline-offset: -2px;
1776
+ .share-bar-seg {
1777
+ height: 100%;
1778
+ min-width: 2px;
1779
+ transition: flex-grow var(--dur-3) var(--ease-out);
1692
1780
  }
1693
1781
 
1694
- .stats-trace-row[data-selected="true"] {
1695
- background: var(--accent-muted);
1782
+ /* Ranked horizontal bar list. */
1783
+ .bar-list {
1784
+ display: flex;
1785
+ flex-direction: column;
1786
+ gap: 2px;
1696
1787
  }
1697
1788
 
1698
- .stats-trace-row-static {
1699
- cursor: default;
1789
+ .bar-list-row {
1790
+ position: relative;
1791
+ display: flex;
1792
+ align-items: center;
1793
+ gap: 10px;
1794
+ height: 30px;
1795
+ padding: 0 8px;
1796
+ border-radius: 6px;
1797
+ text-align: left;
1798
+ width: 100%;
1799
+ isolation: isolate;
1700
1800
  }
1701
1801
 
1702
- .stats-trace-row-static:hover {
1703
- background: transparent;
1802
+ button.bar-list-row:hover {
1803
+ background: var(--hover);
1704
1804
  }
1705
1805
 
1706
- .stats-trace-kind {
1707
- flex-shrink: 0;
1708
- width: 58px;
1709
- font-size: 8px;
1710
- text-transform: uppercase;
1711
- letter-spacing: 0.06em;
1712
- border-radius: 3px;
1713
- padding: 2px 0;
1714
- text-align: center;
1715
- overflow: hidden;
1716
- text-overflow: ellipsis;
1717
- white-space: nowrap;
1806
+ .bar-list-fill {
1807
+ position: absolute;
1808
+ top: 3px;
1809
+ bottom: 3px;
1810
+ left: 0;
1811
+ border-radius: 5px;
1812
+ z-index: -1;
1813
+ opacity: 0.16;
1814
+ transition: width var(--dur-3) var(--ease-out);
1718
1815
  }
1719
1816
 
1720
- .stats-trace-row-meta {
1721
- flex-shrink: 0;
1722
- margin-left: auto;
1723
- font-size: 10px;
1724
- color: var(--dim);
1725
- font-variant-numeric: tabular-nums;
1726
- display: flex;
1727
- gap: 10px;
1817
+ .bar-list-label {
1818
+ flex: 1;
1819
+ min-width: 0;
1820
+ display: flex;
1821
+ align-items: center;
1822
+ gap: 8px;
1823
+ overflow: hidden;
1824
+ white-space: nowrap;
1825
+ text-overflow: ellipsis;
1728
1826
  }
1729
1827
 
1730
- @media (prefers-reduced-motion: reduce) {
1731
- .stats-trace-back,
1732
- .stats-trace-icon-btn,
1733
- .stats-trace-row {
1734
- transition: none;
1735
- }
1828
+ .bar-list-value {
1829
+ font-family: var(--font-mono);
1830
+ font-size: 12px;
1831
+ font-variant-numeric: tabular-nums;
1832
+ color: var(--ink-2);
1736
1833
  }