privateboard 0.1.13 → 0.1.16

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.
@@ -1,6 +1,6 @@
1
1
  /* ═══════════════════════════════════════════
2
- ONBOARDING OVERLAY · first-run wizard
3
- 4 steps: name → themeAPI key → done/demo
2
+ ONBOARDING OVERLAY · first-run storyline (v2)
3
+ 4 beats: name → what → key → cast → (composer + hint)
4
4
  ═══════════════════════════════════════════ */
5
5
 
6
6
  .onb-overlay {
@@ -31,20 +31,16 @@
31
31
  .onb-modal {
32
32
  position: relative;
33
33
  width: 100%;
34
- max-width: 720px;
34
+ max-width: 640px;
35
35
  background: var(--panel, #131312);
36
36
  border: 0.5px solid var(--lime, #6FB572);
37
37
  color: var(--text, #C8C5BE);
38
38
  display: flex;
39
39
  flex-direction: column;
40
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. */
41
+ /* Cap modal height body inside scrolls. */
42
+ max-height: min(calc(100vh - 48px), 620px);
43
+ /* Soft outer separation from the blurred dashboard. */
48
44
  box-shadow: 0 30px 60px -20px rgba(0, 0, 0, 0.65), 0 0 0 1px rgba(0, 0, 0, 0.25);
49
45
  animation: onb-rise 0.24s ease-out;
50
46
  }
@@ -79,18 +75,18 @@
79
75
  .onb-classification .right { color: var(--text-faint, #3A382F); letter-spacing: 0.12em; }
80
76
 
81
77
  .onb-head {
82
- padding: 18px 24px 10px;
78
+ padding: 22px 28px 14px;
83
79
  border-bottom: 0.5px dashed var(--line-bright, #2A2A26);
84
80
  flex: 0 0 auto;
85
81
  }
86
82
  .onb-tag {
87
83
  font-family: var(--mono);
88
- font-size: 9.5px;
84
+ font-size: 10px;
89
85
  font-weight: 700;
90
86
  letter-spacing: 0.18em;
91
87
  text-transform: uppercase;
92
88
  color: var(--lime, #6FB572);
93
- margin-bottom: 6px;
89
+ margin-bottom: 10px;
94
90
  }
95
91
  .onb-title {
96
92
  font-family: var(--font-human, var(--mono));
@@ -101,18 +97,29 @@
101
97
  line-height: 1.22;
102
98
  margin-bottom: 6px;
103
99
  }
100
+ /* Story-beat headings · serif, italic-friendly, larger than the
101
+ mono headline above. Carries the conversational tone of the
102
+ storyline link. */
103
+ .onb-title-serif {
104
+ font-family: "Tiempos Text", "Charter", Georgia, "Times New Roman", serif;
105
+ font-weight: 500;
106
+ font-size: 26px;
107
+ line-height: 1.28;
108
+ letter-spacing: -0.012em;
109
+ }
104
110
  .onb-deck {
105
111
  font-family: var(--font-human, var(--mono));
106
112
  font-size: 13px;
107
113
  color: var(--text-soft, #8E8B83);
108
114
  line-height: 1.55;
115
+ margin-top: 8px;
109
116
  }
110
117
 
111
118
  /* Progress dots */
112
119
  .onb-progress {
113
120
  display: flex;
114
121
  gap: 6px;
115
- padding: 10px 24px;
122
+ padding: 10px 28px;
116
123
  border-bottom: 0.5px dashed var(--line-bright, #2A2A26);
117
124
  flex: 0 0 auto;
118
125
  }
@@ -130,7 +137,7 @@
130
137
  flex: 1 1 auto;
131
138
  min-height: 0;
132
139
  overflow-y: auto;
133
- padding: 22px 24px 18px;
140
+ padding: 22px 28px 22px;
134
141
  }
135
142
 
136
143
  /* Inputs */
@@ -146,7 +153,7 @@
146
153
  }
147
154
  .onb-field-hint {
148
155
  font-family: var(--font-human, var(--mono));
149
- font-size: 11.5px;
156
+ font-size: 12px;
150
157
  color: var(--text-dim, #5C5A52);
151
158
  line-height: 1.5;
152
159
  margin-top: 5px;
@@ -188,10 +195,16 @@
188
195
  width: 100%;
189
196
  }
190
197
  .onb-input::placeholder { color: var(--text-faint, #3A382F); }
198
+ /* Serif variant used by the name field on step 0. */
199
+ .onb-input-serif {
200
+ font-family: "Tiempos Text", "Charter", Georgia, "Times New Roman", serif;
201
+ font-style: italic;
202
+ font-size: 20px;
203
+ padding: 12px 12px;
204
+ letter-spacing: -0.005em;
205
+ }
191
206
 
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. */
207
+ /* Show / hide toggle for the API-key input */
195
208
  .onb-input-reveal {
196
209
  background: none;
197
210
  border: 0;
@@ -208,12 +221,7 @@
208
221
  .onb-input-reveal:hover { color: var(--text-soft, #8E8B83); }
209
222
  .onb-input-reveal[aria-pressed="true"] { color: var(--lime, #6FB572); }
210
223
 
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. */
224
+ /* Autofill suppression (mirrors user-settings.css) */
217
225
  .onb-input:-webkit-autofill,
218
226
  .onb-input:-webkit-autofill:hover,
219
227
  .onb-input:-webkit-autofill:focus,
@@ -223,338 +231,344 @@
223
231
  caret-color: var(--text, #C8C5BE);
224
232
  transition: background-color 0s 9999s;
225
233
  }
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
234
  :root .onb-input { color-scheme: dark; }
231
235
  :root[data-theme="atrium"] .onb-input,
232
- :root[data-theme="pinterest"] .onb-input,
233
- :root[data-theme="apple"] .onb-input { color-scheme: light; }
236
+ :root[data-theme="pinterest"] .onb-input { color-scheme: light; }
234
237
 
235
- /* Theme grid (mirrors Preference) */
236
- .onb-theme-grid {
237
- display: grid;
238
- grid-template-columns: repeat(2, 1fr);
239
- gap: 8px;
238
+ /* ── step 1 · narrative ──────────────────────────────── */
239
+ .onb-narrative {
240
+ display: flex;
241
+ flex-direction: column;
242
+ gap: 14px;
243
+ max-width: 540px;
240
244
  }
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;
245
+ .onb-narrative-p {
246
+ font-family: var(--font-human, "Inter", system-ui, sans-serif);
247
+ font-size: 14px;
248
+ line-height: 1.7;
249
+ color: var(--text-soft, #8E8B83);
250
+ margin: 0;
254
251
  }
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);
252
+ .onb-narrative-note {
253
+ font-family: var(--font-human, "Inter", system-ui, sans-serif);
254
+ font-size: 12px;
255
+ line-height: 1.6;
256
+ color: var(--text-dim, #5C5A52);
257
+ margin: 0;
258
+ padding-left: 12px;
259
+ border-left: 0;
260
+ position: relative;
259
261
  }
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;
262
+ .onb-narrative-note::before {
263
+ content: "// note";
264
+ display: block;
265
+ font-family: var(--mono);
266
+ font-size: 9px;
267
+ letter-spacing: 0.18em;
268
+ text-transform: uppercase;
269
+ color: var(--lime, #6FB572);
270
+ margin-bottom: 4px;
271
+ padding-left: 0;
272
+ }
273
+
274
+ /* ── step 3 · cast preview ───────────────────────────── */
275
+ /* ── step 3 · voice / TTS (optional) ──────────────────
276
+ Reuses the room-preview rendering scoped under `.vonb-banner`
277
+ in voice-onboarding.css — we mount the cloned preview into a
278
+ wrapper that carries that class so the existing CSS just works.
279
+ Compact 180px banner (shorter than the 240px in the marketing
280
+ overlay) to leave room for the provider chips + key input. */
281
+ .onb-voice { display: flex; flex-direction: column; gap: 14px; }
282
+ .onb-voice-banner {
283
+ height: 180px;
266
284
  border: 0.5px solid var(--line-bright, #2A2A26);
267
285
  background: var(--bg, #0A0A0A);
268
286
  }
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);
287
+ .onb-voice-banner-fallback {
288
+ width: 100%;
289
+ height: 100%;
290
+ background: var(--panel-2, #1A1A18);
275
291
  }
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;
292
+ .onb-voice-pitch {
293
+ font-family: var(--font-human, "Inter", system-ui, sans-serif);
294
+ font-size: 13px;
295
+ line-height: 1.6;
296
+ color: var(--text-soft, #8E8B83);
297
+ margin: 0;
282
298
  }
299
+ .onb-voice-providers { margin-top: 2px; }
300
+ .onb-voice-field { margin-bottom: 0; }
283
301
 
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 {
302
+ /* On step 3 the footer carries TWO right-side buttons (Skip · Continue)
303
+ instead of one let them sit side-by-side with a tight gap. The
304
+ .onb-foot-right flex already handles it, but the ghost Skip needs
305
+ slightly different emphasis vs. the primary. */
306
+ .onb-foot-right .onb-btn + .onb-btn { margin-left: 6px; }
307
+
308
+ .onb-cast { display: flex; flex-direction: column; gap: 14px; }
309
+
310
+ /* Three-stage microflow under the cast grid · disambiguates the CTA
311
+ by previewing what actually happens at the composer next. Mono
312
+ numerals on the left, sans label on the right, arrows between.
313
+ Wraps to one-per-row on narrow widths so the labels stay readable. */
314
+ .onb-cast-next { display: flex; flex-direction: column; gap: 8px; margin-top: 6px; }
315
+ .onb-cast-next-kicker {
316
+ font-family: var(--mono);
317
+ font-size: 10px;
318
+ font-weight: 700;
319
+ letter-spacing: 0.16em;
320
+ text-transform: uppercase;
321
+ color: var(--text-faint, #3A382F);
322
+ }
323
+ .onb-cast-next-flow {
287
324
  display: flex;
288
- flex-direction: column;
325
+ flex-wrap: wrap;
326
+ align-items: stretch;
289
327
  gap: 8px;
290
328
  }
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;
329
+ .onb-cast-next-step {
330
+ display: inline-flex;
331
+ align-items: baseline;
332
+ gap: 8px;
333
+ padding: 8px 12px;
298
334
  background: var(--bg, #0A0A0A);
299
335
  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);
336
+ min-width: 0;
337
+ flex: 1 1 auto;
311
338
  }
312
- .onb-starter-tag {
313
- align-self: start;
314
- padding-top: 2px;
339
+ .onb-cast-next-num {
315
340
  font-family: var(--mono);
316
- font-size: 9.5px;
341
+ font-size: 11px;
317
342
  font-weight: 700;
318
- letter-spacing: 0.14em;
319
- text-transform: uppercase;
343
+ letter-spacing: 0.04em;
320
344
  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;
345
+ flex-shrink: 0;
330
346
  }
331
- .onb-starter-text {
332
- font-family: var(--font-human);
333
- font-size: 14.5px;
334
- font-weight: 600;
347
+ .onb-cast-next-label {
348
+ font-family: var(--font-human, "Inter", system-ui, sans-serif);
349
+ font-size: 12px;
350
+ line-height: 1.4;
335
351
  color: var(--text, #C8C5BE);
336
- letter-spacing: -0.005em;
337
- line-height: 1.35;
338
352
  }
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;
353
+ .onb-cast-next-arrow {
354
+ font-family: var(--mono);
355
+ font-size: 13px;
356
+ font-weight: 700;
357
+ color: var(--text-faint, #3A382F);
358
+ align-self: center;
359
+ flex-shrink: 0;
344
360
  }
345
- .onb-starter-meta {
346
- display: flex;
347
- align-items: center;
348
- flex-wrap: wrap;
349
- gap: 6px;
350
- margin-top: 2px;
361
+ @media (max-width: 520px) {
362
+ .onb-cast-next-flow { flex-direction: column; }
363
+ .onb-cast-next-arrow { transform: rotate(90deg); align-self: center; }
351
364
  }
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 {
365
+ .onb-cast-kicker {
366
+ font-family: var(--mono);
367
+ font-size: 10px;
368
+ font-weight: 700;
369
+ letter-spacing: 0.16em;
370
+ text-transform: uppercase;
371
+ color: var(--text-faint, #3A382F);
372
+ }
373
+ .onb-cast-grid {
356
374
  display: grid;
357
- grid-template-columns: repeat(3, 1fr);
358
- align-items: start;
359
- align-self: start;
360
- gap: 8px;
361
- width: 100%;
375
+ grid-template-columns: repeat(6, 1fr);
376
+ gap: 10px;
377
+ }
378
+ @media (max-width: 560px) {
379
+ .onb-cast-grid { grid-template-columns: repeat(3, 1fr); }
362
380
  }
363
- .onb-starter-agent {
381
+ /* Lineup-style cell · NO border / background, otherwise the cells
382
+ read as clickable picker buttons (which they are not — selection
383
+ happens later in the composer). Inherits the modal panel bg, just
384
+ the avatar floats above its name + role. cursor: default + the
385
+ `aria-disabled`-like styling reinforces "this is a portrait, not
386
+ a button." */
387
+ .onb-cast-cell {
364
388
  display: flex;
365
389
  flex-direction: column;
366
390
  align-items: center;
367
391
  gap: 4px;
368
392
  text-align: center;
393
+ padding: 4px 2px;
394
+ background: transparent;
395
+ border: 0;
396
+ cursor: default;
369
397
  min-width: 0;
370
398
  }
371
- .onb-starter-av {
372
- width: 52px;
373
- height: 52px;
399
+ .onb-cast-av {
400
+ width: 56px;
401
+ height: 56px;
374
402
  image-rendering: pixelated;
375
403
  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);
404
+ background: transparent;
383
405
  }
384
- .onb-starter-name {
406
+ .onb-cast-name {
385
407
  font-family: var(--mono);
386
- font-size: 9.5px;
408
+ font-size: 10px;
387
409
  font-weight: 700;
388
- color: var(--text-soft, #8E8B83);
389
410
  letter-spacing: 0.04em;
390
- line-height: 1.2;
391
- width: 100%;
411
+ color: var(--text, #C8C5BE);
412
+ white-space: nowrap;
392
413
  overflow: hidden;
393
414
  text-overflow: ellipsis;
394
- white-space: nowrap;
415
+ width: 100%;
395
416
  }
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);
417
+ .onb-cast-role {
418
+ font-family: var(--font-human);
419
+ font-style: italic;
411
420
  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);
421
+ color: var(--text-dim, #5C5A52);
422
+ white-space: nowrap;
423
+ overflow: hidden;
424
+ text-overflow: ellipsis;
425
+ width: 100%;
449
426
  }
450
- .onb-final-divider::before { left: 0; }
451
- .onb-final-divider::after { right: 0; }
452
- .onb-final-divider span { padding: 0 10px; }
453
427
 
454
- /* Final step "two cards" */
455
- .onb-final {
456
- display: grid;
457
- grid-template-columns: 1fr;
458
- gap: 12px;
428
+ /* ── step 2 · key picker ─────────────────────────────
429
+ Visual hierarchy:
430
+ (1) Recommended card · OpenRouter · multi-model board
431
+ (2) "// or" divider
432
+ (3) Direct provider chips · single-model board
433
+ Selecting either path drives the single input below. */
434
+ .onb-key-frame {
435
+ display: flex;
436
+ flex-direction: column;
437
+ gap: 14px;
459
438
  }
460
- @media (max-width: 500px) { .onb-final { grid-template-columns: 1fr; } }
461
- .onb-final-card {
439
+
440
+ /* Recommended card · OpenRouter. Lime-accented border when active,
441
+ muted but readable when the user has picked a direct provider
442
+ instead (so they still see the trade-off they made). */
443
+ .onb-key-recommend {
444
+ position: relative;
445
+ display: block;
446
+ text-align: left;
462
447
  background: var(--bg, #0A0A0A);
463
448
  border: 0.5px solid var(--line-strong, #3A3A35);
464
- padding: 16px 16px 14px;
465
- text-align: left;
449
+ padding: 12px 14px;
466
450
  cursor: pointer;
467
- transition: all 0.14s;
468
- display: flex;
469
- flex-direction: column;
470
- gap: 6px;
471
- position: relative;
472
451
  font-family: inherit;
473
- width: 100%;
474
- color: var(--text, #C8C5BE);
452
+ color: var(--text-soft, #8E8B83);
453
+ transition: border-color 0.14s, color 0.14s, background 0.14s;
454
+ }
455
+ .onb-key-recommend:hover {
456
+ border-color: var(--lime-dim, #2D5532);
475
457
  }
476
- .onb-final-card:hover {
458
+ .onb-key-recommend.active {
477
459
  border-color: var(--lime, #6FB572);
460
+ color: var(--text, #C8C5BE);
478
461
  background: var(--panel-2, #1A1A18);
479
462
  }
480
- .onb-final-card.primary { border-color: var(--lime-dim, #2D5532); }
481
- .onb-final-mark {
463
+ .onb-key-recommend-head {
464
+ display: flex;
465
+ align-items: baseline;
466
+ gap: 12px;
467
+ margin-bottom: 8px;
468
+ }
469
+ .onb-key-recommend-badge {
482
470
  font-family: var(--mono);
483
- font-size: 9.5px;
471
+ font-size: 9px;
484
472
  font-weight: 700;
485
- letter-spacing: 0.16em;
473
+ letter-spacing: 0.18em;
486
474
  text-transform: uppercase;
487
475
  color: var(--lime, #6FB572);
488
476
  }
489
- .onb-final-card.primary .onb-final-mark { color: var(--lime, #6FB572); }
490
- .onb-final-title {
477
+ .onb-key-recommend-name {
491
478
  font-family: var(--font-human);
492
- font-size: 15px;
493
- font-weight: 700;
494
- color: var(--text, #C8C5BE);
479
+ font-size: 14px;
480
+ font-weight: 600;
481
+ color: inherit;
495
482
  letter-spacing: -0.005em;
496
483
  }
497
- .onb-final-deck {
484
+ .onb-key-recommend.active .onb-key-recommend-name {
485
+ color: var(--text, #C8C5BE);
486
+ }
487
+ .onb-key-recommend-dot {
488
+ width: 6px;
489
+ height: 6px;
490
+ border-radius: 50%;
491
+ background: var(--lime, #6FB572);
492
+ display: inline-block;
493
+ font-size: 0;
494
+ line-height: 0;
495
+ margin-left: auto;
496
+ }
497
+ .onb-key-recommend-body {
498
498
  font-family: var(--font-human);
499
499
  font-size: 12px;
500
+ line-height: 1.55;
501
+ color: var(--text-dim, #5C5A52);
502
+ }
503
+ .onb-key-recommend.active .onb-key-recommend-body {
500
504
  color: var(--text-soft, #8E8B83);
501
- line-height: 1.5;
502
505
  }
503
506
 
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 {
507
+ /* "// or" divider · mono kicker between recommend card and direct
508
+ chips. Hairlines on either side keep it light. */
509
+ .onb-key-or {
510
+ display: flex;
511
+ align-items: center;
512
+ gap: 10px;
513
+ margin: 2px 0 -4px;
514
+ }
515
+ .onb-key-or-line {
516
+ flex: 1;
517
+ height: 1px;
518
+ background: var(--line-bright, #2A2A26);
519
+ }
520
+ .onb-key-or-text {
521
+ font-family: var(--mono);
522
+ font-size: 9px;
523
+ font-weight: 700;
524
+ letter-spacing: 0.2em;
525
+ text-transform: uppercase;
526
+ color: var(--text-faint, #3A382F);
527
+ }
528
+ .onb-key-or-body {
529
+ font-family: var(--font-human);
530
+ font-size: 12px;
531
+ line-height: 1.55;
532
+ color: var(--text-dim, #5C5A52);
533
+ margin: 0;
534
+ }
535
+
536
+ /* Direct provider chips · the three same-model options. Smaller
537
+ visual weight than the recommended card. */
538
+ .onb-key-directs {
509
539
  display: flex;
510
540
  flex-wrap: wrap;
511
- align-items: baseline;
512
- gap: 4px 18px;
513
- margin-bottom: 14px;
541
+ gap: 8px;
514
542
  }
515
- .onb-key-tab {
543
+ .onb-key-direct {
516
544
  position: relative;
517
545
  display: inline-flex;
518
- align-items: baseline;
519
- gap: 6px;
520
- padding: 4px 0 4px 14px;
521
- background: none;
522
- border: 0;
546
+ align-items: center;
547
+ gap: 8px;
548
+ padding: 6px 12px;
549
+ background: var(--bg, #0A0A0A);
550
+ border: 0.5px solid var(--line-strong, #3A3A35);
523
551
  color: var(--text-dim, #5C5A52);
524
552
  cursor: pointer;
525
- text-align: left;
526
553
  font-family: var(--font-human, "Inter", system-ui, sans-serif);
527
554
  font-size: 13px;
528
555
  font-weight: 500;
529
556
  letter-spacing: -0.005em;
530
557
  line-height: 1.2;
531
- transition: color 0.12s;
558
+ transition: border-color 0.12s, color 0.12s, background 0.12s;
532
559
  }
533
- .onb-key-tab:hover {
560
+ .onb-key-direct:hover {
561
+ border-color: var(--lime-dim, #2D5532);
534
562
  color: var(--text-soft, #8E8B83);
535
563
  }
536
- .onb-key-tab.active {
564
+ .onb-key-direct.active {
565
+ border-color: var(--lime, #6FB572);
537
566
  color: var(--text, #C8C5BE);
567
+ background: var(--panel-2, #1A1A18);
538
568
  font-weight: 600;
539
569
  }
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 {
570
+ .onb-key-direct-label { font: inherit; }
571
+ .onb-key-direct-dot {
558
572
  width: 5px;
559
573
  height: 5px;
560
574
  border-radius: 50%;
@@ -562,9 +576,7 @@
562
576
  display: inline-block;
563
577
  font-size: 0;
564
578
  line-height: 0;
565
- opacity: 0.85;
566
579
  }
567
- .onb-key-tab.active .onb-key-tab-dot { opacity: 1; }
568
580
 
569
581
  /* Status chip on the API key field */
570
582
  .onb-key-status {
@@ -626,3 +638,69 @@
626
638
  .onb-locked {
627
639
  overflow: hidden;
628
640
  }
641
+
642
+ /* ─────────────────────────────────────────────
643
+ ONE-SHOT COMPOSER HINT
644
+ Floats over the composer textarea on first run only.
645
+ ───────────────────────────────────────────── */
646
+ .onb-composer-hint {
647
+ position: fixed;
648
+ z-index: 1400;
649
+ max-width: 320px;
650
+ padding: 14px 16px 12px;
651
+ background: var(--panel, #131312);
652
+ border: 0.5px solid var(--lime, #6FB572);
653
+ color: var(--text, #C8C5BE);
654
+ font-family: var(--font-human, "Inter", system-ui, sans-serif);
655
+ opacity: 0;
656
+ transform: translateY(-4px);
657
+ transition: opacity 0.18s ease-out, transform 0.18s ease-out;
658
+ pointer-events: auto;
659
+ }
660
+ .onb-composer-hint.open { opacity: 1; transform: translateY(0); }
661
+ .onb-composer-hint-arrow {
662
+ position: absolute;
663
+ top: -7px;
664
+ left: 28px;
665
+ width: 12px;
666
+ height: 12px;
667
+ background: var(--panel, #131312);
668
+ border-top: 0.5px solid var(--lime, #6FB572);
669
+ border-left: 0.5px solid var(--lime, #6FB572);
670
+ transform: rotate(45deg);
671
+ }
672
+ .onb-composer-hint-kicker {
673
+ font-family: var(--mono);
674
+ font-size: 10px;
675
+ font-weight: 700;
676
+ letter-spacing: 0.18em;
677
+ text-transform: uppercase;
678
+ color: var(--lime, #6FB572);
679
+ margin-bottom: 8px;
680
+ }
681
+ .onb-composer-hint-body {
682
+ font-family: "Tiempos Text", "Charter", Georgia, "Times New Roman", serif;
683
+ font-style: italic;
684
+ font-size: 15px;
685
+ line-height: 1.45;
686
+ letter-spacing: -0.005em;
687
+ color: var(--text, #C8C5BE);
688
+ margin-bottom: 10px;
689
+ }
690
+ .onb-composer-hint-dismiss {
691
+ font-family: var(--mono);
692
+ font-size: 10px;
693
+ font-weight: 700;
694
+ letter-spacing: 0.12em;
695
+ text-transform: uppercase;
696
+ padding: 5px 10px;
697
+ background: transparent;
698
+ border: 0.5px solid var(--line-strong, #3A3A35);
699
+ color: var(--text-soft, #8E8B83);
700
+ cursor: pointer;
701
+ transition: all 0.12s;
702
+ }
703
+ .onb-composer-hint-dismiss:hover {
704
+ border-color: var(--lime, #6FB572);
705
+ color: var(--lime, #6FB572);
706
+ }