@flame0510/project-aether 1.1.9

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 (290) hide show
  1. package/README.md +150 -0
  2. package/agent-templates/README.md +37 -0
  3. package/agent-templates/argus/AGENTS.md +52 -0
  4. package/agent-templates/argus/IDENTITY.md +7 -0
  5. package/agent-templates/argus/MEMORY.md +9 -0
  6. package/agent-templates/argus/SOUL.md +24 -0
  7. package/agent-templates/argus/TOOLS.md +8 -0
  8. package/agent-templates/atlas/AGENTS.md +47 -0
  9. package/agent-templates/atlas/HEARTBEAT.md +10 -0
  10. package/agent-templates/atlas/IDENTITY.md +6 -0
  11. package/agent-templates/atlas/MEMORY.md +9 -0
  12. package/agent-templates/atlas/SOUL.md +21 -0
  13. package/agent-templates/atlas/TOOLS.md +4 -0
  14. package/agent-templates/base-image/.trigger +0 -0
  15. package/agent-templates/base-image/Dockerfile +90 -0
  16. package/agent-templates/base-image/entrypoint.sh +37 -0
  17. package/agent-templates/custom/AGENTS.md +29 -0
  18. package/agent-templates/custom/BOOTSTRAP.md +56 -0
  19. package/agent-templates/custom/MEMORY.md +8 -0
  20. package/agent-templates/prometheus/AGENTS.md +37 -0
  21. package/agent-templates/prometheus/IDENTITY.md +6 -0
  22. package/agent-templates/prometheus/MEMORY.md +9 -0
  23. package/agent-templates/prometheus/SOUL.md +21 -0
  24. package/agent-templates/prometheus/TOOLS.md +4 -0
  25. package/app/agents/ChannelManager.tsx +465 -0
  26. package/app/agents/ImageDownloadBanner.tsx +159 -0
  27. package/app/agents/PageClient.tsx +1285 -0
  28. package/app/agents/create/PageClient.tsx +437 -0
  29. package/app/agents/create/page.tsx +126 -0
  30. package/app/agents/loading.tsx +14 -0
  31. package/app/agents/page.tsx +5 -0
  32. package/app/api/agents/[id]/backup/route.ts +169 -0
  33. package/app/api/agents/[id]/channels/pairing/route.ts +69 -0
  34. package/app/api/agents/[id]/channels/route.ts +14 -0
  35. package/app/api/agents/[id]/channels/telegram/route.ts +50 -0
  36. package/app/api/agents/[id]/lifecycle/route.ts +94 -0
  37. package/app/api/agents/[id]/recreate/route.ts +199 -0
  38. package/app/api/agents/[id]/restart/route.ts +33 -0
  39. package/app/api/agents/[id]/restore/route.ts +81 -0
  40. package/app/api/agents/[id]/route.ts +280 -0
  41. package/app/api/agents/channels-summary/route.ts +39 -0
  42. package/app/api/agents/config-json/route.ts +58 -0
  43. package/app/api/agents/create/route.ts +488 -0
  44. package/app/api/agents/download-image/route.ts +32 -0
  45. package/app/api/agents/image-status/route.ts +126 -0
  46. package/app/api/agents/route.ts +213 -0
  47. package/app/api/agents/token/route.ts +94 -0
  48. package/app/api/agents-active/route.ts +190 -0
  49. package/app/api/agents-config/route.ts +629 -0
  50. package/app/api/alerts/smoke/route.ts +26 -0
  51. package/app/api/aliases/add/route.ts +28 -0
  52. package/app/api/aliases/remove/route.ts +27 -0
  53. package/app/api/assistant/route.ts +204 -0
  54. package/app/api/auth/check/route.ts +38 -0
  55. package/app/api/auth/login/route.ts +85 -0
  56. package/app/api/auth/logout/route.ts +7 -0
  57. package/app/api/auth/status/route.ts +33 -0
  58. package/app/api/config/env/route.ts +132 -0
  59. package/app/api/config/restart/route.ts +26 -0
  60. package/app/api/containers/route.ts +75 -0
  61. package/app/api/cost-override/route.ts +46 -0
  62. package/app/api/costs/route.ts +84 -0
  63. package/app/api/credentials/[id]/reveal/route.ts +21 -0
  64. package/app/api/credentials/[id]/route.ts +52 -0
  65. package/app/api/credentials/[id]/sync/route.ts +58 -0
  66. package/app/api/credentials/detect/route.ts +246 -0
  67. package/app/api/credentials/route.ts +33 -0
  68. package/app/api/crons/[id]/route.ts +69 -0
  69. package/app/api/crons/route.ts +12 -0
  70. package/app/api/crons/runs/route.ts +31 -0
  71. package/app/api/debug/route.ts +11 -0
  72. package/app/api/envcheck/route.ts +18 -0
  73. package/app/api/events/route.ts +24 -0
  74. package/app/api/gateway/agent/route.ts +154 -0
  75. package/app/api/gateway/provider/balance/route.ts +38 -0
  76. package/app/api/gateway/provider/keys.ts +38 -0
  77. package/app/api/gateway/provider/oauth/route.ts +304 -0
  78. package/app/api/gateway/provider/route.ts +209 -0
  79. package/app/api/gateway/route.ts +223 -0
  80. package/app/api/gateway/sync.ts +189 -0
  81. package/app/api/lineage/route.ts +54 -0
  82. package/app/api/memory-context/route.ts +15 -0
  83. package/app/api/metrics/route.ts +35 -0
  84. package/app/api/models/route.ts +77 -0
  85. package/app/api/plugins/route.js +37 -0
  86. package/app/api/provider/upstream.ts +142 -0
  87. package/app/api/provider/v1/chat/completions/route.ts +146 -0
  88. package/app/api/provider/v1/models/route.ts +167 -0
  89. package/app/api/provider-usage/route.ts +629 -0
  90. package/app/api/session/route.ts +39 -0
  91. package/app/api/sessions/[id]/route.ts +38 -0
  92. package/app/api/sessions/route.ts +23 -0
  93. package/app/api/setup/agent-image/route.ts +102 -0
  94. package/app/api/setup/password/route.ts +111 -0
  95. package/app/api/setup/restart/route.ts +76 -0
  96. package/app/api/skills/delete/route.js +105 -0
  97. package/app/api/skills/promote/route.js +129 -0
  98. package/app/api/skills/route.js +203 -0
  99. package/app/api/skills/save/route.js +142 -0
  100. package/app/api/stats/route.ts +34 -0
  101. package/app/api/stats-since/route.ts +20 -0
  102. package/app/api/stream/route.ts +70 -0
  103. package/app/api/system-health/route.ts +233 -0
  104. package/app/api/tool-calls/route.ts +24 -0
  105. package/app/api/tools-config/route.ts +163 -0
  106. package/app/api/update-check/route.ts +127 -0
  107. package/app/api/version/route.ts +25 -0
  108. package/app/api/wizard/complete/route.ts +32 -0
  109. package/app/api/wizard/reset/route.ts +28 -0
  110. package/app/api/wizard/status/route.ts +28 -0
  111. package/app/api/workspace/route.ts +392 -0
  112. package/app/api/workspace/stream/route.ts +136 -0
  113. package/app/components/AppShell.tsx +33 -0
  114. package/app/components/AuthGuard.tsx +91 -0
  115. package/app/components/CostBreakdown.tsx +37 -0
  116. package/app/components/DashboardHeader.tsx +73 -0
  117. package/app/components/DashboardLayout.tsx +76 -0
  118. package/app/components/DashboardToolbar.tsx +61 -0
  119. package/app/components/FloatingActions.tsx +33 -0
  120. package/app/components/Icons.tsx +78 -0
  121. package/app/components/LineageGraphPage.tsx +142 -0
  122. package/app/components/LiveFeed.tsx +48 -0
  123. package/app/components/MobileBottomNav.tsx +84 -0
  124. package/app/components/ModelPickerModal.tsx +94 -0
  125. package/app/components/PasswordInput.tsx +86 -0
  126. package/app/components/PulseChat.tsx +362 -0
  127. package/app/components/Rev4aLoader.tsx +48 -0
  128. package/app/components/SessionDrawer.tsx +263 -0
  129. package/app/components/SessionTopology.tsx +289 -0
  130. package/app/components/Sidebar.tsx +294 -0
  131. package/app/components/Skeleton.tsx +133 -0
  132. package/app/components/SystemCockpit.tsx +169 -0
  133. package/app/components/VersionBanner.tsx +105 -0
  134. package/app/components/WizardButton.tsx +30 -0
  135. package/app/components/ui/Badge.tsx +30 -0
  136. package/app/components/ui/Button.tsx +59 -0
  137. package/app/components/ui/ConfirmModal.tsx +46 -0
  138. package/app/components/ui/FilterBar.tsx +33 -0
  139. package/app/components/ui/Input.tsx +25 -0
  140. package/app/components/ui/ItemList.tsx +83 -0
  141. package/app/components/ui/LoadingSpinner.tsx +30 -0
  142. package/app/components/ui/Metric.tsx +22 -0
  143. package/app/components/ui/Modal.tsx +42 -0
  144. package/app/components/ui/Page.tsx +18 -0
  145. package/app/components/ui/Pill.tsx +6 -0
  146. package/app/components/ui/PropertyList.tsx +24 -0
  147. package/app/components/ui/Select.tsx +26 -0
  148. package/app/components/ui/StatusCard.tsx +32 -0
  149. package/app/components/ui/Surface.tsx +14 -0
  150. package/app/components/ui/Tabs.tsx +55 -0
  151. package/app/components/ui/TemplateOption.tsx +59 -0
  152. package/app/components/ui/Toast.tsx +44 -0
  153. package/app/components/ui/index.ts +19 -0
  154. package/app/components/ui/tokens.ts +18 -0
  155. package/app/config/PageClient.tsx +293 -0
  156. package/app/config/loading.tsx +10 -0
  157. package/app/config/page.tsx +7 -0
  158. package/app/containers/ContainersClient.tsx +129 -0
  159. package/app/containers/loading.tsx +21 -0
  160. package/app/containers/page.tsx +5 -0
  161. package/app/containers/terminal/[id]/TerminalClient.tsx +313 -0
  162. package/app/containers/terminal/[id]/page.tsx +6 -0
  163. package/app/credentials/PageClient.tsx +598 -0
  164. package/app/credentials/loading.tsx +10 -0
  165. package/app/credentials/page.tsx +7 -0
  166. package/app/crons/PageClient.tsx +538 -0
  167. package/app/crons/loading.tsx +10 -0
  168. package/app/crons/page.tsx +5 -0
  169. package/app/design-system.ts +57 -0
  170. package/app/gateway/PageClient.tsx +1048 -0
  171. package/app/gateway/loading.tsx +24 -0
  172. package/app/gateway/page.tsx +5 -0
  173. package/app/globals.css +1474 -0
  174. package/app/layout.tsx +45 -0
  175. package/app/lib/models-context.tsx +41 -0
  176. package/app/lineage/loading.tsx +10 -0
  177. package/app/lineage/page.tsx +13 -0
  178. package/app/loading.tsx +16 -0
  179. package/app/login/page.tsx +160 -0
  180. package/app/memory/MemoryContextPageClient.tsx +196 -0
  181. package/app/memory/loading.tsx +10 -0
  182. package/app/memory/page.tsx +8 -0
  183. package/app/page.tsx +31 -0
  184. package/app/plugins/PageClient.tsx +296 -0
  185. package/app/plugins/loading.tsx +10 -0
  186. package/app/plugins/page.tsx +5 -0
  187. package/app/setup/PageClient.tsx +227 -0
  188. package/app/setup/loading.tsx +21 -0
  189. package/app/setup/page.tsx +7 -0
  190. package/app/skills/PageClient.tsx +499 -0
  191. package/app/skills/loading.tsx +10 -0
  192. package/app/skills/page.tsx +5 -0
  193. package/app/tools/ToolsPageClient.tsx +308 -0
  194. package/app/tools/loading.tsx +10 -0
  195. package/app/tools/page.tsx +62 -0
  196. package/app/tools/tools-catalog.ts +141 -0
  197. package/app/wizard/PageClient.tsx +485 -0
  198. package/app/wizard/icons.tsx +89 -0
  199. package/app/wizard/loading.tsx +24 -0
  200. package/app/wizard/page.tsx +7 -0
  201. package/app/wizard/storage.ts +33 -0
  202. package/app/wizard/useWizard.ts +101 -0
  203. package/app/workspace/WorkspaceClient.tsx +633 -0
  204. package/app/workspace/loading.tsx +36 -0
  205. package/app/workspace/page.tsx +8 -0
  206. package/bin/docker-entrypoint.sh +21 -0
  207. package/bin/postinstall.js +20 -0
  208. package/bin/rev4a.js +696 -0
  209. package/daemon.js +783 -0
  210. package/docs/ARCHITECTURE.md +557 -0
  211. package/docs/CONTAINER-TERMINAL.md +280 -0
  212. package/docs/DESIGN-SYSTEM.md +99 -0
  213. package/docs/FRONTEND-ARCHITECTURE.md +119 -0
  214. package/docs/REV4A.md +504 -0
  215. package/docs/dev/API-REFERENCE.md +1835 -0
  216. package/docs/dev/DATABASE.md +224 -0
  217. package/docs/dev/GATEWAY.md +300 -0
  218. package/docs/dev/PROVIDERS.md +229 -0
  219. package/docs/dev/SESSION-MAINTENANCE-PLAN.md +607 -0
  220. package/docs/dev/WORKSPACE.md +199 -0
  221. package/docs/rag/DATA-FRESHNESS.md +109 -0
  222. package/docs/rag/GLOSSARY.md +125 -0
  223. package/docs/rag/REV4A-OVERVIEW.md +135 -0
  224. package/docs/rag/WHAT-I-CAN-ANSWER.md +124 -0
  225. package/lib/agent-setup.ts +130 -0
  226. package/lib/alerts.ts +115 -0
  227. package/lib/apiFetch.ts +7 -0
  228. package/lib/auth.ts +28 -0
  229. package/lib/billing.ts +100 -0
  230. package/lib/buildAgentImage.ts +346 -0
  231. package/lib/channelManager.ts +386 -0
  232. package/lib/container.ts +60 -0
  233. package/lib/credentials/db.ts +86 -0
  234. package/lib/credentials/delivery.ts +448 -0
  235. package/lib/credentials/detect.ts +149 -0
  236. package/lib/credentials/hash.ts +9 -0
  237. package/lib/credentials/providers.ts +110 -0
  238. package/lib/credentials/vault.ts +195 -0
  239. package/lib/db-bootstrap.d.ts +3 -0
  240. package/lib/db-bootstrap.mjs +144 -0
  241. package/lib/db.ts +25 -0
  242. package/lib/docker-utils.ts +60 -0
  243. package/lib/hooks/useDashboard.ts +264 -0
  244. package/lib/hooks/useRev4aTimezone.ts +28 -0
  245. package/lib/hooks/useScreenshot.ts +30 -0
  246. package/lib/memory-context.ts +385 -0
  247. package/lib/model-catalogue.ts +131 -0
  248. package/lib/model-pricing.ts +63 -0
  249. package/lib/openclaw-cron.ts +350 -0
  250. package/lib/patterns/ApiAdapter.ts +73 -0
  251. package/lib/patterns/ApiClient.ts +65 -0
  252. package/lib/patterns/EventBus.ts +113 -0
  253. package/lib/patterns/FilterStrategy.ts +79 -0
  254. package/lib/patterns/SessionFactory.ts +117 -0
  255. package/lib/patterns/sessionPresentation.ts +117 -0
  256. package/lib/provider-balance.ts +163 -0
  257. package/lib/requireAuth.tsx +38 -0
  258. package/lib/rev4a-auth.d.ts +3 -0
  259. package/lib/rev4a-auth.js +36 -0
  260. package/lib/rev4a-paths.ts +145 -0
  261. package/lib/timezone.ts +46 -0
  262. package/lib/types/index.ts +96 -0
  263. package/lib/utils/format.ts +82 -0
  264. package/lineage.js +56 -0
  265. package/model-pricing.json +482 -0
  266. package/models.config.json +844 -0
  267. package/next-env.d.ts +6 -0
  268. package/next.config.mjs +7 -0
  269. package/package.json +82 -0
  270. package/public/apple-touch-icon.png +0 -0
  271. package/public/favicon-64.png +0 -0
  272. package/public/favicon.svg +58 -0
  273. package/public/icon-192-maskable.png +0 -0
  274. package/public/icon-192.png +0 -0
  275. package/public/icon-512-maskable.png +0 -0
  276. package/public/icon-512.png +0 -0
  277. package/public/manifest.json +38 -0
  278. package/public/rev4a-logo.png +0 -0
  279. package/public/rev4a-logo.svg +58 -0
  280. package/rev4a-rules/AGENTS.md +37 -0
  281. package/scripts/add-auth.cjs +185 -0
  282. package/scripts/backup.sh +66 -0
  283. package/scripts/check-providers.mjs +143 -0
  284. package/scripts/docker/traefik/docker-compose.yml +32 -0
  285. package/scripts/docker/traefik/dynamic/.gitkeep +18 -0
  286. package/scripts/docker/traefik/traefik.yml +37 -0
  287. package/scripts/remove-auth-profile.js +56 -0
  288. package/scripts/restore.sh +82 -0
  289. package/terminal-ws-server.js +139 -0
  290. package/tsconfig.json +42 -0
