@silicaclaw/cli 1.0.0-beta.3 → 1.0.0-beta.30

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 (81) hide show
  1. package/CHANGELOG.md +93 -0
  2. package/INSTALL.md +41 -4
  3. package/README.md +80 -6
  4. package/apps/local-console/public/index.html +1283 -251
  5. package/apps/local-console/src/server.ts +108 -31
  6. package/docs/CLOUDFLARE_RELAY.md +61 -0
  7. package/docs/NEW_USER_INSTALL.md +166 -0
  8. package/docs/NEW_USER_OPERATIONS.md +265 -0
  9. package/package.json +6 -1
  10. package/packages/core/dist/crypto.d.ts +6 -0
  11. package/packages/core/dist/crypto.js +50 -0
  12. package/packages/core/dist/directory.d.ts +17 -0
  13. package/packages/core/dist/directory.js +145 -0
  14. package/packages/core/dist/identity.d.ts +2 -0
  15. package/packages/core/dist/identity.js +18 -0
  16. package/packages/core/dist/index.d.ts +11 -0
  17. package/packages/core/dist/index.js +27 -0
  18. package/packages/core/dist/indexing.d.ts +6 -0
  19. package/packages/core/dist/indexing.js +43 -0
  20. package/packages/core/dist/presence.d.ts +4 -0
  21. package/packages/core/dist/presence.js +23 -0
  22. package/packages/core/dist/profile.d.ts +4 -0
  23. package/packages/core/dist/profile.js +39 -0
  24. package/packages/core/dist/publicProfileSummary.d.ts +70 -0
  25. package/packages/core/dist/publicProfileSummary.js +103 -0
  26. package/packages/core/dist/socialConfig.d.ts +99 -0
  27. package/packages/core/dist/socialConfig.js +288 -0
  28. package/packages/core/dist/socialResolver.d.ts +46 -0
  29. package/packages/core/dist/socialResolver.js +237 -0
  30. package/packages/core/dist/socialTemplate.d.ts +2 -0
  31. package/packages/core/dist/socialTemplate.js +88 -0
  32. package/packages/core/dist/types.d.ts +37 -0
  33. package/packages/core/dist/types.js +2 -0
  34. package/packages/core/src/socialConfig.ts +8 -7
  35. package/packages/core/src/socialResolver.ts +17 -5
  36. package/packages/network/dist/abstractions/messageEnvelope.d.ts +28 -0
  37. package/packages/network/dist/abstractions/messageEnvelope.js +36 -0
  38. package/packages/network/dist/abstractions/peerDiscovery.d.ts +43 -0
  39. package/packages/network/dist/abstractions/peerDiscovery.js +2 -0
  40. package/packages/network/dist/abstractions/topicCodec.d.ts +4 -0
  41. package/packages/network/dist/abstractions/topicCodec.js +2 -0
  42. package/packages/network/dist/abstractions/transport.d.ts +36 -0
  43. package/packages/network/dist/abstractions/transport.js +2 -0
  44. package/packages/network/dist/codec/jsonMessageEnvelopeCodec.d.ts +5 -0
  45. package/packages/network/dist/codec/jsonMessageEnvelopeCodec.js +24 -0
  46. package/packages/network/dist/codec/jsonTopicCodec.d.ts +5 -0
  47. package/packages/network/dist/codec/jsonTopicCodec.js +12 -0
  48. package/packages/network/dist/discovery/heartbeatPeerDiscovery.d.ts +28 -0
  49. package/packages/network/dist/discovery/heartbeatPeerDiscovery.js +144 -0
  50. package/packages/network/dist/index.d.ts +14 -0
  51. package/packages/network/dist/index.js +30 -0
  52. package/packages/network/dist/localEventBus.d.ts +9 -0
  53. package/packages/network/dist/localEventBus.js +47 -0
  54. package/packages/network/dist/mock.d.ts +8 -0
  55. package/packages/network/dist/mock.js +24 -0
  56. package/packages/network/dist/realPreview.d.ts +105 -0
  57. package/packages/network/dist/realPreview.js +327 -0
  58. package/packages/network/dist/relayPreview.d.ts +166 -0
  59. package/packages/network/dist/relayPreview.js +430 -0
  60. package/packages/network/dist/transport/udpLanBroadcastTransport.d.ts +23 -0
  61. package/packages/network/dist/transport/udpLanBroadcastTransport.js +153 -0
  62. package/packages/network/dist/types.d.ts +6 -0
  63. package/packages/network/dist/types.js +2 -0
  64. package/packages/network/dist/webrtcPreview.d.ts +163 -0
  65. package/packages/network/dist/webrtcPreview.js +844 -0
  66. package/packages/network/src/index.ts +1 -0
  67. package/packages/network/src/relayPreview.ts +552 -0
  68. package/packages/storage/dist/index.d.ts +3 -0
  69. package/packages/storage/dist/index.js +19 -0
  70. package/packages/storage/dist/jsonRepo.d.ts +7 -0
  71. package/packages/storage/dist/jsonRepo.js +29 -0
  72. package/packages/storage/dist/repos.d.ts +21 -0
  73. package/packages/storage/dist/repos.js +41 -0
  74. package/packages/storage/dist/socialRuntimeRepo.d.ts +5 -0
  75. package/packages/storage/dist/socialRuntimeRepo.js +52 -0
  76. package/packages/storage/src/socialRuntimeRepo.ts +4 -4
  77. package/packages/storage/tsconfig.json +6 -1
  78. package/scripts/quickstart.sh +314 -36
  79. package/scripts/silicaclaw-cli.mjs +466 -24
  80. package/scripts/silicaclaw-gateway.mjs +475 -0
  81. package/scripts/webrtc-signaling-server.mjs +89 -5
@@ -18,51 +18,103 @@
18
18
  <style>
19
19
  :root {
20
20
  --bg: #0e1015;
21
+ --bg-accent: #13151b;
21
22
  --bg-elevated: #191c24;
22
23
  --bg-hover: #1f2330;
24
+ --bg-muted: #1f2330;
23
25
  --panel: #0e1015;
26
+ --panel-strong: #191c24;
27
+ --panel-hover: #1f2330;
24
28
  --card: #161920;
25
- --line: #1e2028;
26
- --line-strong: #2e3040;
29
+ --card-foreground: #f0f0f2;
30
+ --card-highlight: rgba(255, 255, 255, 0.04);
31
+ --card-soft: rgba(22, 25, 32, 0.86);
32
+ --card-strong: rgba(25, 28, 36, 0.96);
33
+ --chrome: rgba(14, 16, 21, 0.96);
34
+ --chrome-strong: rgba(14, 16, 21, 0.98);
27
35
  --text: #d4d4d8;
28
36
  --text-strong: #f4f4f5;
29
- --muted: #636370;
30
- --brand: #ff5c5c;
31
- --brand-hover: #ff7070;
32
- --brand-soft: rgba(255, 92, 92, 0.1);
37
+ --muted: #838387;
38
+ --muted-strong: #62626a;
39
+ --border: #1e2028;
40
+ --border-strong: #2e3040;
41
+ --border-hover: #3e4050;
42
+ --accent: #ff5c5c;
43
+ --accent-hover: #ff7070;
44
+ --accent-subtle: rgba(255, 92, 92, 0.1);
45
+ --accent-glow: rgba(255, 92, 92, 0.2);
33
46
  --ok: #22c55e;
34
47
  --warn: #f59e0b;
35
- --err: #ef4444;
36
- --chip: #1f2330;
48
+ --danger: #ef4444;
49
+ --info: #3b82f6;
50
+ --focus-ring: 0 0 0 2px var(--bg), 0 0 0 3px color-mix(in srgb, var(--accent) 60%, transparent);
51
+ --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.25);
52
+ --shadow-md: 0 4px 16px rgba(0, 0, 0, 0.3);
53
+ --shadow-lg: 0 12px 32px rgba(0, 0, 0, 0.4);
54
+ --radius-sm: 6px;
55
+ --radius-md: 10px;
56
+ --radius-lg: 14px;
57
+ --radius-xl: 20px;
58
+ --radius-full: 9999px;
59
+ --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
60
+ --duration-fast: 100ms;
61
+ --font-body: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
62
+ --mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
63
+
37
64
  }
38
65
  :root[data-theme-mode="light"] {
39
66
  --bg: #f8f9fa;
40
- --bg-elevated: #f1f3f5;
67
+ --bg-accent: #f1f3f5;
68
+ --bg-elevated: #ffffff;
41
69
  --bg-hover: #eceef0;
70
+ --bg-muted: #eceef0;
42
71
  --panel: #f8f9fa;
72
+ --panel-strong: #f1f3f5;
73
+ --panel-hover: #e6e8eb;
43
74
  --card: #ffffff;
44
- --line: #e5e5ea;
45
- --line-strong: #d1d1d6;
75
+ --card-foreground: #1a1a1e;
76
+ --card-highlight: rgba(0, 0, 0, 0.02);
77
+ --card-soft: rgba(255, 255, 255, 0.9);
78
+ --card-strong: rgba(255, 255, 255, 0.98);
79
+ --chrome: rgba(248, 249, 250, 0.96);
80
+ --chrome-strong: rgba(248, 249, 250, 0.98);
46
81
  --text: #3c3c43;
47
82
  --text-strong: #1a1a1e;
48
- --muted: #8e8e93;
49
- --brand: #dc2626;
50
- --brand-hover: #ef4444;
51
- --brand-soft: rgba(220, 38, 38, 0.08);
52
- --ok: #16a34a;
53
- --warn: #d97706;
54
- --err: #dc2626;
55
- --chip: #f1f3f5;
83
+ --muted: #6e6e73;
84
+ --muted-strong: #545458;
85
+ --border: #e5e5ea;
86
+ --border-strong: #d1d1d6;
87
+ --border-hover: #aeaeb2;
88
+ --accent: #dc2626;
89
+ --accent-hover: #ef4444;
90
+ --accent-subtle: rgba(220, 38, 38, 0.08);
91
+ --accent-glow: rgba(220, 38, 38, 0.1);
92
+ --ok: #15803d;
93
+ --warn: #b45309;
94
+ --danger: #dc2626;
95
+ --info: #2563eb;
96
+ --focus-ring: 0 0 0 2px var(--bg), 0 0 0 3px color-mix(in srgb, var(--accent) 50%, transparent);
97
+ --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.04);
98
+ --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.06);
99
+ --shadow-lg: 0 12px 28px rgba(0, 0, 0, 0.08);
100
+
56
101
  }
57
102
  * { box-sizing: border-box; }
