privateboard 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +120 -0
  3. package/dist/cli.js +10502 -0
  4. package/dist/cli.js.map +1 -0
  5. package/package.json +63 -0
  6. package/public/adjourn-overlay.css +253 -0
  7. package/public/agent-overlay.css +444 -0
  8. package/public/agent-overlay.js +604 -0
  9. package/public/agent-profile.css +3230 -0
  10. package/public/agent-profile.js +3329 -0
  11. package/public/app.js +6629 -0
  12. package/public/auto-hide-scroll.js +90 -0
  13. package/public/avatar-skill.js +793 -0
  14. package/public/avatars/chair.svg +98 -0
  15. package/public/avatars/first-principles.svg +122 -0
  16. package/public/avatars/long-horizon.svg +147 -0
  17. package/public/avatars/open_ai.png +0 -0
  18. package/public/avatars/phenomenologist.svg +130 -0
  19. package/public/avatars/socrates.svg +187 -0
  20. package/public/avatars/user-empathy.svg +117 -0
  21. package/public/avatars/value-investor.svg +117 -0
  22. package/public/favicon.svg +10 -0
  23. package/public/fonts/agent-Italic.woff2 +0 -0
  24. package/public/fonts/human-sans.woff2 +0 -0
  25. package/public/icons.css +103 -0
  26. package/public/models-cache.js +57 -0
  27. package/public/new-agent.css +1359 -0
  28. package/public/new-agent.js +675 -0
  29. package/public/onboarding.css +628 -0
  30. package/public/onboarding.js +782 -0
  31. package/public/prototype-dashboard.html +7596 -0
  32. package/public/report/spines/a16z-thesis.css +1055 -0
  33. package/public/report/spines/anthropic-essay.css +556 -0
  34. package/public/report/spines/boardroom-dark.css +1082 -0
  35. package/public/report/spines/gartner-note.css +538 -0
  36. package/public/report/spines/mckinsey-deck.css +523 -0
  37. package/public/report/spines/openai-paper.css +516 -0
  38. package/public/report.html +1417 -0
  39. package/public/room-settings.css +895 -0
  40. package/public/room-settings.js +1039 -0
  41. package/public/themes.css +338 -0
  42. package/public/user-settings.css +1236 -0
  43. package/public/user-settings.js +1291 -0