@@ -0,0 +1,1474 @@
1
+ *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
2
+
3
+ :root {
4
+ /* Design tokens (semantic) */
5
+ --font-mono-stack: var(--font-mono, "JetBrains Mono"), monospace;
6
+ --font-serif-stack: var(--font-serif, "Instrument Serif"), serif;
7
+
8
+ /* Breakpoint tokens (Bootstrap v5) */
9
+ --bp-sm: 576px;
10
+ --bp-md: 768px;
11
+ --bp-lg: 992px;
12
+ --bp-xl: 1200px;
13
+ --bp-xxl: 1400px;
14
+
15
+ --color-bg-950: #0A0A0B;
16
+ --color-bg-900: #111114;
17
+ --color-bg-800: #18181c;
18
+ --color-border-700: #222228;
19
+ --color-text-100: #E8E8E8;
20
+ --color-text-400: #888;
21
+ --color-text-500: #4b5563;
22
+ --color-accent-500: #925BFC;
23
+ --color-accent-700: #6d4fa0;
24
+ --color-success-500: #22c55e;
25
+ --color-danger-500: #ef4444;
26
+ --color-warning-500: #f59e0b;
27
+ --color-info-500: #818cf8;
28
+ --color-blue-400: #60a5fa;
29
+
30
+ --space-1: 4px;
31
+ --space-2: 8px;
32
+ --space-3: 12px;
33
+ --space-4: 16px;
34
+ --space-5: 20px;
35
+ --space-6: 24px;
36
+
37
+ --radius-xs: 0;
38
+ --radius-sm: 0;
39
+ --radius-md: 0;
40
+
41
+ /* Backward-compatible aliases */
42
+ --bg: var(--color-bg-950);
43
+ --bg2: var(--color-bg-900);
44
+ --bg3: var(--color-bg-800);
45
+ --violet: var(--color-accent-500);
46
+ --violet-dim: var(--color-accent-700);
47
+ --violet-bg: rgba(146, 91, 252, 0.08);
48
+ --text: var(--color-text-100);
49
+ --text-dim: var(--color-text-400);
50
+ --green: var(--color-success-500);
51
+ --red: var(--color-danger-500);
52
+ --yellow: var(--color-warning-500);
53
+ --info: var(--color-info-500);
54
+ --blue: var(--color-blue-400);
55
+ --gray: var(--color-text-500);
56
+ --border: var(--color-border-700);
57
+ }
58
+
59
+ html, body { height: 100%; height: 100dvh; background: var(--bg); color: var(--text); font-family: var(--font-mono-stack); overflow: hidden; }
60
+
61
+ .agent-btn {
62
+ font-family: 'JetBrains Mono', monospace;
63
+ font-size: 10px;
64
+ padding: 3px 10px;
65
+ border: 1px solid var(--border);
66
+ background: var(--bg3);
67
+ color: var(--text-dim);
68
+ border-radius: 0;
69
+ cursor: pointer;
70
+ transition: all 0.15s;
71
+ white-space: nowrap;
72
+ }
73
+ .agent-btn:hover { border-color: var(--violet-dim); color: var(--text); }
74
+ .agent-btn.active { border-color: var(--violet); color: var(--violet); background: #1a1030; }
75
+
76
+ .node circle { stroke-width: 2; transition: r 0.3s; }
77
+ .node.active circle { stroke: var(--green); fill: #0d2818; }
78
+ .node.idle circle { stroke: var(--gray); fill: #111; }
79
+ .node.completed circle { stroke: #4b5563; fill: #0a0a0b; }
80
+ .node.grace { opacity: 0.35; transition: opacity 1s ease-out; }
81
+ .node.error circle { stroke: var(--red); fill: #1a0a0a; }
82
+ .node.working circle { stroke: var(--green); fill: #0d2818; }
83
+ .node.virtual circle { stroke: var(--violet); fill: #120d06; stroke-dasharray: 4,3; }
84
+
85
+ .node text { font-family: 'JetBrains Mono', monospace; fill: var(--text); font-size: 10px; }
86
+
87
+ .link { fill: none; stroke: var(--border); stroke-width: 1.5; }
88
+ .link.virtual-link { stroke: var(--violet-dim); stroke-dasharray: 4,3; stroke-opacity: 0.5; }
89
+
90
+ @keyframes glow {
91
+ 0%, 100% { filter: drop-shadow(0 0 4px #22c55e88); }
92
+ 50% { filter: drop-shadow(0 0 12px #22c55ecc); }
93
+ }
94
+ .node.active, .node.working { animation: glow 2s ease-in-out infinite; }
95
+
96
+ /* ── APP SHELL ─────────────────────────────────────────────────── */
97
+ .app-shell {
98
+ display: flex;
99
+ flex-direction: column;
100
+ height: 100vh;
101
+ height: 100dvh;
102
+ max-height: 100dvh;
103
+ overflow: hidden;
104
+ }
105
+
106
+ .app-shell__body {
107
+ flex: 1;
108
+ min-height: 0;
109
+ display: flex;
110
+ }
111
+ .app-shell__content {
112
+ flex: 1;
113
+ min-width: 0;
114
+ min-height: 0;
115
+ overflow: hidden;
116
+ display: flex;
117
+ flex-direction: column;
118
+ }
119
+
120
+ /* ── SIDEBAR ────────────────────────────────────────────────────── */
121
+ .sidebar {
122
+ width: 200px;
123
+ flex-shrink: 0;
124
+ background: var(--color-bg-900);
125
+ border-right: 1px solid var(--color-border-700);
126
+ display: flex;
127
+ flex-direction: column;
128
+ overflow: hidden;
129
+ }
130
+
131
+ .sidebar__logo {
132
+ display: flex;
133
+ align-items: center;
134
+ gap: 10px;
135
+ padding: 14px 16px;
136
+ border-bottom: 1px solid var(--color-border-700);
137
+ height: 48px;
138
+ flex-shrink: 0;
139
+ }
140
+
141
+ .sidebar__eye { flex-shrink: 0; }
142
+
143
+ .sidebar__title {
144
+ font-family: var(--font-serif-stack);
145
+ font-size: 16px;
146
+ letter-spacing: 3px;
147
+ color: var(--color-accent-500);
148
+ }
149
+
150
+ .sidebar__nav {
151
+ display: flex;
152
+ flex-direction: column;
153
+ padding: 0;
154
+ gap: 0;
155
+ }
156
+
157
+ .sidebar__item {
158
+ display: flex;
159
+ align-items: center;
160
+ gap: 10px;
161
+ padding: 8px 16px;
162
+ font-size: 11px;
163
+ letter-spacing: 0.06em;
164
+ color: var(--color-text-400);
165
+ text-decoration: none;
166
+ border-radius: 0;
167
+ transition: color 0.12s, background 0.12s;
168
+ border-left: 2px solid transparent;
169
+ }
170
+
171
+ .sidebar__item:hover {
172
+ color: var(--color-text-100);
173
+ background: var(--color-bg-800);
174
+ }
175
+
176
+ .sidebar__item--active {
177
+ color: var(--color-accent-500);
178
+ background: var(--violet-bg);
179
+ border-left-color: var(--color-accent-500);
180
+ }
181
+
182
+ .sidebar__bottom {
183
+ margin-top: auto;
184
+ display: flex;
185
+ flex-direction: column;
186
+ }
187
+
188
+ .sidebar__item--logout {
189
+ width: 100%;
190
+ text-align: left;
191
+ background: none;
192
+ border: none;
193
+ cursor: pointer;
194
+ padding: 12px 16px;
195
+ color: var(--text-dim);
196
+ }
197
+ .sidebar__item--logout:hover {
198
+ color: var(--color-text-100);
199
+ background: var(--color-bg-800);
200
+ }
201
+
202
+ .sidebar__footer {
203
+ padding: 12px 16px;
204
+ font-size: 10px;
205
+ color: var(--text-dim);
206
+ border-top: 1px solid var(--border);
207
+ font-family: var(--font-mono);
208
+ opacity: 0.6;
209
+ line-height: 1.4;
210
+ }
211
+
212
+ .sidebar__icon {
213
+ display: flex;
214
+ align-items: center;
215
+ flex-shrink: 0;
216
+ }
217
+
218
+ /* ── MOBILE TOP BAR ─────────────────────────────────────────────── */
219
+ .mobile-topbar {
220
+ display: none;
221
+ position: fixed;
222
+ top: 0;
223
+ left: 0;
224
+ right: 0;
225
+ z-index: 190;
226
+ background: var(--color-bg-900);
227
+ border-bottom: 1px solid var(--color-border-700);
228
+ flex-direction: column;
229
+ padding-top: env(safe-area-inset-top, 0px);
230
+ }
231
+
232
+ .mobile-topbar--open {
233
+ max-height: calc(100dvh - 54px - env(safe-area-inset-bottom, 0px));
234
+ overflow-y: auto;
235
+ box-shadow: 0 12px 32px rgba(0,0,0,0.4);
236
+ border-bottom: 1px solid var(--color-border-700);
237
+ }
238
+
239
+ .mobile-topbar__row {
240
+ display: flex;
241
+ align-items: center;
242
+ justify-content: space-between;
243
+ height: 48px;
244
+ padding-left: 0;
245
+ padding-right: 0;
246
+ flex-shrink: 0;
247
+ }
248
+
249
+ .mobile-topbar__brand {
250
+ display: flex;
251
+ align-items: center;
252
+ gap: 6px;
253
+ flex-shrink: 0;
254
+ padding: 0 12px;
255
+ }
256
+
257
+ .mobile-topbar__brand img {
258
+ width: 20px;
259
+ height: 20px;
260
+ display: block;
261
+ object-fit: contain;
262
+ }
263
+
264
+ .mobile-topbar__brand span {
265
+ font-family: var(--font-serif-stack);
266
+ font-size: 15px;
267
+ letter-spacing: 3px;
268
+ color: var(--color-accent-500);
269
+ }
270
+
271
+ .mobile-topbar__menu {
272
+ display: flex;
273
+ align-items: center;
274
+ justify-content: center;
275
+ background: none;
276
+ border: none;
277
+ color: var(--color-text-100);
278
+ cursor: pointer;
279
+ padding: 12px;
280
+ line-height: 0;
281
+ }
282
+
283
+ /* ── MOBILE DRAWER ──────────────────────────────────────────────── */
284
+ .mobile-drawer__wrapper {
285
+ max-height: 0;
286
+ overflow: hidden;
287
+ transition: max-height 0.2s ease;
288
+ }
289
+
290
+ .mobile-topbar--open .mobile-drawer__wrapper {
291
+ max-height: 1000px; /* large enough to fit all items */
292
+ }
293
+
294
+ .mobile-drawer {
295
+ background: var(--color-bg-900);
296
+ padding: 4px 0;
297
+ }
298
+
299
+ .mobile-drawer__backdrop {
300
+ position: fixed;
301
+ inset: 0;
302
+ top: calc(48px + env(safe-area-inset-top, 0px));
303
+ background: rgba(0,0,0,0.55);
304
+ z-index: 189;
305
+ }
306
+
307
+ /* ── RESPONSIVE ─────────────────────────────────────────────────── */
308
+ @media (max-width: 767px) {
309
+ html, body { height: 100svh; }
310
+ .app-shell { height: 100svh; max-height: 100svh; }
311
+ .sidebar--desktop { display: none !important; }
312
+ .mobile-topbar { display: flex; }
313
+ .app-shell__body {
314
+ width: 100%;
315
+ flex-direction: column;
316
+ }
317
+ .app-shell__content {
318
+ width: 100%;
319
+ padding-top: 48px;
320
+ padding-bottom: calc(72px + env(safe-area-inset-bottom, 0px));
321
+ }
322
+ }
323
+
324
+ /* ── DASHBOARD CLIENT CLASSES ──────────────────────────────────── */
325
+ .shell {
326
+ display: flex;
327
+ flex-direction: column;
328
+ height: 100%;
329
+ overflow: hidden;
330
+ background: var(--bg);
331
+ font-family: var(--font-mono-stack);
332
+ }
333
+
334
+ .header {
335
+ display: flex;
336
+ align-items: center;
337
+ justify-content: space-between;
338
+ padding: 10px 20px;
339
+ border-bottom: 1px solid var(--border);
340
+ background: var(--bg2);
341
+ height: 48px;
342
+ flex-shrink: 0;
343
+ }
344
+
345
+ .logo {
346
+ display: flex;
347
+ align-items: center;
348
+ gap: 10px;
349
+ }
350
+
351
+ .logo img {
352
+ width: 22px;
353
+ height: 22px;
354
+ flex-shrink: 0;
355
+ }
356
+
357
+ .logo span {
358
+ font-family: var(--font-serif-stack);
359
+ font-size: 20px;
360
+ letter-spacing: 4px;
361
+ color: var(--violet);
362
+ }
363
+
364
+ .meta {
365
+ display: flex;
366
+ gap: 24px;
367
+ font-size: 11px;
368
+ color: var(--text-dim);
369
+ }
370
+
371
+ .meta > div {
372
+ display: flex;
373
+ flex-direction: column;
374
+ gap: 2px;
375
+ }
376
+
377
+ .meta-label {
378
+ font-size: 9px;
379
+ letter-spacing: 2px;
380
+ text-transform: uppercase;
381
+ color: var(--text-dim);
382
+ }
383
+
384
+ .meta-value {
385
+ font-size: 12px;
386
+ color: var(--text);
387
+ font-weight: 500;
388
+ }
389
+
390
+ .meta-value.cost {
391
+ color: var(--violet);
392
+ font-weight: 700;
393
+ }
394
+
395
+ .toolbar {
396
+ display: flex;
397
+ align-items: center;
398
+ gap: 8px;
399
+ padding: 6px 16px;
400
+ border-bottom: 1px solid var(--border);
401
+ background: var(--bg2);
402
+ overflow-x: auto;
403
+ flex-shrink: 0;
404
+ }
405
+
406
+ .toolbar::-webkit-scrollbar { height: 3px; }
407
+ .toolbar::-webkit-scrollbar-thumb { background: var(--violet-dim); border-radius: 0; }
408
+
409
+ .toolbar-label {
410
+ font-size: 9px;
411
+ letter-spacing: 2px;
412
+ color: var(--text-dim);
413
+ text-transform: uppercase;
414
+ white-space: nowrap;
415
+ margin-right: 4px;
416
+ }
417
+
418
+ .layout {
419
+ display: grid;
420
+ grid-template-columns: 1fr 360px;
421
+ flex: 1;
422
+ min-height: 0;
423
+ overflow: hidden;
424
+ }
425
+
426
+ .layout--cockpit {
427
+ display: block;
428
+ overflow: hidden;
429
+ }
430
+
431
+ .panel {
432
+ display: flex;
433
+ flex-direction: column;
434
+ overflow: hidden;
435
+ }
436
+
437
+ .panel h2 {
438
+ padding: 8px 16px;
439
+ font-size: 10px;
440
+ letter-spacing: 2px;
441
+ color: var(--violet);
442
+ border-bottom: 1px solid var(--border);
443
+ background: var(--bg2);
444
+ text-transform: uppercase;
445
+ flex-shrink: 0;
446
+ font-weight: normal;
447
+ }
448
+
449
+ .graph-panel {
450
+ border-right: 1px solid var(--border);
451
+ background: var(--bg);
452
+ }
453
+
454
+ .graph-shell {
455
+ flex: 1;
456
+ min-height: 0;
457
+ position: relative;
458
+ overflow: hidden;
459
+ display: flex;
460
+ flex-direction: column;
461
+ }
462
+
463
+ .graph-shell svg {
464
+ flex: 1;
465
+ width: 100%;
466
+ height: 100%;
467
+ display: block;
468
+ cursor: grab;
469
+ }
470
+
471
+ .graph-shell svg:active {
472
+ cursor: grabbing;
473
+ }
474
+
475
+ .empty-state {
476
+ flex: 1;
477
+ display: flex;
478
+ flex-direction: column;
479
+ align-items: center;
480
+ justify-content: center;
481
+ gap: 10px;
482
+ user-select: none;
483
+ }
484
+
485
+ .empty-state-icon {
486
+ font-size: 32px;
487
+ color: var(--violet, #925BFC);
488
+ opacity: 0.25;
489
+ line-height: 1;
490
+ letter-spacing: -1px;
491
+ }
492
+
493
+ .empty-state-msg {
494
+ color: var(--text-dim, #89a1ad);
495
+ font-size: 12px;
496
+ letter-spacing: 0.06em;
497
+ text-transform: uppercase;
498
+ opacity: 0.6;
499
+ }
500
+
501
+ .graph-tooltip {
502
+ display: none;
503
+ position: fixed;
504
+ z-index: 9999;
505
+ background: var(--surface, #16181c);
506
+ border: 1px solid var(--border, #2a2f3a);
507
+ border-radius: 0;
508
+ padding: 8px 12px;
509
+ font-size: 12px;
510
+ color: var(--text, #d6e2e8);
511
+ line-height: 1.6;
512
+ pointer-events: none;
513
+ max-width: 260px;
514
+ box-shadow: 0 4px 16px rgba(0,0,0,0.4);
515
+ white-space: nowrap;
516
+ }
517
+
518
+ .side {
519
+ display: flex;
520
+ flex-direction: column;
521
+ overflow: hidden;
522
+ background: var(--bg);
523
+ }
524
+
525
+ .feed-panel {
526
+ flex: 1.5;
527
+ min-height: 0;
528
+ overflow: hidden;
529
+ display: flex;
530
+ flex-direction: column;
531
+ }
532
+
533
+ .feed-panel > div {
534
+ flex: 1;
535
+ overflow-y: auto;
536
+ padding: 8px 0;
537
+ min-height: 0;
538
+ }
539
+
540
+ .feed-panel > div::-webkit-scrollbar { width: 4px; }
541
+ .feed-panel > div::-webkit-scrollbar-track { background: var(--bg2); }
542
+ .feed-panel > div::-webkit-scrollbar-thumb { background: var(--violet-dim); border-radius: 0; }
543
+
544
+ .feed-time { color: var(--text-dim); font-size: 10px; flex-shrink: 0; width: 52px; margin-right: 4px; }
545
+ .feed-type { color: var(--violet); font-weight: 700; font-size: 10px; flex-shrink: 0; margin-right: 6px; text-transform: uppercase; min-width: 40px; }
546
+ .feed-label { color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 10px; }
547
+
548
+ .feed-item {
549
+ display: flex;
550
+ align-items: baseline;
551
+ gap: 6px;
552
+ padding: 4px 16px;
553
+ font-size: 10px;
554
+ line-height: 1.5;
555
+ border-bottom: 1px solid var(--color-border-700);
556
+ }
557
+
558
+ .cost-panel {
559
+ border-top: 1px solid var(--border);
560
+ background: var(--bg2);
561
+ overflow: hidden;
562
+ display: flex;
563
+ flex-direction: column;
564
+ }
565
+
566
+ .cost-panel > div {
567
+ padding: 8px 16px;
568
+ overflow-y: auto;
569
+ flex: 1;
570
+ }
571
+
572
+ .cost-row { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; padding: 4px 16px; font-size: 10px; border-bottom: 1px solid var(--color-border-700); }
573
+ .cost-row:last-child { border-bottom: none; }
574
+
575
+ .cost-row .k { color: var(--text-dim); font-size: 10px; }
576
+ .cost-row .v { color: var(--violet); font-weight: 700; }
577
+
578
+ @media (max-width: 991px) { .screenshot-btn-desktop { display: none; } }
579
+
580
+ /* Skeleton loaders */
581
+ .skeleton {
582
+ display: inline-block;
583
+ position: relative;
584
+ overflow: hidden;
585
+ background: linear-gradient(90deg, rgba(255,255,255,0.045), rgba(255,255,255,0.09), rgba(255,255,255,0.045));
586
+ background-size: 220% 100%;
587
+ animation: skeleton-shimmer 1.35s ease-in-out infinite;
588
+ border-radius: 0;
589
+ color: transparent !important;
590
+ will-change: background-position;
591
+ }
592
+ .skeleton--text { height: 1em; min-width: 72px; vertical-align: -0.12em; }
593
+ .skeleton--metric { height: 30px; width: 92px; }
594
+ .skeleton--pill { height: 18px; width: 72px; border-radius: 999px; }
595
+ .skeleton--line { height: 10px; width: 100%; }
596
+ .skeleton--card { min-height: 110px; border: 1px solid var(--border); background: var(--bg2); border-radius: 0; padding: 16px; }
597
+ @keyframes skeleton-shimmer { 0% { background-position: 220% 0; } 100% { background-position: -220% 0; } }
598
+ @keyframes progress-indeterminate { 0% { width: 0%; margin-left: 0; } 50% { width: 40%; margin-left: 30%; } 100% { width: 0%; margin-left: 100%; } }
599
+
600
+ /* Rev4a UI system primitives */
601
+ .ui-page { min-height: 100%; background: var(--bg); color: var(--text); padding: 24px 20px 40px; overflow: auto; }
602
+ .ui-page__inner { margin: 0 auto; display: flex; flex-direction: column; gap: 18px; }
603
+ .ui-page-header { display: flex; justify-content: space-between; gap: 12px; align-items: flex-start; flex-wrap: wrap; }
604
+ .ui-eyebrow, .ui-kicker { font-size: 10px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--text-dim); }
605
+ .ui-eyebrow { color: var(--violet); font-size: 12px; margin-bottom: 6px; }
606
+ .ui-kicker--accent { color: var(--violet); }
607
+ .ui-page-title { margin: 0; font-family: var(--font-serif-stack); font-size: 34px; font-weight: 400; }
608
+ .ui-page-description { margin: 10px 0 0; color: var(--text-dim); max-width: 760px; line-height: 1.5; font-size: 13px; }
609
+ .ui-surface { border: 1px solid var(--border); background: var(--bg2); border-radius: 0; padding: 16px; min-height: 110px; }
610
+ .ui-surface--panel { border-radius: 0; min-height: 0; padding: 0; overflow: hidden; }
611
+ .ui-surface--subtle { background: rgba(255,255,255,0.015); }
612
+ .ui-tone--accent { border-color: var(--violet-dim); }
613
+ .ui-tone--success { border-color: #255b3f; }
614
+ .ui-tone--warning { border-color: #7c5a1a; }
615
+ .ui-tone--danger { border-color: #7f1d1d; }
616
+ .ui-muted { color: var(--text-dim); }
617
+ .ui-metric-value { margin-top: 14px; font-size: 26px; font-weight: 800; color: var(--text); }
618
+ .ui-tone--danger .ui-metric-value { color: var(--red); }
619
+ .ui-metric-subtitle { margin-top: 8px; font-size: 11px; }
620
+ .ui-card-head { display: flex; justify-content: space-between; gap: 10px; margin-bottom: 12px; }
621
+ .ui-health { font-size: 10px; text-transform: uppercase; font-weight: 700; }
622
+ .ui-health--ok { color: var(--green); }
623
+ .ui-health--warning { color: #f59e0b; }
624
+ .ui-health--error { color: var(--red); }
625
+ .ui-key-values { display: grid; gap: 8px; }
626
+ .ui-key-value { display: flex; justify-content: space-between; gap: 12px; font-size: 11px; }
627
+ .ui-key-value > span:last-child { color: var(--text); text-align: right; }
628
+ .ui-pill { border: 1px solid var(--border); color: var(--text); background: rgba(255,255,255,0.02); border-radius: 999px; padding: 2px 8px; font-size: 10px; letter-spacing: 0.04em; }
629
+ .ui-pill.ui-tone--success { border-color: #255b3f; color: #5ee9a0; background: rgba(34,197,94,0.08); }
630
+ .ui-pill.ui-tone--warning { border-color: #7c5a1a; color: #f6c66b; background: rgba(245,158,11,0.08); }
631
+ .ui-pill.ui-tone--danger { border-color: #7f1d1d; color: #fca5a5; background: rgba(239,68,68,0.08); }
632
+ .ui-pill.ui-tone--accent { border-color: var(--violet-dim); color: var(--violet); background: rgba(146,91,252,0.08); }
633
+ .ui-pill.ui-tone--info { border-color: rgba(99,102,241,0.28); color: #818cf8; background: rgba(99,102,241,0.12); }
634
+ .ui-tone--info { border-color: rgba(99,102,241,0.28); }
635
+
636
+ .cockpit { overflow: auto; height: 100%; padding: 20px; }
637
+ .cockpit__metrics { display: grid; grid-template-columns: minmax(260px, 1.2fr) repeat(3, minmax(160px, 1fr)); gap: 12px; margin-bottom: 16px; }
638
+ .cockpit__health-row { margin-top: 12px; display: flex; align-items: baseline; gap: 12px; }
639
+ .cockpit__health { font-size: 34px; text-transform: uppercase; font-weight: 800; }
640
+ .cockpit__health--ok { color: var(--green); }
641
+ .cockpit__health--warning { color: #f59e0b; }
642
+ .cockpit__health--error { color: var(--red); }
643
+ .cockpit__main { display: grid; grid-template-columns: 1.15fr 0.85fr; gap: 16px; }
644
+ .cockpit__checks { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
645
+ .cockpit__recommendations { display: flex; flex-direction: column; gap: 10px; list-style: none; }
646
+ .cockpit__recommendation { padding-left: 10px; color: var(--text); font-size: 12px; line-height: 1.5; border-left: 2px solid var(--border); }
647
+ .cockpit__recommendation--warning { border-left-color: #f59e0b; }
648
+ .cockpit__recommendation--error { border-left-color: var(--red); }
649
+ .cockpit__recommendation--info, .cockpit__recommendation--ok { border-left-color: var(--green); }
650
+ .cockpit__recommendation-head { display: flex; justify-content: space-between; gap: 8px; }
651
+ .cockpit__recommendation-head span { color: var(--text-dim); font-size: 10px; text-transform: uppercase; }
652
+ .cockpit__quick-links { margin-top: 18px; padding-top: 14px; border-top: 1px solid var(--border); display: flex; gap: 8px; flex-wrap: wrap; }
653
+
654
+ .cockpit__feed-section { margin-top: 16px; display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
655
+ @media (max-width: 900px) { .cockpit__feed-section { grid-template-columns: 1fr; } }
656
+ .ui-link { color: var(--violet); text-decoration: none; }
657
+ .ui-link:hover { text-decoration: underline; }
658
+ @media (max-width: 991px) {
659
+ .cockpit__metrics, .cockpit__main, .cockpit__checks { grid-template-columns: 1fr; }
660
+ }
661
+
662
+ /* ── Floating actions container (Wizard + Pulse) ──────────────── */
663
+ .floating-actions {
664
+ position: fixed;
665
+ bottom: 24px;
666
+ left: 24px;
667
+ right: 24px;
668
+ z-index: 9000;
669
+ display: flex;
670
+ justify-content: space-between;
671
+ align-items: flex-end;
672
+ pointer-events: none;
673
+ }
674
+
675
+ /* Desktop: pulse always on the right */
676
+ @media (min-width: 768px) {
677
+ .floating-actions {
678
+ left: 224px;
679
+ justify-content: flex-end;
680
+ gap: 0;
681
+ }
682
+ }
683
+
684
+ .floating-actions__left {
685
+ pointer-events: auto;
686
+ display: flex;
687
+ }
688
+
689
+ .floating-actions__right {
690
+ pointer-events: auto;
691
+ display: flex;
692
+ }
693
+
694
+ /* Wizard visible only on mobile (sidebar handles it on desktop) */
695
+ @media (min-width: 768px) {
696
+ .floating-actions__left { display: none; }
697
+ }
698
+
699
+ /* Hide sidebar wizard link on mobile */
700
+ .sidebar__nav a[href="/wizard"] {
701
+ display: none;
702
+ }
703
+ @media (min-width: 768px) {
704
+ .sidebar__nav a[href="/wizard"] {
705
+ display: flex;
706
+ color: var(--violet);
707
+ }
708
+ }
709
+
710
+ /* On desktop, offset Pulse to not overlap sidebar */
711
+ @media (min-width: 768px) {
712
+ .floating-actions {
713
+ left: 224px; /* sidebar ~200px + 24px spacing */
714
+ }
715
+ }
716
+
717
+ .floating-actions > * {
718
+ pointer-events: auto;
719
+ }
720
+
721
+ .floating-actions .ochat__trigger {
722
+ position: static;
723
+ border: 1px solid var(--border);
724
+ }
725
+
726
+ /* Wizard button: wider to fit icon + label */
727
+ .floating-actions .ochat__trigger:first-child {
728
+ width: auto;
729
+ gap: 6px;
730
+ padding: 0 12px;
731
+ text-transform: uppercase;
732
+ letter-spacing: 0.04em;
733
+ font-size: 11px;
734
+ font-family: var(--font-mono-stack);
735
+ }
736
+
737
+ .floating-actions__label {
738
+ white-space: nowrap;
739
+ }
740
+
741
+ .floating-actions__badge {
742
+ position: absolute;
743
+ top: -3px;
744
+ right: -3px;
745
+ width: 10px;
746
+ height: 10px;
747
+ border-radius: 0;
748
+ background: #fbbf24;
749
+ box-shadow: 0 0 6px rgba(251,191,36,0.6);
750
+ border: 2px solid var(--bg2);
751
+ }
752
+
753
+ @media (max-width: 640px) {
754
+ .floating-actions {
755
+ bottom: 16px;
756
+ left: 16px;
757
+ right: 16px;
758
+ }
759
+ }
760
+
761
+ @media (max-width: 900px) {
762
+ .floating-actions {
763
+ bottom: 70px !important;
764
+ }
765
+ }
766
+
767
+ /* ── PulseChat widget ──────────────────────────────────────────── */
768
+ .ochat__trigger {
769
+ position: static;
770
+ width: 44px;
771
+ height: 44px;
772
+ background: var(--bg2);
773
+ color: var(--violet);
774
+ cursor: pointer;
775
+ display: flex;
776
+ align-items: center;
777
+ justify-content: center;
778
+ box-shadow: 0 4px 16px rgba(0,0,0,.5);
779
+ transition: background .15s;
780
+ }
781
+ .floating-actions .ochat__trigger {
782
+ border: 1px solid var(--border);
783
+ }
784
+ .ochat__trigger:hover { background: var(--bg3); }
785
+
786
+ .ochat__panel {
787
+ position: fixed;
788
+ bottom: 78px;
789
+ right: 24px;
790
+ z-index: 9001;
791
+ width: 340px;
792
+ max-height: 520px;
793
+ display: flex;
794
+ flex-direction: column;
795
+ border: 1px solid var(--border);
796
+ border-radius: 0;
797
+ background: var(--bg2);
798
+ box-shadow: 0 8px 32px rgba(0,0,0,.7);
799
+ overflow: hidden;
800
+ }
801
+
802
+ .ochat__header {
803
+ display: flex;
804
+ align-items: center;
805
+ justify-content: space-between;
806
+ padding: 8px 12px;
807
+ border-bottom: 1px solid var(--border);
808
+ background: var(--bg3);
809
+ flex-shrink: 0;
810
+ }
811
+ .ochat__header-title {
812
+ font-size: 10px;
813
+ letter-spacing: .1em;
814
+ text-transform: uppercase;
815
+ color: var(--text-dim);
816
+ display: flex;
817
+ align-items: center;
818
+ }
819
+ .ochat__close {
820
+ background: none;
821
+ border: none;
822
+ color: var(--text-dim);
823
+ cursor: pointer;
824
+ padding: 2px;
825
+ display: flex;
826
+ align-items: center;
827
+ }
828
+ .ochat__close:hover { color: var(--text); }
829
+
830
+ .ochat__clear {
831
+ background: none;
832
+ border: 1px solid var(--border);
833
+ color: var(--text-dim);
834
+ cursor: pointer;
835
+ padding: 3px 5px;
836
+ display: flex;
837
+ align-items: center;
838
+ justify-content: center;
839
+ border-radius: 0;
840
+ font-size: 9px;
841
+ transition: all 0.15s;
842
+ line-height: 1;
843
+ }
844
+ .ochat__clear:hover {
845
+ color: var(--violet);
846
+ border-color: var(--violet);
847
+ }
848
+
849
+ .ochat__messages {
850
+ flex: 1;
851
+ overflow-y: auto;
852
+ padding: 12px;
853
+ display: flex;
854
+ flex-direction: column;
855
+ gap: 8px;
856
+ font-size: 12px;
857
+ line-height: 1.55;
858
+ }
859
+ .ochat__empty {
860
+ color: var(--text-dim);
861
+ font-size: 11px;
862
+ line-height: 1.6;
863
+ }
864
+ .ochat__msg {
865
+ max-width: 90%;
866
+ padding: 7px 10px;
867
+ border-radius: 0;
868
+ word-break: break-word;
869
+ white-space: pre-wrap;
870
+ }
871
+ .ochat__msg--user {
872
+ align-self: flex-end;
873
+ background: var(--bg3);
874
+ border: 1px solid var(--border);
875
+ color: var(--text);
876
+ }
877
+ .ochat__msg--assistant {
878
+ align-self: flex-start;
879
+ background: transparent;
880
+ color: var(--text);
881
+ border: 1px solid transparent;
882
+ }
883
+ .ochat__cursor {
884
+ display: inline-block;
885
+ width: 6px;
886
+ height: 12px;
887
+ background: var(--violet);
888
+ margin-left: 2px;
889
+ vertical-align: text-bottom;
890
+ animation: blink .8s step-end infinite;
891
+ }
892
+ @keyframes blink { 50% { opacity: 0; } }
893
+
894
+ .ochat__footer {
895
+ display: flex;
896
+ align-items: flex-end;
897
+ gap: 6px;
898
+ padding: 8px 10px;
899
+ border-top: 1px solid var(--border);
900
+ background: var(--bg3);
901
+ flex-shrink: 0;
902
+ }
903
+ .ochat__input {
904
+ flex: 1;
905
+ resize: none;
906
+ background: var(--bg);
907
+ border: 1px solid var(--border);
908
+ border-radius: 0;
909
+ color: var(--text);
910
+ font-family: var(--font-mono-stack);
911
+ font-size: 11px;
912
+ line-height: 1.5;
913
+ padding: 5px 8px;
914
+ max-height: 80px;
915
+ overflow-y: auto;
916
+ }
917
+ .ochat__input:focus { outline: none; border-color: var(--violet); }
918
+ .ochat__input::placeholder { color: var(--text-dim); }
919
+ .ochat__input:disabled { opacity: .5; }
920
+ .ochat__send {
921
+ flex-shrink: 0;
922
+ width: 30px;
923
+ height: 30px;
924
+ border-radius: 0;
925
+ border: 1px solid var(--violet);
926
+ background: transparent;
927
+ color: var(--violet);
928
+ cursor: pointer;
929
+ display: flex;
930
+ align-items: center;
931
+ justify-content: center;
932
+ transition: background .15s;
933
+ }
934
+ .ochat__send:hover:not(:disabled) { background: var(--violet); color: var(--bg); }
935
+ .ochat__send:disabled { opacity: .35; cursor: default; }
936
+
937
+ @media (max-width: 575px) {
938
+ .ochat__panel { width: calc(100vw - 32px); right: 16px; }
939
+ .ochat__trigger { right: 16px; bottom: 16px; }
940
+ }
941
+
942
+ /* ============================================================== */
943
+ /* UI Components — Button, Input, Select, Modal, Toast */
944
+ /* ============================================================== */
945
+
946
+ /* ── Button ────────────────────────────────────────────────── */
947
+ .ui-btn {
948
+ display: inline-flex;
949
+ align-items: center;
950
+ justify-content: center;
951
+ gap: 6px;
952
+ border-radius: 0;
953
+ border: 1px solid var(--border);
954
+ font-family: var(--font-mono-stack);
955
+ cursor: pointer;
956
+ transition: background 0.12s, border-color 0.12s, opacity 0.12s;
957
+ white-space: nowrap;
958
+ flex-shrink: 0;
959
+ line-height: 1;
960
+ text-transform: uppercase;
961
+ letter-spacing: 0.04em;
962
+ }
963
+ .ui-btn:disabled { opacity: 0.4; cursor: not-allowed; }
964
+
965
+ .ui-btn--sm { font-size: 10px; padding: 6px 12px; }
966
+ .ui-btn--md { font-size: 11px; padding: 8px 16px; }
967
+
968
+ .ui-btn--primary {
969
+ background: var(--violet);
970
+ border-color: var(--violet);
971
+ color: #111;
972
+ }
973
+ .ui-btn--primary:hover:not(:disabled) {
974
+ background: var(--violet-hover, #7B4FD4);
975
+ }
976
+
977
+ .ui-btn--secondary {
978
+ background: var(--bg3);
979
+ color: var(--text);
980
+ }
981
+ .ui-btn--secondary:hover:not(:disabled) {
982
+ background: #222;
983
+ }
984
+
985
+ .ui-btn--danger {
986
+ border-color: var(--red);
987
+ color: var(--red);
988
+ background: transparent;
989
+ }
990
+ .ui-btn--danger:hover:not(:disabled) {
991
+ background: rgba(239,68,68,0.08);
992
+ }
993
+
994
+ .ui-btn--ghost {
995
+ border-color: transparent;
996
+ background: transparent;
997
+ color: var(--text-dim);
998
+ }
999
+ .ui-btn--ghost:hover:not(:disabled) {
1000
+ color: var(--text);
1001
+ background: var(--bg3);
1002
+ }
1003
+
1004
+ .ui-btn--success {
1005
+ border-color: var(--green);
1006
+ color: var(--green);
1007
+ background: transparent;
1008
+ }
1009
+ .ui-btn--success:hover:not(:disabled) {
1010
+ background: rgba(34,197,94,0.08);
1011
+ }
1012
+
1013
+ /* ── Input / Select ────────────────────────────────────────── */
1014
+ .ui-field { display: flex; flex-direction: column; gap: 4px; }
1015
+ .ui-field__label { font-size: 12px; color: var(--text-dim); }
1016
+ .ui-field__error { font-size: 11px; color: var(--red); }
1017
+
1018
+ .ui-input,
1019
+ .ui-select {
1020
+ width: 100%;
1021
+ padding: 10px 12px;
1022
+ border-radius: 0;
1023
+ border: 1px solid var(--border);
1024
+ background: var(--bg);
1025
+ color: var(--text);
1026
+ font-size: 14px;
1027
+ outline: none;
1028
+ box-sizing: border-box;
1029
+ font-family: var(--font-mono-stack);
1030
+ transition: border-color 0.12s;
1031
+ }
1032
+ .ui-input:focus,
1033
+ .ui-select:focus { border-color: var(--violet); }
1034
+ .ui-input--error,
1035
+ .ui-select--error { border-color: var(--red); }
1036
+ .ui-input::placeholder { color: #555; }
1037
+
1038
+ /* ── Modal ─────────────────────────────────────────────────── */
1039
+ .ui-modal-overlay {
1040
+ position: fixed;
1041
+ inset: 0;
1042
+ z-index: 9999;
1043
+ display: flex;
1044
+ align-items: center;
1045
+ justify-content: center;
1046
+ background: rgba(0,0,0,0.65);
1047
+ padding: 20px;
1048
+ }
1049
+ .ui-modal {
1050
+ width: 100%;
1051
+ max-height: 85vh;
1052
+ background: #111;
1053
+ border: 1px solid var(--border);
1054
+ border-radius: 0;
1055
+ display: flex;
1056
+ flex-direction: column;
1057
+ overflow: hidden;
1058
+ }
1059
+ .ui-modal__head {
1060
+ display: flex;
1061
+ justify-content: space-between;
1062
+ align-items: center;
1063
+ padding: 10px 14px;
1064
+ border-bottom: 1px solid var(--border);
1065
+ }
1066
+ .ui-modal__title {
1067
+ font-size: 12px;
1068
+ color: var(--violet);
1069
+ font-family: var(--font-mono-stack);
1070
+ }
1071
+ .ui-modal__close {
1072
+ background: transparent;
1073
+ border: none;
1074
+ color: #888;
1075
+ font-size: 16px;
1076
+ cursor: pointer;
1077
+ line-height: 1;
1078
+ }
1079
+ .ui-modal__body {
1080
+ flex: 1;
1081
+ overflow: auto;
1082
+ padding: 14px;
1083
+ }
1084
+
1085
+ /* ── Toast ─────────────────────────────────────────────────── */
1086
+ .ui-toast-container {
1087
+ position: fixed;
1088
+ bottom: 80px;
1089
+ right: 24px;
1090
+ z-index: 99999;
1091
+ display: flex;
1092
+ flex-direction: column;
1093
+ gap: 8px;
1094
+ pointer-events: none;
1095
+ }
1096
+ .ui-toast {
1097
+ padding: 12px 20px;
1098
+ border-radius: 0;
1099
+ font-size: 13px;
1100
+ box-shadow: 0 4px 12px rgba(0,0,0,0.4);
1101
+ pointer-events: auto;
1102
+ animation: ui-toast-in 0.3s ease;
1103
+ font-family: var(--font-mono-stack);
1104
+ }
1105
+ @keyframes ui-toast-in {
1106
+ from { opacity: 0; transform: translateY(8px); }
1107
+ to { opacity: 1; transform: translateY(0); }
1108
+ }
1109
+ .ui-toast--success {
1110
+ background: #1a3a1a;
1111
+ border: 1px solid var(--green);
1112
+ color: #bbf7d0;
1113
+ }
1114
+ .ui-toast--error {
1115
+ background: #3a1a1a;
1116
+ border: 1px solid var(--red);
1117
+ color: #fecaca;
1118
+ }
1119
+ .ui-toast--info {
1120
+ background: #1a1a3a;
1121
+ border: 1px solid #818cf8;
1122
+ color: #c7d2fe;
1123
+ }
1124
+
1125
+ @media (max-width: 767px) {
1126
+ .ui-toast-container { right: 16px; left: 16px; bottom: 70px; }
1127
+ .ui-toast { font-size: 12px; padding: 10px 16px; }
1128
+ }
1129
+
1130
+ /* ── Spinner ──────────────────────────────────────────────────── */
1131
+ .ui-spinner {
1132
+ width: 20px;
1133
+ height: 20px;
1134
+ border: 2px solid rgba(146,91,252,0.2);
1135
+ border-top-color: var(--violet);
1136
+ border-radius: 50%;
1137
+ animation: ui-spin 0.7s linear infinite;
1138
+ }
1139
+ .ui-spinner--lg {
1140
+ width: 36px;
1141
+ height: 36px;
1142
+ border-width: 3px;
1143
+ }
1144
+ @keyframes ui-spin {
1145
+ to { transform: rotate(360deg); }
1146
+ }
1147
+
1148
+ /* ── Filter Bar ──────────────────────────────────────────────── */
1149
+ .ui-filter-bar {
1150
+ display: flex;
1151
+ gap: 6px;
1152
+ flex-wrap: wrap;
1153
+ padding: 8px 0;
1154
+ }
1155
+
1156
+ /* ── Property List ───────────────────────────────────────────── */
1157
+ .ui-property-list {
1158
+ display: grid;
1159
+ grid-template-columns: auto 1fr;
1160
+ gap: 4px 12px;
1161
+ font-size: 11px;
1162
+ }
1163
+ .ui-property-label {
1164
+ color: var(--text-dim);
1165
+ white-space: nowrap;
1166
+ }
1167
+ .ui-property-value[data-tone="dim"] {
1168
+ color: #555;
1169
+ }
1170
+ .ui-property-value[data-tone="success"] {
1171
+ color: var(--green);
1172
+ }
1173
+ .ui-property-value[data-tone="warning"] {
1174
+ color: var(--yellow);
1175
+ }
1176
+ .ui-property-value[data-tone="danger"] {
1177
+ color: var(--red);
1178
+ }
1179
+ .ui-property-value[data-tone="accent"] {
1180
+ color: var(--violet);
1181
+ }
1182
+
1183
+ /* ── Crons page ──────────────────────────────────────────────── */
1184
+ .crons-page {
1185
+ flex: 1;
1186
+ background: var(--bg);
1187
+ color: var(--text);
1188
+ font-family: var(--font-mono-stack);
1189
+ display: flex;
1190
+ flex-direction: column;
1191
+ overflow: hidden;
1192
+ }
1193
+ .crons-header {
1194
+ height: 48px;
1195
+ padding: 0 14px;
1196
+ border-bottom: 1px solid var(--border);
1197
+ display: flex;
1198
+ align-items: center;
1199
+ justify-content: space-between;
1200
+ flex-shrink: 0;
1201
+ }
1202
+ .crons-header__title {
1203
+ font-family: var(--font-serif-stack);
1204
+ font-size: 20px;
1205
+ letter-spacing: 4px;
1206
+ color: var(--violet);
1207
+ }
1208
+ .crons-header__meta {
1209
+ font-size: 10px;
1210
+ color: var(--gray);
1211
+ }
1212
+ .crons-mobile-tabs {
1213
+ display: flex;
1214
+ gap: 8px;
1215
+ padding: 8px 10px;
1216
+ border-bottom: 1px solid var(--border);
1217
+ background: var(--bg2);
1218
+ }
1219
+
1220
+ /* ── Containers page ─────────────────────────────────────────── */
1221
+ .container-terminal-link {
1222
+ border: 1px solid var(--border);
1223
+ border-radius: 0;
1224
+ background: transparent;
1225
+ color: var(--violet);
1226
+ font-size: 10px;
1227
+ padding: 4px 8px;
1228
+ text-decoration: none;
1229
+ }
1230
+ .container-terminal-link:hover {
1231
+ background: var(--bg3);
1232
+ }
1233
+
1234
+ /* ── Gateway page ────────────────────────────────────────────── */
1235
+ .gateway-tab {
1236
+ flex: 1;
1237
+ padding: 12px 16px;
1238
+ background: none;
1239
+ border: none;
1240
+ border-bottom: 2px solid transparent;
1241
+ color: var(--text-dim);
1242
+ font-family: var(--font-mono-stack);
1243
+ font-size: 13px;
1244
+ font-weight: 400;
1245
+ letter-spacing: 0.04em;
1246
+ cursor: pointer;
1247
+ text-transform: capitalize;
1248
+ transition: color 0.12s, border-color 0.12s;
1249
+ }
1250
+ .gateway-tab--active {
1251
+ color: var(--violet);
1252
+ border-bottom-color: var(--violet);
1253
+ font-weight: 600;
1254
+ }
1255
+ .gateway-tab:hover {
1256
+ color: var(--text);
1257
+ }
1258
+ .gateway-agent-select {
1259
+ width: 100%;
1260
+ padding: 9px 10px;
1261
+ border-radius: 0;
1262
+ border: 1px solid var(--border);
1263
+ background: var(--surface, var(--bg));
1264
+ color: var(--text);
1265
+ font-size: 12px;
1266
+ cursor: pointer;
1267
+ outline: none;
1268
+ font-family: var(--font-mono-stack);
1269
+ box-shadow: 0 1px 3px rgba(0,0,0,0.15);
1270
+ transition: border-color 0.15s;
1271
+ }
1272
+ .gateway-agent-select:focus {
1273
+ border-color: var(--violet);
1274
+ }
1275
+ .gateway-agent-dot {
1276
+ width: 8px;
1277
+ height: 8px;
1278
+ border-radius: 50%;
1279
+ flex-shrink: 0;
1280
+ }
1281
+ .gateway-agent-dot--ok { background: var(--green); }
1282
+ .gateway-agent-dot--err { background: var(--red); }
1283
+
1284
+ /* ── Shared message classes ──────────────────────────────────── */
1285
+ .msg-success {
1286
+ padding: 8px 12px;
1287
+ border-radius: 0;
1288
+ font-size: 12px;
1289
+ background: rgba(var(--green-rgb,34,197,94),0.1);
1290
+ color: var(--green);
1291
+ }
1292
+ .msg-error {
1293
+ padding: 8px 12px;
1294
+ border-radius: 0;
1295
+ font-size: 12px;
1296
+ background: rgba(var(--red-rgb,239,68,68),0.1);
1297
+ color: var(--red);
1298
+ }
1299
+
1300
+ /* --- Mobile Bottom Navigation --- */
1301
+ .mobile-bottom-nav {
1302
+ display: none;
1303
+ }
1304
+
1305
+ @media (max-width: 767px) {
1306
+ .mobile-bottom-nav {
1307
+ display: flex;
1308
+ position: fixed;
1309
+ bottom: 0;
1310
+ left: 0;
1311
+ right: 0;
1312
+ height: 54px;
1313
+ padding-bottom: env(safe-area-inset-bottom, 0px);
1314
+ background: var(--color-bg-900, #0d0d0d);
1315
+ border-top: 1px solid var(--color-border-700, #2a2a2a);
1316
+ z-index: 250;
1317
+ box-sizing: border-box;
1318
+ overflow-x: auto;
1319
+ overflow-y: hidden;
1320
+ -webkit-overflow-scrolling: touch;
1321
+ scrollbar-width: none;
1322
+ -ms-overflow-style: none;
1323
+ }
1324
+ .mobile-bottom-nav::-webkit-scrollbar { display: none; }
1325
+
1326
+ .mobile-bottom-nav__scroll {
1327
+ display: flex;
1328
+ width: 100%;
1329
+ justify-content: space-evenly;
1330
+ padding: 0 4px;
1331
+ align-items: center;
1332
+ height: 100%;
1333
+ }
1334
+ @media (min-width: 576px) {
1335
+ .mobile-bottom-nav__scroll { justify-content: center; }
1336
+ }
1337
+
1338
+ .mobile-bottom-nav__item {
1339
+ display: inline-flex;
1340
+ flex-direction: column;
1341
+ align-items: center;
1342
+ justify-content: center;
1343
+ gap: 6px;
1344
+ min-width: 44px;
1345
+ text-decoration: none;
1346
+ color: #666;
1347
+ font-family: var(--font-mono-stack, monospace);
1348
+ transition: color 0.2s;
1349
+ padding: 6px 10px;
1350
+ border-radius: 0;
1351
+ flex-shrink: 0;
1352
+ touch-action: manipulation;
1353
+ }
1354
+
1355
+ .mobile-bottom-nav__item:active {
1356
+ background: rgba(255,255,255,0.05);
1357
+ }
1358
+
1359
+ .mobile-bottom-nav__icon svg {
1360
+ display: block;
1361
+ opacity: 0.7;
1362
+ }
1363
+ .mobile-bottom-nav__item--active .mobile-bottom-nav__icon svg {
1364
+ opacity: 1;
1365
+ }
1366
+
1367
+ .mobile-bottom-nav__item--active {
1368
+ color: var(--violet, #925BFC);
1369
+ }
1370
+
1371
+ .mobile-bottom-nav__label {
1372
+ font-size: 8px;
1373
+ line-height: 1;
1374
+ text-transform: uppercase;
1375
+ letter-spacing: 0.3px;
1376
+ white-space: nowrap;
1377
+ }
1378
+
1379
+ /* Padding bottom per non coprire contenuti — handled by .app-shell__content */
1380
+
1381
+ /* Chat button alzato sopra la bottom navbar */
1382
+ .ochat__trigger {
1383
+ bottom: 70px !important;
1384
+ }
1385
+ .ochat__panel {
1386
+ bottom: 124px !important;
1387
+ }
1388
+ }
1389
+
1390
+ /* ── Design System — extra classes ──────────────────────────── */
1391
+ .error-state {
1392
+ color: var(--red);
1393
+ padding: 32px 16px;
1394
+ font-family: var(--font-mono-stack);
1395
+ font-size: 11px;
1396
+ text-align: center;
1397
+ }
1398
+ .ui-select-workspace {
1399
+ background: var(--bg3);
1400
+ color: var(--violet);
1401
+ border: 1px solid var(--border);
1402
+ border-radius: 0;
1403
+ font-size: 11px;
1404
+ padding: 3px 8px;
1405
+ font-family: var(--font-mono-stack);
1406
+ max-width: 220px;
1407
+ cursor: pointer;
1408
+ outline: none;
1409
+ }
1410
+
1411
+ /* ── List item buttons (sidebar items, agent list, provider select) ─── */
1412
+
1413
+ /* ── Pulse animation for in-progress indicators ─────────────── */
1414
+ @keyframes pulse {
1415
+ 0%, 100% { opacity: 1; }
1416
+ 50% { opacity: 0.4; }
1417
+ }
1418
+
1419
+ /* Update banner */
1420
+ .update-banner {
1421
+ flex-shrink: 0;
1422
+ background: linear-gradient(135deg, rgba(146,91,252,0.14) 0%, rgba(146,91,252,0.04) 100%);
1423
+ border-bottom: 1px solid rgba(146,91,252,0.22);
1424
+ z-index: 50;
1425
+ width: 100%;
1426
+ }
1427
+ .update-banner__inner {
1428
+ display: flex;
1429
+ align-items: center;
1430
+ justify-content: space-between;
1431
+ gap: 12px;
1432
+ padding: 0 16px;
1433
+ font-size: 11px;
1434
+ color: var(--text-dim);
1435
+ line-height: 1.3;
1436
+ height: 48px;
1437
+ }
1438
+ .update-banner__text {
1439
+ display: flex;
1440
+ align-items: baseline;
1441
+ gap: 0.4em;
1442
+ flex-wrap: wrap;
1443
+ min-width: 0;
1444
+ }
1445
+ .update-banner__label {
1446
+ color: var(--violet);
1447
+ font-weight: 600;
1448
+ text-transform: uppercase;
1449
+ letter-spacing: 0.04em;
1450
+ font-size: 10px;
1451
+ }
1452
+ .update-banner__version {
1453
+ font-weight: 500;
1454
+ font-size: 11px;
1455
+ font-family: var(--font-mono-stack);
1456
+ }
1457
+ .update-banner__sep {
1458
+ font-size: 10px;
1459
+ opacity: 0.35;
1460
+ }
1461
+ .update-banner__ok {
1462
+ color: var(--green);
1463
+ font-size: 11px;
1464
+ }
1465
+ .update-banner__err {
1466
+ color: var(--red);
1467
+ font-size: 11px;
1468
+ }
1469
+ .update-banner__actions {
1470
+ display: flex;
1471
+ gap: 8px;
1472
+ align-items: center;
1473
+ flex-shrink: 0;
1474
+ }