free-coding-models 0.5.86 → 0.5.88

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 (165) hide show
  1. package/README.md +109 -888
  2. package/bin/free-coding-models.js +4 -1
  3. package/changelog/v0.5.87.md +48 -0
  4. package/changelog/v0.5.88.md +16 -0
  5. package/package.json +13 -5
  6. package/sources.js +4 -4
  7. package/src/core/cache.js +3 -1
  8. package/src/core/config.js +43 -5
  9. package/src/core/endpoint-installer.js +23 -12
  10. package/src/core/installed-models-manager.js +43 -20
  11. package/src/core/kilo-config.js +51 -5
  12. package/src/core/kilo.js +5 -3
  13. package/src/core/legacy-proxy-cleanup.js +22 -5
  14. package/src/core/model-merger.js +4 -0
  15. package/src/core/models-drift.js +9 -0
  16. package/src/core/opencode-config.js +57 -5
  17. package/src/core/opencode.js +67 -41
  18. package/src/core/playground.js +7 -0
  19. package/src/core/probe-cache.js +35 -4
  20. package/src/core/provider-key-tester.js +10 -2
  21. package/src/core/provider-metadata.js +10 -0
  22. package/src/core/provider-quota-fetchers.js +14 -7
  23. package/src/core/router-daemon.js +208 -26
  24. package/src/core/runtime-telemetry.js +27 -1
  25. package/src/core/security.js +170 -24
  26. package/src/core/shared-helpers.js +12 -1
  27. package/src/core/shell-env.js +3 -1
  28. package/src/core/telemetry.js +18 -5
  29. package/src/core/tool-launchers.js +9 -6
  30. package/src/core/updater.js +28 -2
  31. package/src/core/utils.js +173 -71
  32. package/src/tui/app.js +38 -14
  33. package/src/tui/command-palette.js +22 -2
  34. package/src/tui/key-handler.js +123 -179
  35. package/src/tui/overlays.js +21 -71
  36. package/src/tui/render-helpers.js +62 -4
  37. package/src/tui/render-table.js +34 -3
  38. package/src/tui/theme.js +36 -5
  39. package/src/tui/tui-filters.js +28 -8
  40. package/src/tui/tui-state.js +22 -6
  41. package/web/dist/assets/index-CAzFIt8P.css +1 -0
  42. package/web/dist/assets/index-DFg1h0Nd.js +44 -0
  43. package/web/dist/index.html +5 -9
  44. package/web/index.html +3 -7
  45. package/web/server.js +97 -23
  46. package/web/vite.config.js +8 -0
  47. package/web/app.legacy.js +0 -900
  48. package/web/dist/assets/index-C5-Ywvv3.css +0 -1
  49. package/web/dist/assets/index-Dm-Xfby9.js +0 -40
  50. package/web/public/favicon.ico +0 -0
  51. package/web/public/favicons/apple-touch-icon.png +0 -0
  52. package/web/public/favicons/browserconfig.xml +0 -12
  53. package/web/public/favicons/favicon-16x16.png +0 -0
  54. package/web/public/favicons/favicon-192x192.png +0 -0
  55. package/web/public/favicons/favicon-32x32.png +0 -0
  56. package/web/public/favicons/favicon-48x48.png +0 -0
  57. package/web/public/favicons/favicon-512x512.png +0 -0
  58. package/web/public/favicons/favicon-96x96.png +0 -0
  59. package/web/public/favicons/favicon.ico +0 -0
  60. package/web/public/favicons/mstile-150x150.png +0 -0
  61. package/web/public/favicons/mstile-310x150.png +0 -0
  62. package/web/public/favicons/mstile-310x310.png +0 -0
  63. package/web/public/favicons/mstile-512x512.png +0 -0
  64. package/web/public/favicons/mstile-70x70.png +0 -0
  65. package/web/public/favicons/site.webmanifest +0 -25
  66. package/web/src/App.jsx +0 -521
  67. package/web/src/components/analytics/AnalyticsView.jsx +0 -147
  68. package/web/src/components/analytics/AnalyticsView.module.css +0 -190
  69. package/web/src/components/analytics/TokenUsagePanel.jsx +0 -105
  70. package/web/src/components/analytics/TokenUsagePanel.module.css +0 -126
  71. package/web/src/components/atoms/AILatencyCell.jsx +0 -38
  72. package/web/src/components/atoms/AILatencyCell.module.css +0 -51
  73. package/web/src/components/atoms/HealthCell.jsx +0 -143
  74. package/web/src/components/atoms/HealthCell.module.css +0 -60
  75. package/web/src/components/atoms/LastPingCell.jsx +0 -35
  76. package/web/src/components/atoms/LastPingCell.module.css +0 -45
  77. package/web/src/components/atoms/MoodCell.jsx +0 -25
  78. package/web/src/components/atoms/MoodCell.module.css +0 -6
  79. package/web/src/components/atoms/NoKeyIcon.jsx +0 -65
  80. package/web/src/components/atoms/NoKeyIcon.module.css +0 -30
  81. package/web/src/components/atoms/ProviderLogo.jsx +0 -187
  82. package/web/src/components/atoms/ProviderLogo.module.css +0 -103
  83. package/web/src/components/atoms/RankCell.jsx +0 -9
  84. package/web/src/components/atoms/RankCell.module.css +0 -9
  85. package/web/src/components/atoms/Sparkline.jsx +0 -63
  86. package/web/src/components/atoms/StabilityCell.jsx +0 -18
  87. package/web/src/components/atoms/StabilityCell.module.css +0 -13
  88. package/web/src/components/atoms/StatusDot.jsx +0 -13
  89. package/web/src/components/atoms/StatusDot.module.css +0 -29
  90. package/web/src/components/atoms/TPSCell.jsx +0 -36
  91. package/web/src/components/atoms/TPSCell.module.css +0 -44
  92. package/web/src/components/atoms/TierBadge.jsx +0 -10
  93. package/web/src/components/atoms/TierBadge.module.css +0 -29
  94. package/web/src/components/atoms/Toast.jsx +0 -25
  95. package/web/src/components/atoms/Toast.module.css +0 -41
  96. package/web/src/components/atoms/ToastContainer.jsx +0 -16
  97. package/web/src/components/atoms/ToastContainer.module.css +0 -10
  98. package/web/src/components/atoms/VerdictBadge.jsx +0 -36
  99. package/web/src/components/atoms/VerdictBadge.module.css +0 -40
  100. package/web/src/components/changelog/ChangelogView.jsx +0 -135
  101. package/web/src/components/changelog/ChangelogView.module.css +0 -159
  102. package/web/src/components/dashboard/DetailPanel.jsx +0 -217
  103. package/web/src/components/dashboard/DetailPanel.module.css +0 -260
  104. package/web/src/components/dashboard/ExpandedDetailRow.jsx +0 -361
  105. package/web/src/components/dashboard/ExpandedDetailRow.module.css +0 -356
  106. package/web/src/components/dashboard/ExportModal.jsx +0 -84
  107. package/web/src/components/dashboard/ExportModal.module.css +0 -99
  108. package/web/src/components/dashboard/FilterBar.jsx +0 -338
  109. package/web/src/components/dashboard/FilterBar.module.css +0 -342
  110. package/web/src/components/dashboard/ModelTable.jsx +0 -672
  111. package/web/src/components/dashboard/ModelTable.module.css +0 -446
  112. package/web/src/components/dashboard/ProviderDropdown.jsx +0 -156
  113. package/web/src/components/dashboard/ProviderDropdown.module.css +0 -248
  114. package/web/src/components/help/HelpView.jsx +0 -201
  115. package/web/src/components/help/HelpView.module.css +0 -156
  116. package/web/src/components/install/InstallEndpointsView.jsx +0 -309
  117. package/web/src/components/install/InstallEndpointsView.module.css +0 -427
  118. package/web/src/components/installed/InstalledModelsView.jsx +0 -89
  119. package/web/src/components/installed/InstalledModelsView.module.css +0 -200
  120. package/web/src/components/launch/IncompatibleFallbackModal.jsx +0 -69
  121. package/web/src/components/launch/LaunchButton.jsx +0 -30
  122. package/web/src/components/launch/LaunchButton.module.css +0 -35
  123. package/web/src/components/launch/LaunchModal.module.css +0 -125
  124. package/web/src/components/layout/Footer.jsx +0 -19
  125. package/web/src/components/layout/Footer.module.css +0 -10
  126. package/web/src/components/layout/Header.jsx +0 -265
  127. package/web/src/components/layout/Header.module.css +0 -357
  128. package/web/src/components/palette/CommandPalette.jsx +0 -301
  129. package/web/src/components/palette/CommandPalette.module.css +0 -121
  130. package/web/src/components/playground/PlaygroundChat.jsx +0 -527
  131. package/web/src/components/playground/PlaygroundChat.module.css +0 -382
  132. package/web/src/components/playground/PlaygroundView.jsx +0 -371
  133. package/web/src/components/playground/PlaygroundView.module.css +0 -504
  134. package/web/src/components/recommend/RecommendView.jsx +0 -121
  135. package/web/src/components/recommend/RecommendView.module.css +0 -57
  136. package/web/src/components/router/RouterView.jsx +0 -1212
  137. package/web/src/components/router/RouterView.module.css +0 -1289
  138. package/web/src/components/settings/SettingsView.jsx +0 -555
  139. package/web/src/components/settings/SettingsView.module.css +0 -550
  140. package/web/src/components/tools/ToolPicker.jsx +0 -86
  141. package/web/src/components/tools/ToolPicker.module.css +0 -97
  142. package/web/src/components/update/UpdateChip.jsx +0 -104
  143. package/web/src/components/update/UpdateChip.module.css +0 -146
  144. package/web/src/global.css +0 -298
  145. package/web/src/hooks/urlState.constants.js +0 -28
  146. package/web/src/hooks/useChangelog.js +0 -51
  147. package/web/src/hooks/useColumnSizing.js +0 -211
  148. package/web/src/hooks/useFavorites.js +0 -150
  149. package/web/src/hooks/useFilter.js +0 -310
  150. package/web/src/hooks/useInstalledModels.js +0 -42
  151. package/web/src/hooks/useRecommend.js +0 -67
  152. package/web/src/hooks/useRouterDashboard.js +0 -133
  153. package/web/src/hooks/useSSE.js +0 -73
  154. package/web/src/hooks/useSocket.js +0 -203
  155. package/web/src/hooks/useTheme.js +0 -83
  156. package/web/src/hooks/useTokenUsage.js +0 -103
  157. package/web/src/hooks/useToolMode.js +0 -77
  158. package/web/src/hooks/useUpdateChecker.js +0 -91
  159. package/web/src/hooks/useUrlState.js +0 -170
  160. package/web/src/main.jsx +0 -15
  161. package/web/src/utils/download.js +0 -15
  162. package/web/src/utils/format.js +0 -42
  163. package/web/src/utils/m3.js +0 -57
  164. package/web/src/utils/ranks.js +0 -37
  165. package/web/styles.legacy.css +0 -963