58
- html, body { margin: 0; min-height: 100%; }
103
+ html, body {
104
+ margin: 0;
105
+ height: 100%;
106
+ overflow: hidden;
107
+ }
59
108
  body {
60
- font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "PingFang SC", sans-serif;
109
+ font: 400 13.5px/1.55 var(--font-body);
110
+ letter-spacing: -0.01em;
61
111
  color: var(--text);
62
112
  background:
63
113
  radial-gradient(900px 420px at 8% -12%, rgba(255, 92, 92, 0.18), transparent 60%),
64
114
  linear-gradient(180deg, #0e1015 0%, #0e1015 62%, #0f1219 100%);
65
115
  transition: background .2s ease, color .2s ease;
116
+ -webkit-font-smoothing: antialiased;
117
+ -moz-osx-font-smoothing: grayscale;
66
118
  }
67
119
  :root[data-theme-mode="light"] body {
68
120
  background:
@@ -72,35 +124,121 @@
72
124
 
73
125
  .app {
74
126
  display: grid;
75
- grid-template-columns: 240px 1fr;
76
- min-height: 100vh;
127
+ grid-template-columns: 258px 1fr;
128
+ height: 100vh;
129
+ overflow: hidden;
130
+ transition: grid-template-columns .2s ease;
131
+ }
132
+ .app.nav-collapsed {
133
+ grid-template-columns: 78px 1fr;
134
+ }
135
+ .app.focus-mode {
136
+ grid-template-columns: 1fr;
77
137
  }
78
138
 
79
139
  .sidebar {
80
- border-right: 1px solid color-mix(in srgb, var(--line) 74%, transparent);
81
- background: color-mix(in srgb, var(--panel) 96%, transparent);
82
- padding: 18px 14px;
140
+ display: flex;
141
+ flex-direction: column;
142
+ min-height: 0;
143
+ border-right: 1px solid color-mix(in srgb, var(--border) 74%, transparent);
144
+ background: var(--bg);
145
+ padding: 14px 10px 12px;
146
+ position: relative;
147
+ overflow: hidden;
148
+ transition: padding .2s ease;
149
+ }
150
+ :root[data-theme-mode="light"] .sidebar {
151
+ background: var(--panel);
152
+ }
153
+ .app.nav-collapsed .sidebar {
154
+ padding: 12px 8px 10px;
155
+ }
156
+ .sidebar-shell {
157
+ display: flex;
158
+ flex: 1 1 auto;
159
+ min-height: 0;
160
+ flex-direction: column;
161
+ }
162
+ .sidebar-shell__header {
163
+ flex: 0 0 auto;
164
+ display: flex;
165
+ align-items: center;
166
+ justify-content: space-between;
167
+ gap: 12px;
168
+ min-height: 0;
169
+ padding: 0 8px 18px;
170
+ }
171
+ .nav-collapse-toggle {
172
+ width: 36px;
173
+ height: 36px;
174
+ display: flex;
175
+ align-items: center;
176
+ justify-content: center;
177
+ background: var(--bg-elevated);
178
+ border: 1px solid color-mix(in srgb, var(--border-strong) 68%, transparent);
179
+ border-radius: 999px;
180
+ cursor: pointer;
181
+ color: var(--muted);
182
+ flex: 0 0 auto;
183
+ transition:
184
+ background .16s ease,
185
+ border-color .16s ease,
186
+ color .16s ease,
187
+ transform .16s ease;
188
+ }
189
+ .nav-collapse-toggle:hover {
190
+ background: color-mix(in srgb, var(--bg-hover) 90%, transparent);
191
+ border-color: color-mix(in srgb, var(--border-strong) 88%, transparent);
192
+ color: var(--text);
193
+ transform: translateY(-1px);
194
+ }
195
+ .nav-collapse-toggle__icon {
196
+ display: flex;
197
+ align-items: center;
198
+ justify-content: center;
199
+ width: 16px;
200
+ height: 16px;
201
+ color: inherit;
202
+ }
203
+ .nav-collapse-toggle__icon svg {
204
+ width: 16px;
205
+ height: 16px;
206
+ stroke: currentColor;
207
+ fill: none;
208
+ stroke-width: 1.5px;
209
+ stroke-linecap: round;
210
+ stroke-linejoin: round;
211
+ }
212
+ .sidebar-shell__body {
213
+ flex: 1 1 auto;
214
+ min-height: 0;
215
+ display: flex;
216
+ flex-direction: column;
217
+ }
218
+ .sidebar-shell__footer {
219
+ flex: 0 0 auto;
220
+ padding: 12px 8px 0;
83
221
  }
84
222
  .brand {
85
223
  display: flex;
86
224
  align-items: center;
87
225
  gap: 10px;
88
- margin-bottom: 18px;
226
+ margin-bottom: 0;
89
227
  }
90
228
  .brand-logo {
91
- width: 38px;
92
- height: 38px;
229
+ width: 32px;
230
+ height: 32px;
93
231
  border-radius: 10px;
94
232
  object-fit: cover;
95
233
  display: block;
96
- box-shadow: 0 4px 14px rgba(0, 0, 0, 0.24);
97
- border: 1px solid color-mix(in srgb, var(--line) 75%, transparent);
234
+ box-shadow: 0 8px 18px rgba(0, 0, 0, 0.18);
235
+ border: 1px solid color-mix(in srgb, var(--border) 75%, transparent);
98
236
  }
99
237
  .brand-badge {
100
- width: 38px;
101
- height: 38px;
238
+ width: 32px;
239
+ height: 32px;
102
240
  border-radius: 10px;
103
- background: linear-gradient(135deg, var(--brand), var(--brand-hover));
241
+ background: linear-gradient(135deg, var(--accent), var(--accent-hover));
104
242
  color: #fff;
105
243
  font-weight: 900;
106
244
  display: grid;
@@ -109,98 +247,452 @@
109
247
  .brand-badge.hidden { display: none; }
110
248
  .brand h1 {
111
249
  margin: 0;
112
- font-size: 17px;
250
+ font-size: 15px;
251
+ line-height: 1.1;
252
+ letter-spacing: -0.03em;
113
253
  }
114
254
  .brand p {
115
255
  margin: 2px 0 0;
116
256
  color: var(--muted);
117
- font-size: 12px;
257
+ font-size: 10px;
258
+ line-height: 1.15;
259
+ font-weight: 600;
260
+ letter-spacing: 0.08em;
261
+ text-transform: uppercase;
262
+ }
263
+ .version-dot {
264
+ width: 5px;
265
+ height: 5px;
266
+ border-radius: 999px;
267
+ background: var(--accent);
268
+ opacity: .85;
269
+ }
270
+ .app.nav-collapsed .brand h1,
271
+ .app.nav-collapsed .brand p,
272
+ .app.nav-collapsed .sidebar-foot,
273
+ .app.nav-collapsed .sidebar-version__label,
274
+ .app.nav-collapsed .sidebar-nav__label {
275
+ display: none;
276
+ }
277
+ .app.focus-mode .sidebar {
278
+ display: none;
279
+ }
280
+ .app.focus-mode .integration-strip,
281
+ .app.focus-mode .page-hero,
282
+ .app.focus-mode .notice,
283
+ .app.focus-mode #onboardingActions,
284
+ .app.focus-mode #publicDiscoveryHint {
285
+ display: none !important;
286
+ }
287
+ .app.nav-collapsed .brand {
288
+ display: none;
289
+ }
290
+ .app.nav-collapsed .sidebar-shell__header {
291
+ justify-content: center;
292
+ align-items: center;
293
+ gap: 0;
294
+ padding: 0 2px 16px;
295
+ }
296
+ .app.nav-collapsed .nav button {
297
+ justify-content: center;
298
+ width: 44px;
299
+ min-height: 44px;
300
+ padding: 0;
301
+ margin: 0 auto;
302
+ border-radius: 16px;
303
+ border-color: transparent;
304
+ box-shadow: none;
305
+ background: transparent;
306
+ }
307
+ .app.nav-collapsed .nav button .tab-labels {
308
+ display: none;
309
+ }
310
+ .app.nav-collapsed .nav button .tab-icon {
311
+ width: 18px;
312
+ height: 18px;
313
+ }
314
+ .app.nav-collapsed .nav button .tab-icon svg {
315
+ width: 18px;
316
+ height: 18px;
317
+ }
318
+ .app.nav-collapsed .nav button.active::before {
319
+ left: 8px;
320
+ top: 10px;
321
+ bottom: 10px;
322
+ }
323
+ .app.nav-collapsed .sidebar-shell__footer {
324
+ padding: 8px 0 2px;
325
+ }
326
+ .app.nav-collapsed .sidebar-utility {
327
+ display: none;
328
+ }
329
+ .app.nav-collapsed .sidebar-version {
330
+ width: 44px;
331
+ min-height: 44px;
332
+ padding: 0;
333
+ justify-content: center;
334
+ border-radius: 16px;
335
+ }
336
+ .app.nav-collapsed .sidebar-version__text {
337
+ display: none;
118
338
  }
119
339
 
120
340
  .nav {
121
341
  display: grid;
122
- gap: 8px;
342
+ gap: 4px;
343
+ min-height: 0;
344
+ overflow: auto;
345
+ padding: 0;
346
+ scrollbar-width: none;
347
+ }
348
+ .nav::-webkit-scrollbar { display: none; }
349
+ .sidebar-nav__label {
350
+ padding: 0 10px 8px;
351
+ color: var(--muted);
352
+ font-size: 12px;
353
+ font-weight: 700;
354
+ letter-spacing: 0.06em;
355
+ text-transform: uppercase;
123
356
  }
124
357
  .nav button {
358
+ position: relative;
359
+ display: flex;
360
+ align-items: center;
361
+ justify-content: flex-start;
362
+ gap: 8px;
363
+ min-height: 40px;
125
364
  text-align: left;
126
365
  border: 1px solid transparent;
127
366
  background: transparent;
128
367
  color: var(--muted);
129
- padding: 10px 12px;
130
- border-radius: 10px;
368
+ padding: 0 9px;
369
+ border-radius: 12px;
131
370
  cursor: pointer;
132
371
  font: inherit;
372
+ transition:
373
+ border-color .16s ease,
374
+ background .16s ease,
375
+ color .16s ease,
376
+ transform .16s ease;
377
+ }
378
+ .nav button .tab-icon {
379
+ width: 16px;
380
+ height: 16px;
381
+ display: inline-flex;
382
+ align-items: center;
383
+ justify-content: center;
384
+ flex-shrink: 0;
385
+ opacity: .72;
386
+ }
387
+ .nav button .tab-icon svg {
388
+ width: 16px;
389
+ height: 16px;
390
+ stroke: currentColor;
391
+ fill: none;
392
+ stroke-width: 1.5px;
393
+ stroke-linecap: round;
394
+ stroke-linejoin: round;
395
+ }
396
+ .nav button .tab-labels {
397
+ min-width: 0;
398
+ }
399
+ .nav button .tab-title {
400
+ display: block;
401
+ font-size: 14px;
402
+ font-weight: 600;
403
+ color: inherit;
404
+ white-space: nowrap;
405
+ }
406
+ .nav button .tab-copy {
407
+ display: none;
133
408
  }
134
409
  .nav button.active {
135
- color: #e9f7ff;
136
- border-color: color-mix(in srgb, var(--brand) 28%, transparent);
137
- background: var(--brand-soft);
410
+ color: var(--text-strong);
411
+ border-color: color-mix(in srgb, var(--accent) 18%, transparent);
412
+ background: color-mix(in srgb, var(--accent-subtle) 88%, var(--bg-elevated) 12%);
413
+ box-shadow: inset 0 1px 0 color-mix(in srgb, white 10%, transparent);
414
+ }
415
+ .nav button.active .tab-icon {
416
+ opacity: 1;
417
+ color: var(--accent);
418
+ }
419
+ .nav button:hover {
420
+ color: var(--text);
421
+ background: color-mix(in srgb, var(--bg-hover) 68%, transparent);
422
+ border-color: color-mix(in srgb, var(--border) 60%, transparent);
423
+ }
424
+ .nav button:hover .tab-icon {
425
+ opacity: 1;
138
426
  }
139
- .nav button:hover { color: #d2e7ff; }
140
427
 
141
428
  .sidebar-foot {
142
- margin-top: 20px;
143
- border-top: 1px dashed color-mix(in srgb, var(--line-strong) 85%, transparent);
144
- padding-top: 14px;
429
+ margin-top: 12px;
430
+ flex: 0 0 auto;
431
+ border-top: 1px solid color-mix(in srgb, var(--border) 80%, transparent);
432
+ padding-top: 12px;
145
433
  color: var(--muted);
146
434
  font-size: 12px;
147
435
  }
436
+ .sidebar-utility {
437
+ display: grid;
438
+ gap: 8px;
439
+ padding: 12px;
440
+ border-radius: 16px;
441
+ border: 1px solid color-mix(in srgb, var(--border) 72%, transparent);
442
+ background: var(--bg-elevated);
443
+ box-shadow: none;
444
+ }
445
+ .sidebar-utility-row {
446
+ display: flex;
447
+ align-items: center;
448
+ justify-content: space-between;
449
+ gap: 10px;
450
+ }
451
+ .sidebar-utility__label {
452
+ font-size: 11px;
453
+ font-weight: 700;
454
+ color: var(--muted);
455
+ text-transform: uppercase;
456
+ letter-spacing: 0.06em;
457
+ }
458
+ .sidebar-utility__value {
459
+ color: var(--text);
460
+ font-size: 12px;
461
+ font-weight: 600;
462
+ }
463
+ .sidebar-version {
464
+ margin-top: 10px;
465
+ display: flex;
466
+ align-items: center;
467
+ justify-content: space-between;
468
+ gap: 10px;
469
+ min-height: 40px;
470
+ padding: 0 12px;
471
+ border-radius: 14px;
472
+ background: var(--bg-elevated);
473
+ border: 1px solid color-mix(in srgb, var(--border) 72%, transparent);
474
+ box-shadow: none;
475
+ }
476
+ .sidebar-version__label {
477
+ display: inline-flex;
478
+ align-items: center;
479
+ gap: 6px;
480
+ font-size: 11px;
481
+ font-weight: 600;
482
+ color: var(--muted);
483
+ text-transform: uppercase;
484
+ letter-spacing: 0.06em;
485
+ }
486
+ .sidebar-version__text {
487
+ font-size: 12px;
488
+ color: var(--text);
489
+ font-weight: 600;
490
+ }
491
+ .sidebar-version__status {
492
+ width: 8px;
493
+ height: 8px;
494
+ border-radius: 999px;
495
+ flex-shrink: 0;
496
+ margin-left: auto;
497
+ background: var(--danger);
498
+ box-shadow: 0 0 0 4px color-mix(in srgb, var(--danger) 14%, transparent);
499
+ }
500
+ .sidebar-version__status.online {
501
+ background: var(--ok);
502
+ box-shadow: 0 0 0 4px color-mix(in srgb, var(--ok) 14%, transparent);
503
+ }
504
+ .app.nav-collapsed .sidebar-version {
505
+ justify-content: center;
506
+ padding: 0;
507
+ }
508
+ .app.nav-collapsed .sidebar-version__status {
509
+ margin-left: 0;
510
+ }
148
511
 
149
512
  .main {
150
- padding: 18px;
513
+ display: flex;
514
+ flex-direction: column;
515
+ min-width: 0;
516
+ min-height: 0;
517
+ height: 100vh;
518
+ overflow: hidden;
519
+ padding: 0;
151
520
  }
152
521
  .topbar {
522
+ flex: 0 0 auto;
153
523
  display: flex;
154
524
  justify-content: space-between;
155
- gap: 10px;
525
+ gap: 12px;
156
526
  align-items: center;
157
- margin-bottom: 14px;
527
+ min-height: 52px;
528
+ padding: 0 24px;
529
+ border-bottom: 1px solid color-mix(in srgb, var(--border) 74%, transparent);
530
+ background: var(--chrome);
531
+ backdrop-filter: blur(12px) saturate(1.6);
532
+ -webkit-backdrop-filter: blur(12px) saturate(1.6);
158
533
  }
159
534
  .topbar h2 {
535
+ display: none;
160
536
  margin: 0;
161
- font-size: 22px;
162
537
  }
163
538
  .topbar p {
164
- margin: 4px 0 0;
539
+ display: none;
540
+ margin: 0;
165
541
  color: var(--muted);
166
- font-size: 13px;
542
+ font-size: 12px;
543
+ white-space: nowrap;
544
+ overflow: hidden;
545
+ text-overflow: ellipsis;
546
+ }
547
+ .dashboard-header__breadcrumb {
548
+ display: flex;
549
+ align-items: center;
550
+ gap: 8px;
551
+ min-width: 0;
552
+ overflow: hidden;
553
+ font-size: 12px;
554
+ margin-bottom: 2px;
555
+ letter-spacing: 0.01em;
556
+ }
557
+ .dashboard-header__breadcrumb-link,
558
+ .dashboard-header__breadcrumb-sep {
559
+ color: var(--muted);
560
+ }
561
+ .dashboard-header__breadcrumb-current {
562
+ color: var(--text-strong);
563
+ font-weight: 650;
564
+ white-space: nowrap;
565
+ overflow: hidden;
566
+ text-overflow: ellipsis;
167
567
  }
168
568
 
569
+ .topnav-shell__content {
570
+ min-width: 0;
571
+ flex: 1;
572
+ overflow: hidden;
573
+ }
574
+ .main-scroll {
575
+ flex: 1 1 auto;
576
+ min-height: 0;
577
+ overflow: auto;
578
+ padding: 12px 18px 18px;
579
+ }
169
580
  .status-row {
170
581
  display: flex;
171
582
  gap: 8px;
172
- flex-wrap: wrap;
583
+ flex-wrap: nowrap;
173
584
  align-items: center;
585
+ flex-shrink: 0;
586
+ min-width: max-content;
174
587
  }
175
- .theme-switch {
588
+ .topbar-actions {
176
589
  display: inline-flex;
177
- gap: 4px;
178
- padding: 3px;
590
+ align-items: center;
591
+ gap: 8px;
592
+ }
593
+ .icon-btn {
594
+ width: 30px;
595
+ height: 30px;
596
+ display: inline-flex;
597
+ align-items: center;
598
+ justify-content: center;
179
599
  border-radius: 999px;
180
- border: 1px solid var(--line);
600
+ border: 1px solid color-mix(in srgb, var(--border) 86%, transparent);
181
601
  background: var(--bg-elevated);
602
+ color: var(--muted);
603
+ padding: 0;
182
604
  }
183
- .theme-switch button {
605
+ .icon-btn:hover {
606
+ color: var(--text-strong);
607
+ border-color: color-mix(in srgb, var(--accent) 28%, transparent);
608
+ background: color-mix(in srgb, var(--accent-subtle) 65%, var(--bg-elevated));
609
+ }
610
+ .icon-btn.active {
611
+ color: var(--text-strong);
612
+ border-color: color-mix(in srgb, var(--accent) 34%, transparent);
613
+ background: var(--accent-subtle);
614
+ }
615
+ .icon-btn svg {
616
+ width: 15px;
617
+ height: 15px;
618
+ stroke: currentColor;
619
+ }
620
+ .topbar-theme-mode {
621
+ display: inline-flex;
622
+ align-items: center;
623
+ gap: 2px;
624
+ padding: 3px;
625
+ border: 1px solid color-mix(in srgb, var(--border) 84%, transparent);
626
+ border-radius: 999px;
627
+ background: color-mix(in srgb, var(--bg-elevated) 78%, transparent);
628
+ }
629
+ .topbar-theme-mode__btn {
630
+ width: 30px;
631
+ height: 30px;
632
+ display: inline-flex;
633
+ align-items: center;
634
+ justify-content: center;
635
+ padding: 0;
184
636
  border: 1px solid transparent;
637
+ border-radius: 999px;
185
638
  background: transparent;
186
639
  color: var(--muted);
187
- border-radius: 999px;
188
- padding: 5px 10px;
189
- font-size: 12px;
190
- font-weight: 600;
640
+ cursor: pointer;
641
+ transition:
642
+ color var(--duration-fast) ease,
643
+ background var(--duration-fast) ease,
644
+ border-color var(--duration-fast) ease;
191
645
  }
192
- .theme-switch button.active {
193
- color: var(--text-strong);
194
- background: var(--brand-soft);
195
- border-color: color-mix(in srgb, var(--brand) 24%, transparent);
646
+ .topbar-theme-mode__btn:hover {
647
+ color: var(--text);
648
+ background: var(--bg-hover);
649
+ }
650
+ .topbar-theme-mode__btn:focus-visible {
651
+ outline: none;
652
+ box-shadow: var(--focus-ring);
653
+ }
654
+ .topbar-theme-mode__btn--active {
655
+ color: var(--accent);
656
+ background: var(--accent-subtle);
657
+ border-color: color-mix(in srgb, var(--accent) 25%, transparent);
658
+ }
659
+ .topbar-theme-mode__btn svg {
660
+ width: 14px;
661
+ height: 14px;
662
+ stroke: currentColor;
663
+ fill: none;
664
+ stroke-width: 1.75px;
665
+ stroke-linecap: round;
666
+ stroke-linejoin: round;
667
+ }
668
+ .theme-icon {
669
+ width: 14px;
670
+ height: 14px;
671
+ display: inline-flex;
672
+ align-items: center;
673
+ justify-content: center;
674
+ }
675
+ .theme-icon svg {
676
+ width: 14px;
677
+ height: 14px;
678
+ stroke: currentColor;
679
+ fill: none;
680
+ stroke-width: 1.75px;
681
+ stroke-linecap: round;
682
+ stroke-linejoin: round;
196
683
  }
197
684
  .pill {
198
685
  border-radius: 999px;
199
- border: 1px solid var(--line);
200
- background: var(--bg-elevated);
686
+ border: 1px solid color-mix(in srgb, var(--border) 86%, transparent);
687
+ background: color-mix(in srgb, var(--bg-elevated) 96%, transparent);
201
688
  color: var(--muted);
202
- padding: 7px 11px;
689
+ padding: 6px 10px;
203
690
  font-size: 12px;
691
+ font-weight: 500;
692
+ min-height: 32px;
693
+ display: inline-flex;
694
+ align-items: center;
695
+ box-shadow: inset 0 1px 0 color-mix(in srgb, white 4%, transparent);
204
696
  }
205
697
  .pill.ok { color: var(--ok); border-color: rgba(34, 197, 94, 0.45); background: rgba(34, 197, 94, 0.08); }
206
698
  .pill.warn { color: var(--warn); border-color: rgba(245, 158, 11, 0.45); background: rgba(245, 158, 11, 0.08); }
@@ -208,8 +700,8 @@
208
700
  .notice {
209
701
  display: none;
210
702
  margin-bottom: 12px;
211
- border: 1px solid color-mix(in srgb, var(--brand) 28%, transparent);
212
- background: var(--brand-soft);
703
+ border: 1px solid color-mix(in srgb, var(--accent) 28%, transparent);
704
+ background: var(--accent-subtle);
213
705
  border-radius: 10px;
214
706
  padding: 10px 12px;
215
707
  font-size: 13px;
@@ -219,13 +711,16 @@
219
711
  position: sticky;
220
712
  top: 0;
221
713
  z-index: 9;
222
- margin-bottom: 12px;
223
- border: 1px solid var(--line);
224
- border-radius: 10px;
225
- background: color-mix(in srgb, var(--bg-elevated) 92%, transparent);
226
- padding: 9px 12px;
227
- font-size: 13px;
714
+ margin-bottom: 8px;
715
+ border: 1px solid color-mix(in srgb, var(--border) 82%, transparent);
716
+ border-radius: 14px;
717
+ background:
718
+ linear-gradient(180deg, color-mix(in srgb, var(--card-soft) 98%, transparent), color-mix(in srgb, var(--bg-elevated) 94%, transparent));
719
+ padding: 8px 12px;
720
+ font-size: 12px;
721
+ line-height: 1.45;
228
722
  color: var(--text);
723
+ box-shadow: inset 0 1px 0 color-mix(in srgb, white 4%, transparent);
229
724
  }
230
725
  .integration-strip.ok {
231
726
  border-color: rgba(34, 197, 94, 0.35);
@@ -233,40 +728,157 @@
233
728
  .integration-strip.warn {
234
729
  border-color: rgba(245, 158, 11, 0.35);
235
730
  }
731
+ .page-hero {
732
+ display: grid;
733
+ grid-template-columns: 1.2fr .8fr;
734
+ gap: 10px;
735
+ margin-bottom: 8px;
736
+ }
737
+ .hero-copy {
738
+ border: 1px solid color-mix(in srgb, var(--border) 84%, transparent);
739
+ border-radius: 16px;
740
+ background:
741
+ linear-gradient(180deg, color-mix(in srgb, var(--card-strong) 98%, transparent), color-mix(in srgb, var(--card-soft) 96%, transparent));
742
+ padding: 11px 14px;
743
+ box-shadow:
744
+ inset 0 1px 0 color-mix(in srgb, white 4%, transparent),
745
+ 0 10px 24px color-mix(in srgb, black 9%, transparent);
746
+ }
747
+ .hero-copy h3 {
748
+ margin: 0;
749
+ font-size: 17px;
750
+ color: var(--text-strong);
751
+ letter-spacing: -0.02em;
752
+ }
753
+ .hero-copy p {
754
+ margin: 5px 0 0;
755
+ color: var(--muted);
756
+ font-size: 12px;
757
+ line-height: 1.42;
758
+ }
759
+ .hero-meta {
760
+ border: 1px solid color-mix(in srgb, var(--border) 84%, transparent);
761
+ border-radius: 16px;
762
+ background:
763
+ linear-gradient(180deg, color-mix(in srgb, var(--bg-elevated) 97%, transparent), color-mix(in srgb, var(--panel) 98%, transparent));
764
+ padding: 11px;
765
+ box-shadow: inset 0 1px 0 color-mix(in srgb, white 4%, transparent);
766
+ }
767
+ .hero-meta-grid {
768
+ display: grid;
769
+ grid-template-columns: repeat(2, minmax(0, 1fr));
770
+ gap: 6px;
771
+ }
772
+ .hero-meta-item {
773
+ border: 1px solid color-mix(in srgb, var(--border) 76%, transparent);
774
+ border-radius: 12px;
775
+ background: color-mix(in srgb, var(--panel) 90%, transparent);
776
+ padding: 7px 9px;
777
+ }
236
778
 
237
779
  .view { display: none; }
238
- .view.active { display: block; }
780
+ .view.active {
781
+ display: grid;
782
+ gap: 8px;
783
+ }
784
+
785
+ .section-header {
786
+ display: flex;
787
+ align-items: center;
788
+ justify-content: space-between;
789
+ gap: 12px;
790
+ min-width: 0;
791
+ }
792
+ .section-header__copy {
793
+ min-width: 0;
794
+ }
795
+ .section-header__eyebrow {
796
+ margin: 0 0 3px;
797
+ color: var(--muted);
798
+ font-size: 11px;
799
+ font-weight: 700;
800
+ letter-spacing: 0.08em;
801
+ text-transform: uppercase;
802
+ }
803
+ .section-header__title {
804
+ margin: 0;
805
+ color: var(--text-strong);
806
+ font-size: 16px;
807
+ letter-spacing: -0.02em;
808
+ }
809
+ .section-header__body {
810
+ margin: 4px 0 0;
811
+ color: var(--muted);
812
+ font-size: 12px;
813
+ line-height: 1.45;
814
+ }
815
+ .section-surface {
816
+ border: 1px solid color-mix(in srgb, var(--border) 84%, transparent);
817
+ border-radius: 16px;
818
+ background:
819
+ linear-gradient(180deg, color-mix(in srgb, var(--card-strong) 98%, transparent), color-mix(in srgb, var(--card-soft) 96%, transparent));
820
+ padding: 12px;
821
+ box-shadow:
822
+ inset 0 1px 0 color-mix(in srgb, white 4%, transparent),
823
+ 0 14px 30px color-mix(in srgb, black 10%, transparent);
824
+ }
825
+ .section-surface.compact {
826
+ padding: 10px 12px;
827
+ }
239
828
 
240
829
  .grid {
241
830
  display: grid;
242
- gap: 10px;
831
+ gap: 8px;
243
832
  grid-template-columns: repeat(4, minmax(0, 1fr));
244
833
  }
834
+ #networkCards,
835
+ #socialPrimaryCards,
836
+ #socialIntegrationCards,
837
+ #socialAdvancedCards {
838
+ grid-template-columns: repeat(3, minmax(0, 1fr));
839
+ }
245
840
  .card {
246
- border: 1px solid var(--line);
247
- border-radius: 14px;
248
- background: var(--card);
841
+ border: 1px solid color-mix(in srgb, var(--border) 84%, transparent);
842
+ border-radius: 16px;
843
+ background:
844
+ linear-gradient(180deg, color-mix(in srgb, var(--card-strong) 98%, transparent), color-mix(in srgb, var(--card-soft) 96%, transparent));
249
845
  padding: 12px;
250
- box-shadow: 0 1px 2px rgba(0,0,0,0.25);
846
+ box-shadow:
847
+ inset 0 1px 0 color-mix(in srgb, white 4%, transparent),
848
+ 0 14px 30px color-mix(in srgb, black 10%, transparent);
849
+ transition: border-color .16s ease, transform .16s ease, box-shadow .16s ease;
850
+ }
851
+ .card:hover {
852
+ border-color: color-mix(in srgb, var(--accent) 14%, var(--border));
853
+ box-shadow:
854
+ inset 0 1px 0 color-mix(in srgb, white 4%, transparent),
855
+ 0 18px 36px color-mix(in srgb, black 14%, transparent);
251
856
  }
252
857
  .label { font-size: 12px; color: var(--muted); }
253
- .value { margin-top: 4px; font-size: 24px; font-weight: 800; }
858
+ .value { margin-top: 4px; font-size: 22px; font-weight: 800; letter-spacing: -0.03em; }
254
859
 
255
860
  .split {
256
- margin-top: 10px;
861
+ margin-top: 8px;
257
862
  display: grid;
258
- gap: 10px;
863
+ gap: 8px;
259
864
  grid-template-columns: 1.2fr 1fr;
260
865
  }
261
- .title-sm { margin: 0 0 10px; font-size: 18px; }
866
+ .title-sm { margin: 0 0 10px; font-size: 16px; letter-spacing: -0.02em; }
262
867
  .mono { font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12px; }
263
868
 
264
869
  .table {
265
870
  width: 100%;
266
871
  border-collapse: collapse;
267
872
  }
873
+ .table thead th {
874
+ color: var(--muted);
875
+ font-size: 11px;
876
+ font-weight: 700;
877
+ text-transform: uppercase;
878
+ letter-spacing: 0.07em;
879
+ }
268
880
  .table th, .table td {
269
- border-bottom: 1px solid var(--line);
881
+ border-bottom: 1px solid var(--border);
270
882
  text-align: left;
271
883
  padding: 8px 6px;
272
884
  font-size: 13px;
@@ -281,22 +893,33 @@
281
893
  input, textarea {
282
894
  margin-top: 5px;
283
895
  width: 100%;
284
- border-radius: 10px;
285
- border: 1px solid var(--line);
286
- background: var(--bg-elevated);
287
- color: #eaf0ff;
896
+ border-radius: 12px;
897
+ border: 1px solid color-mix(in srgb, var(--border) 84%, transparent);
898
+ background: linear-gradient(180deg, color-mix(in srgb, var(--bg-elevated) 98%, transparent), color-mix(in srgb, var(--panel) 96%, transparent));
899
+ color: var(--text);
288
900
  font: inherit;
289
901
  padding: 10px;
902
+ box-shadow: inset 0 1px 0 color-mix(in srgb, white 3%, transparent);
290
903
  }
291
904
  select {
292
905
  margin-top: 5px;
293
906
  width: 100%;
294
- border-radius: 10px;
295
- border: 1px solid var(--line);
296
- background: var(--bg-elevated);
907
+ border-radius: 12px;
908
+ border: 1px solid color-mix(in srgb, var(--border) 84%, transparent);
909
+ background: linear-gradient(180deg, color-mix(in srgb, var(--bg-elevated) 98%, transparent), color-mix(in srgb, var(--panel) 96%, transparent));
297
910
  color: var(--text);
298
911
  font: inherit;
299
912
  padding: 10px;
913
+ box-shadow: inset 0 1px 0 color-mix(in srgb, white 3%, transparent);
914
+ }
915
+ input:focus,
916
+ textarea:focus,
917
+ select:focus {
918
+ outline: none;
919
+ border-color: color-mix(in srgb, var(--accent) 34%, transparent);
920
+ box-shadow:
921
+ inset 0 1px 0 color-mix(in srgb, white 3%, transparent),
922
+ 0 0 0 3px color-mix(in srgb, var(--accent) 14%, transparent);
300
923
  }
301
924
  textarea { min-height: 90px; resize: vertical; }
302
925
 
@@ -305,28 +928,87 @@
305
928
  gap: 8px;
306
929
  flex-wrap: wrap;
307
930
  }
931
+ .actions button,
932
+ .action-bar button,
933
+ .toolbar button {
934
+ min-height: 38px;
935
+ }
936
+ .action-bar {
937
+ display: flex;
938
+ gap: 8px;
939
+ flex-wrap: wrap;
940
+ margin-bottom: 8px;
941
+ padding: 2px 0 0;
942
+ }
943
+ .summary-list {
944
+ display: grid;
945
+ gap: 8px;
946
+ }
947
+ .summary-item {
948
+ display: grid;
949
+ gap: 3px;
950
+ padding: 10px;
951
+ border-radius: 12px;
952
+ border: 1px solid color-mix(in srgb, var(--border) 82%, transparent);
953
+ background: linear-gradient(180deg, color-mix(in srgb, var(--bg-elevated) 98%, transparent), color-mix(in srgb, var(--panel) 94%, transparent));
954
+ box-shadow: inset 0 1px 0 color-mix(in srgb, white 4%, transparent);
955
+ }
956
+ .empty-state {
957
+ border: 1px dashed color-mix(in srgb, var(--border-strong) 88%, transparent);
958
+ border-radius: 14px;
959
+ padding: 18px;
960
+ color: var(--muted);
961
+ background: linear-gradient(180deg, color-mix(in srgb, var(--panel) 94%, transparent), color-mix(in srgb, var(--bg-elevated) 88%, transparent));
962
+ line-height: 1.55;
963
+ }
308
964
  button {
309
965
  border: 1px solid transparent;
310
- border-radius: 10px;
311
- background: var(--brand);
966
+ border-radius: 12px;
967
+ background: var(--accent);
312
968
  color: #ffffff;
313
969
  font-weight: 700;
314
970
  padding: 9px 13px;
315
971
  cursor: pointer;
972
+ box-shadow: 0 10px 20px color-mix(in srgb, var(--accent) 16%, transparent);
973
+ }
974
+ button:hover {
975
+ transform: translateY(-1px);
976
+ filter: saturate(1.04);
977
+ }
978
+ .nav button,
979
+ .nav-collapse-toggle,
980
+ .icon-btn,
981
+ .topbar-theme-mode__btn {
982
+ box-shadow: none;
983
+ filter: none;
984
+ }
985
+ .nav button,
986
+ .nav-collapse-toggle,
987
+ .icon-btn {
988
+ background: transparent;
989
+ color: var(--muted);
990
+ }
991
+ .nav button:hover,
992
+ .nav-collapse-toggle:hover,
993
+ .icon-btn:hover,
994
+ .topbar-theme-mode__btn:hover {
995
+ filter: none;
316
996
  }
317
997
  button.secondary {
318
- border-color: var(--line-strong);
319
- background: var(--bg-elevated);
998
+ border-color: var(--border-strong);
999
+ background: color-mix(in srgb, var(--bg-elevated) 96%, transparent);
320
1000
  color: var(--text);
1001
+ box-shadow: none;
321
1002
  }
322
1003
 
323
1004
  .feedback {
324
- border: 1px solid var(--line);
325
- border-radius: 10px;
326
- background: var(--bg-elevated);
327
- padding: 9px;
1005
+ border: 1px solid color-mix(in srgb, var(--border) 84%, transparent);
1006
+ border-radius: 12px;
1007
+ background: linear-gradient(180deg, color-mix(in srgb, var(--bg-elevated) 98%, transparent), color-mix(in srgb, var(--panel) 96%, transparent));
1008
+ padding: 10px 11px;
328
1009
  font-size: 13px;
329
1010
  color: var(--muted);
1011
+ box-shadow: inset 0 1px 0 color-mix(in srgb, white 4%, transparent);
330
1012
  }
331
1013
  .profile-layout {
332
1014
  display: grid;
@@ -334,10 +1016,11 @@
334
1016
  grid-template-columns: 1.1fr .9fr;
335
1017
  }
336
1018
  .profile-meta {
337
- border: 1px solid var(--line);
338
- border-radius: 10px;
1019
+ border: 1px solid color-mix(in srgb, var(--border) 82%, transparent);
1020
+ border-radius: 12px;
339
1021
  padding: 10px;
340
- background: color-mix(in srgb, var(--card) 86%, transparent);
1022
+ background: linear-gradient(180deg, color-mix(in srgb, var(--card-soft) 98%, transparent), color-mix(in srgb, var(--bg-elevated) 90%, transparent));
1023
+ box-shadow: inset 0 1px 0 color-mix(in srgb, white 4%, transparent);
341
1024
  }
342
1025
  .profile-meta h4 {
343
1026
  margin: 0 0 8px;
@@ -362,9 +1045,9 @@
362
1045
  flex-wrap: wrap;
363
1046
  }
364
1047
  .tag-chip {
365
- border: 1px solid var(--line-strong);
1048
+ border: 1px solid var(--border-strong);
366
1049
  border-radius: 999px;
367
- background: var(--chip);
1050
+ background: var(--bg-hover);
368
1051
  color: var(--text);
369
1052
  padding: 3px 9px;
370
1053
  font-size: 12px;
@@ -377,14 +1060,15 @@
377
1060
  margin-top: 4px;
378
1061
  color: var(--muted);
379
1062
  font-size: 12px;
1063
+ line-height: 1.45;
380
1064
  }
381
1065
  .field-error {
382
1066
  margin-top: 4px;
383
- color: var(--err);
1067
+ color: var(--danger);
384
1068
  font-size: 12px;
385
1069
  }
386
1070
  .input-invalid {
387
- border-color: color-mix(in srgb, var(--err) 55%, transparent);
1071
+ border-color: color-mix(in srgb, var(--danger) 55%, transparent);
388
1072
  }
389
1073
  .save-busy {
390
1074
  opacity: 0.7;
@@ -394,46 +1078,71 @@
394
1078
  .logs {
395
1079
  max-height: 420px;
396
1080
  overflow: auto;
397
- border: 1px solid var(--line);
398
- border-radius: 12px;
399
- background: var(--panel);
1081
+ border: 1px solid color-mix(in srgb, var(--border) 82%, transparent);
1082
+ border-radius: 14px;
1083
+ background: linear-gradient(180deg, color-mix(in srgb, var(--panel) 96%, transparent), color-mix(in srgb, var(--bg-elevated) 90%, transparent));
400
1084
  padding: 10px;
1085
+ box-shadow: inset 0 1px 0 color-mix(in srgb, white 3%, transparent);
401
1086
  }
402
1087
  .log-item {
403
- border-bottom: 1px dashed var(--line);
1088
+ border-bottom: 1px dashed var(--border);
404
1089
  padding: 7px 0;
405
1090
  }
406
1091
  .log-item:last-child { border-bottom: 0; }
407
1092
  .log-info { color: #8dc6ff; }
408
1093
  .log-warn { color: var(--warn); }
409
- .log-error { color: var(--err); }
1094
+ .log-error { color: var(--danger); }
410
1095
  .toolbar {
411
1096
  display: flex;
412
1097
  gap: 10px;
413
1098
  flex-wrap: wrap;
414
1099
  align-items: end;
415
1100
  margin-bottom: 10px;
1101
+ padding-bottom: 2px;
416
1102
  }
417
1103
  .toolbar .field {
418
1104
  min-width: 180px;
419
1105
  }
420
1106
  .mono-block {
421
- border: 1px solid var(--line);
422
- border-radius: 10px;
423
- background: color-mix(in srgb, var(--bg-elevated) 85%, transparent);
1107
+ border: 1px solid color-mix(in srgb, var(--border) 82%, transparent);
1108
+ border-radius: 12px;
1109
+ background: linear-gradient(180deg, color-mix(in srgb, var(--bg-elevated) 96%, transparent), color-mix(in srgb, var(--panel) 92%, transparent));
424
1110
  padding: 10px;
425
1111
  max-height: 240px;
426
1112
  overflow: auto;
427
1113
  white-space: pre-wrap;
428
1114
  word-break: break-word;
1115
+ box-shadow: inset 0 1px 0 color-mix(in srgb, white 3%, transparent);
1116
+ }
1117
+ .advanced-panel {
1118
+ margin-top: 8px;
1119
+ }
1120
+ .advanced-panel.card > summary,
1121
+ details.card > summary {
1122
+ display: flex;
1123
+ align-items: center;
1124
+ justify-content: space-between;
1125
+ }
1126
+ .advanced-panel summary {
1127
+ cursor: pointer;
1128
+ list-style: none;
1129
+ user-select: none;
429
1130
  }
1131
+ .advanced-panel summary::-webkit-details-marker { display: none; }
1132
+ .advanced-panel summary::after {
1133
+ content: "Show";
1134
+ float: right;
1135
+ color: var(--muted);
1136
+ font-size: 12px;
1137
+ }
1138
+ .advanced-panel[open] summary::after { content: "Hide"; }
430
1139
 
431
1140
  .toast {
432
1141
  position: fixed;
433
1142
  right: 16px;
434
1143
  bottom: 16px;
435
1144
  background: var(--bg-elevated);
436
- border: 1px solid color-mix(in srgb, var(--brand) 32%, transparent);
1145
+ border: 1px solid color-mix(in srgb, var(--accent) 32%, transparent);
437
1146
  color: var(--text);
438
1147
  border-radius: 10px;
439
1148
  padding: 10px 12px;
@@ -449,69 +1158,231 @@
449
1158
  transform: translateY(0);
450
1159
  }
451
1160
 
1161
+ #view-overview .action-bar {
1162
+ margin-bottom: 0;
1163
+ }
1164
+ #view-overview .grid {
1165
+ grid-template-columns: repeat(4, minmax(0, 1fr));
1166
+ }
1167
+ #view-overview .card .field-hint {
1168
+ font-size: 12px;
1169
+ }
1170
+ #view-overview #snapshot {
1171
+ line-height: 1.55;
1172
+ }
1173
+
452
1174
  @media (max-width: 980px) {
453
- .app { grid-template-columns: 1fr; }
454
- .sidebar { border-right: 0; border-bottom: 1px solid var(--line); }
455
- .nav { grid-template-columns: repeat(3, minmax(0,1fr)); }
1175
+ html, body {
1176
+ height: auto;
1177
+ overflow: auto;
1178
+ }
1179
+ .app {
1180
+ grid-template-columns: 1fr;
1181
+ height: auto;
1182
+ overflow: visible;
1183
+ }
1184
+ .sidebar {
1185
+ border-right: 0;
1186
+ border-bottom: 1px solid var(--border);
1187
+ height: auto;
1188
+ overflow: visible;
1189
+ }
1190
+ .sidebar-shell {
1191
+ display: block;
1192
+ }
1193
+ .nav { grid-template-columns: repeat(2, minmax(0,1fr)); }
456
1194
  .grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
457
- .split, .row, .profile-layout { grid-template-columns: 1fr; }
1195
+ .split, .row, .profile-layout, .page-hero { grid-template-columns: 1fr; }
1196
+ .main {
1197
+ height: auto;
1198
+ overflow: visible;
1199
+ padding-bottom: 18px;
1200
+ }
1201
+ .main-scroll {
1202
+ overflow: visible;
1203
+ padding-right: 0;
1204
+ }
458
1205
  }
459
1206
  </style>
460
1207
  </head>
461
1208
  <body>
462
- <div class="app">
1209
+ <div class="app" id="appShell">
463
1210
  <aside class="sidebar">
464
- <div class="brand">
465
- <img id="brandLogo" class="brand-logo" src="/assets/silicaclaw-logo.png" alt="SilicaClaw logo" />
466
- <div id="brandFallback" class="brand-badge hidden">SC</div>
467
- <div>
468
- <h1>SilicaClaw</h1>
469
- <p>Control UI</p>
1211
+ <div class="sidebar-shell">
1212
+ <div class="sidebar-shell__header">
1213
+ <div class="brand">
1214
+ <img id="brandLogo" class="brand-logo" src="/assets/silicaclaw-logo.png" alt="SilicaClaw logo" />
1215
+ <div id="brandFallback" class="brand-badge hidden">SC</div>
1216
+ <div>
1217
+ <h1>SilicaClaw</h1>
1218
+ <p>Control UI</p>
1219
+ </div>
1220
+ </div>
1221
+ <button class="nav-collapse-toggle" id="sidebarToggleBtn" type="button" title="Collapse sidebar" aria-label="Collapse sidebar">
1222
+ <span class="nav-collapse-toggle__icon" aria-hidden="true">
1223
+ <svg viewBox="0 0 24 24">
1224
+ <rect x="3" y="3" width="18" height="18" rx="2"></rect>
1225
+ <path d="M9 3v18"></path>
1226
+ <path d="M16 10l-3 2 3 2"></path>
1227
+ </svg>
1228
+ </span>
1229
+ </button>
1230
+ </div>
1231
+ <div class="sidebar-shell__body">
1232
+ <div class="sidebar-nav__label">Control</div>
1233
+ <nav class="nav">
1234
+ <button class="tab active" data-tab="overview">
1235
+ <span class="tab-icon" aria-hidden="true">
1236
+ <svg viewBox="0 0 24 24">
1237
+ <line x1="12" x2="12" y1="20" y2="10"></line>
1238
+ <line x1="18" x2="18" y1="20" y2="4"></line>
1239
+ <line x1="6" x2="6" y1="20" y2="16"></line>
1240
+ </svg>
1241
+ </span>
1242
+ <span class="tab-labels"><span class="tab-title">Overview</span><span class="tab-copy">Agent summary and discovered peers</span></span>
1243
+ </button>
1244
+ <button class="tab" data-tab="profile">
1245
+ <span class="tab-icon" aria-hidden="true">
1246
+ <svg viewBox="0 0 24 24">
1247
+ <path d="M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z"></path>
1248
+ <polyline points="14 2 14 8 20 8"></polyline>
1249
+ <line x1="16" x2="8" y1="13" y2="13"></line>
1250
+ <line x1="16" x2="8" y1="17" y2="17"></line>
1251
+ <line x1="10" x2="8" y1="9" y2="9"></line>
1252
+ </svg>
1253
+ </span>
1254
+ <span class="tab-labels"><span class="tab-title">Profile</span><span class="tab-copy">Public identity and saved profile</span></span>
1255
+ </button>
1256
+ <button class="tab" data-tab="network">
1257
+ <span class="tab-icon" aria-hidden="true">
1258
+ <svg viewBox="0 0 24 24">
1259
+ <circle cx="12" cy="12" r="2"></circle>
1260
+ <path d="M16.24 7.76a6 6 0 0 1 0 8.49m-8.48-.01a6 6 0 0 1 0-8.49m11.31-2.82a10 10 0 0 1 0 14.14m-14.14 0a10 10 0 0 1 0-14.14"></path>
1261
+ </svg>
1262
+ </span>
1263
+ <span class="tab-labels"><span class="tab-title">Network</span><span class="tab-copy">Relay health, broadcast, diagnostics</span></span>
1264
+ </button>
1265
+ <button class="tab" data-tab="social">
1266
+ <span class="tab-icon" aria-hidden="true">
1267
+ <svg viewBox="0 0 24 24">
1268
+ <path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path>
1269
+ </svg>
1270
+ </span>
1271
+ <span class="tab-labels"><span class="tab-title">Social</span><span class="tab-copy">social.md config and runtime state</span></span>
1272
+ </button>
1273
+ </nav>
1274
+ </div>
1275
+ <div class="sidebar-shell__footer">
1276
+ <div class="sidebar-foot sidebar-utility" id="sideMeta">
1277
+ <div class="sidebar-utility-row"><span class="sidebar-utility__label">Adapter</span><span class="sidebar-utility__value">-</span></div>
1278
+ <div class="sidebar-utility-row"><span class="sidebar-utility__label">Namespace</span><span class="sidebar-utility__value">-</span></div>
1279
+ <div class="sidebar-utility-row"><span class="sidebar-utility__label">Port</span><span class="sidebar-utility__value">-</span></div>
1280
+ </div>
1281
+ <div class="sidebar-version" title="Current version">
1282
+ <span class="sidebar-version__label"><span class="version-dot"></span>Version</span>
1283
+ <span class="sidebar-version__text" id="brandVersion">-</span>
1284
+ <span class="sidebar-version__status" id="brandStatusDot" aria-hidden="true"></span>
1285
+ </div>
470
1286
  </div>
471
1287
  </div>
472
-
473
- <nav class="nav">
474
- <button class="tab active" data-tab="overview">Overview</button>
475
- <button class="tab" data-tab="profile">Profile</button>
476
- <button class="tab" data-tab="network">Network</button>
477
- <button class="tab" data-tab="peers">Peers</button>
478
- <button class="tab" data-tab="discovery">Discovery Events</button>
479
- <button class="tab" data-tab="social">Social Config</button>
480
- <button class="tab" data-tab="logs">Logs</button>
481
- </nav>
482
-
483
- <div class="sidebar-foot" id="sideMeta">adapter: -<br/>namespace: -</div>
484
1288
  </aside>
485
1289
 
486
1290
  <main class="main">
487
1291
  <div class="topbar">
488
- <div>
1292
+ <div class="topnav-shell__content">
1293
+ <div class="dashboard-header__breadcrumb">
1294
+ <span class="dashboard-header__breadcrumb-link">SilicaClaw</span>
1295
+ <span class="dashboard-header__breadcrumb-sep">/</span>
1296
+ <span class="dashboard-header__breadcrumb-current" id="pageBreadcrumb">Overview</span>
1297
+ </div>
489
1298
  <h2>Local Console</h2>
490
1299
  <p>OpenClaw-inspired local-first agent control surface</p>
491
1300
  </div>
492
1301
  <div class="status-row">
493
1302
  <div class="pill" id="pillAdapter">adapter: -</div>
494
1303
  <div class="pill" id="pillBroadcast">broadcast: -</div>
495
- <div class="theme-switch">
496
- <button id="themeDarkBtn" type="button">Dark</button>
497
- <button id="themeLightBtn" type="button">Light</button>
1304
+ <div class="topbar-actions">
1305
+ <button class="icon-btn" id="focusModeBtn" type="button" title="Toggle focus mode" aria-label="Toggle focus mode">
1306
+ <svg viewBox="0 0 24 24" fill="none" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
1307
+ <path d="M4 7V4h3"></path>
1308
+ <path d="M20 7V4h-3"></path>
1309
+ <path d="M4 17v3h3"></path>
1310
+ <path d="M20 17v3h-3"></path>
1311
+ <circle cx="12" cy="12" r="3"></circle>
1312
+ </svg>
1313
+ </button>
1314
+ <div class="topbar-theme-mode" id="themeModeGroup" role="group" aria-label="Color mode">
1315
+ <button class="topbar-theme-mode__btn" data-theme-choice="dark" type="button" title="Dark" aria-label="Color mode: Dark">
1316
+ <span class="theme-icon" aria-hidden="true">
1317
+ <svg viewBox="0 0 24 24">
1318
+ <path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9z"></path>
1319
+ </svg>
1320
+ </span>
1321
+ </button>
1322
+ <button class="topbar-theme-mode__btn" data-theme-choice="light" type="button" title="Light" aria-label="Color mode: Light">
1323
+ <span class="theme-icon" aria-hidden="true">
1324
+ <svg viewBox="0 0 24 24">
1325
+ <circle cx="12" cy="12" r="4"></circle>
1326
+ <path d="M12 2v2"></path>
1327
+ <path d="M12 20v2"></path>
1328
+ <path d="M4.93 4.93l1.41 1.41"></path>
1329
+ <path d="M17.66 17.66l1.41 1.41"></path>
1330
+ <path d="M2 12h2"></path>
1331
+ <path d="M20 12h2"></path>
1332
+ <path d="M4.93 19.07l1.41-1.41"></path>
1333
+ <path d="M17.66 6.34l1.41-1.41"></path>
1334
+ </svg>
1335
+ </span>
1336
+ </button>
1337
+ <button class="topbar-theme-mode__btn" data-theme-choice="system" type="button" title="System" aria-label="Color mode: System">
1338
+ <span class="theme-icon" aria-hidden="true">
1339
+ <svg viewBox="0 0 24 24">
1340
+ <rect x="3" y="4" width="18" height="12" rx="2"></rect>
1341
+ <path d="M8 20h8"></path>
1342
+ <path d="M12 16v4"></path>
1343
+ </svg>
1344
+ </span>
1345
+ </button>
1346
+ </div>
498
1347
  </div>
499
1348
  </div>
500
1349
  </div>
501
- <div class="integration-strip warn" id="integrationStatusBar">
502
- Connected to SilicaClaw: - · Network mode: - · Public discovery: -
503
- </div>
1350
+ <div class="main-scroll">
1351
+ <div class="integration-strip warn" id="integrationStatusBar">
1352
+ Connected to SilicaClaw: - · Network mode: - · Public discovery: -
1353
+ </div>
1354
+ <section class="page-hero">
1355
+ <div class="hero-copy">
1356
+ <h3 id="pageHeroTitle">Overview</h3>
1357
+ <p id="pageHeroBody">See the live state of this node, whether discovery is working, and whether other public agents are visible.</p>
1358
+ </div>
1359
+ <div class="hero-meta">
1360
+ <div class="hero-meta-grid">
1361
+ <div class="hero-meta-item"><div class="label">Mode</div><div class="mono" id="heroMode">-</div></div>
1362
+ <div class="hero-meta-item"><div class="label">Adapter</div><div class="mono" id="heroAdapter">-</div></div>
1363
+ <div class="hero-meta-item"><div class="label">Relay</div><div class="mono" id="heroRelay">-</div></div>
1364
+ <div class="hero-meta-item"><div class="label">Room</div><div class="mono" id="heroRoom">-</div></div>
1365
+ </div>
1366
+ </div>
1367
+ </section>
504
1368
 
505
- <div class="notice" id="initNotice"></div>
506
- <div class="actions" id="onboardingActions" style="display:none; margin:8px 0 12px;">
507
- <button id="enablePublicDiscoveryBtn">Enable Public Discovery</button>
508
- <button class="secondary" id="disablePublicDiscoveryBtn">Disable Public Discovery</button>
509
- </div>
510
- <div class="field-hint" id="publicDiscoveryHint" style="margin-bottom:12px; display:none;">
511
- Public discovery only shares signed profile/presence records. It does not share private files and does not enable chat or remote control.
512
- </div>
1369
+ <div class="notice" id="initNotice"></div>
1370
+ <div class="actions" id="onboardingActions" style="display:none; margin:8px 0 12px;">
1371
+ <button id="enablePublicDiscoveryBtn">Enable Public Discovery</button>
1372
+ <button class="secondary" id="disablePublicDiscoveryBtn">Disable Public Discovery</button>
1373
+ </div>
1374
+ <div class="field-hint" id="publicDiscoveryHint" style="margin-bottom:12px; display:none;">
1375
+ Public discovery only shares signed profile/presence records. It does not share private files and does not enable chat or remote control.
1376
+ </div>
513
1377
 
514
- <section id="view-overview" class="view active">
1378
+ <section id="view-overview" class="view active">
1379
+ <div class="section-surface compact">
1380
+ <div class="action-bar">
1381
+ <button id="overviewBroadcastNowBtn" type="button">Broadcast Now</button>
1382
+ <button class="secondary" id="overviewGoProfileBtn" type="button">Edit Profile</button>
1383
+ <button class="secondary" id="overviewGoNetworkBtn" type="button">Open Network Diagnostics</button>
1384
+ </div>
1385
+ </div>
515
1386
  <div class="grid" id="overviewCards"></div>
516
1387
  <div class="split">
517
1388
  <div class="card">
@@ -528,9 +1399,16 @@
528
1399
  <div class="mono" id="snapshot"></div>
529
1400
  </div>
530
1401
  </div>
531
- </section>
532
-
533
- <section id="view-profile" class="view">
1402
+ </section>
1403
+
1404
+ <section id="view-profile" class="view">
1405
+ <div class="section-header">
1406
+ <div class="section-header__copy">
1407
+ <div class="section-header__eyebrow">Profile</div>
1408
+ <h3 class="section-header__title">Signed public identity</h3>
1409
+ <p class="section-header__body">Edit the public card other nodes discover, then verify that the saved runtime profile and preview stay aligned after restart.</p>
1410
+ </div>
1411
+ </div>
534
1412
  <div class="profile-layout">
535
1413
  <div class="card stack">
536
1414
  <h3 class="title-sm">Public Profile Editor</h3>
@@ -592,96 +1470,146 @@
592
1470
  </div>
593
1471
  </div>
594
1472
  </div>
595
- </section>
596
-
597
- <section id="view-network" class="view">
1473
+ </section>
1474
+
1475
+ <section id="view-network" class="view">
1476
+ <div class="section-header">
1477
+ <div class="section-header__copy">
1478
+ <div class="section-header__eyebrow">Network</div>
1479
+ <h3 class="section-header__title">Relay and discovery summary</h3>
1480
+ <p class="section-header__body">Use the summary first. Open diagnostics only when relay joins, polls, or peer visibility look unhealthy.</p>
1481
+ </div>
1482
+ </div>
598
1483
  <div class="grid" id="networkCards"></div>
599
1484
  <div class="split">
600
1485
  <div class="card">
601
- <h3 class="title-sm">Runtime Components</h3>
602
- <div class="mono" id="networkComponents"></div>
1486
+ <h3 class="title-sm">Connection Summary</h3>
1487
+ <div class="summary-list" id="networkSummaryList"></div>
603
1488
  </div>
604
1489
  <div class="card">
605
- <h3 class="title-sm">Actions</h3>
1490
+ <h3 class="title-sm">Quick Actions</h3>
1491
+ <div class="field-hint" style="margin-bottom:10px;">Use these first. Most discovery issues can be confirmed here before opening diagnostics.</div>
606
1492
  <div class="actions">
607
1493
  <button id="startBroadcastBtn">Start Broadcast</button>
608
1494
  <button class="secondary" id="stopBroadcastBtn">Stop Broadcast</button>
609
1495
  <button class="secondary" id="broadcastNowBtn">Broadcast Now</button>
610
- <button class="secondary" id="refreshCacheBtn">Refresh Cache</button>
611
- <button class="secondary" id="clearCacheBtn">Clear Discovered Cache</button>
612
- <button class="secondary" id="quickGlobalPreviewBtn">Enable Cross-network Preview</button>
613
1496
  </div>
1497
+ <details class="advanced-panel">
1498
+ <summary class="title-sm">Advanced Actions</summary>
1499
+ <div class="actions" style="margin-top:10px;">
1500
+ <button class="secondary" id="refreshCacheBtn">Refresh Cache</button>
1501
+ <button class="secondary" id="clearCacheBtn">Clear Discovered Cache</button>
1502
+ <button class="secondary" id="quickGlobalPreviewBtn">Enable Cross-network Preview</button>
1503
+ </div>
1504
+ </details>
614
1505
  <div id="networkFeedback" class="feedback" style="margin-top:10px;">Ready.</div>
615
1506
  </div>
616
1507
  </div>
617
- <div class="split">
1508
+ <details class="advanced-panel card">
1509
+ <summary class="title-sm">Diagnostics</summary>
618
1510
  <div class="card" style="margin-top:10px;">
619
- <h3 class="title-sm">Config Snapshot</h3>
620
- <div class="mono mono-block" id="networkConfigSnapshot">-</div>
1511
+ <h3 class="title-sm">Runtime Components</h3>
1512
+ <div class="mono" id="networkComponents"></div>
621
1513
  </div>
1514
+ <div class="grid" id="peerCards" style="margin-top:10px;"></div>
622
1515
  <div class="card" style="margin-top:10px;">
623
- <h3 class="title-sm">Stats Snapshot</h3>
624
- <div class="mono mono-block" id="networkStatsSnapshot">-</div>
1516
+ <h3 class="title-sm">Peer Inventory</h3>
1517
+ <div id="peerTableWrap"></div>
625
1518
  </div>
626
- </div>
627
- </section>
628
-
629
- <section id="view-peers" class="view">
630
- <div class="grid" id="peerCards"></div>
631
- <div class="card" style="margin-top:10px;">
632
- <h3 class="title-sm">Peer Inventory</h3>
633
- <div id="peerTableWrap"></div>
634
- </div>
635
- <div class="card" style="margin-top:10px;">
636
- <h3 class="title-sm">Peer Discovery Stats</h3>
637
- <div class="mono mono-block" id="peerStatsWrap">-</div>
638
- </div>
639
- </section>
640
-
641
- <section id="view-discovery" class="view">
642
- <div class="grid" id="discoveryCards"></div>
643
- <div class="split">
644
1519
  <div class="card" style="margin-top:10px;">
645
- <h3 class="title-sm">Recent Discovery Events</h3>
646
- <div class="logs" id="discoveryEventList"></div>
1520
+ <h3 class="title-sm">Peer Discovery Stats</h3>
1521
+ <div class="mono mono-block" id="peerStatsWrap">-</div>
1522
+ </div>
1523
+ <div class="grid" id="discoveryCards" style="margin-top:10px;"></div>
1524
+ <div class="split">
1525
+ <div class="card" style="margin-top:10px;">
1526
+ <h3 class="title-sm">Recent Discovery Events</h3>
1527
+ <div class="logs" id="discoveryEventList"></div>
1528
+ </div>
1529
+ <div class="card" style="margin-top:10px;">
1530
+ <h3 class="title-sm">Discovery Snapshot</h3>
1531
+ <div class="mono mono-block" id="discoverySnapshot">-</div>
1532
+ </div>
647
1533
  </div>
648
1534
  <div class="card" style="margin-top:10px;">
649
- <h3 class="title-sm">Discovery Snapshot</h3>
650
- <div class="mono mono-block" id="discoverySnapshot">-</div>
1535
+ <h3 class="title-sm">Logs</h3>
1536
+ <div class="toolbar">
1537
+ <div class="field">
1538
+ <label for="logLevelFilter">Category</label>
1539
+ <select id="logLevelFilter">
1540
+ <option value="all">all</option>
1541
+ <option value="info">info</option>
1542
+ <option value="warn">warn</option>
1543
+ <option value="error">error</option>
1544
+ </select>
1545
+ </div>
1546
+ <div>
1547
+ <button type="button" class="secondary" id="refreshLogsBtn">Refresh Logs</button>
1548
+ </div>
1549
+ </div>
1550
+ <div class="logs" id="logList"></div>
1551
+ </div>
1552
+ <div class="split">
1553
+ <div class="card" style="margin-top:10px;">
1554
+ <h3 class="title-sm">Config Snapshot</h3>
1555
+ <div class="mono mono-block" id="networkConfigSnapshot">-</div>
1556
+ </div>
1557
+ <div class="card" style="margin-top:10px;">
1558
+ <h3 class="title-sm">Stats Snapshot</h3>
1559
+ <div class="mono mono-block" id="networkStatsSnapshot">-</div>
1560
+ </div>
1561
+ </div>
1562
+ </details>
1563
+ </section>
1564
+
1565
+ <section id="view-social" class="view">
1566
+ <div class="section-header">
1567
+ <div class="section-header__copy">
1568
+ <div class="section-header__eyebrow">Social</div>
1569
+ <h3 class="section-header__title">Public identity and runtime state</h3>
1570
+ <p class="section-header__body">Keep the signed identity, public visibility, and social.md runtime view aligned so discovery survives restart and update.</p>
651
1571
  </div>
652
1572
  </div>
653
- </section>
654
-
655
- <section id="view-social" class="view">
656
1573
  <div class="card">
657
1574
  <h3 class="title-sm">Integration Status</h3>
658
1575
  <div class="feedback" id="socialStatusLine">Checking integration status...</div>
659
1576
  <div class="field-hint" id="socialStatusSubline">-</div>
660
1577
  <div class="field-hint" id="socialStateHint">-</div>
661
1578
  </div>
662
- <div class="grid" id="socialPrimaryCards" style="margin-top:10px;"></div>
663
- <div class="grid" id="socialIntegrationCards"></div>
1579
+ <div class="split" style="margin-top:10px;">
1580
+ <div class="card">
1581
+ <h3 class="title-sm">What Is Active</h3>
1582
+ <div class="grid" id="socialPrimaryCards"></div>
1583
+ </div>
1584
+ <div class="card">
1585
+ <h3 class="title-sm">Identity Binding</h3>
1586
+ <div class="grid" id="socialIntegrationCards"></div>
1587
+ </div>
1588
+ </div>
664
1589
  <details class="card" style="margin-top:10px;">
665
1590
  <summary class="title-sm" style="cursor:pointer;">Advanced Network Details</summary>
666
1591
  <div class="grid" id="socialAdvancedCards" style="margin-top:10px;"></div>
667
1592
  <div class="mono mono-block" id="socialAdvancedWrap" style="margin-top:10px;">-</div>
668
1593
  </details>
669
- <div class="split">
670
- <div class="card" style="margin-top:10px;">
671
- <h3 class="title-sm">Source & Parsed Frontmatter</h3>
672
- <div class="mono mono-block" id="socialSourceWrap">-</div>
673
- <div style="height:10px;"></div>
674
- <div class="mono mono-block" id="socialRawWrap">-</div>
1594
+ <details class="advanced-panel card">
1595
+ <summary class="title-sm">Source / Runtime / Template</summary>
1596
+ <div class="split">
1597
+ <div class="card" style="margin-top:10px;">
1598
+ <h3 class="title-sm">Source & Parsed Frontmatter</h3>
1599
+ <div class="mono mono-block" id="socialSourceWrap">-</div>
1600
+ <div style="height:10px;"></div>
1601
+ <div class="mono mono-block" id="socialRawWrap">-</div>
1602
+ </div>
1603
+ <div class="card" style="margin-top:10px;">
1604
+ <h3 class="title-sm">Runtime Summary</h3>
1605
+ <div class="mono mono-block" id="socialRuntimeWrap">-</div>
1606
+ </div>
675
1607
  </div>
676
1608
  <div class="card" style="margin-top:10px;">
677
- <h3 class="title-sm">Runtime Summary</h3>
678
- <div class="mono mono-block" id="socialRuntimeWrap">-</div>
1609
+ <h3 class="title-sm">Export Template Preview</h3>
1610
+ <div class="mono mono-block" id="socialTemplateWrap">-</div>
679
1611
  </div>
680
- </div>
681
- <div class="card" style="margin-top:10px;">
682
- <h3 class="title-sm">Export Template Preview</h3>
683
- <div class="mono mono-block" id="socialTemplateWrap">-</div>
684
- </div>
1612
+ </details>
685
1613
  <div class="card" style="margin-top:10px;">
686
1614
  <h3 class="title-sm">Actions</h3>
687
1615
  <div class="toolbar">
@@ -706,28 +1634,8 @@
706
1634
  </div>
707
1635
  <div id="socialFeedback" class="feedback" style="margin-top:10px;">Ready.</div>
708
1636
  </div>
709
- </section>
710
-
711
- <section id="view-logs" class="view">
712
- <div class="card">
713
- <h3 class="title-sm">Recent Logs</h3>
714
- <div class="toolbar">
715
- <div class="field">
716
- <label for="logLevelFilter">Category</label>
717
- <select id="logLevelFilter">
718
- <option value="all">all</option>
719
- <option value="info">info</option>
720
- <option value="warn">warn</option>
721
- <option value="error">error</option>
722
- </select>
723
- </div>
724
- <div>
725
- <button type="button" class="secondary" id="refreshLogsBtn">Refresh Logs</button>
726
- </div>
727
- </div>
728
- <div class="logs" id="logList"></div>
729
- </div>
730
- </section>
1637
+ </section>
1638
+ </div>
731
1639
  </main>
732
1640
  </div>
733
1641
 
@@ -742,6 +1650,24 @@
742
1650
  let logLevelFilter = 'all';
743
1651
  let socialTemplate = '';
744
1652
  let onlyShowOnline = false;
1653
+ const pageMeta = {
1654
+ overview: {
1655
+ title: 'Overview',
1656
+ body: 'See the live state of this node, whether discovery is healthy, and whether other public agents are visible through the relay.',
1657
+ },
1658
+ profile: {
1659
+ title: 'Profile',
1660
+ body: 'Edit the signed public identity card that other agents can discover. Saved profile data should survive restart and update.',
1661
+ },
1662
+ network: {
1663
+ title: 'Network',
1664
+ body: 'Inspect relay connectivity, peer inventory, broadcast timing, and diagnostics when cross-device discovery is not working.',
1665
+ },
1666
+ social: {
1667
+ title: 'Social',
1668
+ body: 'Review social.md, runtime resolution, and the effective public visibility state that controls discovery.',
1669
+ },
1670
+ };
745
1671
 
746
1672
  function ago(ts) {
747
1673
  if (!ts) return '-';
@@ -767,6 +1693,12 @@
767
1693
  t.classList.add('show');
768
1694
  setTimeout(() => t.classList.remove('show'), 2000);
769
1695
  }
1696
+ function resolveThemeMode(mode) {
1697
+ if (mode === 'system') {
1698
+ return window.matchMedia && window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark';
1699
+ }
1700
+ return mode === 'light' ? 'light' : 'dark';
1701
+ }
770
1702
  function flashButton(btn, doneText = 'Done') {
771
1703
  if (!btn) return;
772
1704
  const oldText = btn.textContent || '';
@@ -783,11 +1715,16 @@
783
1715
  el.style.color = level === 'error' ? '#ff6b81' : level === 'warn' ? '#ffb454' : '#9aa7c3';
784
1716
  }
785
1717
  function applyTheme(mode) {
786
- const next = mode === 'light' ? 'light' : 'dark';
1718
+ const raw = mode === 'system' ? 'system' : (mode === 'light' ? 'light' : 'dark');
1719
+ const next = resolveThemeMode(raw);
787
1720
  document.documentElement.setAttribute('data-theme-mode', next);
788
- localStorage.setItem('silicaclaw_theme_mode', next);
789
- document.getElementById('themeDarkBtn').classList.toggle('active', next === 'dark');
790
- document.getElementById('themeLightBtn').classList.toggle('active', next === 'light');
1721
+ localStorage.setItem('silicaclaw_theme_mode', raw);
1722
+ document.querySelectorAll('[data-theme-choice]').forEach((btn) => {
1723
+ btn.classList.toggle('active', btn.dataset.themeChoice === raw);
1724
+ btn.classList.toggle('topbar-theme-mode__btn--active', btn.dataset.themeChoice === raw);
1725
+ btn.setAttribute('aria-checked', btn.dataset.themeChoice === raw ? 'true' : 'false');
1726
+ btn.setAttribute('aria-pressed', btn.dataset.themeChoice === raw ? 'true' : 'false');
1727
+ });
791
1728
  }
792
1729
  function parseTags(raw) {
793
1730
  return String(raw || '')
@@ -919,9 +1856,13 @@
919
1856
  }
920
1857
  activeTab = tab;
921
1858
  document.querySelectorAll('.tab').forEach((b) => b.classList.toggle('active', b.dataset.tab === tab));
922
- ['overview', 'profile', 'network', 'peers', 'discovery', 'social', 'logs'].forEach((k) => {
1859
+ ['overview', 'profile', 'network', 'social'].forEach((k) => {
923
1860
  document.getElementById(`view-${k}`).classList.toggle('active', k === tab);
924
1861
  });
1862
+ const meta = pageMeta[tab] || pageMeta.overview;
1863
+ document.getElementById('pageBreadcrumb').textContent = meta.title;
1864
+ document.getElementById('pageHeroTitle').textContent = meta.title;
1865
+ document.getElementById('pageHeroBody').textContent = meta.body;
925
1866
  if (tab === 'profile' && !profileDirty && !profileSaving) {
926
1867
  refreshProfile().catch(() => {});
927
1868
  }
@@ -940,12 +1881,16 @@
940
1881
  ['Presence TTL', `${Math.floor(o.presence_ttl_ms / 1000)}s`],
941
1882
  ].map(([k,v]) => `<div class="card"><div class="label">${k}</div><div class="value">${v}</div></div>`).join('');
942
1883
 
1884
+ document.getElementById('brandVersion').textContent = o.app_version ? `v${o.app_version}` : '-';
1885
+
943
1886
  document.getElementById('snapshot').textContent = [
1887
+ `app_version: ${o.app_version || '-'}`,
944
1888
  `agent_id: ${o.agent_id || '-'}`,
945
1889
  `public_enabled: ${o.public_enabled}`,
946
1890
  `broadcast_enabled: ${o.broadcast_enabled}`,
947
1891
  `last_broadcast: ${ago(o.last_broadcast_at)}`,
948
1892
  ].join('\n');
1893
+ document.getElementById('heroMode').textContent = o.social?.network_mode || '-';
949
1894
 
950
1895
  document.getElementById('pillBroadcast').textContent = o.broadcast_enabled ? 'broadcast: running' : 'broadcast: paused';
951
1896
  document.getElementById('pillBroadcast').className = `pill ${o.broadcast_enabled ? 'ok' : 'warn'}`;
@@ -1045,9 +1990,16 @@
1045
1990
  const d = s.adapter_discovery_stats || {};
1046
1991
  const dx = s.adapter_diagnostics_summary || {};
1047
1992
  const ac = s.adapter_config || c.adapter_config || {};
1993
+ document.getElementById('heroAdapter').textContent = c.adapter || '-';
1994
+ document.getElementById('heroRelay').textContent = dx.signaling_url || '-';
1995
+ document.getElementById('heroRoom').textContent = dx.room || '-';
1048
1996
 
1049
1997
  document.getElementById('pillAdapter').textContent = `adapter: ${c.adapter}`;
1050
- document.getElementById('sideMeta').innerHTML = `adapter: ${c.adapter}<br/>namespace: ${c.namespace || '-'}<br/>port: ${c.port ?? '-'}`;
1998
+ document.getElementById('sideMeta').innerHTML = [
1999
+ ['Adapter', c.adapter || '-'],
2000
+ ['Namespace', c.namespace || '-'],
2001
+ ['Port', c.port ?? '-'],
2002
+ ].map(([k, v]) => `<div class="sidebar-utility-row"><span class="sidebar-utility__label">${k}</span><span class="sidebar-utility__value">${v}</span></div>`).join('');
1051
2003
 
1052
2004
  document.getElementById('networkCards').innerHTML = [
1053
2005
  ['Adapter', c.adapter],
@@ -1070,6 +2022,15 @@
1070
2022
  ['Last Inbound', ago(msg.last_message_at)],
1071
2023
  ['Last Outbound', ago(msg.last_broadcast_at)],
1072
2024
  ].map(([k,v]) => `<div class="card"><div class="label">${k}</div><div class="value" style="font-size:17px;">${v}</div></div>`).join('');
2025
+ document.getElementById('networkSummaryList').innerHTML = [
2026
+ ['Relay health', dx.last_error ? 'degraded' : 'connected'],
2027
+ ['Current relay', dx.signaling_url || '-'],
2028
+ ['Current room', dx.room || '-'],
2029
+ ['Last join', ago(dx.last_join_at)],
2030
+ ['Last poll', ago(dx.last_poll_at)],
2031
+ ['Last publish', ago(dx.last_publish_at)],
2032
+ ['Last error', dx.last_error || 'none'],
2033
+ ].map(([k, v]) => `<div class="summary-item"><div class="label">${k}</div><div class="mono">${v}</div></div>`).join('');
1073
2034
 
1074
2035
  const comp = c.components || {};
1075
2036
  const lim = c.limits || {};
@@ -1097,6 +2058,12 @@
1097
2058
  `discovery_heartbeat_send_errors: ${d.heartbeat_send_errors ?? '-'}`,
1098
2059
  `signaling_messages_sent_total: ${dx.signaling_messages_sent_total ?? '-'}`,
1099
2060
  `signaling_messages_received_total: ${dx.signaling_messages_received_total ?? '-'}`,
2061
+ `last_join_at: ${dx.last_join_at ? new Date(dx.last_join_at).toISOString() : '-'}`,
2062
+ `last_poll_at: ${dx.last_poll_at ? new Date(dx.last_poll_at).toISOString() : '-'}`,
2063
+ `last_publish_at: ${dx.last_publish_at ? new Date(dx.last_publish_at).toISOString() : '-'}`,
2064
+ `last_peer_refresh_at: ${dx.last_peer_refresh_at ? new Date(dx.last_peer_refresh_at).toISOString() : '-'}`,
2065
+ `last_error_at: ${dx.last_error_at ? new Date(dx.last_error_at).toISOString() : '-'}`,
2066
+ `last_error: ${dx.last_error || '-'}`,
1100
2067
  `signaling_endpoints: ${Array.isArray(dx.signaling_endpoints) ? dx.signaling_endpoints.join(', ') : '-'}`,
1101
2068
  `bootstrap_sources: ${Array.isArray(dx.bootstrap_sources) ? dx.bootstrap_sources.join(', ') : '-'}`,
1102
2069
  `seed_peers_count: ${dx.seed_peers_count ?? '-'}`,
@@ -1128,6 +2095,9 @@
1128
2095
  ['Signaling URL', summary.signaling_url || '-'],
1129
2096
  ['Signaling Endpoints', (summary.signaling_endpoints || []).length || 0],
1130
2097
  ['Room', summary.room || '-'],
2098
+ ['Last Join', ago(summary.last_join_at)],
2099
+ ['Last Poll', ago(summary.last_poll_at)],
2100
+ ['Last Publish', ago(summary.last_publish_at)],
1131
2101
  ['Bootstrap Sources', (summary.bootstrap_sources || []).length || 0],
1132
2102
  ['Seed Peers', summary.seed_peers_count ?? 0],
1133
2103
  ['Discovery Events', summary.discovery_events_total ?? 0],
@@ -1139,7 +2109,7 @@
1139
2109
  ].map(([k,v]) => `<div class="card"><div class="label">${k}</div><div class="value" style="font-size:17px;">${v}</div></div>`).join('');
1140
2110
 
1141
2111
  if (!peers.items || !peers.items.length) {
1142
- document.getElementById('peerTableWrap').innerHTML = '<div class="label">No peers discovered yet.</div>';
2112
+ document.getElementById('peerTableWrap').innerHTML = '<div class="empty-state">No peers discovered yet. Confirm both nodes use the same relay URL, room, and public discovery setting.</div>';
1143
2113
  document.getElementById('peerStatsWrap').textContent = toPrettyJson({
1144
2114
  discovery_stats: ds,
1145
2115
  diagnostics_summary: summary,
@@ -1187,7 +2157,7 @@
1187
2157
  ].map(([k,v]) => `<div class="card"><div class="label">${k}</div><div class="value" style="font-size:17px;">${v}</div></div>`).join('');
1188
2158
 
1189
2159
  if (!items.length) {
1190
- document.getElementById('discoveryEventList').innerHTML = '<div class="label">No discovery events yet.</div>';
2160
+ document.getElementById('discoveryEventList').innerHTML = '<div class="empty-state">No discovery events yet. If this stays empty, the node may not be polling or joining the relay successfully.</div>';
1191
2161
  } else {
1192
2162
  document.getElementById('discoveryEventList').innerHTML = items
1193
2163
  .slice()
@@ -1229,6 +2199,7 @@
1229
2199
  const bar = document.getElementById('integrationStatusBar');
1230
2200
  bar.className = `integration-strip ${status.connected_to_silicaclaw && status.public_enabled ? 'ok' : 'warn'}`;
1231
2201
  bar.textContent = `Connected to SilicaClaw: ${status.connected_to_silicaclaw ? 'yes' : 'no'} · Network mode: ${mode} · Public discovery: ${status.public_enabled ? 'enabled' : 'disabled'}`;
2202
+ document.getElementById('brandStatusDot').classList.toggle('online', !!status.connected_to_silicaclaw);
1232
2203
  const reasons = [];
1233
2204
  if (!status.configured && status.configured_reason) reasons.push(`Configured: ${status.configured_reason}`);
1234
2205
  if (!status.running && status.running_reason) reasons.push(`Running: ${status.running_reason}`);
@@ -1295,14 +2266,14 @@
1295
2266
  function renderLogs() {
1296
2267
  const el = document.getElementById('logList');
1297
2268
  if (!logsCache.length) {
1298
- el.innerHTML = '<div class="label">No logs yet.</div>';
2269
+ el.innerHTML = '<div class="empty-state">No logs yet.</div>';
1299
2270
  return;
1300
2271
  }
1301
2272
  const filtered = logLevelFilter === 'all'
1302
2273
  ? logsCache
1303
2274
  : logsCache.filter((l) => String(l.level || '').toLowerCase() === logLevelFilter);
1304
2275
  if (!filtered.length) {
1305
- el.innerHTML = `<div class="label">No ${logLevelFilter} logs.</div>`;
2276
+ el.innerHTML = `<div class="empty-state">No ${logLevelFilter} logs.</div>`;
1306
2277
  return;
1307
2278
  }
1308
2279
  el.innerHTML = filtered.map((l) => `
@@ -1320,7 +2291,10 @@
1320
2291
 
1321
2292
  async function refreshAll() {
1322
2293
  try {
1323
- const tasks = [refreshOverview(), refreshNetwork(), refreshPeers(), refreshDiscovery(), refreshSocial(), refreshLogs(), refreshPublicProfilePreview()];
2294
+ const tasks = [refreshOverview(), refreshNetwork(), refreshSocial(), refreshPublicProfilePreview()];
2295
+ if (activeTab === 'network') {
2296
+ tasks.push(refreshPeers(), refreshDiscovery(), refreshLogs());
2297
+ }
1324
2298
  const shouldRefreshProfile = !(activeTab === 'profile' && profileDirty);
1325
2299
  if (shouldRefreshProfile) {
1326
2300
  tasks.push(refreshProfile());
@@ -1334,8 +2308,52 @@
1334
2308
  document.querySelectorAll('.tab').forEach((btn) => {
1335
2309
  btn.addEventListener('click', () => switchTab(btn.dataset.tab));
1336
2310
  });
1337
- document.getElementById('themeDarkBtn').addEventListener('click', () => applyTheme('dark'));
1338
- document.getElementById('themeLightBtn').addEventListener('click', () => applyTheme('light'));
2311
+ document.getElementById('sidebarToggleBtn').addEventListener('click', () => {
2312
+ const shell = document.getElementById('appShell');
2313
+ const next = !shell.classList.contains('nav-collapsed');
2314
+ shell.classList.toggle('nav-collapsed', next);
2315
+ const btn = document.getElementById('sidebarToggleBtn');
2316
+ const icon = btn.querySelector('.nav-collapse-toggle__icon');
2317
+ btn.classList.toggle('active', next);
2318
+ btn.title = next ? 'Expand sidebar' : 'Collapse sidebar';
2319
+ btn.setAttribute('aria-label', btn.title);
2320
+ if (icon) {
2321
+ icon.innerHTML = next
2322
+ ? `
2323
+ <svg viewBox="0 0 24 24">
2324
+ <rect x="3" y="3" width="18" height="18" rx="2"></rect>
2325
+ <path d="M9 3v18"></path>
2326
+ <path d="M14 10l3 2-3 2"></path>
2327
+ </svg>
2328
+ `
2329
+ : `
2330
+ <svg viewBox="0 0 24 24">
2331
+ <rect x="3" y="3" width="18" height="18" rx="2"></rect>
2332
+ <path d="M9 3v18"></path>
2333
+ <path d="M16 10l-3 2 3 2"></path>
2334
+ </svg>
2335
+ `;
2336
+ }
2337
+ });
2338
+ document.getElementById('focusModeBtn').addEventListener('click', () => {
2339
+ const shell = document.getElementById('appShell');
2340
+ const next = !shell.classList.contains('focus-mode');
2341
+ shell.classList.toggle('focus-mode', next);
2342
+ const btn = document.getElementById('focusModeBtn');
2343
+ btn.classList.toggle('active', next);
2344
+ btn.title = next ? 'Exit focus mode' : 'Toggle focus mode';
2345
+ btn.setAttribute('aria-label', btn.title);
2346
+ });
2347
+ document.querySelectorAll('[data-theme-choice]').forEach((btn) => {
2348
+ btn.addEventListener('click', () => {
2349
+ applyTheme(btn.dataset.themeChoice || 'dark');
2350
+ });
2351
+ });
2352
+ document.getElementById('overviewBroadcastNowBtn').addEventListener('click', () => {
2353
+ document.getElementById('broadcastNowBtn').click();
2354
+ });
2355
+ document.getElementById('overviewGoProfileBtn').addEventListener('click', () => switchTab('profile'));
2356
+ document.getElementById('overviewGoNetworkBtn').addEventListener('click', () => switchTab('network'));
1339
2357
 
1340
2358
  document.getElementById('profileForm').addEventListener('submit', async (event) => {
1341
2359
  event.preventDefault();
@@ -1424,7 +2442,7 @@
1424
2442
  document.getElementById('quickGlobalPreviewBtn').addEventListener('click', async () => {
1425
2443
  const currentSignaling = window.prompt('Signaling URL (publicly reachable):', 'http://localhost:4510');
1426
2444
  if (!currentSignaling) return;
1427
- const room = window.prompt('Room:', 'silicaclaw-demo') || 'silicaclaw-demo';
2445
+ const room = window.prompt('Room:', 'silicaclaw-global-preview') || 'silicaclaw-global-preview';
1428
2446
  setFeedback('networkFeedback', 'Enabling cross-network preview...');
1429
2447
  try {
1430
2448
  const result = await api('/api/network/quick-connect-global-preview', {
@@ -1593,6 +2611,20 @@
1593
2611
  });
1594
2612
  })();
1595
2613
 
2614
+ if (window.matchMedia) {
2615
+ const media = window.matchMedia('(prefers-color-scheme: light)');
2616
+ const handleThemeMedia = () => {
2617
+ if ((localStorage.getItem('silicaclaw_theme_mode') || 'dark') === 'system') {
2618
+ applyTheme('system');
2619
+ }
2620
+ };
2621
+ if (typeof media.addEventListener === 'function') {
2622
+ media.addEventListener('change', handleThemeMedia);
2623
+ } else if (typeof media.addListener === 'function') {
2624
+ media.addListener(handleThemeMedia);
2625
+ }
2626
+ }
2627
+
1596
2628
  applyTheme(localStorage.getItem('silicaclaw_theme_mode') || 'dark');
1597
2629
  refreshAll();
1598
2630
  exportSocialTemplate().catch(() => {});