@@ -0,0 +1,628 @@
1
+ /* ═══════════════════════════════════════════
2
+ ONBOARDING OVERLAY · first-run wizard
3
+ 4 steps: name → theme → API key → done/demo
4
+ ═══════════════════════════════════════════ */
5
+
6
+ .onb-overlay {
7
+ position: fixed;
8
+ inset: 0;
9
+ /* Soft blur · the dashboard underneath is intentionally visible
10
+ through the overlay so the user feels they're configuring INTO
11
+ a live product, not a separate gate. Lower bg opacity + heavier
12
+ gaussian blur (14px) makes the panel softly defocused while the
13
+ overlay content stays readable. */
14
+ background: rgba(8, 8, 8, 0.42);
15
+ -webkit-backdrop-filter: blur(14px) saturate(1.05);
16
+ backdrop-filter: blur(14px) saturate(1.05);
17
+ z-index: 1500;
18
+ display: none;
19
+ align-items: center;
20
+ justify-content: center;
21
+ padding: 24px;
22
+ overflow-y: auto;
23
+ font-family: var(--mono, "Inter", system-ui, sans-serif);
24
+ }
25
+ .onb-overlay.open {
26
+ display: flex;
27
+ animation: onb-fade 0.2s ease-out;
28
+ }
29
+ @keyframes onb-fade { from { opacity: 0; } to { opacity: 1; } }
30
+
31
+ .onb-modal {
32
+ position: relative;
33
+ width: 100%;
34
+ max-width: 720px;
35
+ background: var(--panel, #131312);
36
+ border: 0.5px solid var(--lime, #6FB572);
37
+ color: var(--text, #C8C5BE);
38
+ display: flex;
39
+ flex-direction: column;
40
+ min-height: 0;
41
+ /* Cap the modal so the final step (5 starter cards + final
42
+ card) doesn't stretch the modal close to viewport height.
43
+ The body inside is overflow-y: auto, so anything taller than
44
+ this cap simply scrolls within. */
45
+ max-height: min(calc(100vh - 48px), 680px);
46
+ /* Soft outer glow · separates the modal from the blurred dashboard
47
+ behind it without the heavy black backdrop carrying the contrast. */
48
+ box-shadow: 0 30px 60px -20px rgba(0, 0, 0, 0.65), 0 0 0 1px rgba(0, 0, 0, 0.25);
49
+ animation: onb-rise 0.24s ease-out;
50
+ }
51
+ @keyframes onb-rise {
52
+ from { transform: translateY(10px); opacity: 0; }
53
+ to { transform: translateY(0); opacity: 1; }
54
+ }
55
+ .onb-modal::before, .onb-modal::after {
56
+ content: "";
57
+ position: absolute;
58
+ width: 14px; height: 14px;
59
+ border: 2px solid var(--lime, #6FB572);
60
+ pointer-events: none;
61
+ }
62
+ .onb-modal::before { top: -2px; left: -2px; border-right: none; border-bottom: none; }
63
+ .onb-modal::after { bottom: -2px; right: -2px; border-left: none; border-top: none; }
64
+
65
+ /* Header */
66
+ .onb-classification {
67
+ background: var(--panel-2, #1A1A18);
68
+ border-bottom: 0.5px solid var(--line-bright, #2A2A26);
69
+ padding: 6px 14px;
70
+ font-size: 9px;
71
+ letter-spacing: 0.2em;
72
+ text-transform: uppercase;
73
+ color: var(--lime, #6FB572);
74
+ display: flex;
75
+ justify-content: space-between;
76
+ align-items: center;
77
+ flex: 0 0 auto;
78
+ }
79
+ .onb-classification .right { color: var(--text-faint, #3A382F); letter-spacing: 0.12em; }
80
+
81
+ .onb-head {
82
+ padding: 18px 24px 10px;
83
+ border-bottom: 0.5px dashed var(--line-bright, #2A2A26);
84
+ flex: 0 0 auto;
85
+ }
86
+ .onb-tag {
87
+ font-family: var(--mono);
88
+ font-size: 9.5px;
89
+ font-weight: 700;
90
+ letter-spacing: 0.18em;
91
+ text-transform: uppercase;
92
+ color: var(--lime, #6FB572);
93
+ margin-bottom: 6px;
94
+ }
95
+ .onb-title {
96
+ font-family: var(--font-human, var(--mono));
97
+ font-size: 22px;
98
+ font-weight: 700;
99
+ color: var(--text, #C8C5BE);
100
+ letter-spacing: -0.014em;
101
+ line-height: 1.22;
102
+ margin-bottom: 6px;
103
+ }
104
+ .onb-deck {
105
+ font-family: var(--font-human, var(--mono));
106
+ font-size: 13px;
107
+ color: var(--text-soft, #8E8B83);
108
+ line-height: 1.55;
109
+ }
110
+
111
+ /* Progress dots */
112
+ .onb-progress {
113
+ display: flex;
114
+ gap: 6px;
115
+ padding: 10px 24px;
116
+ border-bottom: 0.5px dashed var(--line-bright, #2A2A26);
117
+ flex: 0 0 auto;
118
+ }
119
+ .onb-dot {
120
+ flex: 1;
121
+ height: 3px;
122
+ background: var(--line-strong, #3A3A35);
123
+ transition: background 0.16s;
124
+ }
125
+ .onb-dot.active { background: var(--lime, #6FB572); }
126
+ .onb-dot.done { background: var(--lime-dim, #2D5532); }
127
+
128
+ /* Body — pane is scrollable; nav is fixed at footer */
129
+ .onb-body {
130
+ flex: 1 1 auto;
131
+ min-height: 0;
132
+ overflow-y: auto;
133
+ padding: 22px 24px 18px;
134
+ }
135
+
136
+ /* Inputs */
137
+ .onb-field { margin-bottom: 16px; }
138
+ .onb-field-label {
139
+ font-family: var(--mono);
140
+ font-size: 10px;
141
+ font-weight: 700;
142
+ letter-spacing: 0.14em;
143
+ text-transform: uppercase;
144
+ color: var(--text-faint, #3A382F);
145
+ margin-bottom: 6px;
146
+ }
147
+ .onb-field-hint {
148
+ font-family: var(--font-human, var(--mono));
149
+ font-size: 11.5px;
150
+ color: var(--text-dim, #5C5A52);
151
+ line-height: 1.5;
152
+ margin-top: 5px;
153
+ }
154
+ .onb-field-hint a {
155
+ color: var(--lime, #6FB572);
156
+ text-decoration: underline;
157
+ text-decoration-color: var(--lime-dim, #2D5532);
158
+ text-underline-offset: 2px;
159
+ }
160
+
161
+ .onb-input-wrap {
162
+ border: 0.5px solid var(--line-strong, #3A3A35);
163
+ background: var(--bg, #0A0A0A);
164
+ display: flex;
165
+ align-items: stretch;
166
+ transition: border-color 0.12s;
167
+ }
168
+ .onb-input-wrap:focus-within { border-color: var(--lime, #6FB572); }
169
+ .onb-input-wrap::before {
170
+ content: ">";
171
+ color: var(--lime, #6FB572);
172
+ font-weight: 700;
173
+ font-size: 13px;
174
+ font-family: var(--mono);
175
+ padding: 9px 0 0 11px;
176
+ align-self: flex-start;
177
+ }
178
+ .onb-input {
179
+ flex: 1;
180
+ border: none;
181
+ background: transparent;
182
+ font-family: var(--font-human, var(--mono));
183
+ font-size: 14px;
184
+ color: var(--text, #C8C5BE);
185
+ outline: none;
186
+ padding: 9px 12px;
187
+ letter-spacing: -0.003em;
188
+ width: 100%;
189
+ }
190
+ .onb-input::placeholder { color: var(--text-faint, #3A382F); }
191
+
192
+ /* Show / hide toggle for the API-key input. Sits inside .onb-input-wrap
193
+ on the right edge — flat, mono, lowercase so it reads as an
194
+ inline affordance rather than a primary action. */
195
+ .onb-input-reveal {
196
+ background: none;
197
+ border: 0;
198
+ color: var(--text-dim, #5C5A52);
199
+ cursor: pointer;
200
+ font-family: var(--mono);
201
+ font-size: 9px;
202
+ letter-spacing: 0.16em;
203
+ text-transform: uppercase;
204
+ padding: 0 12px;
205
+ align-self: stretch;
206
+ transition: color 0.12s;
207
+ }
208
+ .onb-input-reveal:hover { color: var(--text-soft, #8E8B83); }
209
+ .onb-input-reveal[aria-pressed="true"] { color: var(--lime, #6FB572); }
210
+
211
+ /* Prevent browser autofill (Chrome / Edge / Safari) from painting the
212
+ API-key input with a white/yellow background under dark themes.
213
+ Autofill ignores `background: transparent`, so we use a long inset
214
+ box-shadow set to the active theme's bg, plus a -webkit-text-fill-
215
+ color override so the typed text colour stays correct. Mirrors
216
+ `.us-input` in user-settings.css. */
217
+ .onb-input:-webkit-autofill,
218
+ .onb-input:-webkit-autofill:hover,
219
+ .onb-input:-webkit-autofill:focus,
220
+ .onb-input:-webkit-autofill:active {
221
+ -webkit-text-fill-color: var(--text, #C8C5BE);
222
+ -webkit-box-shadow: 0 0 0 1000px var(--bg, #0A0A0A) inset;
223
+ caret-color: var(--text, #C8C5BE);
224
+ transition: background-color 0s 9999s;
225
+ }
226
+ /* Match form-control color-scheme to the active theme so the password-
227
+ reveal icon and other native chrome don't render against a light
228
+ background under dark themes. Atrium (the only light theme) opts
229
+ back to light. */
230
+ :root .onb-input { color-scheme: dark; }
231
+ :root[data-theme="atrium"] .onb-input,
232
+ :root[data-theme="pinterest"] .onb-input,
233
+ :root[data-theme="apple"] .onb-input { color-scheme: light; }
234
+
235
+ /* Theme grid (mirrors Preference) */
236
+ .onb-theme-grid {
237
+ display: grid;
238
+ grid-template-columns: repeat(2, 1fr);
239
+ gap: 8px;
240
+ }
241
+ @media (max-width: 500px) { .onb-theme-grid { grid-template-columns: 1fr; } }
242
+ .onb-theme {
243
+ display: grid;
244
+ grid-template-columns: auto 1fr auto;
245
+ gap: 10px;
246
+ align-items: center;
247
+ padding: 9px 10px;
248
+ background: var(--bg, #0A0A0A);
249
+ border: 0.5px solid var(--line-strong, #3A3A35);
250
+ cursor: pointer;
251
+ text-decoration: none;
252
+ color: var(--text, #C8C5BE);
253
+ transition: all 0.12s;
254
+ }
255
+ .onb-theme:hover { border-color: var(--lime-dim, #2D5532); }
256
+ .onb-theme.active {
257
+ border-color: var(--lime, #6FB572);
258
+ background: var(--panel-2, #1A1A18);
259
+ }
260
+ .onb-theme-swatch {
261
+ display: inline-grid;
262
+ grid-template-columns: repeat(4, 6px);
263
+ grid-template-rows: repeat(2, 6px);
264
+ gap: 1px;
265
+ padding: 3px;
266
+ border: 0.5px solid var(--line-bright, #2A2A26);
267
+ background: var(--bg, #0A0A0A);
268
+ }
269
+ .onb-theme-swatch span { width: 6px; height: 6px; display: block; }
270
+ .onb-theme-name {
271
+ font-family: var(--mono);
272
+ font-size: 11.5px;
273
+ font-weight: 700;
274
+ color: var(--text, #C8C5BE);
275
+ }
276
+ .onb-theme.active .onb-theme-name { color: var(--lime, #6FB572); }
277
+ .onb-theme-desc {
278
+ font-family: var(--font-human);
279
+ font-size: 10.5px;
280
+ color: var(--text-dim);
281
+ margin-top: 1px;
282
+ }
283
+
284
+ /* Starter-question list — shown on the final onboarding step.
285
+ Each row is a full-width card with the question prominent. */
286
+ .onb-starters {
287
+ display: flex;
288
+ flex-direction: column;
289
+ gap: 8px;
290
+ }
291
+ /* Three-column grid keeps the title, hint, meta tags, and avatar block
292
+ aligned at the same horizontal position on every card. */
293
+ .onb-starter {
294
+ display: grid;
295
+ grid-template-columns: 92px 1fr 280px;
296
+ column-gap: 16px;
297
+ padding: 13px 18px;
298
+ background: var(--bg, #0A0A0A);
299
+ border: 0.5px solid var(--line-strong, #3A3A35);
300
+ font-family: inherit;
301
+ text-align: left;
302
+ cursor: pointer;
303
+ transition: all 0.12s;
304
+ position: relative;
305
+ color: var(--text, #C8C5BE);
306
+ min-height: 96px;
307
+ }
308
+ .onb-starter:hover {
309
+ border-color: var(--lime, #6FB572);
310
+ background: var(--panel-2, #1A1A18);
311
+ }
312
+ .onb-starter-tag {
313
+ align-self: start;
314
+ padding-top: 2px;
315
+ font-family: var(--mono);
316
+ font-size: 9.5px;
317
+ font-weight: 700;
318
+ letter-spacing: 0.14em;
319
+ text-transform: uppercase;
320
+ color: var(--lime, #6FB572);
321
+ white-space: nowrap;
322
+ }
323
+ /* All title-aligned content (title, hint, meta tags) stacks here so the
324
+ left edge is identical regardless of tag width. */
325
+ .onb-starter-main {
326
+ display: flex;
327
+ flex-direction: column;
328
+ gap: 8px;
329
+ min-width: 0;
330
+ }
331
+ .onb-starter-text {
332
+ font-family: var(--font-human);
333
+ font-size: 14.5px;
334
+ font-weight: 600;
335
+ color: var(--text, #C8C5BE);
336
+ letter-spacing: -0.005em;
337
+ line-height: 1.35;
338
+ }
339
+ .onb-starter-hint {
340
+ font-family: var(--font-human);
341
+ font-size: 11.5px;
342
+ color: var(--text-soft, #8E8B83);
343
+ line-height: 1.4;
344
+ }
345
+ .onb-starter-meta {
346
+ display: flex;
347
+ align-items: center;
348
+ flex-wrap: wrap;
349
+ gap: 6px;
350
+ margin-top: 2px;
351
+ }
352
+ /* Cast lives in the third grid column at a fixed width, so the avatar
353
+ block lines up at the same x-position across every card regardless of
354
+ how long the tag or title is. */
355
+ .onb-starter-cast {
356
+ display: grid;
357
+ grid-template-columns: repeat(3, 1fr);
358
+ align-items: start;
359
+ align-self: start;
360
+ gap: 8px;
361
+ width: 100%;
362
+ }
363
+ .onb-starter-agent {
364
+ display: flex;
365
+ flex-direction: column;
366
+ align-items: center;
367
+ gap: 4px;
368
+ text-align: center;
369
+ min-width: 0;
370
+ }
371
+ .onb-starter-av {
372
+ width: 52px;
373
+ height: 52px;
374
+ image-rendering: pixelated;
375
+ image-rendering: crisp-edges;
376
+ border: 0.5px solid var(--line-strong, #3A3A35);
377
+ background: var(--bg, #0A0A0A);
378
+ transition: transform 0.12s, border-color 0.12s;
379
+ }
380
+ .onb-starter-agent:hover .onb-starter-av {
381
+ border-color: var(--lime, #6FB572);
382
+ transform: translateY(-1px);
383
+ }
384
+ .onb-starter-name {
385
+ font-family: var(--mono);
386
+ font-size: 9.5px;
387
+ font-weight: 700;
388
+ color: var(--text-soft, #8E8B83);
389
+ letter-spacing: 0.04em;
390
+ line-height: 1.2;
391
+ width: 100%;
392
+ overflow: hidden;
393
+ text-overflow: ellipsis;
394
+ white-space: nowrap;
395
+ }
396
+ .onb-starter-agent:hover .onb-starter-name { color: var(--lime, #6FB572); }
397
+ /* Start button hovers in the bottom-right of the card, so it doesn't
398
+ nudge the cast or the title row. */
399
+ .onb-starter-start {
400
+ position: absolute;
401
+ bottom: 12px;
402
+ right: 14px;
403
+ display: inline-flex;
404
+ align-items: center;
405
+ gap: 6px;
406
+ background: var(--lime, #6FB572);
407
+ color: var(--bg, #0A0A0A);
408
+ border: 0.5px solid var(--lime, #6FB572);
409
+ padding: 5px 10px;
410
+ font-family: var(--mono);
411
+ font-size: 10px;
412
+ font-weight: 700;
413
+ letter-spacing: 0.14em;
414
+ text-transform: uppercase;
415
+ cursor: pointer;
416
+ opacity: 0;
417
+ transform: translateX(6px);
418
+ transition: opacity 0.12s, transform 0.12s, background 0.12s, color 0.12s;
419
+ pointer-events: none;
420
+ }
421
+ .onb-starter:hover .onb-starter-start {
422
+ opacity: 1;
423
+ transform: translateX(0);
424
+ pointer-events: auto;
425
+ }
426
+ .onb-starter-start:hover {
427
+ background: var(--bg, #0A0A0A);
428
+ color: var(--lime, #6FB572);
429
+ }
430
+ .onb-starter-start-arrow { font-size: 8.5px; line-height: 1; }
431
+ .onb-final-divider {
432
+ text-align: center;
433
+ margin: 14px 0 10px;
434
+ font-family: var(--mono);
435
+ font-size: 9px;
436
+ letter-spacing: 0.2em;
437
+ text-transform: uppercase;
438
+ color: var(--text-faint, #3A382F);
439
+ position: relative;
440
+ }
441
+ .onb-final-divider::before,
442
+ .onb-final-divider::after {
443
+ content: "";
444
+ position: absolute;
445
+ top: 50%;
446
+ width: calc(50% - 18px);
447
+ height: 1px;
448
+ background: var(--line-bright, #2A2A26);
449
+ }
450
+ .onb-final-divider::before { left: 0; }
451
+ .onb-final-divider::after { right: 0; }
452
+ .onb-final-divider span { padding: 0 10px; }
453
+
454
+ /* Final step "two cards" */
455
+ .onb-final {
456
+ display: grid;
457
+ grid-template-columns: 1fr;
458
+ gap: 12px;
459
+ }
460
+ @media (max-width: 500px) { .onb-final { grid-template-columns: 1fr; } }
461
+ .onb-final-card {
462
+ background: var(--bg, #0A0A0A);
463
+ border: 0.5px solid var(--line-strong, #3A3A35);
464
+ padding: 16px 16px 14px;
465
+ text-align: left;
466
+ cursor: pointer;
467
+ transition: all 0.14s;
468
+ display: flex;
469
+ flex-direction: column;
470
+ gap: 6px;
471
+ position: relative;
472
+ font-family: inherit;
473
+ width: 100%;
474
+ color: var(--text, #C8C5BE);
475
+ }
476
+ .onb-final-card:hover {
477
+ border-color: var(--lime, #6FB572);
478
+ background: var(--panel-2, #1A1A18);
479
+ }
480
+ .onb-final-card.primary { border-color: var(--lime-dim, #2D5532); }
481
+ .onb-final-mark {
482
+ font-family: var(--mono);
483
+ font-size: 9.5px;
484
+ font-weight: 700;
485
+ letter-spacing: 0.16em;
486
+ text-transform: uppercase;
487
+ color: var(--lime, #6FB572);
488
+ }
489
+ .onb-final-card.primary .onb-final-mark { color: var(--lime, #6FB572); }
490
+ .onb-final-title {
491
+ font-family: var(--font-human);
492
+ font-size: 15px;
493
+ font-weight: 700;
494
+ color: var(--text, #C8C5BE);
495
+ letter-spacing: -0.005em;
496
+ }
497
+ .onb-final-deck {
498
+ font-family: var(--font-human);
499
+ font-size: 12px;
500
+ color: var(--text-soft, #8E8B83);
501
+ line-height: 1.5;
502
+ }
503
+
504
+ /* Provider selector · inline label row that declares which provider
505
+ the single input below is for. Intentionally NOT styled as cards —
506
+ no backgrounds, no borders — so the row reads as a label/legend,
507
+ not a second set of input fields. */
508
+ .onb-key-tabs {
509
+ display: flex;
510
+ flex-wrap: wrap;
511
+ align-items: baseline;
512
+ gap: 4px 18px;
513
+ margin-bottom: 14px;
514
+ }
515
+ .onb-key-tab {
516
+ position: relative;
517
+ display: inline-flex;
518
+ align-items: baseline;
519
+ gap: 6px;
520
+ padding: 4px 0 4px 14px;
521
+ background: none;
522
+ border: 0;
523
+ color: var(--text-dim, #5C5A52);
524
+ cursor: pointer;
525
+ text-align: left;
526
+ font-family: var(--font-human, "Inter", system-ui, sans-serif);
527
+ font-size: 13px;
528
+ font-weight: 500;
529
+ letter-spacing: -0.005em;
530
+ line-height: 1.2;
531
+ transition: color 0.12s;
532
+ }
533
+ .onb-key-tab:hover {
534
+ color: var(--text-soft, #8E8B83);
535
+ }
536
+ .onb-key-tab.active {
537
+ color: var(--text, #C8C5BE);
538
+ font-weight: 600;
539
+ }
540
+ .onb-key-tab.active::before {
541
+ content: "▸";
542
+ position: absolute;
543
+ left: 0;
544
+ top: 50%;
545
+ transform: translateY(-50%);
546
+ font-family: var(--mono, monospace);
547
+ font-size: 10px;
548
+ font-weight: 700;
549
+ line-height: 1;
550
+ color: var(--lime, #6FB572);
551
+ }
552
+ .onb-key-tab-label { font: inherit; }
553
+ .onb-key-tab-sub { display: none; }
554
+ /* Configured · single small lime dot trailing the label. With the
555
+ single-provider invariant on this step, at most one tab carries
556
+ the dot at any time. */
557
+ .onb-key-tab-dot {
558
+ width: 5px;
559
+ height: 5px;
560
+ border-radius: 50%;
561
+ background: var(--lime, #6FB572);
562
+ display: inline-block;
563
+ font-size: 0;
564
+ line-height: 0;
565
+ opacity: 0.85;
566
+ }
567
+ .onb-key-tab.active .onb-key-tab-dot { opacity: 1; }
568
+
569
+ /* Status chip on the API key field */
570
+ .onb-key-status {
571
+ font-family: var(--mono);
572
+ font-size: 10px;
573
+ letter-spacing: 0.1em;
574
+ text-transform: uppercase;
575
+ margin-top: 6px;
576
+ }
577
+ .onb-key-status.ok { color: var(--lime, #6FB572); }
578
+ .onb-key-status.warn { color: var(--amber, #B59560); }
579
+ .onb-key-status.error { color: var(--red, #B5706A); }
580
+
581
+ /* Footer · nav */
582
+ .onb-foot {
583
+ border-top: 0.5px solid var(--line-bright, #2A2A26);
584
+ background: var(--panel-2, #1A1A18);
585
+ padding: 12px 18px;
586
+ display: flex;
587
+ justify-content: space-between;
588
+ align-items: center;
589
+ gap: 10px;
590
+ flex: 0 0 auto;
591
+ }
592
+ .onb-foot-left,
593
+ .onb-foot-right { display: flex; gap: 6px; }
594
+
595
+ .onb-btn {
596
+ font-family: var(--mono);
597
+ font-size: 10px;
598
+ font-weight: 700;
599
+ text-transform: uppercase;
600
+ letter-spacing: 0.1em;
601
+ padding: 7px 13px;
602
+ border: 0.5px solid var(--line-strong, #3A3A35);
603
+ background: transparent;
604
+ color: var(--text-soft, #8E8B83);
605
+ cursor: pointer;
606
+ text-decoration: none;
607
+ transition: all 0.12s;
608
+ }
609
+ .onb-btn:hover { border-color: var(--lime, #6FB572); color: var(--lime, #6FB572); }
610
+ .onb-btn.primary {
611
+ background: var(--lime, #6FB572);
612
+ color: var(--bg, #0A0A0A);
613
+ border-color: var(--lime, #6FB572);
614
+ }
615
+ .onb-btn.primary:hover { background: transparent; color: var(--lime, #6FB572); }
616
+ .onb-btn:disabled,
617
+ .onb-btn.primary:disabled {
618
+ opacity: 0.4;
619
+ cursor: not-allowed;
620
+ background: transparent;
621
+ color: var(--text-faint);
622
+ border-color: var(--line-bright);
623
+ }
624
+
625
+ /* When onboarding is open, prevent the rest of the dashboard from scrolling */
626
+ .onb-locked {
627
+ overflow: hidden;
628
+ }