@mooncompany/uplink-chat 0.5.2 → 0.32.3

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 (215) hide show
  1. package/LICENSE +14 -1
  2. package/README.md +105 -3
  3. package/bin/uplink.js +3 -0
  4. package/middleware/error-handler.js +1 -0
  5. package/package.json +89 -5
  6. package/public/css/agents.1fd7567a.css +1499 -0
  7. package/public/css/app.bc7e7484.css +2819 -0
  8. package/public/css/artifacts.css +488 -0
  9. package/public/css/commands.css +77 -0
  10. package/public/css/connection.css +131 -0
  11. package/public/css/cron-panel.css +364 -0
  12. package/public/css/dashboard.css +233 -0
  13. package/public/css/developer.css +342 -0
  14. package/public/css/files.css +123 -0
  15. package/public/css/markdown.css +156 -0
  16. package/public/css/message-actions.css +285 -0
  17. package/public/css/mobile.css +614 -0
  18. package/public/css/panels-unified.css +485 -0
  19. package/public/css/premium.css +415 -0
  20. package/public/css/realtime.css +189 -0
  21. package/public/css/satellites.7fa72088.css +632 -0
  22. package/public/css/settings-redesign.css +1322 -0
  23. package/public/css/shortcuts.css +185 -0
  24. package/public/css/split-view.4bc23474.css +858 -0
  25. package/public/css/themes.css +387 -0
  26. package/public/css/timestamps.css +54 -0
  27. package/public/css/variables.css +81 -0
  28. package/public/dist/bundle.493af136.js +1 -0
  29. package/public/favicon-256.png +0 -0
  30. package/public/icon-192.png +0 -0
  31. package/public/icon-512.png +0 -0
  32. package/public/img/icons/icon-alert-triangle.svg +17 -0
  33. package/public/img/icons/icon-brain.svg +20 -0
  34. package/public/img/icons/icon-brand-python.svg +19 -0
  35. package/public/img/icons/icon-camera.svg +16 -0
  36. package/public/img/icons/icon-chart-bar.svg +18 -0
  37. package/public/img/icons/icon-check.svg +15 -0
  38. package/public/img/icons/icon-circle-check.svg +16 -0
  39. package/public/img/icons/icon-clipboard.svg +16 -0
  40. package/public/img/icons/icon-cloud.svg +15 -0
  41. package/public/img/icons/icon-confetti.svg +24 -0
  42. package/public/img/icons/icon-device-mobile.svg +17 -0
  43. package/public/img/icons/icon-diamond.svg +16 -0
  44. package/public/img/icons/icon-file-text.svg +19 -0
  45. package/public/img/icons/icon-file-type-css.svg +19 -0
  46. package/public/img/icons/icon-file-type-csv.svg +19 -0
  47. package/public/img/icons/icon-file-type-doc.svg +19 -0
  48. package/public/img/icons/icon-file-type-html.svg +23 -0
  49. package/public/img/icons/icon-file-type-js.svg +18 -0
  50. package/public/img/icons/icon-file-type-pdf.svg +20 -0
  51. package/public/img/icons/icon-file-zip.svg +22 -0
  52. package/public/img/icons/icon-file.svg +16 -0
  53. package/public/img/icons/icon-folder.svg +15 -0
  54. package/public/img/icons/icon-headphones.svg +17 -0
  55. package/public/img/icons/icon-hourglass.svg +18 -0
  56. package/public/img/icons/icon-keyboard.svg +22 -0
  57. package/public/img/icons/icon-link.svg +17 -0
  58. package/public/img/icons/icon-lock-open.svg +17 -0
  59. package/public/img/icons/icon-lock.svg +17 -0
  60. package/public/img/icons/icon-mail.svg +16 -0
  61. package/public/img/icons/icon-message-dots.svg +18 -0
  62. package/public/img/icons/icon-microphone-2.svg +16 -0
  63. package/public/img/icons/icon-microphone.svg +18 -0
  64. package/public/img/icons/icon-movie.svg +22 -0
  65. package/public/img/icons/icon-music.svg +18 -0
  66. package/public/img/icons/icon-palette.svg +18 -0
  67. package/public/img/icons/icon-paperclip.svg +15 -0
  68. package/public/img/icons/icon-pencil.svg +16 -0
  69. package/public/img/icons/icon-photo.svg +18 -0
  70. package/public/img/icons/icon-presentation.svg +19 -0
  71. package/public/img/icons/icon-robot.svg +23 -0
  72. package/public/img/icons/icon-rocket.svg +17 -0
  73. package/public/img/icons/icon-satellite.svg +20 -0
  74. package/public/img/icons/icon-settings.svg +16 -0
  75. package/public/img/icons/icon-shield-lock.svg +17 -0
  76. package/public/img/icons/icon-sparkles.svg +15 -0
  77. package/public/img/icons/icon-star-filled.svg +11 -0
  78. package/public/img/icons/icon-tool.svg +15 -0
  79. package/public/img/icons/icon-trash.svg +19 -0
  80. package/public/img/icons/icon-volume.svg +17 -0
  81. package/public/img/icons/icon-world.svg +19 -0
  82. package/public/img/icons/icon-x.svg +16 -0
  83. package/public/img/logo.svg +13 -0
  84. package/public/img/wordmark.svg +35 -0
  85. package/public/index.html +1195 -0
  86. package/public/js/agents-data.js +1 -0
  87. package/public/js/agents-ui.js +1 -0
  88. package/public/js/agents.js +1 -0
  89. package/public/js/app.js +1 -0
  90. package/public/js/appearance-settings.js +1 -0
  91. package/public/js/artifacts.js +1 -0
  92. package/public/js/audio-pcm-processor.js +1 -0
  93. package/public/js/audio-queue.js +1 -0
  94. package/public/js/bootstrap.js +1 -0
  95. package/public/js/chat.js +1 -0
  96. package/public/js/commands.js +1 -0
  97. package/public/js/connection-api.js +1 -0
  98. package/public/js/connection.js +1 -0
  99. package/public/js/context-tracker.js +1 -0
  100. package/public/js/core.js +1 -0
  101. package/public/js/cron-panel.js +1 -0
  102. package/public/js/dashboard.js +1 -0
  103. package/public/js/developer.js +1 -0
  104. package/public/js/encryption.js +1 -0
  105. package/public/js/errors.js +1 -0
  106. package/public/js/event-bus.js +1 -0
  107. package/public/js/fetch-utils.js +1 -0
  108. package/public/js/file-handler.js +1 -0
  109. package/public/js/files.js +1 -0
  110. package/public/js/gateway-chat.js +1 -0
  111. package/public/js/logger.js +1 -0
  112. package/public/js/markdown.js +1 -0
  113. package/public/js/message-actions.js +1 -0
  114. package/public/js/message-renderer.js +1 -0
  115. package/public/js/missed-messages.js +1 -0
  116. package/public/js/mobile-debug.js +1 -0
  117. package/public/js/notifications.js +1 -0
  118. package/public/js/offline-queue.js +1 -0
  119. package/public/js/onboarding.js +1 -0
  120. package/public/js/panels.js +1 -0
  121. package/public/js/premium.js +1 -0
  122. package/public/js/primary-header.js +1 -0
  123. package/public/js/realtime-voice.js +1 -0
  124. package/public/js/satellite-sync.js +1 -0
  125. package/public/js/satellite-ui.js +1 -0
  126. package/public/js/satellites.js +1 -0
  127. package/public/js/settings.js +1 -0
  128. package/public/js/shortcuts.js +1 -0
  129. package/public/js/split-chat.js +1 -0
  130. package/public/js/split-resize.js +1 -0
  131. package/public/js/splitview.js +1 -0
  132. package/public/js/storage.js +1 -0
  133. package/public/js/streaming-handler.js +1 -0
  134. package/public/js/stt-settings.js +1 -0
  135. package/public/js/themes.js +1 -0
  136. package/public/js/timestamps.js +1 -0
  137. package/public/js/tts-settings.js +1 -0
  138. package/public/js/ui.js +1 -0
  139. package/public/js/update-notifier.js +1 -0
  140. package/public/js/utils/constants.js +1 -0
  141. package/public/js/utils/icons.js +1 -0
  142. package/public/js/utils/sanitize.js +1 -0
  143. package/public/js/utils/sse-parser.js +1 -0
  144. package/public/js/vad.js +1 -0
  145. package/public/js/vendor/dompurify.min.js +2 -0
  146. package/public/js/voice-settings-v2.js +1 -0
  147. package/public/js/voice.js +1 -0
  148. package/public/manifest.json +66 -0
  149. package/public/moon_texture.jpg +0 -0
  150. package/public/sw.js +1 -0
  151. package/public/three.min.js +6 -0
  152. package/public/u-icon.png +0 -0
  153. package/server/channel.js +1 -0
  154. package/server/chat.js +1 -0
  155. package/server/config-store.js +1 -0
  156. package/server/config.js +1 -0
  157. package/server/context.js +1 -0
  158. package/server/gateway-api-proxy.js +1 -0
  159. package/server/gateway-commands.js +1 -0
  160. package/server/gateway-proxy.js +1 -0
  161. package/server/index.js +1 -0
  162. package/server/logger.js +1 -0
  163. package/server/message-store.js +1 -0
  164. package/server/middleware/auth.js +1 -0
  165. package/server/middleware.js +1 -0
  166. package/server/openclaw-discover.js +1 -0
  167. package/server/premium/index.js +1 -0
  168. package/server/premium/license.js +1 -0
  169. package/server/realtime/bridge.js +1 -0
  170. package/server/realtime/index.js +1 -0
  171. package/server/realtime/tts-stream.js +1 -0
  172. package/server/routes/agents.js +1 -0
  173. package/server/routes/artifacts.js +1 -0
  174. package/server/routes/chat.js +1 -0
  175. package/server/routes/config-settings.js +1 -0
  176. package/server/routes/config.js +1 -0
  177. package/server/routes/cron.js +1 -0
  178. package/server/routes/files.js +1 -0
  179. package/server/routes/index.js +1 -0
  180. package/server/routes/media.js +1 -0
  181. package/server/routes/missed-messages.js +1 -0
  182. package/server/routes/premium.js +1 -0
  183. package/server/routes/push.js +1 -0
  184. package/server/routes/satellite.js +1 -0
  185. package/server/routes/status.js +1 -0
  186. package/server/routes/stt.js +1 -0
  187. package/server/routes/voice.js +1 -0
  188. package/server/routes/webhooks.js +1 -0
  189. package/server/routes.js +1 -0
  190. package/server/runtime-config.js +1 -0
  191. package/server/share.js +1 -0
  192. package/server/stt/faster-whisper.js +1 -0
  193. package/server/stt/groq.js +1 -0
  194. package/server/stt/index.js +1 -0
  195. package/server/stt/openai.js +1 -0
  196. package/server/sync.js +1 -0
  197. package/server/tailscale-https.js +1 -0
  198. package/server/tts.js +1 -0
  199. package/server/update-checker.js +1 -0
  200. package/server/utils/filename.js +1 -0
  201. package/server/utils.js +1 -0
  202. package/server/watchdog.js +3 -0
  203. package/server/websocket/broadcast.js +1 -0
  204. package/server/websocket/connections.js +1 -0
  205. package/server/websocket/index.js +1 -0
  206. package/server/websocket/routing.js +1 -0
  207. package/server/websocket/sync.js +1 -0
  208. package/server.js +1 -0
  209. package/utils/detect-tool-usage.js +1 -0
  210. package/utils/errors.js +1 -0
  211. package/utils/html-escape.js +1 -0
  212. package/utils/id-sanitize.js +1 -0
  213. package/utils/response.js +1 -0
  214. package/utils/with-retry.js +1 -0
  215. package/index.js +0 -2