@@ -1,963 +0,0 @@
1
- /* ═══════════════════════════════════════════════════════════════════════════
2
- free-coding-models — Web Dashboard Styles V2
3
- Premium glassmorphism dark-mode design with sidebar, settings, analytics
4
- ═══════════════════════════════════════════════════════════════════════════ */
5
-
6
- /* ─── CSS Custom Properties (Design Tokens) ─── */
7
- :root {
8
- /* Palette */
9
- --color-bg: #0a0a0f;
10
- --color-bg-elevated: #12121a;
11
- --color-bg-card: rgba(18, 18, 30, 0.7);
12
- --color-bg-hover: rgba(30, 30, 50, 0.8);
13
- --color-bg-active: rgba(40, 40, 65, 0.9);
14
- --color-surface: #1a1a2e;
15
- --color-border: rgba(255, 255, 255, 0.06);
16
- --color-border-hover: rgba(255, 255, 255, 0.12);
17
-
18
- --color-text: #e8e8f0;
19
- --color-text-muted: #8888a8;
20
- --color-text-dim: #555570;
21
-
22
- --color-accent: #76b900;
23
- --color-accent-hover: #8ad100;
24
- --color-accent-glow: rgba(118, 185, 0, 0.25);
25
- --color-accent-dim: rgba(118, 185, 0, 0.08);
26
-
27
- --color-danger: #ff4444;
28
- --color-danger-dim: rgba(255, 68, 68, 0.1);
29
- --color-warning: #ffaa00;
30
- --color-warning-dim: rgba(255, 170, 0, 0.1);
31
- --color-success: #00ff88;
32
- --color-success-dim: rgba(0, 255, 136, 0.1);
33
- --color-info: #06b6d4;
34
- --color-info-dim: rgba(6, 182, 212, 0.1);
35
-
36
- /* Tier colors */
37
- --tier-splus: #ffd700;
38
- --tier-s: #ff8c00;
39
- --tier-aplus: #00c8ff;
40
- --tier-a: #3ddc84;
41
- --tier-aminus: #7ecf7e;
42
- --tier-bplus: #a8a8c8;
43
- --tier-b: #808098;
44
- --tier-c: #606078;
45
-
46
- /* Verdict colors */
47
- --verdict-perfect: #00ff88;
48
- --verdict-normal: #76b900;
49
- --verdict-slow: #ffaa00;
50
- --verdict-spiky: #ff6600;
51
- --verdict-veryslow: #ff4444;
52
- --verdict-overloaded: #ff2222;
53
- --verdict-unstable: #cc0000;
54
- --verdict-notactive: #555570;
55
- --verdict-pending: #444460;
56
-
57
- /* Typography */
58
- --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
59
- --font-mono: 'JetBrains Mono', 'Fira Code', 'Cascadia Code', monospace;
60
-
61
- /* Sizing */
62
- --header-h: 60px;
63
- --sidebar-w: 64px;
64
- --sidebar-w-expanded: 200px;
65
- --radius-sm: 6px;
66
- --radius-md: 10px;
67
- --radius-lg: 16px;
68
- --radius-xl: 20px;
69
-
70
- /* Shadows */
71
- --shadow-sm: 0 1px 3px rgba(0,0,0,0.3);
72
- --shadow-md: 0 4px 12px rgba(0,0,0,0.4);
73
- --shadow-lg: 0 8px 32px rgba(0,0,0,0.5);
74
- --shadow-glow: 0 0 30px var(--color-accent-glow);
75
-
76
- /* Transitions */
77
- --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
78
- --transition-fast: 150ms var(--ease-out);
79
- --transition-medium: 250ms var(--ease-out);
80
- --transition-slow: 400ms var(--ease-out);
81
- }
82
-
83
- /* ─── Light Theme ─── */
84
- [data-theme="light"] {
85
- --color-bg: #f5f5fa;
86
- --color-bg-elevated: #ffffff;
87
- --color-bg-card: rgba(255, 255, 255, 0.85);
88
- --color-bg-hover: rgba(240, 240, 248, 0.9);
89
- --color-bg-active: rgba(230, 230, 242, 0.95);
90
- --color-surface: #eeeef4;
91
- --color-border: rgba(0, 0, 0, 0.08);
92
- --color-border-hover: rgba(0, 0, 0, 0.15);
93
- --color-text: #1a1a2e;
94
- --color-text-muted: #666688;
95
- --color-text-dim: #9999aa;
96
- --color-accent-glow: rgba(118, 185, 0, 0.15);
97
- --color-accent-dim: rgba(118, 185, 0, 0.05);
98
- --color-danger-dim: rgba(255, 68, 68, 0.08);
99
- --color-warning-dim: rgba(255, 170, 0, 0.08);
100
- --color-success-dim: rgba(0, 255, 136, 0.08);
101
- --color-info-dim: rgba(6, 182, 212, 0.08);
102
- --shadow-sm: 0 1px 3px rgba(0,0,0,0.08);
103
- --shadow-md: 0 4px 12px rgba(0,0,0,0.1);
104
- --shadow-lg: 0 8px 32px rgba(0,0,0,0.12);
105
- }
106
-
107
- /* ─── Reset & Base ─── */
108
- *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
109
-
110
- html {
111
- font-size: 14px;
112
- scroll-behavior: smooth;
113
- -webkit-font-smoothing: antialiased;
114
- -moz-osx-font-smoothing: grayscale;
115
- }
116
-
117
- body {
118
- font-family: var(--font-sans);
119
- background: var(--color-bg);
120
- color: var(--color-text);
121
- min-height: 100vh;
122
- overflow-x: hidden;
123
- position: relative;
124
- display: flex;
125
- }
126
-
127
- a { color: var(--color-accent); text-decoration: none; }
128
- a:hover { color: var(--color-accent-hover); }
129
- code { font-family: var(--font-mono); font-size: 12px; background: var(--color-surface); padding: 2px 6px; border-radius: 4px; }
130
-
131
- /* ─── Background Effects ─── */
132
- .bg-grid {
133
- position: fixed; inset: 0; z-index: 0; pointer-events: none;
134
- background-image:
135
- linear-gradient(rgba(255,255,255,0.02) 1px, transparent 1px),
136
- linear-gradient(90deg, rgba(255,255,255,0.02) 1px, transparent 1px);
137
- background-size: 60px 60px;
138
- }
139
-
140
- .bg-glow {
141
- position: fixed; z-index: 0; pointer-events: none;
142
- border-radius: 50%;
143
- filter: blur(120px);
144
- opacity: 0.3;
145
- animation: float 20s ease-in-out infinite;
146
- }
147
- .bg-glow--1 {
148
- width: 600px; height: 600px;
149
- background: radial-gradient(circle, var(--color-accent) 0%, transparent 70%);
150
- top: -200px; left: -200px;
151
- }
152
- .bg-glow--2 {
153
- width: 400px; height: 400px;
154
- background: radial-gradient(circle, #6366f1 0%, transparent 70%);
155
- top: 50%; right: -150px; animation-delay: -7s;
156
- }
157
- .bg-glow--3 {
158
- width: 500px; height: 500px;
159
- background: radial-gradient(circle, #06b6d4 0%, transparent 70%);
160
- bottom: -200px; left: 30%; animation-delay: -14s;
161
- }
162
-
163
- @keyframes float {
164
- 0%, 100% { transform: translate(0, 0) scale(1); }
165
- 33% { transform: translate(30px, -30px) scale(1.05); }
166
- 66% { transform: translate(-20px, 20px) scale(0.95); }
167
- }
168
-
169
- [data-theme="light"] .bg-glow { opacity: 0.12; }
170
- [data-theme="light"] .bg-grid { background-image:
171
- linear-gradient(rgba(0,0,0,0.04) 1px, transparent 1px),
172
- linear-gradient(90deg, rgba(0,0,0,0.04) 1px, transparent 1px);
173
- }
174
-
175
- /* ═══════ SIDEBAR ═══════ */
176
- .sidebar {
177
- position: fixed; left: 0; top: 0; bottom: 0;
178
- width: var(--sidebar-w); z-index: 200;
179
- background: var(--color-bg-elevated);
180
- border-right: 1px solid var(--color-border);
181
- display: flex; flex-direction: column;
182
- padding: 12px 0;
183
- transition: width var(--transition-medium);
184
- overflow: hidden;
185
- }
186
- .sidebar:hover { width: var(--sidebar-w-expanded); }
187
-
188
- .sidebar__logo {
189
- display: flex; align-items: center; gap: 10px;
190
- padding: 8px 18px; margin-bottom: 16px;
191
- white-space: nowrap; overflow: hidden;
192
- }
193
- .sidebar__logo-icon { font-size: 24px; flex-shrink: 0; }
194
- .sidebar__logo-text {
195
- font-size: 16px; font-weight: 800;
196
- background: linear-gradient(135deg, var(--color-accent), #06b6d4);
197
- -webkit-background-clip: text; -webkit-text-fill-color: transparent;
198
- background-clip: text; opacity: 0;
199
- transition: opacity var(--transition-medium);
200
- }
201
- .sidebar:hover .sidebar__logo-text { opacity: 1; }
202
-
203
- .sidebar__nav { flex: 1; display: flex; flex-direction: column; gap: 4px; }
204
- .sidebar__bottom { display: flex; flex-direction: column; gap: 4px; }
205
-
206
- .sidebar__nav-item {
207
- display: flex; align-items: center; gap: 12px;
208
- padding: 10px 20px; border: none; background: none;
209
- color: var(--color-text-muted); cursor: pointer;
210
- white-space: nowrap; overflow: hidden;
211
- border-radius: 0; transition: all var(--transition-fast);
212
- font-family: var(--font-sans); font-size: 13px; font-weight: 500;
213
- }
214
- .sidebar__nav-item:hover {
215
- color: var(--color-text);
216
- background: var(--color-bg-hover);
217
- }
218
- .sidebar__nav-item--active {
219
- color: var(--color-accent) !important;
220
- background: var(--color-accent-dim) !important;
221
- border-right: 3px solid var(--color-accent);
222
- }
223
- .sidebar__nav-item svg { flex-shrink: 0; }
224
- .sidebar__nav-label {
225
- opacity: 0; transition: opacity var(--transition-medium);
226
- }
227
- .sidebar:hover .sidebar__nav-label { opacity: 1; }
228
-
229
- /* ═══════ APP CONTENT ═══════ */
230
- .app-content {
231
- flex: 1; margin-left: var(--sidebar-w);
232
- position: relative; z-index: 1;
233
- min-height: 100vh;
234
- display: flex; flex-direction: column;
235
- transition: margin-left var(--transition-medium);
236
- }
237
-
238
- /* Views */
239
- .view { display: flex; flex-direction: column; flex: 1; }
240
- .view--hidden { display: none !important; }
241
-
242
- /* ─── Header ─── */
243
- .header {
244
- position: sticky; top: 0; z-index: 100;
245
- height: var(--header-h);
246
- display: flex; align-items: center; justify-content: space-between;
247
- padding: 0 24px; gap: 20px;
248
- background: var(--color-bg-card);
249
- backdrop-filter: blur(20px) saturate(1.5);
250
- -webkit-backdrop-filter: blur(20px) saturate(1.5);
251
- border-bottom: 1px solid var(--color-border);
252
- }
253
-
254
- .header__left { display: flex; align-items: center; gap: 12px; }
255
- .header__center { flex: 1; max-width: 480px; }
256
- .header__right { display: flex; align-items: center; gap: 10px; }
257
- .sidebar-toggle { display: none; }
258
-
259
- .logo { display: flex; align-items: center; gap: 8px; }
260
- .logo__icon { font-size: 22px; }
261
- .logo__text {
262
- font-size: 16px; font-weight: 700;
263
- background: linear-gradient(135deg, var(--color-accent), #06b6d4);
264
- -webkit-background-clip: text; -webkit-text-fill-color: transparent;
265
- background-clip: text;
266
- }
267
-
268
- .header__version {
269
- font-size: 11px; font-weight: 500; font-family: var(--font-mono);
270
- color: var(--color-text-dim);
271
- background: var(--color-accent-dim);
272
- padding: 2px 8px; border-radius: 999px;
273
- border: 1px solid var(--color-border);
274
- }
275
-
276
- /* Search Bar */
277
- .search-bar {
278
- display: flex; align-items: center; gap: 8px;
279
- background: var(--color-surface);
280
- border: 1px solid var(--color-border);
281
- border-radius: var(--radius-md);
282
- padding: 0 12px; height: 36px;
283
- transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
284
- }
285
- .search-bar:focus-within {
286
- border-color: var(--color-accent);
287
- box-shadow: 0 0 0 3px var(--color-accent-glow);
288
- }
289
- .search-bar__icon { color: var(--color-text-dim); flex-shrink: 0; }
290
- .search-bar__input {
291
- flex: 1; background: none; border: none; outline: none;
292
- color: var(--color-text); font-size: 13px; font-family: var(--font-sans);
293
- }
294
- .search-bar__input::placeholder { color: var(--color-text-dim); }
295
- .search-bar__kbd {
296
- font-size: 10px; font-family: var(--font-mono);
297
- color: var(--color-text-dim);
298
- background: var(--color-bg);
299
- border: 1px solid var(--color-border);
300
- padding: 2px 6px; border-radius: 4px; flex-shrink: 0;
301
- }
302
-
303
- /* Buttons */
304
- .btn {
305
- display: inline-flex; align-items: center; gap: 6px;
306
- border: 1px solid var(--color-border); border-radius: var(--radius-sm);
307
- padding: 6px 14px; font-size: 13px; font-weight: 500;
308
- cursor: pointer; background: var(--color-surface); color: var(--color-text);
309
- transition: all var(--transition-fast);
310
- font-family: var(--font-sans);
311
- }
312
- .btn:hover { background: var(--color-bg-hover); border-color: var(--color-border-hover); }
313
- .btn--icon { padding: 6px 8px; }
314
- .btn--primary { background: var(--color-accent); color: #000; border-color: var(--color-accent); font-weight: 600; }
315
- .btn--primary:hover { background: var(--color-accent-hover); }
316
- .btn--danger { background: var(--color-danger-dim); color: var(--color-danger); border-color: rgba(255,68,68,0.2); }
317
- .btn--danger:hover { background: rgba(255,68,68,0.2); }
318
- .btn--sm { padding: 4px 10px; font-size: 12px; }
319
- .btn--success { background: var(--color-success-dim); color: var(--color-success); border-color: rgba(0,255,136,0.2); }
320
-
321
- /* ─── Toast Notifications ─── */
322
- .toast-container {
323
- position: fixed; top: 20px; right: 20px; z-index: 10000;
324
- display: flex; flex-direction: column; gap: 8px;
325
- pointer-events: none;
326
- }
327
- .toast {
328
- pointer-events: auto;
329
- display: flex; align-items: center; gap: 10px;
330
- padding: 12px 18px; border-radius: var(--radius-md);
331
- background: var(--color-bg-elevated);
332
- border: 1px solid var(--color-border);
333
- box-shadow: var(--shadow-lg);
334
- font-size: 13px; font-weight: 500;
335
- animation: toastIn 300ms var(--ease-out);
336
- min-width: 280px; max-width: 420px;
337
- }
338
- .toast--success { border-left: 4px solid var(--color-success); }
339
- .toast--error { border-left: 4px solid var(--color-danger); }
340
- .toast--warning { border-left: 4px solid var(--color-warning); }
341
- .toast--info { border-left: 4px solid var(--color-info); }
342
- .toast__icon { font-size: 18px; flex-shrink: 0; }
343
- .toast__message { flex: 1; }
344
- .toast__close {
345
- background: none; border: none; color: var(--color-text-dim);
346
- cursor: pointer; font-size: 16px; padding: 0; line-height: 1;
347
- }
348
- .toast--exiting { animation: toastOut 300ms var(--ease-out) forwards; }
349
-
350
- @keyframes toastIn { from { transform: translateX(100%); opacity: 0; } to { transform: translateX(0); opacity: 1; } }
351
- @keyframes toastOut { from { transform: translateX(0); opacity: 1; } to { transform: translateX(100%); opacity: 0; } }
352
-
353
- /* ─── Stats Bar ─── */
354
- .stats-bar {
355
- position: relative; z-index: 1;
356
- display: grid; grid-template-columns: repeat(5, 1fr); gap: 14px;
357
- padding: 20px 24px 0;
358
- }
359
-
360
- .stat-card {
361
- display: flex; align-items: center; gap: 12px;
362
- background: var(--color-bg-card);
363
- backdrop-filter: blur(12px);
364
- -webkit-backdrop-filter: blur(12px);
365
- border: 1px solid var(--color-border);
366
- border-radius: var(--radius-lg);
367
- padding: 16px 18px;
368
- transition: all var(--transition-medium);
369
- }
370
- .stat-card:hover {
371
- border-color: var(--color-border-hover);
372
- transform: translateY(-2px);
373
- box-shadow: var(--shadow-md);
374
- }
375
- .stat-card__icon { font-size: 28px; }
376
- .stat-card__value {
377
- font-size: 22px; font-weight: 800;
378
- font-family: var(--font-mono); line-height: 1;
379
- }
380
- .stat-card__label {
381
- font-size: 11px; color: var(--color-text-muted);
382
- text-transform: uppercase; letter-spacing: 0.5px; font-weight: 500;
383
- margin-top: 2px;
384
- }
385
-
386
- /* ─── Filters ─── */
387
- .filters {
388
- position: relative; z-index: 1;
389
- display: flex; align-items: center; gap: 20px; flex-wrap: wrap;
390
- padding: 16px 24px;
391
- }
392
- .filters__group { display: flex; align-items: center; gap: 8px; }
393
- .filters__spacer { flex: 1; }
394
- .filter-label {
395
- font-size: 11px; font-weight: 600; color: var(--color-text-muted);
396
- text-transform: uppercase; letter-spacing: 0.5px;
397
- }
398
-
399
- .tier-btn, .status-btn {
400
- font-size: 12px; font-weight: 600; font-family: var(--font-mono);
401
- padding: 4px 10px; border-radius: var(--radius-sm);
402
- border: 1px solid var(--color-border);
403
- background: var(--color-surface); color: var(--color-text-muted);
404
- cursor: pointer; transition: all var(--transition-fast);
405
- }
406
- .tier-btn:hover, .status-btn:hover {
407
- background: var(--color-bg-hover); color: var(--color-text);
408
- border-color: var(--color-border-hover);
409
- }
410
- .tier-btn--active, .status-btn--active {
411
- background: var(--color-accent) !important; color: #000 !important;
412
- border-color: var(--color-accent) !important; font-weight: 700;
413
- }
414
-
415
- .provider-select {
416
- background: var(--color-surface); color: var(--color-text);
417
- border: 1px solid var(--color-border); border-radius: var(--radius-sm);
418
- padding: 5px 10px; font-size: 12px; font-family: var(--font-sans);
419
- cursor: pointer; outline: none;
420
- }
421
- .provider-select:focus { border-color: var(--color-accent); }
422
-
423
- /* Live Indicator */
424
- .live-indicator {
425
- display: flex; align-items: center; gap: 6px;
426
- font-size: 11px; font-weight: 700; color: var(--color-accent);
427
- text-transform: uppercase; letter-spacing: 1px;
428
- }
429
- .live-dot {
430
- width: 8px; height: 8px; border-radius: 50%;
431
- background: var(--color-accent);
432
- animation: pulse-dot 2s ease-in-out infinite;
433
- }
434
- @keyframes pulse-dot {
435
- 0%, 100% { box-shadow: 0 0 0 0 var(--color-accent-glow); }
436
- 50% { box-shadow: 0 0 0 6px transparent; }
437
- }
438
-
439
- /* ─── Main Table ─── */
440
- .main {
441
- position: relative; z-index: 1;
442
- padding: 0 24px 24px; flex: 1;
443
- }
444
-
445
- .table-container {
446
- background: var(--color-bg-card);
447
- backdrop-filter: blur(12px);
448
- -webkit-backdrop-filter: blur(12px);
449
- border: 1px solid var(--color-border);
450
- border-radius: var(--radius-lg);
451
- overflow: hidden;
452
- }
453
-
454
- .models-table { width: 100%; border-collapse: collapse; font-size: 13px; }
455
- .models-table thead { position: sticky; top: 0; z-index: 10; }
456
-
457
- .models-table th {
458
- padding: 12px 14px;
459
- font-size: 11px; font-weight: 700;
460
- text-transform: uppercase; letter-spacing: 0.8px;
461
- color: var(--color-text-muted); text-align: left;
462
- background: var(--color-bg-elevated);
463
- border-bottom: 1px solid var(--color-border);
464
- white-space: nowrap; user-select: none;
465
- }
466
- .models-table th.sortable { cursor: pointer; }
467
- .models-table th.sortable:hover { color: var(--color-accent); }
468
- .models-table th.sort-active { color: var(--color-accent); }
469
-
470
- .models-table td {
471
- padding: 10px 14px;
472
- border-bottom: 1px solid var(--color-border);
473
- white-space: nowrap;
474
- transition: background var(--transition-fast);
475
- }
476
-
477
- .models-table tbody tr {
478
- cursor: pointer; transition: background var(--transition-fast);
479
- }
480
- .models-table tbody tr:hover { background: var(--color-bg-hover); }
481
- .models-table tbody tr:active { background: var(--color-bg-active); }
482
-
483
- /* Medal rows */
484
- .models-table tbody tr.rank-1 td:first-child { border-left: 3px solid #ffd700; }
485
- .models-table tbody tr.rank-2 td:first-child { border-left: 3px solid #c0c0c0; }
486
- .models-table tbody tr.rank-3 td:first-child { border-left: 3px solid #cd7f32; }
487
-
488
- .th--rank { width: 50px; text-align: center; }
489
- .td--rank { text-align: center; font-family: var(--font-mono); font-weight: 600; color: var(--color-text-dim); }
490
-
491
- /* Tier badges */
492
- .tier-badge {
493
- display: inline-block;
494
- font-family: var(--font-mono); font-weight: 700; font-size: 11px;
495
- padding: 2px 8px; border-radius: 4px;
496
- text-align: center; min-width: 32px;
497
- }
498
- .tier-badge--splus { background: rgba(255,215,0,0.15); color: var(--tier-splus); border: 1px solid rgba(255,215,0,0.3); }
499
- .tier-badge--s { background: rgba(255,140,0,0.12); color: var(--tier-s); border: 1px solid rgba(255,140,0,0.25); }
500
- .tier-badge--aplus { background: rgba(0,200,255,0.1); color: var(--tier-aplus); border: 1px solid rgba(0,200,255,0.2); }
501
- .tier-badge--a { background: rgba(61,220,132,0.1); color: var(--tier-a); border: 1px solid rgba(61,220,132,0.2); }
502
- .tier-badge--aminus{ background: rgba(126,207,126,0.1); color: var(--tier-aminus); border: 1px solid rgba(126,207,126,0.2); }
503
- .tier-badge--bplus { background: rgba(168,168,200,0.1); color: var(--tier-bplus); border: 1px solid rgba(168,168,200,0.15); }
504
- .tier-badge--b { background: rgba(128,128,152,0.1); color: var(--tier-b); border: 1px solid rgba(128,128,152,0.15); }
505
- .tier-badge--c { background: rgba(96,96,120,0.1); color: var(--tier-c); border: 1px solid rgba(96,96,120,0.15); }
506
-
507
- /* Model name */
508
- .model-name {
509
- font-weight: 600; font-size: 13px;
510
- max-width: 200px; overflow: hidden; text-overflow: ellipsis;
511
- }
512
- .model-id {
513
- font-family: var(--font-mono); font-size: 10px;
514
- color: var(--color-text-dim); margin-top: 1px;
515
- max-width: 200px; overflow: hidden; text-overflow: ellipsis;
516
- }
517
-
518
- .provider-pill {
519
- display: inline-block; font-size: 11px; font-weight: 500;
520
- padding: 2px 8px; border-radius: 999px;
521
- background: var(--color-accent-dim);
522
- color: var(--color-text-muted);
523
- border: 1px solid var(--color-border);
524
- }
525
-
526
- .swe-score { font-family: var(--font-mono); font-weight: 600; }
527
- .swe-high { color: var(--tier-splus); }
528
- .swe-mid { color: var(--tier-a); }
529
- .swe-low { color: var(--color-text-dim); }
530
- .ctx-value { font-family: var(--font-mono); font-size: 12px; color: var(--color-text-muted); }
531
-
532
- .ping-value { font-family: var(--font-mono); font-weight: 600; }
533
- .ping-fast { color: #00ff88; }
534
- .ping-medium { color: #ffaa00; }
535
- .ping-slow { color: #ff4444; }
536
- .ping-none { color: var(--color-text-dim); }
537
-
538
- /* Stability bar */
539
- .stability-cell { display: flex; align-items: center; gap: 6px; }
540
- .stability-bar {
541
- width: 48px; height: 6px; border-radius: 3px;
542
- background: var(--color-surface); overflow: hidden;
543
- }
544
- .stability-bar__fill {
545
- height: 100%; border-radius: 3px;
546
- transition: width var(--transition-medium);
547
- }
548
- .stability-bar__fill--high { background: linear-gradient(90deg, #00ff88, #76b900); }
549
- .stability-bar__fill--mid { background: linear-gradient(90deg, #ffaa00, #ff8c00); }
550
- .stability-bar__fill--low { background: linear-gradient(90deg, #ff4444, #cc0000); }
551
- .stability-value { font-family: var(--font-mono); font-size: 12px; font-weight: 600; }
552
-
553
- /* Verdict badges */
554
- .verdict-badge {
555
- display: inline-block;
556
- font-size: 10px; font-weight: 700; text-transform: uppercase;
557
- padding: 2px 8px; border-radius: 999px; letter-spacing: 0.5px;
558
- }
559
- .verdict--perfect { background: rgba(0,255,136,0.12); color: var(--verdict-perfect); border: 1px solid rgba(0,255,136,0.25); }
560
- .verdict--normal { background: rgba(118,185,0,0.12); color: var(--verdict-normal); border: 1px solid rgba(118,185,0,0.25); }
561
- .verdict--slow { background: rgba(255,170,0,0.12); color: var(--verdict-slow); border: 1px solid rgba(255,170,0,0.25); }
562
- .verdict--spiky { background: rgba(255,102,0,0.12); color: var(--verdict-spiky); border: 1px solid rgba(255,102,0,0.25); }
563
- .verdict--veryslow { background: rgba(255,68,68,0.12); color: var(--verdict-veryslow); border: 1px solid rgba(255,68,68,0.2); }
564
- .verdict--overloaded { background: rgba(255,34,34,0.12); color: var(--verdict-overloaded); border: 1px solid rgba(255,34,34,0.2); }
565
- .verdict--unstable { background: rgba(204,0,0,0.12); color: var(--verdict-unstable); border: 1px solid rgba(204,0,0,0.2); }
566
- .verdict--notactive { background: rgba(85,85,112,0.12); color: var(--verdict-notactive); border: 1px solid rgba(85,85,112,0.15); }
567
- .verdict--pending { background: rgba(68,68,96,0.1); color: var(--verdict-pending); border: 1px solid rgba(68,68,96,0.15); }
568
- .verdict--ratelimited { background: rgba(255,170,0,0.15); color: #ffaa00; border: 1px solid rgba(255,170,0,0.3); }
569
-
570
- .uptime-value { font-family: var(--font-mono); font-size: 12px; }
571
- .sparkline-svg { vertical-align: middle; }
572
-
573
- /* Status dot */
574
- .status-dot {
575
- display: inline-block; width: 8px; height: 8px;
576
- border-radius: 50%; margin-right: 6px; vertical-align: middle;
577
- }
578
- .status-dot--up { background: #00ff88; box-shadow: 0 0 6px rgba(0,255,136,0.4); }
579
- .status-dot--down { background: #ff4444; }
580
- .status-dot--timeout { background: #ff4444; }
581
- .status-dot--pending { background: #555570; animation: pulse-dot 1.5s ease-in-out infinite; }
582
-
583
- /* Loading */
584
- .loading-row td { text-align: center; padding: 60px 0; }
585
- .loading-spinner { display: flex; align-items: center; justify-content: center; gap: 12px; color: var(--color-text-muted); }
586
- .spinner {
587
- width: 24px; height: 24px;
588
- border: 3px solid var(--color-border);
589
- border-top-color: var(--color-accent);
590
- border-radius: 50%; animation: spin 0.8s linear infinite;
591
- }
592
- @keyframes spin { to { transform: rotate(360deg); } }
593
-
594
- .no-key-badge {
595
- font-size: 10px; font-weight: 600;
596
- padding: 1px 6px; border-radius: 3px;
597
- background: rgba(255,170,0,0.12); color: #ffaa00;
598
- border: 1px solid rgba(255,170,0,0.2); margin-left: 6px;
599
- }
600
-
601
- /* ═══════ SETTINGS PAGE ═══════ */
602
- .settings-page { padding: 24px; max-width: 900px; }
603
- .settings-page__header { margin-bottom: 24px; }
604
- .settings-page__title { font-size: 24px; font-weight: 800; margin-bottom: 6px; }
605
- .settings-page__subtitle { font-size: 13px; color: var(--color-text-muted); line-height: 1.5; }
606
-
607
- .settings-toolbar {
608
- display: flex; align-items: center; gap: 12px; margin-bottom: 20px;
609
- flex-wrap: wrap;
610
- }
611
- .settings-toolbar__search {
612
- display: flex; align-items: center; gap: 8px;
613
- background: var(--color-surface); border: 1px solid var(--color-border);
614
- border-radius: var(--radius-md); padding: 0 12px; height: 36px; flex: 1; min-width: 200px;
615
- }
616
- .settings-toolbar__search svg { color: var(--color-text-dim); flex-shrink: 0; }
617
- .settings-toolbar__search input {
618
- flex: 1; background: none; border: none; outline: none;
619
- color: var(--color-text); font-size: 13px; font-family: var(--font-sans);
620
- }
621
- .settings-toolbar__search input::placeholder { color: var(--color-text-dim); }
622
- .settings-toolbar__actions { display: flex; gap: 8px; }
623
-
624
- /* Provider Card */
625
- .settings-card {
626
- background: var(--color-bg-card);
627
- backdrop-filter: blur(12px);
628
- border: 1px solid var(--color-border);
629
- border-radius: var(--radius-lg);
630
- margin-bottom: 12px;
631
- overflow: hidden;
632
- transition: border-color var(--transition-fast);
633
- }
634
- .settings-card:hover { border-color: var(--color-border-hover); }
635
-
636
- .settings-card__header {
637
- display: flex; align-items: center; gap: 12px;
638
- padding: 16px 20px; cursor: pointer;
639
- transition: background var(--transition-fast);
640
- }
641
- .settings-card__header:hover { background: var(--color-bg-hover); }
642
-
643
- .settings-card__icon {
644
- width: 36px; height: 36px;
645
- display: flex; align-items: center; justify-content: center;
646
- border-radius: var(--radius-sm); font-size: 18px;
647
- background: var(--color-accent-dim);
648
- }
649
- .settings-card__info { flex: 1; }
650
- .settings-card__name { font-weight: 700; font-size: 14px; }
651
- .settings-card__meta { font-size: 11px; color: var(--color-text-muted); margin-top: 2px; }
652
-
653
- .settings-card__status {
654
- font-size: 11px; font-weight: 700; padding: 3px 10px; border-radius: 999px;
655
- }
656
- .settings-card__status--configured { background: var(--color-success-dim); color: var(--color-success); }
657
- .settings-card__status--missing { background: var(--color-warning-dim); color: var(--color-warning); }
658
-
659
- .settings-card__toggle-icon {
660
- color: var(--color-text-dim); transition: transform var(--transition-fast);
661
- font-size: 18px;
662
- }
663
- .settings-card--expanded .settings-card__toggle-icon { transform: rotate(180deg); }
664
-
665
- .settings-card__body {
666
- max-height: 0; overflow: hidden;
667
- transition: max-height var(--transition-medium);
668
- border-top: 0px solid transparent;
669
- }
670
- .settings-card--expanded .settings-card__body {
671
- max-height: 500px;
672
- border-top: 1px solid var(--color-border);
673
- }
674
-
675
- .settings-card__content { padding: 16px 20px; }
676
-
677
- /* API Key Input Group */
678
- .api-key-group { margin-bottom: 12px; }
679
- .api-key-group__label {
680
- display: block; font-size: 11px; font-weight: 600;
681
- color: var(--color-text-muted); text-transform: uppercase;
682
- letter-spacing: 0.5px; margin-bottom: 6px;
683
- }
684
- .api-key-group__row {
685
- display: flex; gap: 8px; align-items: center;
686
- }
687
- .api-key-group__input {
688
- flex: 1; background: var(--color-surface);
689
- border: 1px solid var(--color-border); border-radius: var(--radius-sm);
690
- padding: 8px 12px; font-size: 13px; font-family: var(--font-mono);
691
- color: var(--color-text); outline: none;
692
- transition: border-color var(--transition-fast);
693
- }
694
- .api-key-group__input:focus { border-color: var(--color-accent); }
695
- .api-key-group__input::placeholder { color: var(--color-text-dim); }
696
-
697
- .api-key-group__actions { display: flex; gap: 4px; }
698
-
699
- .api-key-display {
700
- display: flex; align-items: center; gap: 8px;
701
- background: var(--color-surface);
702
- border: 1px solid var(--color-border); border-radius: var(--radius-sm);
703
- padding: 8px 12px; margin-bottom: 8px;
704
- }
705
- .api-key-display__value {
706
- flex: 1; font-family: var(--font-mono); font-size: 13px;
707
- color: var(--color-text-muted); word-break: break-all;
708
- }
709
- .api-key-display__actions { display: flex; gap: 4px; flex-shrink: 0; }
710
-
711
- .settings-card__enabled {
712
- display: flex; align-items: center; justify-content: space-between;
713
- padding-top: 12px; border-top: 1px solid var(--color-border);
714
- margin-top: 12px;
715
- }
716
- .settings-card__enabled-label { font-size: 12px; color: var(--color-text-muted); font-weight: 500; }
717
-
718
- /* Toggle Switch */
719
- .toggle-switch {
720
- position: relative; width: 44px; height: 24px;
721
- cursor: pointer;
722
- }
723
- .toggle-switch input { display: none; }
724
- .toggle-switch__slider {
725
- position: absolute; inset: 0;
726
- background: var(--color-surface);
727
- border: 1px solid var(--color-border);
728
- border-radius: 12px;
729
- transition: all var(--transition-fast);
730
- }
731
- .toggle-switch__slider::after {
732
- content: '';
733
- position: absolute; left: 3px; top: 3px;
734
- width: 16px; height: 16px;
735
- background: var(--color-text-dim);
736
- border-radius: 50%;
737
- transition: all var(--transition-fast);
738
- }
739
- .toggle-switch input:checked + .toggle-switch__slider {
740
- background: var(--color-accent-dim);
741
- border-color: var(--color-accent);
742
- }
743
- .toggle-switch input:checked + .toggle-switch__slider::after {
744
- transform: translateX(20px);
745
- background: var(--color-accent);
746
- }
747
-
748
- /* ═══════ ANALYTICS PAGE ═══════ */
749
- .analytics-page { padding: 24px; }
750
- .analytics-page__header { margin-bottom: 24px; }
751
- .analytics-page__title { font-size: 24px; font-weight: 800; margin-bottom: 6px; }
752
- .analytics-page__subtitle { font-size: 13px; color: var(--color-text-muted); }
753
-
754
- .analytics-grid {
755
- display: grid;
756
- grid-template-columns: repeat(2, 1fr);
757
- gap: 16px;
758
- }
759
-
760
- .analytics-card {
761
- background: var(--color-bg-card);
762
- backdrop-filter: blur(12px);
763
- border: 1px solid var(--color-border);
764
- border-radius: var(--radius-lg);
765
- padding: 20px; overflow: hidden;
766
- }
767
- .analytics-card--wide { grid-column: span 2; }
768
- .analytics-card__title {
769
- font-size: 14px; font-weight: 700; margin-bottom: 16px;
770
- }
771
- .analytics-card__body { }
772
-
773
- /* Provider health bar */
774
- .provider-health-item {
775
- display: flex; align-items: center; gap: 12px;
776
- padding: 8px 0; border-bottom: 1px solid var(--color-border);
777
- }
778
- .provider-health-item:last-child { border-bottom: none; }
779
- .provider-health__name { width: 120px; font-size: 12px; font-weight: 600; flex-shrink: 0; }
780
- .provider-health__bar {
781
- flex: 1; height: 8px; border-radius: 4px;
782
- background: var(--color-surface); overflow: hidden;
783
- }
784
- .provider-health__fill {
785
- height: 100%; border-radius: 4px;
786
- background: linear-gradient(90deg, var(--color-accent), var(--color-success));
787
- transition: width var(--transition-medium);
788
- }
789
- .provider-health__pct {
790
- width: 40px; text-align: right;
791
- font-family: var(--font-mono); font-size: 12px; font-weight: 600;
792
- }
793
-
794
- /* Leaderboard */
795
- .leaderboard-item {
796
- display: flex; align-items: center; gap: 10px;
797
- padding: 8px 0; border-bottom: 1px solid var(--color-border);
798
- }
799
- .leaderboard-item:last-child { border-bottom: none; }
800
- .leaderboard__rank {
801
- width: 28px; height: 28px;
802
- display: flex; align-items: center; justify-content: center;
803
- border-radius: 50%; font-size: 12px; font-weight: 700;
804
- background: var(--color-surface); color: var(--color-text-dim);
805
- }
806
- .leaderboard__rank--1 { background: rgba(255,215,0,0.15); color: #ffd700; }
807
- .leaderboard__rank--2 { background: rgba(192,192,192,0.15); color: #c0c0c0; }
808
- .leaderboard__rank--3 { background: rgba(205,127,50,0.15); color: #cd7f32; }
809
- .leaderboard__name { flex: 1; font-size: 12px; font-weight: 600; }
810
- .leaderboard__latency { font-family: var(--font-mono); font-size: 12px; font-weight: 600; color: var(--color-success); }
811
-
812
- /* Tier distribution */
813
- .tier-dist-item {
814
- display: flex; align-items: center; gap: 10px;
815
- padding: 6px 0;
816
- }
817
- .tier-dist__badge { width: 40px; flex-shrink: 0; }
818
- .tier-dist__bar {
819
- flex: 1; height: 10px; border-radius: 5px;
820
- background: var(--color-surface); overflow: hidden;
821
- }
822
- .tier-dist__fill { height: 100%; border-radius: 5px; transition: width var(--transition-medium); }
823
- .tier-dist__count { width: 30px; text-align: right; font-family: var(--font-mono); font-size: 12px; color: var(--color-text-muted); }
824
-
825
- /* ─── Detail Panel ─── */
826
- .detail-panel {
827
- position: fixed; right: 0; top: 0; bottom: 0;
828
- width: min(420px, 90vw); z-index: 300;
829
- background: var(--color-bg-elevated);
830
- border-left: 1px solid var(--color-border);
831
- box-shadow: var(--shadow-lg);
832
- transform: translateX(100%);
833
- transition: transform var(--transition-medium);
834
- overflow-y: auto;
835
- }
836
- .detail-panel:not([hidden]) { transform: translateX(0); }
837
- .detail-panel__header {
838
- display: flex; align-items: center; justify-content: space-between;
839
- padding: 20px 24px;
840
- border-bottom: 1px solid var(--color-border);
841
- }
842
- .detail-panel__title { font-size: 16px; font-weight: 700; }
843
- .detail-panel__close {
844
- background: none; border: none; color: var(--color-text-muted);
845
- font-size: 22px; cursor: pointer; line-height: 1;
846
- }
847
- .detail-panel__close:hover { color: var(--color-text); }
848
- .detail-panel__body { padding: 24px; }
849
-
850
- .detail-stat {
851
- display: flex; justify-content: space-between; align-items: center;
852
- padding: 10px 0;
853
- border-bottom: 1px solid var(--color-border);
854
- }
855
- .detail-stat__label { font-size: 12px; color: var(--color-text-muted); text-transform: uppercase; letter-spacing: 0.5px; font-weight: 600; }
856
- .detail-stat__value { font-family: var(--font-mono); font-weight: 600; }
857
-
858
- .detail-chart {
859
- margin: 20px 0; padding: 16px;
860
- background: var(--color-surface);
861
- border-radius: var(--radius-md);
862
- border: 1px solid var(--color-border);
863
- }
864
- .detail-chart__title {
865
- font-size: 11px; font-weight: 700; color: var(--color-text-muted);
866
- text-transform: uppercase; letter-spacing: 0.8px; margin-bottom: 12px;
867
- }
868
-
869
- /* ─── Modal ─── */
870
- .modal-overlay {
871
- position: fixed; inset: 0; z-index: 1000;
872
- background: rgba(0,0,0,0.6);
873
- backdrop-filter: blur(4px);
874
- display: flex; align-items: center; justify-content: center;
875
- animation: fadeIn 200ms ease-out;
876
- }
877
- .modal-overlay[hidden] { display: none; }
878
- @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
879
-
880
- .modal {
881
- background: var(--color-bg-elevated);
882
- border: 1px solid var(--color-border);
883
- border-radius: var(--radius-xl);
884
- width: min(500px, 90vw);
885
- max-height: 80vh; overflow-y: auto;
886
- box-shadow: var(--shadow-lg);
887
- animation: modalSlideIn 300ms var(--ease-out);
888
- }
889
- @keyframes modalSlideIn {
890
- from { transform: translateY(20px) scale(0.96); opacity: 0; }
891
- to { transform: translateY(0) scale(1); opacity: 1; }
892
- }
893
- .modal__header {
894
- display: flex; align-items: center; justify-content: space-between;
895
- padding: 20px 24px;
896
- border-bottom: 1px solid var(--color-border);
897
- }
898
- .modal__title { font-size: 18px; font-weight: 700; }
899
- .modal__close {
900
- background: none; border: none; color: var(--color-text-muted);
901
- font-size: 24px; cursor: pointer; padding: 0; line-height: 1;
902
- }
903
- .modal__close:hover { color: var(--color-text); }
904
- .modal__body { padding: 24px; }
905
-
906
- /* Export options */
907
- .export-options { display: flex; flex-direction: column; gap: 10px; }
908
- .export-option {
909
- display: flex; align-items: center; gap: 14px;
910
- padding: 14px 18px; border: 1px solid var(--color-border);
911
- border-radius: var(--radius-md);
912
- background: var(--color-surface);
913
- cursor: pointer; transition: all var(--transition-fast);
914
- text-align: left; font-family: var(--font-sans);
915
- color: var(--color-text);
916
- }
917
- .export-option:hover {
918
- border-color: var(--color-accent);
919
- background: var(--color-accent-dim);
920
- }
921
- .export-option__icon { font-size: 24px; flex-shrink: 0; }
922
- .export-option__label { font-weight: 600; font-size: 14px; }
923
- .export-option__desc { font-size: 11px; color: var(--color-text-muted); margin-top: 2px; }
924
-
925
- /* ─── Footer ─── */
926
- .footer {
927
- position: relative; z-index: 1;
928
- display: flex; align-items: center; justify-content: space-between;
929
- padding: 16px 24px;
930
- border-top: 1px solid var(--color-border);
931
- font-size: 12px; color: var(--color-text-dim);
932
- }
933
- .footer__right { display: flex; gap: 16px; }
934
- .footer__right a { color: var(--color-text-dim); }
935
- .footer__right a:hover { color: var(--color-accent); }
936
-
937
- /* ─── Responsive ─── */
938
- @media (max-width: 1024px) {
939
- .stats-bar { grid-template-columns: repeat(3, 1fr); }
940
- .analytics-grid { grid-template-columns: 1fr; }
941
- .analytics-card--wide { grid-column: span 1; }
942
- }
943
- @media (max-width: 768px) {
944
- .sidebar { display: none; }
945
- .app-content { margin-left: 0; }
946
- .sidebar-toggle { display: inline-flex !important; }
947
- .stats-bar { grid-template-columns: repeat(2, 1fr); }
948
- .header__center { display: none; }
949
- .models-table { font-size: 12px; }
950
- .th--stability, .td--stability,
951
- .th--sparkline, .td--sparkline,
952
- .th--uptime, .td--uptime { display: none; }
953
- }
954
- @media (max-width: 480px) {
955
- .stats-bar { grid-template-columns: 1fr; }
956
- .filters { flex-direction: column; align-items: flex-start; }
957
- }
958
-
959
- /* ─── Scrollbar ─── */
960
- ::-webkit-scrollbar { width: 6px; }
961
- ::-webkit-scrollbar-track { background: transparent; }
962
- ::-webkit-scrollbar-thumb { background: var(--color-border); border-radius: 3px; }
963
- ::-webkit-scrollbar-thumb:hover { background: var(--color-text-dim); }