@@ -0,0 +1,364 @@
1
+ /* ============================================
2
+ CRON PANEL
3
+ Tab bar and cron job run history within the artifacts panel
4
+ ============================================ */
5
+
6
+ /* ---- Tab bar ---- */
7
+ .artifacts-tab-bar {
8
+ display: flex;
9
+ gap: 0;
10
+ flex-shrink: 0;
11
+ }
12
+
13
+ .artifacts-tab {
14
+ padding: var(--space-2, 8px) var(--space-4, 16px);
15
+ border: none;
16
+ background: none;
17
+ color: var(--text-muted, var(--text-secondary));
18
+ font-family: var(--font-mono);
19
+ font-size: var(--text-sm, 13px);
20
+ font-weight: 500;
21
+ letter-spacing: 0.5px;
22
+ text-transform: uppercase;
23
+ cursor: pointer;
24
+ position: relative;
25
+ transition: color 0.15s;
26
+ min-height: 44px;
27
+ display: flex;
28
+ align-items: center;
29
+ }
30
+
31
+ .artifacts-tab:hover {
32
+ color: var(--text);
33
+ }
34
+
35
+ .artifacts-tab.active {
36
+ color: var(--accent);
37
+ }
38
+
39
+ .artifacts-tab.active::after {
40
+ content: '';
41
+ position: absolute;
42
+ bottom: 0;
43
+ left: var(--space-4, 16px);
44
+ right: var(--space-4, 16px);
45
+ height: 2px;
46
+ background: var(--accent);
47
+ border-radius: 1px;
48
+ }
49
+
50
+ /* Active tab dot — matches the artifacts title dot */
51
+ .artifacts-tab.active::before {
52
+ content: '';
53
+ display: inline-block;
54
+ width: 6px;
55
+ height: 6px;
56
+ border-radius: 50%;
57
+ background: var(--accent);
58
+ box-shadow: 0 0 6px var(--accent-30);
59
+ margin-right: var(--space-2, 8px);
60
+ flex-shrink: 0;
61
+ }
62
+
63
+ /* ---- Cron list ---- */
64
+ .cron-list {
65
+ display: flex;
66
+ flex-direction: column;
67
+ gap: 0;
68
+ }
69
+
70
+ .cron-loading {
71
+ padding: var(--space-6, 24px);
72
+ text-align: center;
73
+ color: var(--text-muted, var(--text-secondary));
74
+ font-size: var(--text-sm, 14px);
75
+ }
76
+
77
+ /* ---- Cron run item ---- */
78
+ .cron-run-item {
79
+ display: flex;
80
+ align-items: flex-start;
81
+ gap: var(--space-3, 12px);
82
+ padding: var(--space-3, 12px) var(--space-3, 12px);
83
+ border: 1px solid transparent;
84
+ border-radius: var(--radius-md);
85
+ cursor: pointer;
86
+ transition: background 0.15s, border-color 0.15s;
87
+ min-height: 44px;
88
+ }
89
+
90
+ .cron-run-item:hover {
91
+ background: var(--white-05, var(--hover));
92
+ border-color: var(--accent);
93
+ }
94
+
95
+ /* Status indicator */
96
+ .cron-run-status {
97
+ width: 24px;
98
+ height: 24px;
99
+ border-radius: 50%;
100
+ display: flex;
101
+ align-items: center;
102
+ justify-content: center;
103
+ font-size: 12px;
104
+ font-weight: 700;
105
+ flex-shrink: 0;
106
+ margin-top: 2px;
107
+ }
108
+
109
+ .cron-status-ok {
110
+ background: rgba(34, 197, 94, 0.15);
111
+ color: #22c55e;
112
+ }
113
+
114
+ .cron-status-error {
115
+ background: rgba(239, 68, 68, 0.15);
116
+ color: #ef4444;
117
+ }
118
+
119
+ .cron-status-skipped {
120
+ background: rgba(250, 204, 21, 0.15);
121
+ color: #facc15;
122
+ }
123
+
124
+ .cron-status-unknown {
125
+ background: var(--white-05, rgba(255, 255, 255, 0.05));
126
+ color: var(--text-muted, var(--text-secondary));
127
+ }
128
+
129
+ /* Run info */
130
+ .cron-run-info {
131
+ flex: 1;
132
+ min-width: 0;
133
+ }
134
+
135
+ .cron-run-name {
136
+ font-size: var(--text-sm, 14px);
137
+ font-weight: 600;
138
+ color: var(--text);
139
+ display: flex;
140
+ align-items: center;
141
+ gap: var(--space-2, 8px);
142
+ flex-wrap: wrap;
143
+ }
144
+
145
+ .cron-agent-badge {
146
+ font-size: var(--text-xs, 11px);
147
+ font-weight: 500;
148
+ padding: 1px 8px;
149
+ border-radius: var(--radius-full, 9999px);
150
+ background: var(--accent-10, rgba(120, 90, 255, 0.1));
151
+ color: var(--accent);
152
+ font-family: var(--font-mono);
153
+ white-space: nowrap;
154
+ }
155
+
156
+ .cron-run-subtitle {
157
+ font-size: var(--text-xs, 12px);
158
+ color: var(--text-muted, var(--text-secondary));
159
+ margin-top: 2px;
160
+ overflow: hidden;
161
+ text-overflow: ellipsis;
162
+ white-space: nowrap;
163
+ }
164
+
165
+ .cron-run-meta {
166
+ font-size: var(--text-xs, 11px);
167
+ color: var(--text-muted, var(--text-secondary));
168
+ margin-top: 4px;
169
+ opacity: 0.8;
170
+ }
171
+
172
+ .cron-run-chevron {
173
+ flex-shrink: 0;
174
+ color: var(--text-muted, var(--text-secondary));
175
+ opacity: 0.5;
176
+ margin-top: 6px;
177
+ }
178
+
179
+ /* ---- Cron detail view ---- */
180
+ .cron-detail {
181
+ display: flex;
182
+ flex-direction: column;
183
+ gap: var(--space-4, 16px);
184
+ }
185
+
186
+ .cron-detail-toolbar {
187
+ display: flex;
188
+ align-items: center;
189
+ gap: var(--space-2, 8px);
190
+ }
191
+
192
+ .cron-detail-title {
193
+ font-size: var(--text-lg, 18px);
194
+ font-weight: 600;
195
+ color: var(--text);
196
+ margin: 0;
197
+ word-break: break-word;
198
+ }
199
+
200
+ /* Detail metadata grid */
201
+ .cron-detail-meta {
202
+ display: flex;
203
+ flex-direction: column;
204
+ gap: var(--space-2, 6px);
205
+ padding: var(--space-3, 12px);
206
+ background: var(--bg-input, var(--bg-secondary));
207
+ border: 1px solid var(--border);
208
+ border-radius: var(--radius-md);
209
+ }
210
+
211
+ .cron-detail-meta-row {
212
+ display: flex;
213
+ align-items: center;
214
+ gap: var(--space-3, 12px);
215
+ font-size: var(--text-sm, 13px);
216
+ }
217
+
218
+ .cron-meta-label {
219
+ color: var(--text-muted, var(--text-secondary));
220
+ font-weight: 500;
221
+ min-width: 72px;
222
+ flex-shrink: 0;
223
+ }
224
+
225
+ .cron-meta-value {
226
+ color: var(--text);
227
+ font-family: var(--font-mono);
228
+ font-size: var(--text-xs, 12px);
229
+ }
230
+
231
+ /* Run history entries */
232
+ .cron-detail-runs {
233
+ display: flex;
234
+ flex-direction: column;
235
+ gap: var(--space-2, 6px);
236
+ }
237
+
238
+ .cron-entry {
239
+ border: 1px solid var(--border);
240
+ border-radius: var(--radius-md);
241
+ overflow: hidden;
242
+ }
243
+
244
+ .cron-entry-header {
245
+ display: flex;
246
+ align-items: center;
247
+ gap: var(--space-2, 8px);
248
+ padding: var(--space-2, 8px) var(--space-3, 12px);
249
+ background: var(--bg-input, var(--bg-secondary));
250
+ font-size: var(--text-xs, 12px);
251
+ }
252
+
253
+ .cron-entry-header .cron-run-status {
254
+ width: 18px;
255
+ height: 18px;
256
+ font-size: 10px;
257
+ }
258
+
259
+ .cron-entry-time {
260
+ color: var(--text);
261
+ font-weight: 500;
262
+ }
263
+
264
+ .cron-entry-duration {
265
+ color: var(--text-muted, var(--text-secondary));
266
+ font-family: var(--font-mono);
267
+ }
268
+
269
+ .cron-entry-model {
270
+ color: var(--text-muted, var(--text-secondary));
271
+ font-family: var(--font-mono);
272
+ margin-left: auto;
273
+ }
274
+
275
+ .cron-entry-body {
276
+ padding: var(--space-3, 12px);
277
+ }
278
+
279
+ .cron-entry-error {
280
+ font-size: var(--text-xs, 12px);
281
+ color: #ef4444;
282
+ font-family: var(--font-mono);
283
+ padding: var(--space-2, 6px) var(--space-3, 12px);
284
+ background: rgba(239, 68, 68, 0.08);
285
+ border-radius: var(--radius-sm, 4px);
286
+ margin-bottom: var(--space-2, 6px);
287
+ word-break: break-word;
288
+ }
289
+
290
+ .cron-entry-summary {
291
+ font-size: var(--text-sm, 13px);
292
+ line-height: 1.6;
293
+ color: var(--text);
294
+ overflow-wrap: break-word;
295
+ }
296
+
297
+ /* Markdown within summaries — tighter spacing */
298
+ .cron-entry-summary h1,
299
+ .cron-entry-summary h2,
300
+ .cron-entry-summary h3 {
301
+ margin-top: var(--space-3, 12px);
302
+ margin-bottom: var(--space-2, 6px);
303
+ font-size: var(--text-sm, 14px);
304
+ font-weight: 600;
305
+ }
306
+
307
+ .cron-entry-summary p {
308
+ margin: 0 0 var(--space-2, 6px);
309
+ }
310
+
311
+ .cron-entry-summary ul,
312
+ .cron-entry-summary ol {
313
+ margin: 0 0 var(--space-2, 6px);
314
+ padding-left: var(--space-5, 20px);
315
+ }
316
+
317
+ .cron-entry-summary li {
318
+ margin-bottom: 2px;
319
+ }
320
+
321
+ .cron-entry-summary code {
322
+ background: var(--bg-input, var(--bg-secondary));
323
+ border: 1px solid var(--border);
324
+ padding: 1px 4px;
325
+ border-radius: var(--radius-sm, 4px);
326
+ font-family: var(--font-mono);
327
+ font-size: 0.9em;
328
+ }
329
+
330
+ .cron-entry-summary pre {
331
+ background: var(--bg-input, var(--bg-secondary));
332
+ border: 1px solid var(--border);
333
+ padding: var(--space-2, 8px);
334
+ border-radius: var(--radius-md);
335
+ overflow-x: auto;
336
+ margin: 0 0 var(--space-2, 6px);
337
+ font-size: var(--text-xs, 12px);
338
+ }
339
+
340
+ .cron-entry-summary table {
341
+ width: 100%;
342
+ border-collapse: collapse;
343
+ font-size: var(--text-xs, 12px);
344
+ margin: 0 0 var(--space-2, 6px);
345
+ }
346
+
347
+ .cron-entry-summary table th,
348
+ .cron-entry-summary table td {
349
+ border: 1px solid var(--border);
350
+ padding: var(--space-1, 4px) var(--space-2, 8px);
351
+ text-align: left;
352
+ }
353
+
354
+ .cron-entry-summary table th {
355
+ background: var(--bg-input, var(--bg-secondary));
356
+ font-weight: 600;
357
+ }
358
+
359
+ /* ---- Mobile ---- */
360
+ @media (max-width: 768px) {
361
+ .cron-run-item {
362
+ padding: var(--space-3, 12px) var(--space-2, 8px);
363
+ }
364
+ }
@@ -0,0 +1,233 @@
1
+ /* ============================================
2
+ DASHBOARD STYLES
3
+ Usage analytics and stats
4
+ ============================================ */
5
+
6
+ .dashboard-overlay {
7
+ position: fixed;
8
+ top: 0;
9
+ left: 0;
10
+ right: 0;
11
+ bottom: 0;
12
+ background: var(--black-80);
13
+ backdrop-filter: blur(4px);
14
+ z-index: var(--z-toast);
15
+ display: none;
16
+ align-items: center;
17
+ justify-content: center;
18
+ /* Safe area support for notched devices */
19
+ padding: calc(var(--space-5) + env(safe-area-inset-top, 0px))
20
+ calc(var(--space-5) + env(safe-area-inset-right, 0px))
21
+ calc(var(--space-5) + env(safe-area-inset-bottom, 0px))
22
+ calc(var(--space-5) + env(safe-area-inset-left, 0px));
23
+ }
24
+
25
+ .dashboard-overlay.visible {
26
+ display: flex;
27
+ }
28
+
29
+ .dashboard-panel {
30
+ background: linear-gradient(180deg, rgba(10, 25, 50, 0.98) 0%, rgba(5, 15, 35, 0.98) 100%);
31
+ border: 1px solid var(--border);
32
+ border-radius: var(--radius-2xl);
33
+ width: 100%;
34
+ max-width: 500px;
35
+ max-height: 90vh;
36
+ overflow: hidden;
37
+ display: flex;
38
+ flex-direction: column;
39
+ animation: dashboardAppear 0.3s ease-out;
40
+ }
41
+
42
+ @keyframes dashboardAppear {
43
+ from {
44
+ opacity: 0;
45
+ transform: scale(0.95) translateY(20px);
46
+ }
47
+ to {
48
+ opacity: 1;
49
+ transform: scale(1) translateY(0);
50
+ }
51
+ }
52
+
53
+ .dashboard-header {
54
+ display: flex;
55
+ align-items: center;
56
+ justify-content: space-between;
57
+ padding: var(--space-4) var(--space-5);
58
+ border-bottom: 1px solid var(--border);
59
+ }
60
+
61
+ .dashboard-header h2 {
62
+ font-size: var(--text-lg);
63
+ font-weight: 600;
64
+ color: var(--text);
65
+ margin: 0;
66
+ }
67
+
68
+ .dashboard-close {
69
+ min-width: 44px;
70
+ min-height: 44px;
71
+ border: none;
72
+ border-radius: var(--radius-md);
73
+ background: var(--white-10);
74
+ color: var(--text-muted);
75
+ font-size: var(--text-xl);
76
+ cursor: pointer;
77
+ transition: all 0.2s;
78
+ display: flex;
79
+ align-items: center;
80
+ justify-content: center;
81
+ }
82
+
83
+ .dashboard-close:hover {
84
+ background: var(--error-20);
85
+ color: var(--error);
86
+ }
87
+
88
+ .dashboard-content {
89
+ flex: 1;
90
+ overflow-y: auto;
91
+ padding: var(--space-4) var(--space-5);
92
+ }
93
+
94
+ .dashboard-section {
95
+ margin-bottom: var(--space-6);
96
+ }
97
+
98
+ .dashboard-section:last-child {
99
+ margin-bottom: 0;
100
+ }
101
+
102
+ .dashboard-section h3 {
103
+ font-size: var(--text-sm);
104
+ font-weight: 500;
105
+ color: var(--text-muted);
106
+ margin: 0 0 var(--space-3) 0;
107
+ text-transform: uppercase;
108
+ letter-spacing: 0.5px;
109
+ }
110
+
111
+ /* Stat Grid */
112
+ .stat-grid {
113
+ display: grid;
114
+ grid-template-columns: repeat(2, 1fr);
115
+ gap: var(--space-3);
116
+ }
117
+
118
+ .stat-card {
119
+ background: var(--black-30);
120
+ border: 1px solid var(--border);
121
+ border-radius: var(--radius-lg);
122
+ padding: var(--space-4);
123
+ text-align: center;
124
+ }
125
+
126
+ .stat-value {
127
+ display: block;
128
+ font-size: var(--text-2xl);
129
+ font-weight: 600;
130
+ color: var(--accent);
131
+ margin-bottom: var(--space-1);
132
+ }
133
+
134
+ .stat-label {
135
+ font-size: var(--text-xs);
136
+ color: var(--text-muted);
137
+ text-transform: uppercase;
138
+ letter-spacing: 0.5px;
139
+ }
140
+
141
+ /* Charts */
142
+ .chart-container {
143
+ background: var(--black-20);
144
+ border: 1px solid var(--border);
145
+ border-radius: var(--radius-lg);
146
+ padding: var(--space-4);
147
+ }
148
+
149
+ .chart-container canvas {
150
+ width: 100%;
151
+ height: auto;
152
+ }
153
+
154
+ /* Actions */
155
+ .dashboard-actions {
156
+ display: flex;
157
+ gap: var(--space-3);
158
+ margin-top: var(--space-5);
159
+ padding-top: var(--space-4);
160
+ border-top: 1px solid var(--border);
161
+ }
162
+
163
+ .dashboard-btn {
164
+ flex: 1;
165
+ padding: var(--space-2) var(--space-4);
166
+ border: 1px solid var(--border);
167
+ border-radius: var(--radius-md);
168
+ background: var(--accent-10);
169
+ color: var(--accent);
170
+ font-size: var(--text-sm);
171
+ cursor: pointer;
172
+ transition: all 0.2s;
173
+ }
174
+
175
+ .dashboard-btn:hover {
176
+ background: var(--accent-20);
177
+ border-color: var(--accent);
178
+ }
179
+
180
+ .dashboard-btn.danger {
181
+ background: var(--error-10);
182
+ color: var(--error);
183
+ border-color: var(--error-30);
184
+ }
185
+
186
+ .dashboard-btn.danger:hover {
187
+ background: var(--error-20);
188
+ border-color: var(--error);
189
+ }
190
+
191
+ /* Scrollbar */
192
+ .dashboard-content::-webkit-scrollbar {
193
+ width: 6px;
194
+ }
195
+
196
+ .dashboard-content::-webkit-scrollbar-track {
197
+ background: transparent;
198
+ }
199
+
200
+ .dashboard-content::-webkit-scrollbar-thumb {
201
+ background: var(--border);
202
+ border-radius: 3px;
203
+ }
204
+
205
+ /* Responsive (slightly above --breakpoint-sm for dashboard) */
206
+ @media (max-width: 500px) {
207
+ .dashboard-panel {
208
+ max-height: 100vh;
209
+ border-radius: 0;
210
+ /* Safe area for full-screen panel on notched devices */
211
+ padding-top: env(safe-area-inset-top, 0px);
212
+ padding-bottom: env(safe-area-inset-bottom, 0px);
213
+ }
214
+
215
+ .stat-grid {
216
+ grid-template-columns: repeat(2, 1fr);
217
+ }
218
+
219
+ .stat-value {
220
+ font-size: var(--text-xl);
221
+ }
222
+ }
223
+
224
+ /* Accessibility: Respect reduced motion preference (M-09) */
225
+ @media (prefers-reduced-motion: reduce) {
226
+ *,
227
+ *::before,
228
+ *::after {
229
+ animation-duration: 0.01ms !important;
230
+ animation-iteration-count: 1 !important;
231
+ transition-duration: 0.01ms !important;
232
+ }
233
+ }