@bakapiano/ccsm 0.22.5 → 0.22.7

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 (59) hide show
  1. package/CLAUDE.md +538 -538
  2. package/README.md +189 -189
  3. package/bin/ccsm.js +235 -235
  4. package/lib/cliActivity.js +139 -139
  5. package/lib/codexSeed.js +183 -183
  6. package/lib/config.js +279 -274
  7. package/lib/devices.js +229 -229
  8. package/lib/folders.js +124 -124
  9. package/lib/localCliSessions.js +519 -519
  10. package/lib/persistedSessions.js +129 -129
  11. package/lib/tunnel.js +621 -621
  12. package/lib/webTerminal.js +225 -225
  13. package/lib/workspace.js +233 -233
  14. package/package.json +57 -57
  15. package/public/css/base.css +99 -99
  16. package/public/css/cards.css +183 -183
  17. package/public/css/feedback.css +504 -504
  18. package/public/css/forms.css +453 -453
  19. package/public/css/layout.css +177 -176
  20. package/public/css/modal.css +190 -190
  21. package/public/css/responsive.css +176 -176
  22. package/public/css/sidebar.css +707 -707
  23. package/public/css/terminals.css +547 -553
  24. package/public/css/tokens.css +81 -81
  25. package/public/css/wco.css +196 -196
  26. package/public/css/widgets.css +2725 -2725
  27. package/public/index.html +152 -152
  28. package/public/js/api.js +371 -371
  29. package/public/js/backend.js +149 -149
  30. package/public/js/components/App.js +73 -73
  31. package/public/js/components/DirectoryPicker.js +203 -203
  32. package/public/js/components/EntityFormModal.js +153 -153
  33. package/public/js/components/Modal.js +57 -57
  34. package/public/js/components/OfflineBanner.js +67 -67
  35. package/public/js/components/PageTitleBar.js +13 -13
  36. package/public/js/components/PendingApprovalOverlay.js +128 -128
  37. package/public/js/components/Picker.js +179 -179
  38. package/public/js/components/Popover.js +55 -55
  39. package/public/js/components/RestartOverlay.js +36 -36
  40. package/public/js/components/Sidebar.js +380 -380
  41. package/public/js/components/TerminalInstance.js +28 -9
  42. package/public/js/components/XtermTerminal.js +62 -2
  43. package/public/js/components/useDragSort.js +67 -67
  44. package/public/js/dialog.js +67 -67
  45. package/public/js/icons.js +212 -212
  46. package/public/js/main.js +296 -296
  47. package/public/js/pages/AboutPage.js +90 -90
  48. package/public/js/pages/ConfigurePage.js +728 -713
  49. package/public/js/pages/LaunchPage.js +421 -421
  50. package/public/js/pages/RemotePage.js +743 -743
  51. package/public/js/pages/SessionsPage.js +73 -80
  52. package/public/js/state.js +335 -335
  53. package/scripts/dev.js +149 -149
  54. package/scripts/install.js +153 -153
  55. package/scripts/restart-helper.js +96 -96
  56. package/scripts/upgrade-helper.js +687 -687
  57. package/server.js +1820 -1807
  58. package/public/manifest.webmanifest +0 -25
  59. package/public/setup/index.html +0 -567
@@ -1,2725 +1,2725 @@
1
- /* Workspace cards · clone-progress list · pagination · snapshot preview */
2
-
3
- .workspace-grid {
4
- display: grid;
5
- grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
6
- gap: var(--s-3);
7
- }
8
- .workspace-card {
9
- padding: var(--s-4);
10
- border: 1px solid var(--border-soft);
11
- background: var(--bg-elev);
12
- border-radius: 6px;
13
- transition: border-color .18s, box-shadow .18s, transform .18s;
14
- }
15
- .workspace-card:hover {
16
- border-color: var(--ink-faint);
17
- box-shadow: var(--shadow-md);
18
- transform: translateY(-1px);
19
- }
20
- .workspace-card.in-use {
21
- background: var(--bg);
22
- border-color: var(--ink-faint);
23
- box-shadow: inset 3px 0 0 var(--accent);
24
- }
25
- .workspace-card .ws-head {
26
- display: flex;
27
- align-items: baseline;
28
- justify-content: space-between;
29
- gap: var(--s-2);
30
- margin-bottom: 6px;
31
- }
32
- .workspace-card .ws-name {
33
- font-size: 14.5px;
34
- font-weight: 600;
35
- letter-spacing: -0.01em;
36
- color: var(--ink);
37
- line-height: 1.2;
38
- }
39
- .workspace-card .ws-tag {
40
- font-family: var(--mono);
41
- font-size: 10px;
42
- text-transform: uppercase;
43
- letter-spacing: 0.08em;
44
- padding: 2px 7px;
45
- border-radius: 4px;
46
- background: var(--bg);
47
- color: var(--ink-muted);
48
- border: 1px solid var(--border-soft);
49
- }
50
- .workspace-card.in-use .ws-tag {
51
- background: var(--bg-elev);
52
- color: var(--ink-mid);
53
- border-color: var(--ink-faint);
54
- }
55
- .workspace-card .ws-path {
56
- font-family: var(--mono);
57
- font-size: 11px;
58
- color: var(--ink-muted);
59
- word-break: break-all;
60
- margin-bottom: var(--s-3);
61
- }
62
- .workspace-card .ws-repos {
63
- display: flex;
64
- flex-wrap: wrap;
65
- gap: 4px;
66
- }
67
- .workspace-card .ws-repo {
68
- font-family: var(--mono);
69
- font-size: 10.5px;
70
- padding: 2px 7px;
71
- border-radius: 4px;
72
- background: var(--bg);
73
- color: var(--ink-muted);
74
- border: 1px solid var(--border-soft);
75
- }
76
- .workspace-card .ws-repo.cloned {
77
- color: var(--green);
78
- background: rgba(74, 138, 74, 0.06);
79
- border-color: rgba(74, 138, 74, 0.25);
80
- }
81
-
82
- /* Clone progress — one row per repo, NDJSON-driven by /api/sessions/new */
83
- .progress-list {
84
- display: flex;
85
- flex-direction: column;
86
- gap: var(--s-2);
87
- margin-top: var(--s-3);
88
- }
89
- .progress-list:empty { display: none; }
90
-
91
- .progress-item {
92
- border: 1px solid var(--border);
93
- background: var(--bg);
94
- border-radius: var(--r-sm);
95
- padding: var(--s-3) var(--s-4);
96
- }
97
- .progress-item .head {
98
- display: grid;
99
- grid-template-columns: 1fr auto auto;
100
- align-items: baseline;
101
- gap: var(--s-3);
102
- margin-bottom: var(--s-2);
103
- }
104
- .progress-item .name {
105
- font-family: var(--body);
106
- font-size: 12.5px;
107
- font-weight: 600;
108
- color: var(--ink);
109
- }
110
- .progress-item .phase {
111
- font-family: var(--mono);
112
- font-size: 10.5px;
113
- color: var(--ink-muted);
114
- letter-spacing: 0.04em;
115
- }
116
- .progress-item .pct {
117
- font-family: var(--mono);
118
- font-size: 11.5px;
119
- color: var(--ink-mid);
120
- font-variant-numeric: tabular-nums;
121
- }
122
- .progress-bar {
123
- height: 3px;
124
- background: var(--border);
125
- position: relative;
126
- overflow: hidden;
127
- border-radius: 2px;
128
- }
129
- .progress-bar .fill {
130
- height: 100%;
131
- width: 0;
132
- background: var(--ink);
133
- transition: width .2s ease;
134
- border-radius: 2px;
135
- }
136
- .progress-bar .fill.indeterminate {
137
- width: 35% !important;
138
- animation: indeterm 1.4s ease-in-out infinite;
139
- }
140
- @keyframes indeterm {
141
- from { transform: translateX(-110%); }
142
- to { transform: translateX(330%); }
143
- }
144
- .progress-item.ok .fill { background: var(--green); }
145
- .progress-item.error .fill { background: var(--red); }
146
- .progress-item .detail {
147
- margin-top: 4px;
148
- font-family: var(--mono);
149
- font-size: 10.5px;
150
- color: var(--ink-muted);
151
- min-height: 12px;
152
- }
153
-
154
- /* Pagination row — sits below table inside .card-body-flush card */
155
- .pagination {
156
- display: flex;
157
- align-items: center;
158
- gap: var(--s-3);
159
- padding: var(--s-3) var(--s-6);
160
- border-top: 1px solid var(--border-soft);
161
- background: var(--bg);
162
- font-size: 12.5px;
163
- color: var(--ink-mid);
164
- flex-wrap: wrap;
165
- }
166
- .pagination-info {
167
- flex: 1;
168
- text-align: center;
169
- font-family: var(--mono);
170
- font-size: 11.5px;
171
- color: var(--ink-muted);
172
- }
173
- .pagination-info strong {
174
- color: var(--ink);
175
- font-weight: 600;
176
- }
177
- .pagination select {
178
- font-size: 11.5px;
179
- padding: 4px 24px 4px 8px;
180
- }
181
-
182
- /* Snapshot raw-text preview (collapsible <details>) */
183
- .snapshot-detail { margin-top: var(--s-4); }
184
- .snapshot-detail summary {
185
- cursor: pointer;
186
- font-size: 12.5px;
187
- color: var(--ink-mid);
188
- padding: var(--s-2) 0;
189
- user-select: none;
190
- font-weight: 500;
191
- }
192
- .snapshot-detail summary::marker { color: var(--ink-mid); }
193
- .snapshot-detail summary:hover { color: var(--ink); }
194
- .preview {
195
- font-family: var(--mono);
196
- font-size: 11.5px;
197
- color: var(--ink-mid);
198
- background: var(--bg);
199
- border: 1px solid var(--border);
200
- border-radius: var(--r-sm);
201
- padding: var(--s-3);
202
- margin-top: var(--s-2);
203
- max-height: 280px;
204
- overflow: auto;
205
- white-space: pre;
206
- line-height: 1.55;
207
- }
208
-
209
- /* === Launch page hero · ChatGPT-style centered composer ============= */
210
-
211
- .launch-hero {
212
- max-width: 640px;
213
- width: 100%;
214
- margin: 0 auto;
215
- padding: var(--s-4);
216
- display: flex;
217
- flex-direction: column;
218
- align-items: center;
219
- justify-content: center;
220
- gap: var(--s-5);
221
- flex: 1;
222
- min-height: 0;
223
- }
224
-
225
- .launch-brand {
226
- display: inline-flex;
227
- align-items: center;
228
- justify-content: center;
229
- color: var(--accent);
230
- }
231
- .launch-brand-mark svg {
232
- width: 88px;
233
- height: 88px;
234
- display: block;
235
- }
236
-
237
- .launch-tagline {
238
- font-size: 26px;
239
- font-weight: 500;
240
- letter-spacing: -0.02em;
241
- color: var(--ink);
242
- text-align: center;
243
- margin: 0;
244
- line-height: 1.25;
245
- max-width: 32ch;
246
- }
247
- .launch-tagline em {
248
- font-style: normal;
249
- color: var(--accent);
250
- font-weight: 500;
251
- }
252
-
253
-
254
-
255
- .launch-status {
256
- font-family: var(--mono);
257
- font-size: 11.5px;
258
- color: var(--ink-muted);
259
- align-self: stretch;
260
- text-align: center;
261
- }
262
-
263
- .launch-import-link {
264
- display: inline-flex;
265
- align-items: center;
266
- background: transparent;
267
- border: none;
268
- font: inherit;
269
- font-size: 12px;
270
- color: var(--ink-faint);
271
- cursor: pointer;
272
- padding: 4px 8px;
273
- border-radius: 6px;
274
- transition: color 120ms ease;
275
- }
276
- .launch-import-link:hover { color: var(--ink-mid); }
277
- .launch-import-arrow {
278
- display: inline-flex;
279
- align-items: center;
280
- margin-left: 6px;
281
- transition: transform 180ms cubic-bezier(.4, 0, .2, 1);
282
- }
283
- .launch-import-link:hover .launch-import-arrow { transform: translateX(3px); }
284
-
285
- /* === Launch toolbar · A · Pill toolbar =========================== */
286
-
287
- .launch-toolbar {
288
- width: 100%;
289
- display: flex;
290
- align-items: center;
291
- justify-content: center;
292
- flex-wrap: wrap;
293
- gap: var(--s-2);
294
- }
295
-
296
- .pill {
297
- appearance: none;
298
- background: var(--bg);
299
- border: 1px solid var(--border-soft);
300
- border-radius: 999px;
301
- padding: 8px 14px 8px 12px;
302
- display: inline-flex;
303
- align-items: center;
304
- justify-content: center;
305
- gap: 8px;
306
- cursor: pointer;
307
- color: var(--ink);
308
- font: inherit;
309
- font-size: 13px;
310
- font-weight: 500;
311
- line-height: 1;
312
- white-space: nowrap;
313
- transition: background .12s ease, border-color .12s ease, color .12s ease;
314
- flex: 0 0 160px;
315
- width: 160px;
316
- min-width: 0;
317
- }
318
- .pill:hover {
319
- background: var(--sidebar-hover);
320
- border-color: var(--border);
321
- }
322
- .pill.is-open {
323
- background: var(--sidebar-active);
324
- border-color: var(--ink-faint);
325
- }
326
- .pill.is-set {
327
- border-color: var(--ink-faint);
328
- background: var(--sidebar-active);
329
- }
330
- .pill.is-disabled,
331
- .pill:disabled {
332
- opacity: 0.45;
333
- cursor: not-allowed;
334
- }
335
- .pill.is-disabled:hover,
336
- .pill:disabled:hover { background: var(--bg-elev); border-color: var(--border); }
337
-
338
- /* --- Workdir picker (Launch page) ----------------------------------- */
339
- .workdir-modal {
340
- display: flex;
341
- flex-direction: column;
342
- gap: 14px;
343
- padding: 18px 20px;
344
- }
345
- .workdir-mode-grid {
346
- display: grid;
347
- grid-template-columns: 1fr 1fr;
348
- gap: 10px;
349
- }
350
- .workdir-mode-opt {
351
- appearance: none;
352
- background: var(--bg-elev);
353
- border: 1px solid var(--border);
354
- border-radius: 10px;
355
- padding: 14px 14px 12px;
356
- cursor: pointer;
357
- display: grid;
358
- grid-template-columns: 32px 1fr;
359
- grid-template-rows: auto auto;
360
- column-gap: 10px;
361
- row-gap: 2px;
362
- text-align: left;
363
- align-items: center;
364
- font: inherit;
365
- color: var(--ink);
366
- transition: border-color .12s ease, background .12s ease, box-shadow .12s ease;
367
- }
368
- .workdir-mode-opt:hover {
369
- border-color: var(--ink-faint);
370
- }
371
- .workdir-mode-opt.is-active {
372
- border-color: var(--ink);
373
- background: var(--bg-elev);
374
- box-shadow: 0 0 0 1px var(--ink) inset;
375
- }
376
- .workdir-mode-icon {
377
- grid-row: 1 / span 2;
378
- width: 32px;
379
- height: 32px;
380
- display: inline-flex;
381
- align-items: center;
382
- justify-content: center;
383
- border-radius: 8px;
384
- background: var(--bg);
385
- color: var(--ink-mid);
386
- }
387
- .workdir-mode-opt.is-active .workdir-mode-icon {
388
- background: var(--ink);
389
- color: var(--bg-elev);
390
- }
391
- .workdir-mode-icon svg,
392
- .workdir-mode-icon img { width: 18px; height: 18px; display: block; }
393
- .workdir-mode-name {
394
- font-size: 13px;
395
- font-weight: 600;
396
- letter-spacing: -0.005em;
397
- }
398
- .workdir-mode-sub {
399
- font-size: 11.5px;
400
- color: var(--ink-muted);
401
- line-height: 1.35;
402
- }
403
- .workdir-mode-opt.is-active .workdir-mode-sub { color: var(--ink-mid); }
404
-
405
- .workdir-detail {
406
- border: 1px solid var(--border);
407
- border-radius: 10px;
408
- background: var(--bg);
409
- overflow: hidden;
410
- }
411
- .workdir-detail .picker { max-height: min(56vh, 420px); }
412
- .workdir-detail .filex {
413
- padding: 10px;
414
- gap: 10px;
415
- }
416
- .workdir-detail .filex-body { height: 320px; }
417
-
418
-
419
- .icon-radio-sub {
420
- font-size: 11px;
421
- font-weight: 400;
422
- color: var(--ink-muted);
423
- margin-top: 1px;
424
- }
425
- .icon-radio-opt.is-active .icon-radio-sub { color: var(--accent-deep); opacity: 0.85; }
426
-
427
- /* --- File-Explorer-style directory picker --------------------------- */
428
- .filex {
429
- display: flex;
430
- flex-direction: column;
431
- gap: 8px;
432
- font-size: 12.5px;
433
- }
434
- .filex-loading, .filex-empty {
435
- padding: 24px;
436
- text-align: center;
437
- font-size: 12px;
438
- color: var(--ink-muted);
439
- font-style: italic;
440
- }
441
-
442
- /* toolbar: back/fwd/up + breadcrumb */
443
- .filex-toolbar {
444
- display: flex;
445
- align-items: center;
446
- gap: 6px;
447
- padding: 4px;
448
- border: 1px solid var(--border);
449
- border-radius: 8px;
450
- background: var(--bg-elev);
451
- }
452
- .filex-navbtns {
453
- display: flex;
454
- gap: 2px;
455
- flex-shrink: 0;
456
- }
457
- .filex-navbtn {
458
- appearance: none;
459
- background: transparent;
460
- border: 0;
461
- width: 28px;
462
- height: 28px;
463
- border-radius: 6px;
464
- display: inline-flex;
465
- align-items: center;
466
- justify-content: center;
467
- color: var(--ink-mid);
468
- cursor: pointer;
469
- transition: background .12s ease, color .12s ease;
470
- }
471
- .filex-navbtn:hover:not(:disabled) {
472
- background: var(--sidebar-hover);
473
- color: var(--ink);
474
- }
475
- .filex-navbtn:disabled {
476
- opacity: 0.35;
477
- cursor: not-allowed;
478
- }
479
- .filex-navbtn svg { width: 14px; height: 14px; }
480
-
481
- .filex-breadcrumb {
482
- flex: 1;
483
- min-width: 0;
484
- display: flex;
485
- align-items: center;
486
- gap: 1px;
487
- flex-wrap: nowrap;
488
- overflow: hidden;
489
- padding: 0 6px;
490
- cursor: text;
491
- min-height: 28px;
492
- }
493
- .filex-crumb {
494
- appearance: none;
495
- background: transparent;
496
- border: 0;
497
- font: inherit;
498
- font-size: 12.5px;
499
- color: var(--ink);
500
- padding: 4px 8px;
501
- border-radius: 4px;
502
- cursor: pointer;
503
- white-space: nowrap;
504
- transition: background .1s ease;
505
- }
506
- .filex-crumb:hover { background: var(--bg); }
507
- .filex-crumb-sep {
508
- color: var(--ink-faint);
509
- font-size: 13px;
510
- user-select: none;
511
- flex-shrink: 0;
512
- }
513
- .filex-address-edit-btn {
514
- appearance: none;
515
- background: transparent;
516
- border: 0;
517
- width: 26px;
518
- height: 26px;
519
- border-radius: 4px;
520
- display: inline-flex;
521
- align-items: center;
522
- justify-content: center;
523
- color: var(--ink-faint);
524
- cursor: pointer;
525
- margin-left: auto;
526
- flex-shrink: 0;
527
- opacity: 0;
528
- transition: opacity .12s ease, background .12s ease, color .12s ease;
529
- }
530
- .filex-toolbar:hover .filex-address-edit-btn { opacity: 0.7; }
531
- .filex-address-edit-btn:hover {
532
- background: var(--sidebar-hover);
533
- color: var(--ink);
534
- opacity: 1;
535
- }
536
- .filex-address-edit-btn svg { width: 12px; height: 12px; }
537
- .filex-address-edit {
538
- flex: 1;
539
- display: flex;
540
- padding: 0 4px;
541
- }
542
- .filex-address-input {
543
- width: 100%;
544
- appearance: none;
545
- background: var(--bg);
546
- border: 1px solid var(--accent);
547
- border-radius: 5px;
548
- padding: 5px 8px;
549
- font-size: 12.5px;
550
- color: var(--ink);
551
- outline: none;
552
- }
553
-
554
- /* body: sidebar (quick access) + main file list */
555
- .filex-body {
556
- display: grid;
557
- grid-template-columns: 150px 1fr;
558
- gap: 8px;
559
- height: 360px;
560
- border: 1px solid var(--border);
561
- border-radius: 8px;
562
- background: var(--bg-elev);
563
- overflow: hidden;
564
- }
565
- .filex-side {
566
- border-right: 1px solid var(--border);
567
- background: var(--bg);
568
- overflow-y: auto;
569
- padding: 6px 4px;
570
- display: flex;
571
- flex-direction: column;
572
- gap: 1px;
573
- }
574
- .filex-side-label {
575
- font-size: 10px;
576
- font-weight: 600;
577
- text-transform: uppercase;
578
- letter-spacing: 0.08em;
579
- color: var(--ink-faint);
580
- padding: 4px 8px;
581
- }
582
- .filex-side-item {
583
- appearance: none;
584
- background: transparent;
585
- border: 0;
586
- text-align: left;
587
- font: inherit;
588
- font-size: 12px;
589
- color: var(--ink-mid);
590
- cursor: pointer;
591
- padding: 5px 8px;
592
- border-radius: 4px;
593
- display: flex;
594
- align-items: center;
595
- gap: 6px;
596
- width: 100%;
597
- overflow: hidden;
598
- text-overflow: ellipsis;
599
- white-space: nowrap;
600
- }
601
- .filex-side-item:hover { background: var(--sidebar-hover); color: var(--ink); }
602
- .filex-side-item.is-active {
603
- background: var(--sidebar-active);
604
- color: var(--ink);
605
- font-weight: 500;
606
- }
607
- .filex-side-icon {
608
- display: inline-flex;
609
- width: 14px;
610
- height: 14px;
611
- align-items: center;
612
- justify-content: center;
613
- color: var(--ink-faint);
614
- }
615
- .filex-side-icon svg { width: 13px; height: 13px; }
616
- .filex-side-name {
617
- flex: 1;
618
- min-width: 0;
619
- overflow: hidden;
620
- text-overflow: ellipsis;
621
- }
622
-
623
- .filex-main { overflow-y: auto; }
624
- .filex-list { padding: 4px; }
625
- .filex-row {
626
- appearance: none;
627
- display: flex;
628
- align-items: center;
629
- gap: 10px;
630
- width: 100%;
631
- padding: 8px 10px;
632
- background: transparent;
633
- border: 0;
634
- border-radius: 5px;
635
- text-align: left;
636
- font: inherit;
637
- font-size: 12.5px;
638
- color: var(--ink);
639
- cursor: pointer;
640
- transition: background .08s ease;
641
- }
642
- .filex-row:hover { background: var(--bg); }
643
- .filex-row[data-active="true"] {
644
- background: var(--accent-soft);
645
- color: var(--accent-deep);
646
- }
647
- .filex-row[data-active="true"] .filex-row-icon { color: var(--accent); }
648
- .filex-row-icon {
649
- display: inline-flex;
650
- width: 18px;
651
- height: 18px;
652
- align-items: center;
653
- justify-content: center;
654
- color: var(--ink-muted);
655
- flex-shrink: 0;
656
- }
657
- .filex-row-icon svg { width: 16px; height: 16px; }
658
- .filex-row-name {
659
- flex: 1;
660
- min-width: 0;
661
- overflow: hidden;
662
- text-overflow: ellipsis;
663
- white-space: nowrap;
664
- }
665
-
666
- .filex-foot {
667
- display: flex;
668
- align-items: center;
669
- gap: 8px;
670
- padding-top: 6px;
671
- border-top: 1px solid var(--border);
672
- }
673
- .filex-foot-current {
674
- flex: 1;
675
- min-width: 0;
676
- font-size: 11px;
677
- color: var(--ink-muted);
678
- overflow: hidden;
679
- text-overflow: ellipsis;
680
- white-space: nowrap;
681
- }
682
- .filex-foot-actions {
683
- display: flex;
684
- gap: 6px;
685
- flex-shrink: 0;
686
- }
687
- .pill-icon {
688
- display: inline-flex;
689
- align-items: center;
690
- color: var(--ink-muted);
691
- flex: 0 0 auto;
692
- }
693
- .pill-icon svg { width: 14px; height: 14px; }
694
- .pill-label {
695
- flex: 0 1 auto;
696
- min-width: 0;
697
- overflow: hidden;
698
- text-overflow: ellipsis;
699
- }
700
- .pill-chev {
701
- display: inline-flex;
702
- color: var(--ink-faint);
703
- margin-left: 2px;
704
- flex: 0 0 auto;
705
- transition: transform .15s ease;
706
- }
707
- .pill-chev svg { width: 12px; height: 12px; }
708
- .pill.is-open .pill-chev { transform: rotate(180deg); }
709
-
710
- .action.launch-cta {
711
- align-self: center;
712
- border-radius: 6px;
713
- padding: 7px 22px;
714
- font-size: 13px;
715
- font-weight: 500;
716
- letter-spacing: -0.005em;
717
- display: inline-flex;
718
- align-items: center;
719
- justify-content: center;
720
- gap: 6px;
721
- min-width: 0;
722
- margin-top: var(--s-1);
723
- background: var(--accent);
724
- border-color: var(--accent);
725
- color: #fff;
726
- }
727
- .action.launch-cta:hover:not(:disabled) {
728
- background: var(--accent-deep);
729
- border-color: var(--accent-deep);
730
- box-shadow: 0 4px 12px -4px var(--accent-soft);
731
- }
732
-
733
- /* === Settings page scroll container ================================
734
- .tab-panel is flex:1 inside .content which clips overflow. Without a
735
- scroll layer Settings cards beyond the viewport bottom get cut off. */
736
- .settings-scroll {
737
- flex: 1;
738
- min-height: 0;
739
- overflow-y: auto;
740
- display: flex;
741
- flex-direction: column;
742
- gap: var(--s-4);
743
- /* Negative right margin = -var(--s-4) cancels .main's padding-right
744
- so the scroll container — and therefore the scrollbar — reach the
745
- full window edge. Padding-right = var(--s-4) preserves the same
746
- visual gap between content and the right edge that was there
747
- before. Top padding bumped to var(--s-3) so the first section title
748
- has visible breathing room from the page-title-bar separator above
749
- it (4px was almost flush). Negative margin-top stays in sync. */
750
- padding: var(--s-4) var(--s-4) var(--s-4) 4px;
751
- margin: -4px calc(-1 * var(--s-4)) 0 -4px;
752
- }
753
- /* In a flex column container, items default to flex-shrink:1 which
754
- causes the cards to compress instead of pushing the scroll container
755
- to actually scroll. flex:0 0 auto pins them to their natural height. */
756
- .settings-scroll > .card { flex: 0 0 auto; }
757
- .settings-scroll > .settings-section { flex: 0 0 auto; }
758
-
759
- /* === Settings section · A · flat, no card ========================== */
760
- .settings-section {
761
- display: flex;
762
- flex-direction: column;
763
- gap: var(--s-3);
764
- padding-bottom: var(--s-5);
765
- border-bottom: 1px solid var(--border-soft);
766
- }
767
- .settings-section:last-child { border-bottom: 0; }
768
- .settings-section-head {
769
- display: flex;
770
- flex-direction: column;
771
- gap: 2px;
772
- }
773
- .settings-section-title {
774
- font-size: 15px;
775
- font-weight: 600;
776
- letter-spacing: -0.012em;
777
- color: var(--ink);
778
- line-height: 1.2;
779
- margin: 0;
780
- }
781
- .settings-section-meta {
782
- font-size: 12.5px;
783
- color: var(--ink-muted);
784
- margin: 0;
785
- }
786
- .settings-section-body { display: flex; flex-direction: column; gap: var(--s-2); }
787
-
788
- /* === Settings entity list (CLIs / Repos / Folders) ================== */
789
- .entity-list {
790
- display: flex;
791
- flex-direction: column;
792
- gap: 2px;
793
- }
794
- .entity-row {
795
- display: flex;
796
- align-items: center;
797
- gap: var(--s-3);
798
- padding: 8px 8px 8px 4px;
799
- border-radius: 6px;
800
- transition: background .1s ease;
801
- }
802
- .entity-row.is-draggable { cursor: grab; }
803
- .entity-row.is-draggable:active { cursor: grabbing; }
804
- .entity-row[data-dnd-over="true"] {
805
- box-shadow: 0 -2px 0 var(--accent) inset;
806
- }
807
- .entity-row-grip {
808
- display: inline-flex;
809
- align-items: center;
810
- justify-content: center;
811
- width: 14px;
812
- color: var(--ink-faint);
813
- font-size: 12px;
814
- letter-spacing: -1px;
815
- user-select: none;
816
- pointer-events: none;
817
- flex: 0 0 14px;
818
- }
819
- .entity-row:hover { background: var(--bg); }
820
- .entity-row-icon {
821
- display: inline-flex;
822
- align-items: center;
823
- justify-content: center;
824
- width: 20px;
825
- height: 20px;
826
- color: var(--ink-muted);
827
- flex: 0 0 20px;
828
- }
829
- .entity-row-icon svg { width: 16px; height: 16px; }
830
- .entity-row-main {
831
- flex: 0 1 auto;
832
- min-width: 0;
833
- display: flex;
834
- flex-direction: column;
835
- gap: 1px;
836
- }
837
- .entity-row-primary {
838
- font-size: 13px;
839
- font-weight: 500;
840
- color: var(--ink);
841
- display: inline-flex;
842
- align-items: center;
843
- gap: 6px;
844
- }
845
- .entity-row-badge {
846
- font-family: var(--mono);
847
- font-size: 10px;
848
- letter-spacing: 0.06em;
849
- text-transform: uppercase;
850
- padding: 1px 6px;
851
- border-radius: 4px;
852
- font-weight: 500;
853
- }
854
- .entity-row-badge.tone-accent {
855
- background: var(--accent-soft);
856
- color: var(--accent-deep);
857
- }
858
- .entity-row-badge.tone-ok {
859
- background: rgba(74, 138, 74, 0.12);
860
- color: var(--green);
861
- }
862
- .entity-row-badge.tone-warn {
863
- background: rgba(196, 137, 43, 0.14);
864
- color: var(--yellow);
865
- }
866
- .entity-row-secondary {
867
- font-size: 11.5px;
868
- color: var(--ink-muted);
869
- overflow: hidden;
870
- text-overflow: ellipsis;
871
- white-space: nowrap;
872
- }
873
- .entity-row-actions {
874
- display: flex;
875
- align-items: center;
876
- gap: 2px;
877
- flex-shrink: 0;
878
- opacity: 0;
879
- transition: opacity .12s ease;
880
- margin-right: auto; /* pin actions next to the name, let trailing space stay empty */
881
- }
882
- .entity-row:hover .entity-row-actions,
883
- .entity-row:focus-within .entity-row-actions {
884
- opacity: 1;
885
- }
886
- .entity-row-action {
887
- appearance: none;
888
- background: transparent;
889
- border: 0;
890
- display: inline-flex;
891
- align-items: center;
892
- justify-content: center;
893
- width: 30px;
894
- height: 30px;
895
- border-radius: 6px;
896
- cursor: pointer;
897
- color: var(--ink-mid);
898
- font: inherit;
899
- font-size: 16px;
900
- transition: background .12s ease, color .12s ease;
901
- }
902
- .entity-row-action:hover { background: var(--sidebar-hover); color: var(--ink); }
903
- .entity-row-action.danger:hover { color: var(--red); }
904
- .entity-row-action svg { width: 16px; height: 16px; }
905
-
906
- .entity-empty {
907
- padding: 14px 10px;
908
- font-size: 12.5px;
909
- color: var(--ink-muted);
910
- font-style: italic;
911
- }
912
-
913
- .entity-add {
914
- appearance: none;
915
- background: var(--accent);
916
- border: 0;
917
- display: inline-flex;
918
- align-self: flex-start;
919
- align-items: center;
920
- gap: 6px;
921
- padding: 6px 12px;
922
- margin-top: 4px;
923
- border-radius: 6px;
924
- cursor: pointer;
925
- color: #fff;
926
- font: inherit;
927
- font-size: 12.5px;
928
- font-weight: 500;
929
- transition: background .12s ease, box-shadow .12s ease;
930
- }
931
- .entity-add:hover {
932
- background: var(--accent-deep);
933
- box-shadow: 0 2px 6px -2px var(--accent-soft);
934
- }
935
- .entity-add svg { width: 13px; height: 13px; }
936
-
937
- /* === EntityFormModal · shared form layout ========================== */
938
- .entity-form {
939
- padding: var(--s-4);
940
- display: flex;
941
- flex-direction: column;
942
- gap: var(--s-3);
943
- }
944
- .entity-field {
945
- display: flex;
946
- flex-direction: column;
947
- gap: 4px;
948
- }
949
- .entity-field-label {
950
- font-size: 11.5px;
951
- color: var(--ink-muted);
952
- font-weight: 500;
953
- }
954
- .entity-field .input {
955
- padding: 8px 10px;
956
- font-size: 13px;
957
- max-width: none;
958
- }
959
- .entity-field .input[readonly],
960
- .entity-field .input:disabled {
961
- background: var(--bg);
962
- color: var(--ink-muted);
963
- cursor: not-allowed;
964
- }
965
- .entity-field-hint {
966
- font-size: 11px;
967
- color: var(--ink-muted);
968
- }
969
- .entity-checkbox-row {
970
- display: inline-flex;
971
- align-items: center;
972
- gap: 8px;
973
- padding: 4px 0;
974
- }
975
- /* EntityFormModal's actions live in the modal footer (.modal-foot) now;
976
- this keeps the Test button pushed to the left of Cancel/Save there. */
977
- .modal-foot .entity-test-button { margin-right: auto; }
978
-
979
- .entity-test-result {
980
- margin-top: 4px;
981
- padding: 8px 10px;
982
- border-radius: 6px;
983
- border: 1px solid var(--border);
984
- background: var(--bg);
985
- display: flex;
986
- flex-direction: column;
987
- gap: 6px;
988
- font-size: 12.5px;
989
- }
990
- .entity-test-result.is-ok { border-color: rgba(74, 138, 74, 0.4); background: rgba(74, 138, 74, 0.06); }
991
- .entity-test-result.is-fail { border-color: rgba(183, 63, 63, 0.4); background: rgba(183, 63, 63, 0.06); }
992
- .entity-test-summary {
993
- font-family: var(--body);
994
- font-weight: 500;
995
- color: var(--ink);
996
- }
997
- .entity-test-result.is-fail .entity-test-summary { color: var(--red); }
998
- .entity-test-out {
999
- margin: 0;
1000
- font-family: var(--mono);
1001
- font-size: 11.5px;
1002
- color: var(--ink-mid);
1003
- white-space: pre-wrap;
1004
- word-break: break-word;
1005
- max-height: 120px;
1006
- overflow-y: auto;
1007
- }
1008
- .entity-test-out.is-stderr { color: var(--ink-muted); border-top: 1px dashed var(--border); padding-top: 4px; }
1009
-
1010
- .icon-radio {
1011
- display: grid;
1012
- grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
1013
- gap: 6px;
1014
- }
1015
- .icon-radio.is-disabled { opacity: 0.6; pointer-events: none; }
1016
- .icon-radio-opt {
1017
- appearance: none;
1018
- background: var(--bg-elev);
1019
- border: 1px solid var(--border);
1020
- border-radius: 6px;
1021
- padding: 10px 8px 8px;
1022
- cursor: pointer;
1023
- display: flex;
1024
- flex-direction: column;
1025
- align-items: center;
1026
- gap: 6px;
1027
- color: var(--ink-mid);
1028
- font: inherit;
1029
- font-size: 12px;
1030
- font-weight: 500;
1031
- transition: border-color .12s ease, background .12s ease, color .12s ease;
1032
- }
1033
- .icon-radio-opt:hover { border-color: var(--ink-faint); color: var(--ink); }
1034
- .icon-radio-opt.is-active {
1035
- background: var(--accent-soft);
1036
- border-color: var(--accent);
1037
- color: var(--accent-deep);
1038
- }
1039
- .icon-radio-opt:disabled { cursor: not-allowed; }
1040
- .icon-radio-icon {
1041
- display: inline-flex;
1042
- align-items: center;
1043
- justify-content: center;
1044
- width: 24px;
1045
- height: 24px;
1046
- }
1047
- .icon-radio-icon svg,
1048
- .icon-radio-icon img { width: 24px; height: 24px; display: block; }
1049
- .launch-cta-plane {
1050
- display: inline-flex;
1051
- align-items: center;
1052
- justify-content: center;
1053
- width: 16px;
1054
- height: 16px;
1055
- /* Resting state: tilted slightly clockwise, like a paper plane caught
1056
- mid-glide. */
1057
- transform: translate(0, 0) rotate(8deg);
1058
- transform-origin: 60% 50%;
1059
- transition: transform .35s cubic-bezier(.4, 0, .2, 1),
1060
- opacity .25s ease;
1061
- will-change: transform, opacity;
1062
- }
1063
- .launch-cta-plane svg { width: 100%; height: 100%; }
1064
- .launch-cta:hover:not(:disabled) .launch-cta-plane {
1065
- /* Small lift + glide forward — no big arc, no fade-out. */
1066
- transform: translate(4px, -3px) rotate(14deg);
1067
- }
1068
-
1069
- /* Narrow viewport — toolbar wraps. Push the Launch button onto its own
1070
- row so the pills stay readable. */
1071
- @media (max-width: 720px) {
1072
- .launch-toolbar {
1073
- flex-direction: column;
1074
- align-items: center;
1075
- }
1076
- .pill { justify-content: center; flex: 0 0 auto; }
1077
- }
1078
-
1079
- /* === Popover + Picker ============================================== */
1080
- .popover-panel {
1081
- position: fixed;
1082
- /* Above the modal backdrop (200) so pickers opened from inside a modal
1083
- — e.g. "Import as" in the adopt modal — float on top, not behind it.
1084
- Still below toasts (1200). */
1085
- z-index: 250;
1086
- background: var(--bg-elev);
1087
- border: 1px solid var(--border);
1088
- border-radius: 10px;
1089
- box-shadow: var(--shadow-lg);
1090
- overflow: hidden;
1091
- animation: popover-in .14s ease-out;
1092
- }
1093
- @keyframes popover-in {
1094
- from { opacity: 0; transform: translateY(-4px); }
1095
- to { opacity: 1; transform: translateY(0); }
1096
- }
1097
-
1098
- .picker {
1099
- display: flex;
1100
- flex-direction: column;
1101
- max-height: min(60vh, 460px);
1102
- }
1103
- .picker-title {
1104
- padding: 10px 14px 6px;
1105
- font-size: 11px;
1106
- color: var(--ink-muted);
1107
- font-weight: 500;
1108
- letter-spacing: 0;
1109
- border-bottom: 1px solid var(--border-soft);
1110
- }
1111
- .picker-search {
1112
- display: flex;
1113
- align-items: center;
1114
- gap: 8px;
1115
- padding: 8px 12px;
1116
- border-bottom: 1px solid var(--border-soft);
1117
- }
1118
- .picker-search-icon {
1119
- display: inline-flex;
1120
- align-items: center;
1121
- color: var(--ink-faint);
1122
- }
1123
- .picker-search-icon svg { width: 14px; height: 14px; }
1124
- .picker-search-input {
1125
- flex: 1;
1126
- appearance: none;
1127
- background: transparent;
1128
- border: 0;
1129
- outline: none;
1130
- padding: 4px 0;
1131
- font: inherit;
1132
- font-size: 13px;
1133
- color: var(--ink);
1134
- }
1135
- .picker-search-input::placeholder { color: var(--ink-faint); }
1136
- .picker-search-clear {
1137
- appearance: none;
1138
- background: transparent;
1139
- border: 0;
1140
- padding: 2px;
1141
- cursor: pointer;
1142
- color: var(--ink-muted);
1143
- display: inline-flex;
1144
- align-items: center;
1145
- border-radius: 4px;
1146
- }
1147
- .picker-search-clear:hover { background: var(--sidebar-hover); color: var(--ink); }
1148
- .picker-search-clear svg { width: 12px; height: 12px; }
1149
-
1150
- .picker-list {
1151
- overflow-y: auto;
1152
- padding: 4px;
1153
- flex: 1 1 auto;
1154
- min-height: 0;
1155
- }
1156
- .picker-empty {
1157
- padding: 18px 14px;
1158
- font-size: 12.5px;
1159
- color: var(--ink-muted);
1160
- text-align: center;
1161
- line-height: 1.5;
1162
- }
1163
- .picker-item {
1164
- appearance: none;
1165
- background: transparent;
1166
- border: 0;
1167
- width: 100%;
1168
- text-align: left;
1169
- display: flex;
1170
- align-items: center;
1171
- gap: 10px;
1172
- padding: 7px 10px;
1173
- border-radius: 6px;
1174
- cursor: pointer;
1175
- color: var(--ink);
1176
- font: inherit;
1177
- font-size: 13px;
1178
- transition: background .1s ease;
1179
- }
1180
- .picker-item-wrap {
1181
- position: relative;
1182
- display: flex;
1183
- align-items: center;
1184
- }
1185
- .picker-item-wrap.is-draggable { cursor: grab; }
1186
- .picker-item-wrap.is-draggable:active { cursor: grabbing; }
1187
- .picker-item-wrap[data-dnd-over="true"] {
1188
- box-shadow: 0 -2px 0 var(--accent) inset;
1189
- }
1190
- .picker-item-grip {
1191
- display: inline-flex;
1192
- align-items: center;
1193
- justify-content: center;
1194
- width: 14px;
1195
- margin-left: 2px;
1196
- color: var(--ink-faint);
1197
- font-size: 11px;
1198
- letter-spacing: -1px;
1199
- user-select: none;
1200
- pointer-events: none;
1201
- flex: 0 0 14px;
1202
- }
1203
- .picker-item:hover { background: var(--sidebar-hover); }
1204
- .picker-item.is-selected {
1205
- background: var(--sidebar-active);
1206
- font-weight: 500;
1207
- }
1208
- .picker-item:disabled {
1209
- opacity: 0.45;
1210
- cursor: not-allowed;
1211
- }
1212
- .picker-item-icon {
1213
- display: inline-flex;
1214
- align-items: center;
1215
- justify-content: center;
1216
- width: 18px;
1217
- height: 18px;
1218
- flex: 0 0 18px;
1219
- color: var(--ink-muted);
1220
- }
1221
- .picker-item-icon svg,
1222
- .picker-item-icon img { width: 18px; height: 18px; display: block; }
1223
- .picker-item-label {
1224
- flex: 0 0 auto;
1225
- white-space: nowrap;
1226
- }
1227
- .picker-item-meta {
1228
- flex: 1 1 auto;
1229
- min-width: 0;
1230
- font-family: var(--mono);
1231
- font-size: 11px;
1232
- color: var(--ink-muted);
1233
- overflow: hidden;
1234
- text-overflow: ellipsis;
1235
- white-space: nowrap;
1236
- }
1237
- .picker-item-check {
1238
- margin-left: auto;
1239
- font-size: 12px;
1240
- color: var(--accent);
1241
- flex: 0 0 auto;
1242
- }
1243
-
1244
- .picker-create {
1245
- border-top: 1px solid var(--border-soft);
1246
- padding: 6px;
1247
- }
1248
- .picker-create-toggle {
1249
- appearance: none;
1250
- background: transparent;
1251
- border: 0;
1252
- width: 100%;
1253
- display: flex;
1254
- align-items: center;
1255
- gap: 8px;
1256
- padding: 8px 10px;
1257
- border-radius: 6px;
1258
- cursor: pointer;
1259
- color: var(--ink-mid);
1260
- font: inherit;
1261
- font-size: 12.5px;
1262
- font-weight: 500;
1263
- transition: background .1s ease, color .1s ease;
1264
- }
1265
- .picker-create-toggle:hover {
1266
- background: var(--sidebar-hover);
1267
- color: var(--ink);
1268
- }
1269
- .picker-create-toggle svg { width: 14px; height: 14px; }
1270
-
1271
- .picker-create-form {
1272
- padding: 10px;
1273
- display: flex;
1274
- flex-direction: column;
1275
- gap: 8px;
1276
- }
1277
- .picker-field {
1278
- display: flex;
1279
- flex-direction: column;
1280
- gap: 4px;
1281
- }
1282
- .picker-field-label {
1283
- font-size: 11px;
1284
- color: var(--ink-muted);
1285
- font-weight: 500;
1286
- }
1287
- .picker-field .input {
1288
- padding: 6px 10px;
1289
- font-size: 12.5px;
1290
- max-width: none;
1291
- }
1292
- .picker-create-actions {
1293
- display: flex;
1294
- justify-content: flex-end;
1295
- gap: 6px;
1296
- margin-top: 4px;
1297
- }
1298
-
1299
- /* --- Adopt (import existing CLI session) modal --------------------- */
1300
- /* Fills the (flush, scrolling) modal body: a pinned head (tabs + tools)
1301
- and a scrolling list below it; pagination lives in the modal footer. */
1302
- .adopt { display: flex; flex-direction: column; min-height: 360px; }
1303
-
1304
- .adopt-head {
1305
- position: sticky;
1306
- top: 0;
1307
- z-index: 2;
1308
- display: flex;
1309
- flex-direction: column;
1310
- gap: 12px;
1311
- padding: 14px 18px 12px;
1312
- background: var(--bg-elev);
1313
- border-bottom: 1px solid var(--border-soft);
1314
- }
1315
-
1316
- /* Underline tab bar (was solid pills) — calmer, matches the app. */
1317
- .adopt-tabs {
1318
- display: flex;
1319
- align-items: center;
1320
- gap: 2px;
1321
- }
1322
- .adopt-tab {
1323
- appearance: none;
1324
- display: inline-flex;
1325
- align-items: center;
1326
- gap: 7px;
1327
- padding: 6px 11px 8px;
1328
- background: transparent;
1329
- border: 0;
1330
- border-bottom: 2px solid transparent;
1331
- font: inherit;
1332
- font-size: 13px;
1333
- font-weight: 500;
1334
- color: var(--ink-muted);
1335
- cursor: pointer;
1336
- transition: color .12s ease, border-color .12s ease;
1337
- }
1338
- .adopt-tab:hover { color: var(--ink); }
1339
- .adopt-tab.is-active {
1340
- color: var(--ink);
1341
- border-bottom-color: var(--ink);
1342
- }
1343
- .adopt-tab-icon { display: inline-flex; width: 16px; height: 16px; }
1344
- .adopt-tab-icon svg, .adopt-tab-icon img { width: 100%; height: 100%; }
1345
- .adopt-tab-count {
1346
- display: inline-flex;
1347
- align-items: center;
1348
- justify-content: center;
1349
- min-width: 17px;
1350
- height: 16px;
1351
- padding: 0 5px;
1352
- border-radius: 999px;
1353
- background: var(--ui-bg);
1354
- color: var(--ink-mid);
1355
- font-size: 10.5px;
1356
- font-weight: 600;
1357
- font-variant-numeric: tabular-nums;
1358
- }
1359
- .adopt-rescan {
1360
- appearance: none;
1361
- margin-left: auto;
1362
- display: inline-flex;
1363
- align-items: center;
1364
- justify-content: center;
1365
- width: 28px;
1366
- height: 28px;
1367
- padding: 0;
1368
- border: 1px solid var(--border);
1369
- background: var(--bg-elev);
1370
- color: var(--ink-muted);
1371
- border-radius: 8px;
1372
- cursor: pointer;
1373
- transition: color .12s ease, border-color .12s ease, transform .3s ease;
1374
- }
1375
- .adopt-rescan:hover { color: var(--ink); border-color: var(--ink-faint); transform: rotate(90deg); }
1376
- .adopt-rescan svg { width: 14px; height: 14px; }
1377
-
1378
- /* Tools row: CLI picker pill + search input */
1379
- .adopt-tools {
1380
- display: flex;
1381
- align-items: center;
1382
- gap: 10px;
1383
- flex-wrap: wrap;
1384
- }
1385
- .adopt-cli-pill {
1386
- appearance: none;
1387
- display: inline-flex;
1388
- align-items: center;
1389
- gap: 6px;
1390
- padding: 5px 8px 5px 10px;
1391
- height: 30px;
1392
- border: 1px solid var(--border);
1393
- border-radius: 8px;
1394
- background: var(--bg-elev);
1395
- color: var(--ink);
1396
- font: inherit;
1397
- font-size: 12px;
1398
- cursor: pointer;
1399
- transition: border-color .12s ease, background .12s ease;
1400
- }
1401
- .adopt-cli-pill:hover { border-color: var(--ink-faint); background: var(--bg); }
1402
- .adopt-cli-pill.is-open { border-color: var(--ink); }
1403
- .adopt-cli-pill-prefix { color: var(--ink-muted); font-size: 11.5px; }
1404
- .adopt-cli-pill-icon {
1405
- display: inline-flex; align-items: center; justify-content: center;
1406
- width: 14px; height: 14px;
1407
- }
1408
- .adopt-cli-pill-icon svg { width: 100%; height: 100%; }
1409
- .adopt-cli-pill-name { font-weight: 500; }
1410
- .adopt-cli-pill > svg { color: var(--ink-faint); width: 12px; height: 12px; }
1411
-
1412
- .adopt-search {
1413
- position: relative;
1414
- flex: 1 1 200px;
1415
- min-width: 200px;
1416
- }
1417
- .adopt-search-icon {
1418
- position: absolute;
1419
- left: 9px;
1420
- top: 50%;
1421
- transform: translateY(-50%);
1422
- display: inline-flex;
1423
- color: var(--ink-faint);
1424
- pointer-events: none;
1425
- }
1426
- .adopt-search-icon svg { width: 13px; height: 13px; }
1427
- .adopt-search-input {
1428
- appearance: none;
1429
- width: 100%;
1430
- height: 30px;
1431
- padding: 0 28px 0 28px;
1432
- border: 1px solid var(--border);
1433
- border-radius: 8px;
1434
- background: var(--bg-elev);
1435
- color: var(--ink);
1436
- font: inherit;
1437
- font-size: 12px;
1438
- outline: none;
1439
- transition: border-color .12s ease;
1440
- }
1441
- .adopt-search-input:focus { border-color: var(--ink-faint); }
1442
- .adopt-search-input:disabled { color: var(--ink-faint); }
1443
- .adopt-search-clear {
1444
- appearance: none;
1445
- position: absolute;
1446
- right: 6px;
1447
- top: 50%;
1448
- transform: translateY(-50%);
1449
- border: 0;
1450
- background: transparent;
1451
- color: var(--ink-faint);
1452
- padding: 4px;
1453
- border-radius: 6px;
1454
- cursor: pointer;
1455
- display: inline-flex;
1456
- }
1457
- .adopt-search-clear:hover { color: var(--ink); background: var(--bg); }
1458
- .adopt-search-clear svg { width: 11px; height: 11px; }
1459
-
1460
- /* The list scrolls inside the modal body now (not its own overflow box);
1461
- this is just the padded wrapper. */
1462
- .adopt-list {
1463
- padding: 12px 18px 16px;
1464
- }
1465
- .adopt-empty {
1466
- padding: 48px 12px;
1467
- text-align: center;
1468
- color: var(--ink-muted);
1469
- font-size: 12.5px;
1470
- display: flex;
1471
- flex-direction: column;
1472
- align-items: center;
1473
- gap: 10px;
1474
- }
1475
- .adopt-error { color: var(--danger); }
1476
- .adopt-empty-mark {
1477
- font-size: 24px;
1478
- color: var(--ink-faint);
1479
- width: 44px;
1480
- height: 44px;
1481
- border-radius: 50%;
1482
- background: var(--bg);
1483
- display: inline-flex;
1484
- align-items: center;
1485
- justify-content: center;
1486
- border: 1px dashed var(--border);
1487
- }
1488
- .adopt-empty-spinner {
1489
- width: 14px; height: 14px; border-radius: 50%;
1490
- border: 1.6px solid var(--border);
1491
- border-top-color: var(--ink-faint);
1492
- animation: adopt-spin 0.8s linear infinite;
1493
- display: inline-block;
1494
- vertical-align: -2px;
1495
- margin-right: 6px;
1496
- }
1497
- @keyframes adopt-spin { to { transform: rotate(360deg); } }
1498
-
1499
- .adopt-rows {
1500
- list-style: none;
1501
- margin: 0;
1502
- padding: 0;
1503
- display: flex;
1504
- flex-direction: column;
1505
- gap: 6px;
1506
- }
1507
- .adopt-row {
1508
- display: flex;
1509
- align-items: center;
1510
- gap: 11px;
1511
- padding: 10px 12px;
1512
- border: 1px solid var(--border);
1513
- background: var(--bg-elev);
1514
- border-radius: 10px;
1515
- transition: border-color .12s ease, background .12s ease, transform .12s ease;
1516
- }
1517
- .adopt-row-icon {
1518
- position: relative;
1519
- flex: 0 0 auto;
1520
- display: inline-flex;
1521
- align-items: center;
1522
- justify-content: center;
1523
- width: 30px;
1524
- height: 30px;
1525
- border-radius: 8px;
1526
- background: var(--bg);
1527
- border: 1px solid var(--border-soft);
1528
- }
1529
- .adopt-row-icon svg, .adopt-row-icon img { width: 17px; height: 17px; }
1530
- .adopt-row:hover {
1531
- border-color: var(--ink-faint);
1532
- transform: translateY(-1px);
1533
- }
1534
- .adopt-row.is-adopted {
1535
- opacity: 0.6;
1536
- background: var(--bg);
1537
- }
1538
- .adopt-row.is-adopted:hover { transform: none; border-color: var(--border); }
1539
- /* A session a cli process currently has open. Quiet treatment: the row
1540
- itself stays neutral (many rows can be live at once — a wall of green
1541
- slabs is noise) and the "alive" signal rides on the icon as a small
1542
- green presence dot, the way a chat avatar shows online. The icon tile
1543
- picks up a faint green tint + green glyph so the eye still lands. */
1544
- .adopt-row.is-active .adopt-row-icon {
1545
- border-color: rgba(74, 138, 74, 0.4);
1546
- background: rgba(74, 138, 74, 0.1);
1547
- color: var(--green);
1548
- }
1549
- /* Static dot — punched out of the card with a bg-elev ring so it reads as
1550
- a badge sitting on the icon corner. */
1551
- .adopt-row.is-active .adopt-row-icon::after {
1552
- content: "";
1553
- position: absolute;
1554
- right: -3px;
1555
- bottom: -3px;
1556
- width: 10px;
1557
- height: 10px;
1558
- border-radius: 50%;
1559
- background: var(--green);
1560
- border: 2px solid var(--bg-elev);
1561
- }
1562
- /* Soft presence pulse — a ring expanding off the dot. Opacity-animated on
1563
- its own layer so it stays GPU-cheap even with a dozen live rows (the old
1564
- box-shadow pulse pegged the paint thread). */
1565
- .adopt-row.is-active .adopt-row-icon::before {
1566
- content: "";
1567
- position: absolute;
1568
- right: -1px;
1569
- bottom: -1px;
1570
- width: 6px;
1571
- height: 6px;
1572
- border-radius: 50%;
1573
- border: 1px solid var(--green);
1574
- opacity: 0;
1575
- animation: adopt-live-pulse 1.9s ease-in-out infinite;
1576
- pointer-events: none;
1577
- z-index: 1;
1578
- }
1579
- @keyframes adopt-live-pulse {
1580
- 0% { opacity: 0.55; transform: scale(0.8); }
1581
- 70%, 100% { opacity: 0; transform: scale(2.6); }
1582
- }
1583
- .adopt-row-main { flex: 1 1 auto; min-width: 0; }
1584
- .adopt-row-title {
1585
- font-size: 13px;
1586
- color: var(--ink);
1587
- font-weight: 500;
1588
- overflow: hidden;
1589
- text-overflow: ellipsis;
1590
- white-space: nowrap;
1591
- line-height: 1.35;
1592
- display: flex;
1593
- align-items: center;
1594
- gap: 8px;
1595
- }
1596
- .adopt-row-untitled { color: var(--ink-faint); font-weight: 400; font-style: italic; }
1597
- /* Minimal caption next to the title — the dot carries the signal, this
1598
- just names it. No pill, no border, no ring. */
1599
- .adopt-row-live {
1600
- flex: 0 0 auto;
1601
- font-size: 10px;
1602
- font-weight: 600;
1603
- letter-spacing: 0.05em;
1604
- text-transform: uppercase;
1605
- color: var(--green);
1606
- cursor: default;
1607
- }
1608
-
1609
- /* Footer pagination (rendered into .modal-foot): ‹ Prev · X–Y of Z · Next ›.
1610
- The flex:1 info pushes the two buttons to the edges and centres the count. */
1611
- .adopt-pager-info {
1612
- flex: 1;
1613
- text-align: center;
1614
- font-size: 12px;
1615
- color: var(--ink-muted);
1616
- font-variant-numeric: tabular-nums;
1617
- }
1618
- .adopt-pager-btn { min-width: 78px; gap: 4px; }
1619
- .adopt-pager-btn svg { width: 13px; height: 13px; }
1620
- .adopt-row-meta {
1621
- display: flex;
1622
- align-items: center;
1623
- font-size: 11px;
1624
- color: var(--ink-muted);
1625
- margin-top: 4px;
1626
- white-space: nowrap;
1627
- overflow: hidden;
1628
- }
1629
- .adopt-row-path {
1630
- min-width: 0;
1631
- overflow: hidden;
1632
- text-overflow: ellipsis;
1633
- white-space: nowrap;
1634
- flex: 0 1 auto;
1635
- }
1636
- .adopt-row-dot { margin: 0 8px; color: var(--ink-faint); }
1637
- .adopt-row-id { color: var(--ink-faint); }
1638
- .adopt-row-actions {
1639
- display: flex;
1640
- align-items: center;
1641
- gap: 6px;
1642
- flex: 0 0 auto;
1643
- }
1644
- .adopt-row-btn { padding: 6px 14px; font-size: 12px; }
1645
- .adopt-row-badge {
1646
- font-size: 11px;
1647
- color: var(--ink-muted);
1648
- padding: 5px 12px;
1649
- border-radius: 999px;
1650
- background: var(--bg);
1651
- border: 1px solid var(--border);
1652
- }
1653
-
1654
- /* ── Remote page ──────────────────────────────────────────────────
1655
- Uses the existing .settings-scroll + Section + .config-grid + .field
1656
- + .chip system from ConfigurePage. Only adds the bits that don't
1657
- already exist: the inline status line per provider, the token-row
1658
- input + action cluster, the URL row, the CLI log block, and the
1659
- bulleted security list. */
1660
-
1661
- /* Provider picker tiles — large clickable cards with the brand mark
1662
- front and center, replacing the old chip-row radio pair. Two-wide
1663
- on desktop, stacks at narrow widths. */
1664
- .provider-tile-row {
1665
- display: grid;
1666
- grid-template-columns: repeat(2, minmax(0, 1fr));
1667
- gap: var(--s-3);
1668
- max-width: 560px;
1669
- }
1670
- @media (max-width: 560px) {
1671
- .provider-tile-row { grid-template-columns: 1fr; }
1672
- }
1673
- .provider-tile {
1674
- appearance: none;
1675
- display: flex;
1676
- align-items: center;
1677
- gap: var(--s-3);
1678
- padding: var(--s-3) var(--s-4);
1679
- background: var(--bg-elev);
1680
- border: 1px solid var(--border);
1681
- border-radius: 10px;
1682
- cursor: pointer;
1683
- text-align: left;
1684
- color: var(--ink);
1685
- font: inherit;
1686
- transition: border-color .12s, background-color .12s, box-shadow .12s;
1687
- }
1688
- .provider-tile:hover { border-color: var(--border-strong); }
1689
- .provider-tile.is-selected {
1690
- border-color: var(--ink);
1691
- background: var(--bg-elev);
1692
- box-shadow: 0 0 0 1px var(--ink);
1693
- }
1694
- .provider-tile.is-disabled,
1695
- .provider-tile:disabled {
1696
- cursor: not-allowed;
1697
- opacity: 0.55;
1698
- }
1699
- .provider-tile.is-disabled:hover,
1700
- .provider-tile:disabled:hover {
1701
- border-color: var(--border);
1702
- }
1703
- .provider-tile:focus-visible {
1704
- outline: 2px solid var(--ink);
1705
- outline-offset: 2px;
1706
- }
1707
- .provider-tile-icon {
1708
- flex: 0 0 32px;
1709
- width: 32px;
1710
- height: 32px;
1711
- display: inline-flex;
1712
- align-items: center;
1713
- justify-content: center;
1714
- }
1715
- .provider-tile-body {
1716
- display: flex;
1717
- flex-direction: column;
1718
- gap: 2px;
1719
- min-width: 0;
1720
- }
1721
- .provider-tile-label {
1722
- font-size: 14px;
1723
- font-weight: 500;
1724
- letter-spacing: -0.005em;
1725
- }
1726
- .provider-tile-hint {
1727
- font-size: 11.5px;
1728
- color: var(--ink-muted);
1729
- }
1730
- /* ── Provider status row + sign-in card ───────────────────────────
1731
- Replaces the older devtunnel-login + .remote-status-line inline
1732
- bag-of-spans with a single composable card vocabulary so the
1733
- signed-in / signed-out / mid-sign-in states all read as parts of
1734
- one design rather than three different debug widgets. */
1735
- .provider-status {
1736
- display: flex;
1737
- align-items: center;
1738
- flex-wrap: wrap;
1739
- gap: var(--s-2) var(--s-3);
1740
- }
1741
- .provider-status.is-stack {
1742
- flex-direction: column;
1743
- align-items: stretch;
1744
- gap: var(--s-2);
1745
- }
1746
- .provider-status.is-stack .provider-status-row {
1747
- display: flex;
1748
- align-items: center;
1749
- gap: var(--s-2) var(--s-3);
1750
- flex-wrap: wrap;
1751
- }
1752
- .provider-status-muted { color: var(--ink-muted); font-size: 13px; }
1753
- .provider-status-state {
1754
- display: inline-flex;
1755
- align-items: center;
1756
- gap: 6px;
1757
- font-size: 12.5px;
1758
- font-weight: 500;
1759
- letter-spacing: -0.003em;
1760
- color: var(--ink);
1761
- }
1762
- .provider-status-state.is-warn { color: #8b3a3a; }
1763
- .provider-status-state.is-ok { color: #2f6e3a; }
1764
- .provider-status-dot {
1765
- width: 7px;
1766
- height: 7px;
1767
- border-radius: 50%;
1768
- background: var(--ink-muted);
1769
- display: inline-block;
1770
- }
1771
- .provider-status-dot.is-ok { background: #4a8a4a; }
1772
- .provider-status-dot.is-warn { background: #b86a2a; }
1773
- .provider-status-user {
1774
- font-family: var(--mono);
1775
- font-size: 12px;
1776
- padding: 2px 8px;
1777
- border-radius: 4px;
1778
- background: var(--bg);
1779
- color: var(--ink);
1780
- border: 1px solid var(--border);
1781
- max-width: 28ch;
1782
- overflow: hidden;
1783
- text-overflow: ellipsis;
1784
- white-space: nowrap;
1785
- }
1786
- .provider-status-version {
1787
- font-family: var(--mono);
1788
- font-size: 11px;
1789
- color: var(--ink-muted);
1790
- }
1791
- .provider-status-switch { margin-left: auto; }
1792
- .provider-status-signin { margin-left: auto; }
1793
-
1794
- /* DevtunnelTunnelIdRow — shown under the signed-in Microsoft Dev
1795
- Tunnel status. The tunnel id is the persistent identifier that
1796
- keeps the public URL stable across `devtunnel host` restarts;
1797
- surfaced so the user knows what's being reused and can rotate it
1798
- when they want fresh credentials. */
1799
- .tunnel-id-row {
1800
- display: flex;
1801
- align-items: center;
1802
- flex-wrap: wrap;
1803
- gap: var(--s-2);
1804
- margin-top: var(--s-2);
1805
- padding: 6px 10px;
1806
- border: 1px solid var(--border-soft);
1807
- border-radius: 6px;
1808
- background: var(--bg);
1809
- font-size: 12px;
1810
- color: var(--ink-mid);
1811
- }
1812
- .tunnel-id-row.is-empty { color: var(--ink-muted); }
1813
- .tunnel-id-label {
1814
- font-size: 10.5px;
1815
- letter-spacing: 0.16em;
1816
- text-transform: uppercase;
1817
- font-weight: 600;
1818
- color: var(--ink-muted);
1819
- }
1820
- .tunnel-id-value {
1821
- font-family: var(--mono);
1822
- font-size: 12px;
1823
- color: var(--ink);
1824
- user-select: all;
1825
- padding: 1px 6px;
1826
- border-radius: 4px;
1827
- background: var(--bg-elev);
1828
- border: 1px solid var(--border-soft);
1829
- }
1830
- .tunnel-id-value-empty {
1831
- font-style: italic;
1832
- color: var(--ink-muted);
1833
- }
1834
- .tunnel-id-reset { margin-left: auto; }
1835
-
1836
- /* ── Tunnel section: hero (idle) + live banner (running) ──────────
1837
- Idle: a single horizontal card with the headline + start CTA.
1838
- Running: a status banner (state · provider · uptime · stop link)
1839
- followed by a copyable share URL block and an optional collapsed
1840
- CLI log. */
1841
- .tunnel-autostart {
1842
- display: flex;
1843
- flex-direction: column;
1844
- gap: 6px;
1845
- margin-bottom: var(--s-4);
1846
- }
1847
- .tunnel-autostart-row {
1848
- display: flex;
1849
- align-items: center;
1850
- gap: 9px;
1851
- cursor: pointer;
1852
- font-size: 13px;
1853
- color: var(--ink-mid);
1854
- }
1855
- .tunnel-autostart-row input {
1856
- flex: 0 0 auto;
1857
- cursor: pointer;
1858
- }
1859
- .tunnel-autostart-label {
1860
- user-select: none;
1861
- }
1862
- .tunnel-autostart-hint {
1863
- /* indent under the checkbox so it lines up with the label text */
1864
- padding-left: 26px;
1865
- }
1866
-
1867
- .tunnel-hero {
1868
- display: flex;
1869
- align-items: center;
1870
- justify-content: space-between;
1871
- gap: var(--s-4);
1872
- padding: var(--s-4) var(--s-5);
1873
- border: 1px solid var(--border);
1874
- border-radius: 10px;
1875
- background: var(--bg-elev);
1876
- }
1877
- .tunnel-hero-body {
1878
- display: flex;
1879
- flex-direction: column;
1880
- gap: 4px;
1881
- min-width: 0;
1882
- }
1883
- .tunnel-hero-title {
1884
- font-size: 15px;
1885
- font-weight: 600;
1886
- letter-spacing: -0.01em;
1887
- color: var(--ink);
1888
- }
1889
- .tunnel-hero-meta {
1890
- font-size: 12.5px;
1891
- color: var(--ink-mid);
1892
- line-height: 1.5;
1893
- }
1894
- .tunnel-hero-meta code {
1895
- font-family: var(--mono);
1896
- font-size: 11.5px;
1897
- padding: 1px 5px;
1898
- border-radius: 3px;
1899
- background: var(--bg);
1900
- border: 1px solid var(--border-soft);
1901
- }
1902
- .tunnel-hero-cta {
1903
- /* Pick up theme accent + match the default size of other `.action`
1904
- buttons across the app. No `min-width` override (was 140px, too
1905
- wide compared to the Copy/Open pair). */
1906
- flex: 0 0 auto;
1907
- background: var(--accent);
1908
- border-color: var(--accent);
1909
- color: #fff;
1910
- }
1911
- .tunnel-hero-cta:hover {
1912
- background: var(--accent-deep, var(--accent));
1913
- border-color: var(--accent-deep, var(--accent));
1914
- }
1915
- .tunnel-hero-cta:disabled {
1916
- opacity: 0.6;
1917
- cursor: wait;
1918
- }
1919
-
1920
- .tunnel-live {
1921
- display: flex;
1922
- flex-direction: column;
1923
- gap: var(--s-3);
1924
- }
1925
- .tunnel-live-head {
1926
- display: flex;
1927
- align-items: center;
1928
- flex-wrap: wrap;
1929
- gap: 6px 8px;
1930
- padding: 6px 10px 6px 12px;
1931
- border-radius: 999px;
1932
- background: rgba(74, 138, 74, 0.08);
1933
- border: 1px solid rgba(74, 138, 74, 0.32);
1934
- font-size: 12.5px;
1935
- color: var(--ink);
1936
- width: fit-content;
1937
- max-width: 100%;
1938
- }
1939
- .tunnel-live-state {
1940
- display: inline-flex;
1941
- align-items: center;
1942
- gap: 6px;
1943
- font-weight: 600;
1944
- letter-spacing: 0.02em;
1945
- color: #2f6e3a;
1946
- }
1947
- .tunnel-live-dot {
1948
- width: 8px;
1949
- height: 8px;
1950
- border-radius: 50%;
1951
- background: #4a8a4a;
1952
- box-shadow: 0 0 0 0 rgba(74, 138, 74, 0.6);
1953
- animation: tunnel-live-pulse 2s ease-in-out infinite;
1954
- }
1955
- @keyframes tunnel-live-pulse {
1956
- 0% { box-shadow: 0 0 0 0 rgba(74, 138, 74, 0.55); }
1957
- 70% { box-shadow: 0 0 0 8px rgba(74, 138, 74, 0); }
1958
- 100% { box-shadow: 0 0 0 0 rgba(74, 138, 74, 0); }
1959
- }
1960
- .tunnel-live-divider { color: var(--ink-faint); }
1961
- .tunnel-live-provider { color: var(--ink); font-weight: 500; }
1962
- .tunnel-live-meta { color: var(--ink-mid); }
1963
- .tunnel-stop-link {
1964
- appearance: none;
1965
- background: transparent;
1966
- border: 0;
1967
- padding: 0 4px 0 10px;
1968
- margin-left: 4px;
1969
- display: inline-flex;
1970
- align-items: center;
1971
- gap: 4px;
1972
- font: inherit;
1973
- font-size: 12px;
1974
- font-weight: 500;
1975
- color: #b73f3f;
1976
- cursor: pointer;
1977
- border-left: 1px solid rgba(74, 138, 74, 0.25);
1978
- transition: color .12s;
1979
- }
1980
- .tunnel-stop-link:hover { color: #8b2a2a; }
1981
- .tunnel-stop-link:disabled { opacity: 0.5; cursor: wait; }
1982
- .tunnel-stop-link svg { width: 11px; height: 11px; }
1983
-
1984
- .tunnel-share {
1985
- display: flex;
1986
- flex-direction: column;
1987
- gap: 6px;
1988
- padding: var(--s-3) var(--s-4);
1989
- border: 1px solid var(--border);
1990
- border-radius: 10px;
1991
- background: var(--bg);
1992
- }
1993
- .tunnel-share.is-waiting {
1994
- flex-direction: row;
1995
- align-items: center;
1996
- gap: var(--s-2);
1997
- color: var(--ink-muted);
1998
- font-size: 13px;
1999
- }
2000
- .tunnel-share-label {
2001
- font-size: 10.5px;
2002
- letter-spacing: 0.16em;
2003
- text-transform: uppercase;
2004
- color: var(--ink-muted);
2005
- font-weight: 500;
2006
- }
2007
- .tunnel-share-url {
2008
- display: flex;
2009
- align-items: center;
2010
- gap: var(--s-3);
2011
- flex-wrap: wrap;
2012
- }
2013
- .tunnel-share-value {
2014
- flex: 1;
2015
- min-width: 0;
2016
- font-family: var(--mono);
2017
- font-size: 13px;
2018
- color: var(--ink);
2019
- padding: 6px 10px;
2020
- border: 1px solid var(--border-soft);
2021
- border-radius: 6px;
2022
- background: var(--bg-elev);
2023
- overflow: hidden;
2024
- text-overflow: ellipsis;
2025
- white-space: nowrap;
2026
- user-select: all;
2027
- }
2028
- .tunnel-share-actions {
2029
- display: inline-flex;
2030
- gap: 6px;
2031
- flex: 0 0 auto;
2032
- }
2033
- .tunnel-share-hint {
2034
- font-size: 11.5px;
2035
- color: var(--ink-muted);
2036
- }
2037
- .tunnel-log { font-size: 12px; }
2038
- .tunnel-log summary {
2039
- cursor: pointer;
2040
- user-select: none;
2041
- color: var(--ink-mid);
2042
- padding: 4px 0;
2043
- }
2044
- .tunnel-log pre {
2045
- margin: 6px 0 0;
2046
- padding: var(--s-2) var(--s-3);
2047
- background: var(--bg);
2048
- border: 1px solid var(--border-soft);
2049
- border-radius: 6px;
2050
- font-family: var(--mono);
2051
- font-size: 11.5px;
2052
- line-height: 1.45;
2053
- color: var(--ink-mid);
2054
- max-height: 220px;
2055
- overflow: auto;
2056
- white-space: pre-wrap;
2057
- word-break: break-word;
2058
- }
2059
-
2060
- /* Version-update card — Configure → Version field. Idle state is a
2061
- muted "you're on the latest" pill; update-available flips a subtle
2062
- blue tint and surfaces a primary upgrade CTA. */
2063
- .version-card {
2064
- display: flex;
2065
- align-items: center;
2066
- justify-content: space-between;
2067
- gap: var(--s-4);
2068
- padding: var(--s-3) var(--s-4);
2069
- border: 1px solid var(--border);
2070
- border-radius: 10px;
2071
- background: var(--bg-elev);
2072
- flex-wrap: wrap;
2073
- }
2074
- .version-card.has-update {
2075
- border-color: rgba(0, 120, 212, 0.35);
2076
- background: linear-gradient(180deg, rgba(0, 120, 212, 0.04) 0%, var(--bg-elev) 100%);
2077
- }
2078
- .version-card.has-error {
2079
- border-color: rgba(183, 63, 63, 0.30);
2080
- background: rgba(183, 63, 63, 0.03);
2081
- }
2082
- .version-card-main {
2083
- display: flex;
2084
- flex-direction: column;
2085
- gap: 4px;
2086
- min-width: 0;
2087
- flex: 1;
2088
- }
2089
- .version-card-current {
2090
- display: flex;
2091
- align-items: baseline;
2092
- gap: 8px;
2093
- flex-wrap: wrap;
2094
- }
2095
- .version-card-label {
2096
- font-size: 10.5px;
2097
- letter-spacing: 0.16em;
2098
- text-transform: uppercase;
2099
- color: var(--ink-muted);
2100
- font-weight: 500;
2101
- }
2102
- .version-card-version {
2103
- font-family: var(--mono);
2104
- font-size: 18px;
2105
- font-weight: 600;
2106
- letter-spacing: -0.01em;
2107
- color: var(--ink);
2108
- font-variant-numeric: tabular-nums;
2109
- }
2110
- .version-card-badge {
2111
- font-size: 10.5px;
2112
- letter-spacing: 0.08em;
2113
- text-transform: uppercase;
2114
- font-weight: 600;
2115
- padding: 1px 8px;
2116
- border-radius: 999px;
2117
- background: rgba(74, 138, 74, 0.12);
2118
- color: #2f6e3a;
2119
- border: 1px solid rgba(74, 138, 74, 0.3);
2120
- }
2121
- .version-card.has-update .version-card-badge {
2122
- background: rgba(0, 120, 212, 0.12);
2123
- color: #005a9e;
2124
- border-color: rgba(0, 120, 212, 0.35);
2125
- }
2126
- .version-card-meta {
2127
- font-size: 12.5px;
2128
- color: var(--ink-mid);
2129
- line-height: 1.5;
2130
- }
2131
- .version-card-meta .mono {
2132
- font-family: var(--mono);
2133
- font-size: 12px;
2134
- color: var(--ink);
2135
- }
2136
- .version-card-error {
2137
- color: #8b3a3a;
2138
- }
2139
- .version-card-error code {
2140
- font-family: var(--mono);
2141
- font-size: 11px;
2142
- }
2143
- .version-card-actions {
2144
- display: inline-flex;
2145
- align-items: center;
2146
- gap: var(--s-2);
2147
- flex-shrink: 0;
2148
- flex-wrap: wrap;
2149
- justify-content: flex-end;
2150
- }
2151
- .version-card-check {
2152
- background: var(--accent);
2153
- border-color: var(--accent);
2154
- color: #fff;
2155
- }
2156
- .version-card-check:hover {
2157
- background: var(--accent-deep, var(--accent));
2158
- border-color: var(--accent-deep, var(--accent));
2159
- }
2160
- .version-card-check:disabled { opacity: 0.6; cursor: wait; }
2161
- .version-card-check svg { stroke: #fff; }
2162
-
2163
- /* Cards inside the Configure → General config-grid would otherwise
2164
- stretch full row width (flex column → align-stretch). For the
2165
- Restart button we still want it to shrink to the text — keep the
2166
- inline wrapper. The Version card stays full-width to read like the
2167
- other settings rows. */
2168
- .config-grid .field .restart-button-wrap {
2169
- align-self: stretch;
2170
- }
2171
- .restart-button-wrap { display: inline-flex; }
2172
-
2173
- /* Microsoft brand-style sign-in button. Microsoft's published guidance
2174
- is a white pill with the 4-square logo on the left and "Sign in
2175
- with Microsoft" in Segoe-ish type. We can't ship Segoe in a web
2176
- font here so the body family takes over — the visual still reads
2177
- correctly thanks to the logo + spacing. White surface + thin
2178
- border keeps it distinct from our own black `.action.primary`
2179
- slab (which the user found too heavy for an external-auth CTA). */
2180
- .btn-signin-microsoft {
2181
- appearance: none;
2182
- display: inline-flex;
2183
- align-items: center;
2184
- gap: 10px;
2185
- align-self: flex-start;
2186
- padding: 8px 16px;
2187
- min-height: 36px;
2188
- background: #ffffff;
2189
- color: #1a1815;
2190
- border: 1px solid #d3d3d3;
2191
- border-radius: 4px; /* MS guidance: rectangular, ~2-4px radius */
2192
- font: inherit;
2193
- font-size: 13.5px;
2194
- font-weight: 500;
2195
- letter-spacing: -0.005em;
2196
- cursor: pointer;
2197
- transition: background-color .12s, border-color .12s, box-shadow .12s;
2198
- }
2199
- .btn-signin-microsoft:hover {
2200
- background: #f3f3f3;
2201
- border-color: #b8b8b8;
2202
- }
2203
- .btn-signin-microsoft:active { background: #ebebeb; }
2204
- .btn-signin-microsoft:focus-visible {
2205
- outline: 2px solid #2f6fa3;
2206
- outline-offset: 2px;
2207
- }
2208
- .btn-signin-microsoft img { display: block; }
2209
-
2210
- /* The mid-sign-in "card" — replaces .devtunnel-login. Bigger device
2211
- code, primary CTA, slimmer chrome. */
2212
- .signin-card {
2213
- margin-top: var(--s-3);
2214
- padding: var(--s-5);
2215
- border: 1px solid var(--border);
2216
- border-radius: 10px;
2217
- background: var(--bg-elev);
2218
- display: flex;
2219
- flex-direction: column;
2220
- gap: var(--s-4);
2221
- font-size: 13px;
2222
- }
2223
- .signin-card.is-done { border-color: rgba(74, 138, 74, 0.4); }
2224
- .signin-card.is-error { border-color: rgba(183, 63, 63, 0.4); }
2225
- .signin-card-header {
2226
- display: flex;
2227
- align-items: center;
2228
- gap: var(--s-2);
2229
- color: var(--ink-mid);
2230
- }
2231
- .signin-card-cancel {
2232
- margin-left: auto;
2233
- appearance: none;
2234
- display: inline-flex;
2235
- align-items: center;
2236
- gap: 4px;
2237
- padding: 4px 10px;
2238
- border-radius: 6px;
2239
- border: 1px solid rgba(183, 63, 63, 0.35);
2240
- background: transparent;
2241
- color: #b73f3f;
2242
- font: inherit;
2243
- font-size: 12px;
2244
- font-weight: 500;
2245
- letter-spacing: 0.02em;
2246
- cursor: pointer;
2247
- transition: background-color .12s, border-color .12s, color .12s;
2248
- }
2249
- .signin-card-cancel:hover {
2250
- background: rgba(183, 63, 63, 0.08);
2251
- border-color: rgba(183, 63, 63, 0.55);
2252
- color: #8b2a2a;
2253
- }
2254
- .signin-card-cancel svg { width: 12px; height: 12px; }
2255
- .signin-card-eyebrow {
2256
- font-size: 11px;
2257
- letter-spacing: 0.14em;
2258
- text-transform: uppercase;
2259
- font-weight: 600;
2260
- }
2261
- .signin-card-spinner {
2262
- width: 12px;
2263
- height: 12px;
2264
- border-radius: 50%;
2265
- border: 2px solid var(--border-strong);
2266
- border-top-color: var(--ink);
2267
- animation: remote-spin 0.7s linear infinite;
2268
- }
2269
- .signin-card-code-block {
2270
- display: flex;
2271
- flex-direction: column;
2272
- gap: 6px;
2273
- padding: var(--s-3) var(--s-4);
2274
- background: var(--bg);
2275
- border: 1px solid var(--border);
2276
- border-radius: 8px;
2277
- }
2278
- .signin-card-code-label {
2279
- font-size: 10.5px;
2280
- letter-spacing: 0.16em;
2281
- text-transform: uppercase;
2282
- color: var(--ink-muted);
2283
- }
2284
- .signin-card-code-row {
2285
- display: flex;
2286
- align-items: center;
2287
- gap: var(--s-2);
2288
- }
2289
- .signin-card-code {
2290
- font-family: var(--mono);
2291
- font-size: 22px;
2292
- font-weight: 600;
2293
- letter-spacing: 0.12em;
2294
- color: var(--ink);
2295
- user-select: all;
2296
- font-variant-numeric: tabular-nums;
2297
- }
2298
- .signin-card-code-pending {
2299
- font-size: 13px;
2300
- color: var(--ink-muted);
2301
- font-style: italic;
2302
- }
2303
- .signin-card-code-copy { margin-left: 4px; }
2304
- .signin-card-steps {
2305
- margin: 0;
2306
- padding-left: var(--s-5);
2307
- display: flex;
2308
- flex-direction: column;
2309
- gap: 6px;
2310
- color: var(--ink-mid);
2311
- font-size: 13px;
2312
- line-height: 1.5;
2313
- }
2314
- .signin-card-steps li::marker {
2315
- color: var(--ink-faint);
2316
- font-variant-numeric: tabular-nums;
2317
- }
2318
- .signin-card-step-muted { color: var(--ink-muted); }
2319
- .signin-card-open {
2320
- display: inline-flex;
2321
- align-items: center;
2322
- gap: 6px;
2323
- color: #0067b8;
2324
- font-weight: 500;
2325
- text-decoration: underline;
2326
- text-decoration-color: rgba(0, 103, 184, 0.4);
2327
- text-underline-offset: 3px;
2328
- transition: color .12s, text-decoration-color .12s;
2329
- }
2330
- .signin-card-open:hover {
2331
- color: #005a9e;
2332
- text-decoration-color: #005a9e;
2333
- }
2334
- .signin-card-open svg { width: 13px; height: 13px; }
2335
- .signin-card-host {
2336
- font-family: var(--mono);
2337
- font-size: 12.5px;
2338
- }
2339
- .signin-card-actions {
2340
- display: flex;
2341
- gap: var(--s-2);
2342
- flex-wrap: wrap;
2343
- justify-content: flex-end;
2344
- }
2345
- .signin-card-result {
2346
- display: flex;
2347
- align-items: flex-start;
2348
- gap: var(--s-3);
2349
- padding: var(--s-3) var(--s-4);
2350
- border-radius: 8px;
2351
- background: var(--bg);
2352
- border: 1px solid var(--border);
2353
- }
2354
- .signin-card-result.is-ok { border-color: rgba(74, 138, 74, 0.35); background: #f1f6f0; }
2355
- .signin-card-result.is-error { border-color: rgba(183, 63, 63, 0.35); background: #faf0f0; }
2356
- .signin-card-result.is-muted { background: var(--bg); }
2357
- .signin-card-result-icon {
2358
- flex: 0 0 24px;
2359
- width: 24px;
2360
- height: 24px;
2361
- border-radius: 50%;
2362
- display: inline-flex;
2363
- align-items: center;
2364
- justify-content: center;
2365
- font-weight: 700;
2366
- color: #fff;
2367
- background: var(--ink-muted);
2368
- font-size: 13px;
2369
- }
2370
- .signin-card-result.is-ok .signin-card-result-icon { background: #4a8a4a; }
2371
- .signin-card-result.is-error .signin-card-result-icon { background: #b73f3f; }
2372
- .signin-card-result-body {
2373
- flex: 1;
2374
- min-width: 0;
2375
- display: flex;
2376
- flex-direction: column;
2377
- gap: 2px;
2378
- }
2379
- .signin-card-result-title {
2380
- font-weight: 600;
2381
- color: var(--ink);
2382
- letter-spacing: -0.005em;
2383
- }
2384
- .signin-card-result-meta {
2385
- font-size: 12.5px;
2386
- color: var(--ink-mid);
2387
- line-height: 1.45;
2388
- }
2389
- .signin-card-result-actions {
2390
- display: flex;
2391
- gap: var(--s-2);
2392
- flex-wrap: wrap;
2393
- }
2394
- .signin-card-log {
2395
- font-size: 11.5px;
2396
- color: var(--ink-muted);
2397
- border-top: 1px solid var(--border);
2398
- padding-top: var(--s-3);
2399
- }
2400
- .signin-card-log summary {
2401
- cursor: pointer;
2402
- user-select: none;
2403
- padding: 2px 0;
2404
- }
2405
- .signin-card-log pre {
2406
- margin: var(--s-2) 0 0;
2407
- padding: var(--s-2) var(--s-3);
2408
- background: var(--bg);
2409
- border: 1px solid var(--border-soft);
2410
- border-radius: 4px;
2411
- font-family: var(--mono);
2412
- font-size: 11px;
2413
- line-height: 1.45;
2414
- color: var(--ink-mid);
2415
- max-height: 180px;
2416
- overflow: auto;
2417
- white-space: pre-wrap;
2418
- word-break: break-word;
2419
- }
2420
-
2421
- .remote-status-line {
2422
- display: flex;
2423
- align-items: center;
2424
- flex-wrap: wrap;
2425
- gap: var(--s-2);
2426
- font-size: 12.5px;
2427
- color: var(--ink-mid);
2428
- }
2429
- .remote-status-line .small-mono { font-size: 11px; }
2430
- .remote-status-line .warn { color: #b86a2a; font-weight: 500; }
2431
- .remote-status-line .muted { color: var(--ink-muted); }
2432
- .remote-status-line code {
2433
- font-family: var(--mono);
2434
- font-size: 11.5px;
2435
- background: var(--bg);
2436
- padding: 1px 5px;
2437
- border-radius: 3px;
2438
- }
2439
-
2440
- .remote-token-row {
2441
- display: flex;
2442
- gap: var(--s-2);
2443
- align-items: center;
2444
- flex-wrap: wrap;
2445
- }
2446
- .remote-token-input {
2447
- flex: 1;
2448
- min-width: 240px;
2449
- font-family: var(--mono);
2450
- font-size: 12.5px;
2451
- padding: 7px 11px;
2452
- border: 1px solid var(--border-strong);
2453
- border-radius: var(--r-sm);
2454
- background: var(--bg-elev);
2455
- color: var(--ink);
2456
- }
2457
- .remote-token-input:focus {
2458
- outline: none;
2459
- border-color: var(--ink);
2460
- box-shadow: 0 0 0 1px var(--ink);
2461
- }
2462
-
2463
- .remote-url-line {
2464
- display: flex;
2465
- gap: var(--s-2);
2466
- align-items: center;
2467
- flex-wrap: wrap;
2468
- }
2469
- .remote-url-value {
2470
- flex: 1;
2471
- min-width: 0;
2472
- font-family: var(--mono);
2473
- font-size: 12px;
2474
- color: var(--ink);
2475
- background: var(--bg);
2476
- padding: 6px 10px;
2477
- border-radius: 4px;
2478
- border: 1px solid var(--border);
2479
- overflow: hidden;
2480
- text-overflow: ellipsis;
2481
- white-space: nowrap;
2482
- }
2483
-
2484
- .remote-log {
2485
- font-size: 11.5px;
2486
- color: var(--ink-mid);
2487
- }
2488
- .remote-log summary { cursor: pointer; user-select: none; }
2489
- .remote-log pre {
2490
- margin-top: var(--s-2);
2491
- padding: var(--s-3);
2492
- background: var(--ink);
2493
- color: var(--bg-elev);
2494
- border-radius: var(--r-sm);
2495
- font-family: var(--mono);
2496
- font-size: 11px;
2497
- line-height: 1.5;
2498
- max-height: 220px;
2499
- overflow: auto;
2500
- white-space: pre-wrap;
2501
- word-break: break-all;
2502
- }
2503
-
2504
- .remote-loading {
2505
- display: flex;
2506
- flex-direction: column;
2507
- align-items: center;
2508
- justify-content: center;
2509
- gap: var(--s-3);
2510
- /* Fill the entire scroll container so the spinner sits dead-center
2511
- of the visible Remote panel — both axes — instead of pinning to a
2512
- fixed 260px box near the top. flex:1 makes us claim all remaining
2513
- space inside .settings-scroll (column flex). */
2514
- flex: 1;
2515
- min-height: 0;
2516
- color: var(--ink-muted);
2517
- font-size: 13px;
2518
- }
2519
- .remote-loading p { margin: 0; }
2520
- .remote-loading-spinner {
2521
- width: 28px;
2522
- height: 28px;
2523
- border-radius: 50%;
2524
- border: 2px solid var(--border-strong);
2525
- border-top-color: var(--ink);
2526
- animation: remote-spin 0.75s linear infinite;
2527
- }
2528
- @keyframes remote-spin { to { transform: rotate(360deg); } }
2529
-
2530
- .remote-empty {
2531
- margin: 0;
2532
- font-size: 12.5px;
2533
- color: var(--ink-muted);
2534
- padding: var(--s-3);
2535
- background: var(--bg);
2536
- border-radius: var(--r-sm);
2537
- text-align: center;
2538
- }
2539
- .remote-devices {
2540
- display: flex;
2541
- flex-direction: column;
2542
- gap: var(--s-4);
2543
- }
2544
- .remote-devices-group {
2545
- display: flex;
2546
- flex-direction: column;
2547
- gap: 6px;
2548
- }
2549
- .remote-devices-group-head {
2550
- display: flex;
2551
- align-items: baseline;
2552
- gap: var(--s-2);
2553
- margin-bottom: 2px;
2554
- }
2555
- .remote-devices-group-title {
2556
- font-size: 11px;
2557
- font-weight: 600;
2558
- text-transform: uppercase;
2559
- letter-spacing: 0.06em;
2560
- color: var(--ink-mid);
2561
- }
2562
- .remote-devices-group-count {
2563
- font-family: var(--mono);
2564
- font-size: 11px;
2565
- color: var(--ink-muted);
2566
- background: var(--bg);
2567
- padding: 1px 7px;
2568
- border-radius: 999px;
2569
- border: 1px solid var(--border);
2570
- }
2571
- .remote-devices-group-hint {
2572
- font-size: 11px;
2573
- font-style: italic;
2574
- color: var(--ink-muted);
2575
- }
2576
- .remote-device {
2577
- display: flex;
2578
- align-items: center;
2579
- gap: var(--s-3);
2580
- padding: 10px 12px;
2581
- background: var(--bg-elev);
2582
- border: 1px solid var(--border);
2583
- border-radius: var(--r-sm);
2584
- }
2585
- .remote-device.is-pending {
2586
- border-color: #b86a2a;
2587
- background: rgba(184, 106, 42, 0.04);
2588
- }
2589
- .remote-device.is-rejected {
2590
- background: var(--bg);
2591
- opacity: 0.8;
2592
- }
2593
- .remote-device-main {
2594
- flex: 1;
2595
- min-width: 0;
2596
- }
2597
- .remote-device-label {
2598
- display: flex;
2599
- align-items: center;
2600
- gap: 6px;
2601
- font-size: 13px;
2602
- font-weight: 500;
2603
- color: var(--ink);
2604
- }
2605
- .remote-device-label .icon-btn {
2606
- background: transparent;
2607
- border: 0;
2608
- padding: 2px;
2609
- cursor: pointer;
2610
- color: var(--ink-muted);
2611
- border-radius: 3px;
2612
- display: inline-flex;
2613
- align-items: center;
2614
- }
2615
- .remote-device-label .icon-btn:hover { color: var(--ink); background: var(--bg); }
2616
- /* 4-digit identification code rendered as a small pill before the
2617
- device label. Distinct background so the operator's eye lands on
2618
- it first — that's the thing they're cross-referencing against what
2619
- the requesting user reads off their own screen. */
2620
- .remote-device-code {
2621
- font-family: var(--mono);
2622
- font-size: 12px;
2623
- font-weight: 600;
2624
- letter-spacing: 0.08em;
2625
- padding: 1px 7px;
2626
- border-radius: 999px;
2627
- /* Brand-accent chip, not the ink slab. var(--ink) flips to a light cream
2628
- in dark mode, which made this a glaring white pill; the accent is a
2629
- saturated mid-tone that's distinct (eye lands on it) and identical in
2630
- both themes. */
2631
- background: var(--accent);
2632
- color: #fff;
2633
- font-variant-numeric: tabular-nums;
2634
- }
2635
- .remote-device-name { min-width: 0; }
2636
- .remote-device-meta {
2637
- font-size: 11.5px;
2638
- color: var(--ink-mid);
2639
- margin-top: 2px;
2640
- display: flex;
2641
- align-items: baseline;
2642
- flex-wrap: wrap;
2643
- gap: 4px;
2644
- }
2645
- .remote-device-meta .mono { font-family: var(--mono); font-size: 11px; }
2646
- .remote-device-ua {
2647
- font-family: var(--mono);
2648
- font-size: 11px;
2649
- color: var(--ink-muted);
2650
- overflow: hidden;
2651
- text-overflow: ellipsis;
2652
- max-width: 380px;
2653
- white-space: nowrap;
2654
- }
2655
- .remote-device-actions {
2656
- display: flex;
2657
- gap: 6px;
2658
- flex-shrink: 0;
2659
- }
2660
- .remote-device-actions .action.small { padding: 4px 10px; font-size: 11.5px; }
2661
-
2662
- /* Remote · "How access works" — three fact rows separated by hairlines,
2663
- inset on the left by a 2px ink bar so the section reads as quiet
2664
- reference material instead of an alert. */
2665
- .remote-facts {
2666
- margin: 0;
2667
- padding: 0;
2668
- display: flex;
2669
- flex-direction: column;
2670
- }
2671
- .remote-fact {
2672
- position: relative;
2673
- padding: var(--s-3) var(--s-3) var(--s-3) var(--s-5);
2674
- border-bottom: 1px solid var(--border);
2675
- }
2676
- .remote-fact:first-child { padding-top: var(--s-2); }
2677
- .remote-fact:last-child { border-bottom: 0; padding-bottom: var(--s-2); }
2678
- .remote-fact::before {
2679
- content: "";
2680
- position: absolute;
2681
- left: 0;
2682
- top: var(--s-3);
2683
- bottom: var(--s-3);
2684
- width: 2px;
2685
- background: var(--ink);
2686
- border-radius: 1px;
2687
- opacity: 0.35;
2688
- }
2689
- .remote-fact dt {
2690
- font-size: 12.5px;
2691
- font-weight: 600;
2692
- color: var(--ink);
2693
- letter-spacing: -0.005em;
2694
- margin-bottom: 4px;
2695
- }
2696
- .remote-fact dd {
2697
- margin: 0;
2698
- font-size: 12px;
2699
- color: var(--ink-mid);
2700
- line-height: 1.6;
2701
- }
2702
- .remote-fact dd code {
2703
- font-family: var(--mono);
2704
- font-size: 11px;
2705
- background: var(--bg);
2706
- padding: 1px 5px;
2707
- border-radius: 3px;
2708
- }
2709
- .remote-fact dd strong {
2710
- color: var(--ink);
2711
- font-weight: 600;
2712
- }
2713
- .remote-fact dd em {
2714
- font-style: italic;
2715
- color: var(--ink);
2716
- }
2717
- .remote-fact-pill {
2718
- display: inline-block;
2719
- font-size: 11px;
2720
- padding: 1px 7px;
2721
- border-radius: 999px;
2722
- background: rgba(184, 106, 42, 0.14);
2723
- color: #8b4f1f;
2724
- font-weight: 500;
2725
- }
1
+ /* Workspace cards · clone-progress list · pagination · snapshot preview */
2
+
3
+ .workspace-grid {
4
+ display: grid;
5
+ grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
6
+ gap: var(--s-3);
7
+ }
8
+ .workspace-card {
9
+ padding: var(--s-4);
10
+ border: 1px solid var(--border-soft);
11
+ background: var(--bg-elev);
12
+ border-radius: 6px;
13
+ transition: border-color .18s, box-shadow .18s, transform .18s;
14
+ }
15
+ .workspace-card:hover {
16
+ border-color: var(--ink-faint);
17
+ box-shadow: var(--shadow-md);
18
+ transform: translateY(-1px);
19
+ }
20
+ .workspace-card.in-use {
21
+ background: var(--bg);
22
+ border-color: var(--ink-faint);
23
+ box-shadow: inset 3px 0 0 var(--accent);
24
+ }
25
+ .workspace-card .ws-head {
26
+ display: flex;
27
+ align-items: baseline;
28
+ justify-content: space-between;
29
+ gap: var(--s-2);
30
+ margin-bottom: 6px;
31
+ }
32
+ .workspace-card .ws-name {
33
+ font-size: 14.5px;
34
+ font-weight: 600;
35
+ letter-spacing: -0.01em;
36
+ color: var(--ink);
37
+ line-height: 1.2;
38
+ }
39
+ .workspace-card .ws-tag {
40
+ font-family: var(--mono);
41
+ font-size: 10px;
42
+ text-transform: uppercase;
43
+ letter-spacing: 0.08em;
44
+ padding: 2px 7px;
45
+ border-radius: 4px;
46
+ background: var(--bg);
47
+ color: var(--ink-muted);
48
+ border: 1px solid var(--border-soft);
49
+ }
50
+ .workspace-card.in-use .ws-tag {
51
+ background: var(--bg-elev);
52
+ color: var(--ink-mid);
53
+ border-color: var(--ink-faint);
54
+ }
55
+ .workspace-card .ws-path {
56
+ font-family: var(--mono);
57
+ font-size: 11px;
58
+ color: var(--ink-muted);
59
+ word-break: break-all;
60
+ margin-bottom: var(--s-3);
61
+ }
62
+ .workspace-card .ws-repos {
63
+ display: flex;
64
+ flex-wrap: wrap;
65
+ gap: 4px;
66
+ }
67
+ .workspace-card .ws-repo {
68
+ font-family: var(--mono);
69
+ font-size: 10.5px;
70
+ padding: 2px 7px;
71
+ border-radius: 4px;
72
+ background: var(--bg);
73
+ color: var(--ink-muted);
74
+ border: 1px solid var(--border-soft);
75
+ }
76
+ .workspace-card .ws-repo.cloned {
77
+ color: var(--green);
78
+ background: rgba(74, 138, 74, 0.06);
79
+ border-color: rgba(74, 138, 74, 0.25);
80
+ }
81
+
82
+ /* Clone progress — one row per repo, NDJSON-driven by /api/sessions/new */
83
+ .progress-list {
84
+ display: flex;
85
+ flex-direction: column;
86
+ gap: var(--s-2);
87
+ margin-top: var(--s-3);
88
+ }
89
+ .progress-list:empty { display: none; }
90
+
91
+ .progress-item {
92
+ border: 1px solid var(--border);
93
+ background: var(--bg);
94
+ border-radius: var(--r-sm);
95
+ padding: var(--s-3) var(--s-4);
96
+ }
97
+ .progress-item .head {
98
+ display: grid;
99
+ grid-template-columns: 1fr auto auto;
100
+ align-items: baseline;
101
+ gap: var(--s-3);
102
+ margin-bottom: var(--s-2);
103
+ }
104
+ .progress-item .name {
105
+ font-family: var(--body);
106
+ font-size: 12.5px;
107
+ font-weight: 600;
108
+ color: var(--ink);
109
+ }
110
+ .progress-item .phase {
111
+ font-family: var(--mono);
112
+ font-size: 10.5px;
113
+ color: var(--ink-muted);
114
+ letter-spacing: 0.04em;
115
+ }
116
+ .progress-item .pct {
117
+ font-family: var(--mono);
118
+ font-size: 11.5px;
119
+ color: var(--ink-mid);
120
+ font-variant-numeric: tabular-nums;
121
+ }
122
+ .progress-bar {
123
+ height: 3px;
124
+ background: var(--border);
125
+ position: relative;
126
+ overflow: hidden;
127
+ border-radius: 2px;
128
+ }
129
+ .progress-bar .fill {
130
+ height: 100%;
131
+ width: 0;
132
+ background: var(--ink);
133
+ transition: width .2s ease;
134
+ border-radius: 2px;
135
+ }
136
+ .progress-bar .fill.indeterminate {
137
+ width: 35% !important;
138
+ animation: indeterm 1.4s ease-in-out infinite;
139
+ }
140
+ @keyframes indeterm {
141
+ from { transform: translateX(-110%); }
142
+ to { transform: translateX(330%); }
143
+ }
144
+ .progress-item.ok .fill { background: var(--green); }
145
+ .progress-item.error .fill { background: var(--red); }
146
+ .progress-item .detail {
147
+ margin-top: 4px;
148
+ font-family: var(--mono);
149
+ font-size: 10.5px;
150
+ color: var(--ink-muted);
151
+ min-height: 12px;
152
+ }
153
+
154
+ /* Pagination row — sits below table inside .card-body-flush card */
155
+ .pagination {
156
+ display: flex;
157
+ align-items: center;
158
+ gap: var(--s-3);
159
+ padding: var(--s-3) var(--s-6);
160
+ border-top: 1px solid var(--border-soft);
161
+ background: var(--bg);
162
+ font-size: 12.5px;
163
+ color: var(--ink-mid);
164
+ flex-wrap: wrap;
165
+ }
166
+ .pagination-info {
167
+ flex: 1;
168
+ text-align: center;
169
+ font-family: var(--mono);
170
+ font-size: 11.5px;
171
+ color: var(--ink-muted);
172
+ }
173
+ .pagination-info strong {
174
+ color: var(--ink);
175
+ font-weight: 600;
176
+ }
177
+ .pagination select {
178
+ font-size: 11.5px;
179
+ padding: 4px 24px 4px 8px;
180
+ }
181
+
182
+ /* Snapshot raw-text preview (collapsible <details>) */
183
+ .snapshot-detail { margin-top: var(--s-4); }
184
+ .snapshot-detail summary {
185
+ cursor: pointer;
186
+ font-size: 12.5px;
187
+ color: var(--ink-mid);
188
+ padding: var(--s-2) 0;
189
+ user-select: none;
190
+ font-weight: 500;
191
+ }
192
+ .snapshot-detail summary::marker { color: var(--ink-mid); }
193
+ .snapshot-detail summary:hover { color: var(--ink); }
194
+ .preview {
195
+ font-family: var(--mono);
196
+ font-size: 11.5px;
197
+ color: var(--ink-mid);
198
+ background: var(--bg);
199
+ border: 1px solid var(--border);
200
+ border-radius: var(--r-sm);
201
+ padding: var(--s-3);
202
+ margin-top: var(--s-2);
203
+ max-height: 280px;
204
+ overflow: auto;
205
+ white-space: pre;
206
+ line-height: 1.55;
207
+ }
208
+
209
+ /* === Launch page hero · ChatGPT-style centered composer ============= */
210
+
211
+ .launch-hero {
212
+ max-width: 640px;
213
+ width: 100%;
214
+ margin: 0 auto;
215
+ padding: var(--s-4);
216
+ display: flex;
217
+ flex-direction: column;
218
+ align-items: center;
219
+ justify-content: center;
220
+ gap: var(--s-5);
221
+ flex: 1;
222
+ min-height: 0;
223
+ }
224
+
225
+ .launch-brand {
226
+ display: inline-flex;
227
+ align-items: center;
228
+ justify-content: center;
229
+ color: var(--accent);
230
+ }
231
+ .launch-brand-mark svg {
232
+ width: 88px;
233
+ height: 88px;
234
+ display: block;
235
+ }
236
+
237
+ .launch-tagline {
238
+ font-size: 26px;
239
+ font-weight: 500;
240
+ letter-spacing: -0.02em;
241
+ color: var(--ink);
242
+ text-align: center;
243
+ margin: 0;
244
+ line-height: 1.25;
245
+ max-width: 32ch;
246
+ }
247
+ .launch-tagline em {
248
+ font-style: normal;
249
+ color: var(--accent);
250
+ font-weight: 500;
251
+ }
252
+
253
+
254
+
255
+ .launch-status {
256
+ font-family: var(--mono);
257
+ font-size: 11.5px;
258
+ color: var(--ink-muted);
259
+ align-self: stretch;
260
+ text-align: center;
261
+ }
262
+
263
+ .launch-import-link {
264
+ display: inline-flex;
265
+ align-items: center;
266
+ background: transparent;
267
+ border: none;
268
+ font: inherit;
269
+ font-size: 12px;
270
+ color: var(--ink-faint);
271
+ cursor: pointer;
272
+ padding: 4px 8px;
273
+ border-radius: 6px;
274
+ transition: color 120ms ease;
275
+ }
276
+ .launch-import-link:hover { color: var(--ink-mid); }
277
+ .launch-import-arrow {
278
+ display: inline-flex;
279
+ align-items: center;
280
+ margin-left: 6px;
281
+ transition: transform 180ms cubic-bezier(.4, 0, .2, 1);
282
+ }
283
+ .launch-import-link:hover .launch-import-arrow { transform: translateX(3px); }
284
+
285
+ /* === Launch toolbar · A · Pill toolbar =========================== */
286
+
287
+ .launch-toolbar {
288
+ width: 100%;
289
+ display: flex;
290
+ align-items: center;
291
+ justify-content: center;
292
+ flex-wrap: wrap;
293
+ gap: var(--s-2);
294
+ }
295
+
296
+ .pill {
297
+ appearance: none;
298
+ background: var(--bg);
299
+ border: 1px solid var(--border-soft);
300
+ border-radius: 999px;
301
+ padding: 8px 14px 8px 12px;
302
+ display: inline-flex;
303
+ align-items: center;
304
+ justify-content: center;
305
+ gap: 8px;
306
+ cursor: pointer;
307
+ color: var(--ink);
308
+ font: inherit;
309
+ font-size: 13px;
310
+ font-weight: 500;
311
+ line-height: 1;
312
+ white-space: nowrap;
313
+ transition: background .12s ease, border-color .12s ease, color .12s ease;
314
+ flex: 0 0 160px;
315
+ width: 160px;
316
+ min-width: 0;
317
+ }
318
+ .pill:hover {
319
+ background: var(--sidebar-hover);
320
+ border-color: var(--border);
321
+ }
322
+ .pill.is-open {
323
+ background: var(--sidebar-active);
324
+ border-color: var(--ink-faint);
325
+ }
326
+ .pill.is-set {
327
+ border-color: var(--ink-faint);
328
+ background: var(--sidebar-active);
329
+ }
330
+ .pill.is-disabled,
331
+ .pill:disabled {
332
+ opacity: 0.45;
333
+ cursor: not-allowed;
334
+ }
335
+ .pill.is-disabled:hover,
336
+ .pill:disabled:hover { background: var(--bg-elev); border-color: var(--border); }
337
+
338
+ /* --- Workdir picker (Launch page) ----------------------------------- */
339
+ .workdir-modal {
340
+ display: flex;
341
+ flex-direction: column;
342
+ gap: 14px;
343
+ padding: 18px 20px;
344
+ }
345
+ .workdir-mode-grid {
346
+ display: grid;
347
+ grid-template-columns: 1fr 1fr;
348
+ gap: 10px;
349
+ }
350
+ .workdir-mode-opt {
351
+ appearance: none;
352
+ background: var(--bg-elev);
353
+ border: 1px solid var(--border);
354
+ border-radius: 10px;
355
+ padding: 14px 14px 12px;
356
+ cursor: pointer;
357
+ display: grid;
358
+ grid-template-columns: 32px 1fr;
359
+ grid-template-rows: auto auto;
360
+ column-gap: 10px;
361
+ row-gap: 2px;
362
+ text-align: left;
363
+ align-items: center;
364
+ font: inherit;
365
+ color: var(--ink);
366
+ transition: border-color .12s ease, background .12s ease, box-shadow .12s ease;
367
+ }
368
+ .workdir-mode-opt:hover {
369
+ border-color: var(--ink-faint);
370
+ }
371
+ .workdir-mode-opt.is-active {
372
+ border-color: var(--ink);
373
+ background: var(--bg-elev);
374
+ box-shadow: 0 0 0 1px var(--ink) inset;
375
+ }
376
+ .workdir-mode-icon {
377
+ grid-row: 1 / span 2;
378
+ width: 32px;
379
+ height: 32px;
380
+ display: inline-flex;
381
+ align-items: center;
382
+ justify-content: center;
383
+ border-radius: 8px;
384
+ background: var(--bg);
385
+ color: var(--ink-mid);
386
+ }
387
+ .workdir-mode-opt.is-active .workdir-mode-icon {
388
+ background: var(--ink);
389
+ color: var(--bg-elev);
390
+ }
391
+ .workdir-mode-icon svg,
392
+ .workdir-mode-icon img { width: 18px; height: 18px; display: block; }
393
+ .workdir-mode-name {
394
+ font-size: 13px;
395
+ font-weight: 600;
396
+ letter-spacing: -0.005em;
397
+ }
398
+ .workdir-mode-sub {
399
+ font-size: 11.5px;
400
+ color: var(--ink-muted);
401
+ line-height: 1.35;
402
+ }
403
+ .workdir-mode-opt.is-active .workdir-mode-sub { color: var(--ink-mid); }
404
+
405
+ .workdir-detail {
406
+ border: 1px solid var(--border);
407
+ border-radius: 10px;
408
+ background: var(--bg);
409
+ overflow: hidden;
410
+ }
411
+ .workdir-detail .picker { max-height: min(56vh, 420px); }
412
+ .workdir-detail .filex {
413
+ padding: 10px;
414
+ gap: 10px;
415
+ }
416
+ .workdir-detail .filex-body { height: 320px; }
417
+
418
+
419
+ .icon-radio-sub {
420
+ font-size: 11px;
421
+ font-weight: 400;
422
+ color: var(--ink-muted);
423
+ margin-top: 1px;
424
+ }
425
+ .icon-radio-opt.is-active .icon-radio-sub { color: var(--accent-deep); opacity: 0.85; }
426
+
427
+ /* --- File-Explorer-style directory picker --------------------------- */
428
+ .filex {
429
+ display: flex;
430
+ flex-direction: column;
431
+ gap: 8px;
432
+ font-size: 12.5px;
433
+ }
434
+ .filex-loading, .filex-empty {
435
+ padding: 24px;
436
+ text-align: center;
437
+ font-size: 12px;
438
+ color: var(--ink-muted);
439
+ font-style: italic;
440
+ }
441
+
442
+ /* toolbar: back/fwd/up + breadcrumb */
443
+ .filex-toolbar {
444
+ display: flex;
445
+ align-items: center;
446
+ gap: 6px;
447
+ padding: 4px;
448
+ border: 1px solid var(--border);
449
+ border-radius: 8px;
450
+ background: var(--bg-elev);
451
+ }
452
+ .filex-navbtns {
453
+ display: flex;
454
+ gap: 2px;
455
+ flex-shrink: 0;
456
+ }
457
+ .filex-navbtn {
458
+ appearance: none;
459
+ background: transparent;
460
+ border: 0;
461
+ width: 28px;
462
+ height: 28px;
463
+ border-radius: 6px;
464
+ display: inline-flex;
465
+ align-items: center;
466
+ justify-content: center;
467
+ color: var(--ink-mid);
468
+ cursor: pointer;
469
+ transition: background .12s ease, color .12s ease;
470
+ }
471
+ .filex-navbtn:hover:not(:disabled) {
472
+ background: var(--sidebar-hover);
473
+ color: var(--ink);
474
+ }
475
+ .filex-navbtn:disabled {
476
+ opacity: 0.35;
477
+ cursor: not-allowed;
478
+ }
479
+ .filex-navbtn svg { width: 14px; height: 14px; }
480
+
481
+ .filex-breadcrumb {
482
+ flex: 1;
483
+ min-width: 0;
484
+ display: flex;
485
+ align-items: center;
486
+ gap: 1px;
487
+ flex-wrap: nowrap;
488
+ overflow: hidden;
489
+ padding: 0 6px;
490
+ cursor: text;
491
+ min-height: 28px;
492
+ }
493
+ .filex-crumb {
494
+ appearance: none;
495
+ background: transparent;
496
+ border: 0;
497
+ font: inherit;
498
+ font-size: 12.5px;
499
+ color: var(--ink);
500
+ padding: 4px 8px;
501
+ border-radius: 4px;
502
+ cursor: pointer;
503
+ white-space: nowrap;
504
+ transition: background .1s ease;
505
+ }
506
+ .filex-crumb:hover { background: var(--bg); }
507
+ .filex-crumb-sep {
508
+ color: var(--ink-faint);
509
+ font-size: 13px;
510
+ user-select: none;
511
+ flex-shrink: 0;
512
+ }
513
+ .filex-address-edit-btn {
514
+ appearance: none;
515
+ background: transparent;
516
+ border: 0;
517
+ width: 26px;
518
+ height: 26px;
519
+ border-radius: 4px;
520
+ display: inline-flex;
521
+ align-items: center;
522
+ justify-content: center;
523
+ color: var(--ink-faint);
524
+ cursor: pointer;
525
+ margin-left: auto;
526
+ flex-shrink: 0;
527
+ opacity: 0;
528
+ transition: opacity .12s ease, background .12s ease, color .12s ease;
529
+ }
530
+ .filex-toolbar:hover .filex-address-edit-btn { opacity: 0.7; }
531
+ .filex-address-edit-btn:hover {
532
+ background: var(--sidebar-hover);
533
+ color: var(--ink);
534
+ opacity: 1;
535
+ }
536
+ .filex-address-edit-btn svg { width: 12px; height: 12px; }
537
+ .filex-address-edit {
538
+ flex: 1;
539
+ display: flex;
540
+ padding: 0 4px;
541
+ }
542
+ .filex-address-input {
543
+ width: 100%;
544
+ appearance: none;
545
+ background: var(--bg);
546
+ border: 1px solid var(--accent);
547
+ border-radius: 5px;
548
+ padding: 5px 8px;
549
+ font-size: 12.5px;
550
+ color: var(--ink);
551
+ outline: none;
552
+ }
553
+
554
+ /* body: sidebar (quick access) + main file list */
555
+ .filex-body {
556
+ display: grid;
557
+ grid-template-columns: 150px 1fr;
558
+ gap: 8px;
559
+ height: 360px;
560
+ border: 1px solid var(--border);
561
+ border-radius: 8px;
562
+ background: var(--bg-elev);
563
+ overflow: hidden;
564
+ }
565
+ .filex-side {
566
+ border-right: 1px solid var(--border);
567
+ background: var(--bg);
568
+ overflow-y: auto;
569
+ padding: 6px 4px;
570
+ display: flex;
571
+ flex-direction: column;
572
+ gap: 1px;
573
+ }
574
+ .filex-side-label {
575
+ font-size: 10px;
576
+ font-weight: 600;
577
+ text-transform: uppercase;
578
+ letter-spacing: 0.08em;
579
+ color: var(--ink-faint);
580
+ padding: 4px 8px;
581
+ }
582
+ .filex-side-item {
583
+ appearance: none;
584
+ background: transparent;
585
+ border: 0;
586
+ text-align: left;
587
+ font: inherit;
588
+ font-size: 12px;
589
+ color: var(--ink-mid);
590
+ cursor: pointer;
591
+ padding: 5px 8px;
592
+ border-radius: 4px;
593
+ display: flex;
594
+ align-items: center;
595
+ gap: 6px;
596
+ width: 100%;
597
+ overflow: hidden;
598
+ text-overflow: ellipsis;
599
+ white-space: nowrap;
600
+ }
601
+ .filex-side-item:hover { background: var(--sidebar-hover); color: var(--ink); }
602
+ .filex-side-item.is-active {
603
+ background: var(--sidebar-active);
604
+ color: var(--ink);
605
+ font-weight: 500;
606
+ }
607
+ .filex-side-icon {
608
+ display: inline-flex;
609
+ width: 14px;
610
+ height: 14px;
611
+ align-items: center;
612
+ justify-content: center;
613
+ color: var(--ink-faint);
614
+ }
615
+ .filex-side-icon svg { width: 13px; height: 13px; }
616
+ .filex-side-name {
617
+ flex: 1;
618
+ min-width: 0;
619
+ overflow: hidden;
620
+ text-overflow: ellipsis;
621
+ }
622
+
623
+ .filex-main { overflow-y: auto; }
624
+ .filex-list { padding: 4px; }
625
+ .filex-row {
626
+ appearance: none;
627
+ display: flex;
628
+ align-items: center;
629
+ gap: 10px;
630
+ width: 100%;
631
+ padding: 8px 10px;
632
+ background: transparent;
633
+ border: 0;
634
+ border-radius: 5px;
635
+ text-align: left;
636
+ font: inherit;
637
+ font-size: 12.5px;
638
+ color: var(--ink);
639
+ cursor: pointer;
640
+ transition: background .08s ease;
641
+ }
642
+ .filex-row:hover { background: var(--bg); }
643
+ .filex-row[data-active="true"] {
644
+ background: var(--accent-soft);
645
+ color: var(--accent-deep);
646
+ }
647
+ .filex-row[data-active="true"] .filex-row-icon { color: var(--accent); }
648
+ .filex-row-icon {
649
+ display: inline-flex;
650
+ width: 18px;
651
+ height: 18px;
652
+ align-items: center;
653
+ justify-content: center;
654
+ color: var(--ink-muted);
655
+ flex-shrink: 0;
656
+ }
657
+ .filex-row-icon svg { width: 16px; height: 16px; }
658
+ .filex-row-name {
659
+ flex: 1;
660
+ min-width: 0;
661
+ overflow: hidden;
662
+ text-overflow: ellipsis;
663
+ white-space: nowrap;
664
+ }
665
+
666
+ .filex-foot {
667
+ display: flex;
668
+ align-items: center;
669
+ gap: 8px;
670
+ padding-top: 6px;
671
+ border-top: 1px solid var(--border);
672
+ }
673
+ .filex-foot-current {
674
+ flex: 1;
675
+ min-width: 0;
676
+ font-size: 11px;
677
+ color: var(--ink-muted);
678
+ overflow: hidden;
679
+ text-overflow: ellipsis;
680
+ white-space: nowrap;
681
+ }
682
+ .filex-foot-actions {
683
+ display: flex;
684
+ gap: 6px;
685
+ flex-shrink: 0;
686
+ }
687
+ .pill-icon {
688
+ display: inline-flex;
689
+ align-items: center;
690
+ color: var(--ink-muted);
691
+ flex: 0 0 auto;
692
+ }
693
+ .pill-icon svg { width: 14px; height: 14px; }
694
+ .pill-label {
695
+ flex: 0 1 auto;
696
+ min-width: 0;
697
+ overflow: hidden;
698
+ text-overflow: ellipsis;
699
+ }
700
+ .pill-chev {
701
+ display: inline-flex;
702
+ color: var(--ink-faint);
703
+ margin-left: 2px;
704
+ flex: 0 0 auto;
705
+ transition: transform .15s ease;
706
+ }
707
+ .pill-chev svg { width: 12px; height: 12px; }
708
+ .pill.is-open .pill-chev { transform: rotate(180deg); }
709
+
710
+ .action.launch-cta {
711
+ align-self: center;
712
+ border-radius: 6px;
713
+ padding: 7px 22px;
714
+ font-size: 13px;
715
+ font-weight: 500;
716
+ letter-spacing: -0.005em;
717
+ display: inline-flex;
718
+ align-items: center;
719
+ justify-content: center;
720
+ gap: 6px;
721
+ min-width: 0;
722
+ margin-top: var(--s-1);
723
+ background: var(--accent);
724
+ border-color: var(--accent);
725
+ color: #fff;
726
+ }
727
+ .action.launch-cta:hover:not(:disabled) {
728
+ background: var(--accent-deep);
729
+ border-color: var(--accent-deep);
730
+ box-shadow: 0 4px 12px -4px var(--accent-soft);
731
+ }
732
+
733
+ /* === Settings page scroll container ================================
734
+ .tab-panel is flex:1 inside .content which clips overflow. Without a
735
+ scroll layer Settings cards beyond the viewport bottom get cut off. */
736
+ .settings-scroll {
737
+ flex: 1;
738
+ min-height: 0;
739
+ overflow-y: auto;
740
+ display: flex;
741
+ flex-direction: column;
742
+ gap: var(--s-4);
743
+ /* Negative right margin = -var(--s-4) cancels .main's padding-right
744
+ so the scroll container — and therefore the scrollbar — reach the
745
+ full window edge. Padding-right = var(--s-4) preserves the same
746
+ visual gap between content and the right edge that was there
747
+ before. Top padding bumped to var(--s-3) so the first section title
748
+ has visible breathing room from the page-title-bar separator above
749
+ it (4px was almost flush). Negative margin-top stays in sync. */
750
+ padding: var(--s-4) var(--s-4) var(--s-4) 4px;
751
+ margin: -4px calc(-1 * var(--s-4)) 0 -4px;
752
+ }
753
+ /* In a flex column container, items default to flex-shrink:1 which
754
+ causes the cards to compress instead of pushing the scroll container
755
+ to actually scroll. flex:0 0 auto pins them to their natural height. */
756
+ .settings-scroll > .card { flex: 0 0 auto; }
757
+ .settings-scroll > .settings-section { flex: 0 0 auto; }
758
+
759
+ /* === Settings section · A · flat, no card ========================== */
760
+ .settings-section {
761
+ display: flex;
762
+ flex-direction: column;
763
+ gap: var(--s-3);
764
+ padding-bottom: var(--s-5);
765
+ border-bottom: 1px solid var(--border-soft);
766
+ }
767
+ .settings-section:last-child { border-bottom: 0; }
768
+ .settings-section-head {
769
+ display: flex;
770
+ flex-direction: column;
771
+ gap: 2px;
772
+ }
773
+ .settings-section-title {
774
+ font-size: 15px;
775
+ font-weight: 600;
776
+ letter-spacing: -0.012em;
777
+ color: var(--ink);
778
+ line-height: 1.2;
779
+ margin: 0;
780
+ }
781
+ .settings-section-meta {
782
+ font-size: 12.5px;
783
+ color: var(--ink-muted);
784
+ margin: 0;
785
+ }
786
+ .settings-section-body { display: flex; flex-direction: column; gap: var(--s-2); }
787
+
788
+ /* === Settings entity list (CLIs / Repos / Folders) ================== */
789
+ .entity-list {
790
+ display: flex;
791
+ flex-direction: column;
792
+ gap: 2px;
793
+ }
794
+ .entity-row {
795
+ display: flex;
796
+ align-items: center;
797
+ gap: var(--s-3);
798
+ padding: 8px 8px 8px 4px;
799
+ border-radius: 6px;
800
+ transition: background .1s ease;
801
+ }
802
+ .entity-row.is-draggable { cursor: grab; }
803
+ .entity-row.is-draggable:active { cursor: grabbing; }
804
+ .entity-row[data-dnd-over="true"] {
805
+ box-shadow: 0 -2px 0 var(--accent) inset;
806
+ }
807
+ .entity-row-grip {
808
+ display: inline-flex;
809
+ align-items: center;
810
+ justify-content: center;
811
+ width: 14px;
812
+ color: var(--ink-faint);
813
+ font-size: 12px;
814
+ letter-spacing: -1px;
815
+ user-select: none;
816
+ pointer-events: none;
817
+ flex: 0 0 14px;
818
+ }
819
+ .entity-row:hover { background: var(--bg); }
820
+ .entity-row-icon {
821
+ display: inline-flex;
822
+ align-items: center;
823
+ justify-content: center;
824
+ width: 20px;
825
+ height: 20px;
826
+ color: var(--ink-muted);
827
+ flex: 0 0 20px;
828
+ }
829
+ .entity-row-icon svg { width: 16px; height: 16px; }
830
+ .entity-row-main {
831
+ flex: 0 1 auto;
832
+ min-width: 0;
833
+ display: flex;
834
+ flex-direction: column;
835
+ gap: 1px;
836
+ }
837
+ .entity-row-primary {
838
+ font-size: 13px;
839
+ font-weight: 500;
840
+ color: var(--ink);
841
+ display: inline-flex;
842
+ align-items: center;
843
+ gap: 6px;
844
+ }
845
+ .entity-row-badge {
846
+ font-family: var(--mono);
847
+ font-size: 10px;
848
+ letter-spacing: 0.06em;
849
+ text-transform: uppercase;
850
+ padding: 1px 6px;
851
+ border-radius: 4px;
852
+ font-weight: 500;
853
+ }
854
+ .entity-row-badge.tone-accent {
855
+ background: var(--accent-soft);
856
+ color: var(--accent-deep);
857
+ }
858
+ .entity-row-badge.tone-ok {
859
+ background: rgba(74, 138, 74, 0.12);
860
+ color: var(--green);
861
+ }
862
+ .entity-row-badge.tone-warn {
863
+ background: rgba(196, 137, 43, 0.14);
864
+ color: var(--yellow);
865
+ }
866
+ .entity-row-secondary {
867
+ font-size: 11.5px;
868
+ color: var(--ink-muted);
869
+ overflow: hidden;
870
+ text-overflow: ellipsis;
871
+ white-space: nowrap;
872
+ }
873
+ .entity-row-actions {
874
+ display: flex;
875
+ align-items: center;
876
+ gap: 2px;
877
+ flex-shrink: 0;
878
+ opacity: 0;
879
+ transition: opacity .12s ease;
880
+ margin-right: auto; /* pin actions next to the name, let trailing space stay empty */
881
+ }
882
+ .entity-row:hover .entity-row-actions,
883
+ .entity-row:focus-within .entity-row-actions {
884
+ opacity: 1;
885
+ }
886
+ .entity-row-action {
887
+ appearance: none;
888
+ background: transparent;
889
+ border: 0;
890
+ display: inline-flex;
891
+ align-items: center;
892
+ justify-content: center;
893
+ width: 30px;
894
+ height: 30px;
895
+ border-radius: 6px;
896
+ cursor: pointer;
897
+ color: var(--ink-mid);
898
+ font: inherit;
899
+ font-size: 16px;
900
+ transition: background .12s ease, color .12s ease;
901
+ }
902
+ .entity-row-action:hover { background: var(--sidebar-hover); color: var(--ink); }
903
+ .entity-row-action.danger:hover { color: var(--red); }
904
+ .entity-row-action svg { width: 16px; height: 16px; }
905
+
906
+ .entity-empty {
907
+ padding: 14px 10px;
908
+ font-size: 12.5px;
909
+ color: var(--ink-muted);
910
+ font-style: italic;
911
+ }
912
+
913
+ .entity-add {
914
+ appearance: none;
915
+ background: var(--accent);
916
+ border: 0;
917
+ display: inline-flex;
918
+ align-self: flex-start;
919
+ align-items: center;
920
+ gap: 6px;
921
+ padding: 6px 12px;
922
+ margin-top: 4px;
923
+ border-radius: 6px;
924
+ cursor: pointer;
925
+ color: #fff;
926
+ font: inherit;
927
+ font-size: 12.5px;
928
+ font-weight: 500;
929
+ transition: background .12s ease, box-shadow .12s ease;
930
+ }
931
+ .entity-add:hover {
932
+ background: var(--accent-deep);
933
+ box-shadow: 0 2px 6px -2px var(--accent-soft);
934
+ }
935
+ .entity-add svg { width: 13px; height: 13px; }
936
+
937
+ /* === EntityFormModal · shared form layout ========================== */
938
+ .entity-form {
939
+ padding: var(--s-4);
940
+ display: flex;
941
+ flex-direction: column;
942
+ gap: var(--s-3);
943
+ }
944
+ .entity-field {
945
+ display: flex;
946
+ flex-direction: column;
947
+ gap: 4px;
948
+ }
949
+ .entity-field-label {
950
+ font-size: 11.5px;
951
+ color: var(--ink-muted);
952
+ font-weight: 500;
953
+ }
954
+ .entity-field .input {
955
+ padding: 8px 10px;
956
+ font-size: 13px;
957
+ max-width: none;
958
+ }
959
+ .entity-field .input[readonly],
960
+ .entity-field .input:disabled {
961
+ background: var(--bg);
962
+ color: var(--ink-muted);
963
+ cursor: not-allowed;
964
+ }
965
+ .entity-field-hint {
966
+ font-size: 11px;
967
+ color: var(--ink-muted);
968
+ }
969
+ .entity-checkbox-row {
970
+ display: inline-flex;
971
+ align-items: center;
972
+ gap: 8px;
973
+ padding: 4px 0;
974
+ }
975
+ /* EntityFormModal's actions live in the modal footer (.modal-foot) now;
976
+ this keeps the Test button pushed to the left of Cancel/Save there. */
977
+ .modal-foot .entity-test-button { margin-right: auto; }
978
+
979
+ .entity-test-result {
980
+ margin-top: 4px;
981
+ padding: 8px 10px;
982
+ border-radius: 6px;
983
+ border: 1px solid var(--border);
984
+ background: var(--bg);
985
+ display: flex;
986
+ flex-direction: column;
987
+ gap: 6px;
988
+ font-size: 12.5px;
989
+ }
990
+ .entity-test-result.is-ok { border-color: rgba(74, 138, 74, 0.4); background: rgba(74, 138, 74, 0.06); }
991
+ .entity-test-result.is-fail { border-color: rgba(183, 63, 63, 0.4); background: rgba(183, 63, 63, 0.06); }
992
+ .entity-test-summary {
993
+ font-family: var(--body);
994
+ font-weight: 500;
995
+ color: var(--ink);
996
+ }
997
+ .entity-test-result.is-fail .entity-test-summary { color: var(--red); }
998
+ .entity-test-out {
999
+ margin: 0;
1000
+ font-family: var(--mono);
1001
+ font-size: 11.5px;
1002
+ color: var(--ink-mid);
1003
+ white-space: pre-wrap;
1004
+ word-break: break-word;
1005
+ max-height: 120px;
1006
+ overflow-y: auto;
1007
+ }
1008
+ .entity-test-out.is-stderr { color: var(--ink-muted); border-top: 1px dashed var(--border); padding-top: 4px; }
1009
+
1010
+ .icon-radio {
1011
+ display: grid;
1012
+ grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
1013
+ gap: 6px;
1014
+ }
1015
+ .icon-radio.is-disabled { opacity: 0.6; pointer-events: none; }
1016
+ .icon-radio-opt {
1017
+ appearance: none;
1018
+ background: var(--bg-elev);
1019
+ border: 1px solid var(--border);
1020
+ border-radius: 6px;
1021
+ padding: 10px 8px 8px;
1022
+ cursor: pointer;
1023
+ display: flex;
1024
+ flex-direction: column;
1025
+ align-items: center;
1026
+ gap: 6px;
1027
+ color: var(--ink-mid);
1028
+ font: inherit;
1029
+ font-size: 12px;
1030
+ font-weight: 500;
1031
+ transition: border-color .12s ease, background .12s ease, color .12s ease;
1032
+ }
1033
+ .icon-radio-opt:hover { border-color: var(--ink-faint); color: var(--ink); }
1034
+ .icon-radio-opt.is-active {
1035
+ background: var(--accent-soft);
1036
+ border-color: var(--accent);
1037
+ color: var(--accent-deep);
1038
+ }
1039
+ .icon-radio-opt:disabled { cursor: not-allowed; }
1040
+ .icon-radio-icon {
1041
+ display: inline-flex;
1042
+ align-items: center;
1043
+ justify-content: center;
1044
+ width: 24px;
1045
+ height: 24px;
1046
+ }
1047
+ .icon-radio-icon svg,
1048
+ .icon-radio-icon img { width: 24px; height: 24px; display: block; }
1049
+ .launch-cta-plane {
1050
+ display: inline-flex;
1051
+ align-items: center;
1052
+ justify-content: center;
1053
+ width: 16px;
1054
+ height: 16px;
1055
+ /* Resting state: tilted slightly clockwise, like a paper plane caught
1056
+ mid-glide. */
1057
+ transform: translate(0, 0) rotate(8deg);
1058
+ transform-origin: 60% 50%;
1059
+ transition: transform .35s cubic-bezier(.4, 0, .2, 1),
1060
+ opacity .25s ease;
1061
+ will-change: transform, opacity;
1062
+ }
1063
+ .launch-cta-plane svg { width: 100%; height: 100%; }
1064
+ .launch-cta:hover:not(:disabled) .launch-cta-plane {
1065
+ /* Small lift + glide forward — no big arc, no fade-out. */
1066
+ transform: translate(4px, -3px) rotate(14deg);
1067
+ }
1068
+
1069
+ /* Narrow viewport — toolbar wraps. Push the Launch button onto its own
1070
+ row so the pills stay readable. */
1071
+ @media (max-width: 720px) {
1072
+ .launch-toolbar {
1073
+ flex-direction: column;
1074
+ align-items: center;
1075
+ }
1076
+ .pill { justify-content: center; flex: 0 0 auto; }
1077
+ }
1078
+
1079
+ /* === Popover + Picker ============================================== */
1080
+ .popover-panel {
1081
+ position: fixed;
1082
+ /* Above the modal backdrop (200) so pickers opened from inside a modal
1083
+ — e.g. "Import as" in the adopt modal — float on top, not behind it.
1084
+ Still below toasts (1200). */
1085
+ z-index: 250;
1086
+ background: var(--bg-elev);
1087
+ border: 1px solid var(--border);
1088
+ border-radius: 10px;
1089
+ box-shadow: var(--shadow-lg);
1090
+ overflow: hidden;
1091
+ animation: popover-in .14s ease-out;
1092
+ }
1093
+ @keyframes popover-in {
1094
+ from { opacity: 0; transform: translateY(-4px); }
1095
+ to { opacity: 1; transform: translateY(0); }
1096
+ }
1097
+
1098
+ .picker {
1099
+ display: flex;
1100
+ flex-direction: column;
1101
+ max-height: min(60vh, 460px);
1102
+ }
1103
+ .picker-title {
1104
+ padding: 10px 14px 6px;
1105
+ font-size: 11px;
1106
+ color: var(--ink-muted);
1107
+ font-weight: 500;
1108
+ letter-spacing: 0;
1109
+ border-bottom: 1px solid var(--border-soft);
1110
+ }
1111
+ .picker-search {
1112
+ display: flex;
1113
+ align-items: center;
1114
+ gap: 8px;
1115
+ padding: 8px 12px;
1116
+ border-bottom: 1px solid var(--border-soft);
1117
+ }
1118
+ .picker-search-icon {
1119
+ display: inline-flex;
1120
+ align-items: center;
1121
+ color: var(--ink-faint);
1122
+ }
1123
+ .picker-search-icon svg { width: 14px; height: 14px; }
1124
+ .picker-search-input {
1125
+ flex: 1;
1126
+ appearance: none;
1127
+ background: transparent;
1128
+ border: 0;
1129
+ outline: none;
1130
+ padding: 4px 0;
1131
+ font: inherit;
1132
+ font-size: 13px;
1133
+ color: var(--ink);
1134
+ }
1135
+ .picker-search-input::placeholder { color: var(--ink-faint); }
1136
+ .picker-search-clear {
1137
+ appearance: none;
1138
+ background: transparent;
1139
+ border: 0;
1140
+ padding: 2px;
1141
+ cursor: pointer;
1142
+ color: var(--ink-muted);
1143
+ display: inline-flex;
1144
+ align-items: center;
1145
+ border-radius: 4px;
1146
+ }
1147
+ .picker-search-clear:hover { background: var(--sidebar-hover); color: var(--ink); }
1148
+ .picker-search-clear svg { width: 12px; height: 12px; }
1149
+
1150
+ .picker-list {
1151
+ overflow-y: auto;
1152
+ padding: 4px;
1153
+ flex: 1 1 auto;
1154
+ min-height: 0;
1155
+ }
1156
+ .picker-empty {
1157
+ padding: 18px 14px;
1158
+ font-size: 12.5px;
1159
+ color: var(--ink-muted);
1160
+ text-align: center;
1161
+ line-height: 1.5;
1162
+ }
1163
+ .picker-item {
1164
+ appearance: none;
1165
+ background: transparent;
1166
+ border: 0;
1167
+ width: 100%;
1168
+ text-align: left;
1169
+ display: flex;
1170
+ align-items: center;
1171
+ gap: 10px;
1172
+ padding: 7px 10px;
1173
+ border-radius: 6px;
1174
+ cursor: pointer;
1175
+ color: var(--ink);
1176
+ font: inherit;
1177
+ font-size: 13px;
1178
+ transition: background .1s ease;
1179
+ }
1180
+ .picker-item-wrap {
1181
+ position: relative;
1182
+ display: flex;
1183
+ align-items: center;
1184
+ }
1185
+ .picker-item-wrap.is-draggable { cursor: grab; }
1186
+ .picker-item-wrap.is-draggable:active { cursor: grabbing; }
1187
+ .picker-item-wrap[data-dnd-over="true"] {
1188
+ box-shadow: 0 -2px 0 var(--accent) inset;
1189
+ }
1190
+ .picker-item-grip {
1191
+ display: inline-flex;
1192
+ align-items: center;
1193
+ justify-content: center;
1194
+ width: 14px;
1195
+ margin-left: 2px;
1196
+ color: var(--ink-faint);
1197
+ font-size: 11px;
1198
+ letter-spacing: -1px;
1199
+ user-select: none;
1200
+ pointer-events: none;
1201
+ flex: 0 0 14px;
1202
+ }
1203
+ .picker-item:hover { background: var(--sidebar-hover); }
1204
+ .picker-item.is-selected {
1205
+ background: var(--sidebar-active);
1206
+ font-weight: 500;
1207
+ }
1208
+ .picker-item:disabled {
1209
+ opacity: 0.45;
1210
+ cursor: not-allowed;
1211
+ }
1212
+ .picker-item-icon {
1213
+ display: inline-flex;
1214
+ align-items: center;
1215
+ justify-content: center;
1216
+ width: 18px;
1217
+ height: 18px;
1218
+ flex: 0 0 18px;
1219
+ color: var(--ink-muted);
1220
+ }
1221
+ .picker-item-icon svg,
1222
+ .picker-item-icon img { width: 18px; height: 18px; display: block; }
1223
+ .picker-item-label {
1224
+ flex: 0 0 auto;
1225
+ white-space: nowrap;
1226
+ }
1227
+ .picker-item-meta {
1228
+ flex: 1 1 auto;
1229
+ min-width: 0;
1230
+ font-family: var(--mono);
1231
+ font-size: 11px;
1232
+ color: var(--ink-muted);
1233
+ overflow: hidden;
1234
+ text-overflow: ellipsis;
1235
+ white-space: nowrap;
1236
+ }
1237
+ .picker-item-check {
1238
+ margin-left: auto;
1239
+ font-size: 12px;
1240
+ color: var(--accent);
1241
+ flex: 0 0 auto;
1242
+ }
1243
+
1244
+ .picker-create {
1245
+ border-top: 1px solid var(--border-soft);
1246
+ padding: 6px;
1247
+ }
1248
+ .picker-create-toggle {
1249
+ appearance: none;
1250
+ background: transparent;
1251
+ border: 0;
1252
+ width: 100%;
1253
+ display: flex;
1254
+ align-items: center;
1255
+ gap: 8px;
1256
+ padding: 8px 10px;
1257
+ border-radius: 6px;
1258
+ cursor: pointer;
1259
+ color: var(--ink-mid);
1260
+ font: inherit;
1261
+ font-size: 12.5px;
1262
+ font-weight: 500;
1263
+ transition: background .1s ease, color .1s ease;
1264
+ }
1265
+ .picker-create-toggle:hover {
1266
+ background: var(--sidebar-hover);
1267
+ color: var(--ink);
1268
+ }
1269
+ .picker-create-toggle svg { width: 14px; height: 14px; }
1270
+
1271
+ .picker-create-form {
1272
+ padding: 10px;
1273
+ display: flex;
1274
+ flex-direction: column;
1275
+ gap: 8px;
1276
+ }
1277
+ .picker-field {
1278
+ display: flex;
1279
+ flex-direction: column;
1280
+ gap: 4px;
1281
+ }
1282
+ .picker-field-label {
1283
+ font-size: 11px;
1284
+ color: var(--ink-muted);
1285
+ font-weight: 500;
1286
+ }
1287
+ .picker-field .input {
1288
+ padding: 6px 10px;
1289
+ font-size: 12.5px;
1290
+ max-width: none;
1291
+ }
1292
+ .picker-create-actions {
1293
+ display: flex;
1294
+ justify-content: flex-end;
1295
+ gap: 6px;
1296
+ margin-top: 4px;
1297
+ }
1298
+
1299
+ /* --- Adopt (import existing CLI session) modal --------------------- */
1300
+ /* Fills the (flush, scrolling) modal body: a pinned head (tabs + tools)
1301
+ and a scrolling list below it; pagination lives in the modal footer. */
1302
+ .adopt { display: flex; flex-direction: column; min-height: 360px; }
1303
+
1304
+ .adopt-head {
1305
+ position: sticky;
1306
+ top: 0;
1307
+ z-index: 2;
1308
+ display: flex;
1309
+ flex-direction: column;
1310
+ gap: 12px;
1311
+ padding: 14px 18px 12px;
1312
+ background: var(--bg-elev);
1313
+ border-bottom: 1px solid var(--border-soft);
1314
+ }
1315
+
1316
+ /* Underline tab bar (was solid pills) — calmer, matches the app. */
1317
+ .adopt-tabs {
1318
+ display: flex;
1319
+ align-items: center;
1320
+ gap: 2px;
1321
+ }
1322
+ .adopt-tab {
1323
+ appearance: none;
1324
+ display: inline-flex;
1325
+ align-items: center;
1326
+ gap: 7px;
1327
+ padding: 6px 11px 8px;
1328
+ background: transparent;
1329
+ border: 0;
1330
+ border-bottom: 2px solid transparent;
1331
+ font: inherit;
1332
+ font-size: 13px;
1333
+ font-weight: 500;
1334
+ color: var(--ink-muted);
1335
+ cursor: pointer;
1336
+ transition: color .12s ease, border-color .12s ease;
1337
+ }
1338
+ .adopt-tab:hover { color: var(--ink); }
1339
+ .adopt-tab.is-active {
1340
+ color: var(--ink);
1341
+ border-bottom-color: var(--ink);
1342
+ }
1343
+ .adopt-tab-icon { display: inline-flex; width: 16px; height: 16px; }
1344
+ .adopt-tab-icon svg, .adopt-tab-icon img { width: 100%; height: 100%; }
1345
+ .adopt-tab-count {
1346
+ display: inline-flex;
1347
+ align-items: center;
1348
+ justify-content: center;
1349
+ min-width: 17px;
1350
+ height: 16px;
1351
+ padding: 0 5px;
1352
+ border-radius: 999px;
1353
+ background: var(--ui-bg);
1354
+ color: var(--ink-mid);
1355
+ font-size: 10.5px;
1356
+ font-weight: 600;
1357
+ font-variant-numeric: tabular-nums;
1358
+ }
1359
+ .adopt-rescan {
1360
+ appearance: none;
1361
+ margin-left: auto;
1362
+ display: inline-flex;
1363
+ align-items: center;
1364
+ justify-content: center;
1365
+ width: 28px;
1366
+ height: 28px;
1367
+ padding: 0;
1368
+ border: 1px solid var(--border);
1369
+ background: var(--bg-elev);
1370
+ color: var(--ink-muted);
1371
+ border-radius: 8px;
1372
+ cursor: pointer;
1373
+ transition: color .12s ease, border-color .12s ease, transform .3s ease;
1374
+ }
1375
+ .adopt-rescan:hover { color: var(--ink); border-color: var(--ink-faint); transform: rotate(90deg); }
1376
+ .adopt-rescan svg { width: 14px; height: 14px; }
1377
+
1378
+ /* Tools row: CLI picker pill + search input */
1379
+ .adopt-tools {
1380
+ display: flex;
1381
+ align-items: center;
1382
+ gap: 10px;
1383
+ flex-wrap: wrap;
1384
+ }
1385
+ .adopt-cli-pill {
1386
+ appearance: none;
1387
+ display: inline-flex;
1388
+ align-items: center;
1389
+ gap: 6px;
1390
+ padding: 5px 8px 5px 10px;
1391
+ height: 30px;
1392
+ border: 1px solid var(--border);
1393
+ border-radius: 8px;
1394
+ background: var(--bg-elev);
1395
+ color: var(--ink);
1396
+ font: inherit;
1397
+ font-size: 12px;
1398
+ cursor: pointer;
1399
+ transition: border-color .12s ease, background .12s ease;
1400
+ }
1401
+ .adopt-cli-pill:hover { border-color: var(--ink-faint); background: var(--bg); }
1402
+ .adopt-cli-pill.is-open { border-color: var(--ink); }
1403
+ .adopt-cli-pill-prefix { color: var(--ink-muted); font-size: 11.5px; }
1404
+ .adopt-cli-pill-icon {
1405
+ display: inline-flex; align-items: center; justify-content: center;
1406
+ width: 14px; height: 14px;
1407
+ }
1408
+ .adopt-cli-pill-icon svg { width: 100%; height: 100%; }
1409
+ .adopt-cli-pill-name { font-weight: 500; }
1410
+ .adopt-cli-pill > svg { color: var(--ink-faint); width: 12px; height: 12px; }
1411
+
1412
+ .adopt-search {
1413
+ position: relative;
1414
+ flex: 1 1 200px;
1415
+ min-width: 200px;
1416
+ }
1417
+ .adopt-search-icon {
1418
+ position: absolute;
1419
+ left: 9px;
1420
+ top: 50%;
1421
+ transform: translateY(-50%);
1422
+ display: inline-flex;
1423
+ color: var(--ink-faint);
1424
+ pointer-events: none;
1425
+ }
1426
+ .adopt-search-icon svg { width: 13px; height: 13px; }
1427
+ .adopt-search-input {
1428
+ appearance: none;
1429
+ width: 100%;
1430
+ height: 30px;
1431
+ padding: 0 28px 0 28px;
1432
+ border: 1px solid var(--border);
1433
+ border-radius: 8px;
1434
+ background: var(--bg-elev);
1435
+ color: var(--ink);
1436
+ font: inherit;
1437
+ font-size: 12px;
1438
+ outline: none;
1439
+ transition: border-color .12s ease;
1440
+ }
1441
+ .adopt-search-input:focus { border-color: var(--ink-faint); }
1442
+ .adopt-search-input:disabled { color: var(--ink-faint); }
1443
+ .adopt-search-clear {
1444
+ appearance: none;
1445
+ position: absolute;
1446
+ right: 6px;
1447
+ top: 50%;
1448
+ transform: translateY(-50%);
1449
+ border: 0;
1450
+ background: transparent;
1451
+ color: var(--ink-faint);
1452
+ padding: 4px;
1453
+ border-radius: 6px;
1454
+ cursor: pointer;
1455
+ display: inline-flex;
1456
+ }
1457
+ .adopt-search-clear:hover { color: var(--ink); background: var(--bg); }
1458
+ .adopt-search-clear svg { width: 11px; height: 11px; }
1459
+
1460
+ /* The list scrolls inside the modal body now (not its own overflow box);
1461
+ this is just the padded wrapper. */
1462
+ .adopt-list {
1463
+ padding: 12px 18px 16px;
1464
+ }
1465
+ .adopt-empty {
1466
+ padding: 48px 12px;
1467
+ text-align: center;
1468
+ color: var(--ink-muted);
1469
+ font-size: 12.5px;
1470
+ display: flex;
1471
+ flex-direction: column;
1472
+ align-items: center;
1473
+ gap: 10px;
1474
+ }
1475
+ .adopt-error { color: var(--danger); }
1476
+ .adopt-empty-mark {
1477
+ font-size: 24px;
1478
+ color: var(--ink-faint);
1479
+ width: 44px;
1480
+ height: 44px;
1481
+ border-radius: 50%;
1482
+ background: var(--bg);
1483
+ display: inline-flex;
1484
+ align-items: center;
1485
+ justify-content: center;
1486
+ border: 1px dashed var(--border);
1487
+ }
1488
+ .adopt-empty-spinner {
1489
+ width: 14px; height: 14px; border-radius: 50%;
1490
+ border: 1.6px solid var(--border);
1491
+ border-top-color: var(--ink-faint);
1492
+ animation: adopt-spin 0.8s linear infinite;
1493
+ display: inline-block;
1494
+ vertical-align: -2px;
1495
+ margin-right: 6px;
1496
+ }
1497
+ @keyframes adopt-spin { to { transform: rotate(360deg); } }
1498
+
1499
+ .adopt-rows {
1500
+ list-style: none;
1501
+ margin: 0;
1502
+ padding: 0;
1503
+ display: flex;
1504
+ flex-direction: column;
1505
+ gap: 6px;
1506
+ }
1507
+ .adopt-row {
1508
+ display: flex;
1509
+ align-items: center;
1510
+ gap: 11px;
1511
+ padding: 10px 12px;
1512
+ border: 1px solid var(--border);
1513
+ background: var(--bg-elev);
1514
+ border-radius: 10px;
1515
+ transition: border-color .12s ease, background .12s ease, transform .12s ease;
1516
+ }
1517
+ .adopt-row-icon {
1518
+ position: relative;
1519
+ flex: 0 0 auto;
1520
+ display: inline-flex;
1521
+ align-items: center;
1522
+ justify-content: center;
1523
+ width: 30px;
1524
+ height: 30px;
1525
+ border-radius: 8px;
1526
+ background: var(--bg);
1527
+ border: 1px solid var(--border-soft);
1528
+ }
1529
+ .adopt-row-icon svg, .adopt-row-icon img { width: 17px; height: 17px; }
1530
+ .adopt-row:hover {
1531
+ border-color: var(--ink-faint);
1532
+ transform: translateY(-1px);
1533
+ }
1534
+ .adopt-row.is-adopted {
1535
+ opacity: 0.6;
1536
+ background: var(--bg);
1537
+ }
1538
+ .adopt-row.is-adopted:hover { transform: none; border-color: var(--border); }
1539
+ /* A session a cli process currently has open. Quiet treatment: the row
1540
+ itself stays neutral (many rows can be live at once — a wall of green
1541
+ slabs is noise) and the "alive" signal rides on the icon as a small
1542
+ green presence dot, the way a chat avatar shows online. The icon tile
1543
+ picks up a faint green tint + green glyph so the eye still lands. */
1544
+ .adopt-row.is-active .adopt-row-icon {
1545
+ border-color: rgba(74, 138, 74, 0.4);
1546
+ background: rgba(74, 138, 74, 0.1);
1547
+ color: var(--green);
1548
+ }
1549
+ /* Static dot — punched out of the card with a bg-elev ring so it reads as
1550
+ a badge sitting on the icon corner. */
1551
+ .adopt-row.is-active .adopt-row-icon::after {
1552
+ content: "";
1553
+ position: absolute;
1554
+ right: -3px;
1555
+ bottom: -3px;
1556
+ width: 10px;
1557
+ height: 10px;
1558
+ border-radius: 50%;
1559
+ background: var(--green);
1560
+ border: 2px solid var(--bg-elev);
1561
+ }
1562
+ /* Soft presence pulse — a ring expanding off the dot. Opacity-animated on
1563
+ its own layer so it stays GPU-cheap even with a dozen live rows (the old
1564
+ box-shadow pulse pegged the paint thread). */
1565
+ .adopt-row.is-active .adopt-row-icon::before {
1566
+ content: "";
1567
+ position: absolute;
1568
+ right: -1px;
1569
+ bottom: -1px;
1570
+ width: 6px;
1571
+ height: 6px;
1572
+ border-radius: 50%;
1573
+ border: 1px solid var(--green);
1574
+ opacity: 0;
1575
+ animation: adopt-live-pulse 1.9s ease-in-out infinite;
1576
+ pointer-events: none;
1577
+ z-index: 1;
1578
+ }
1579
+ @keyframes adopt-live-pulse {
1580
+ 0% { opacity: 0.55; transform: scale(0.8); }
1581
+ 70%, 100% { opacity: 0; transform: scale(2.6); }
1582
+ }
1583
+ .adopt-row-main { flex: 1 1 auto; min-width: 0; }
1584
+ .adopt-row-title {
1585
+ font-size: 13px;
1586
+ color: var(--ink);
1587
+ font-weight: 500;
1588
+ overflow: hidden;
1589
+ text-overflow: ellipsis;
1590
+ white-space: nowrap;
1591
+ line-height: 1.35;
1592
+ display: flex;
1593
+ align-items: center;
1594
+ gap: 8px;
1595
+ }
1596
+ .adopt-row-untitled { color: var(--ink-faint); font-weight: 400; font-style: italic; }
1597
+ /* Minimal caption next to the title — the dot carries the signal, this
1598
+ just names it. No pill, no border, no ring. */
1599
+ .adopt-row-live {
1600
+ flex: 0 0 auto;
1601
+ font-size: 10px;
1602
+ font-weight: 600;
1603
+ letter-spacing: 0.05em;
1604
+ text-transform: uppercase;
1605
+ color: var(--green);
1606
+ cursor: default;
1607
+ }
1608
+
1609
+ /* Footer pagination (rendered into .modal-foot): ‹ Prev · X–Y of Z · Next ›.
1610
+ The flex:1 info pushes the two buttons to the edges and centres the count. */
1611
+ .adopt-pager-info {
1612
+ flex: 1;
1613
+ text-align: center;
1614
+ font-size: 12px;
1615
+ color: var(--ink-muted);
1616
+ font-variant-numeric: tabular-nums;
1617
+ }
1618
+ .adopt-pager-btn { min-width: 78px; gap: 4px; }
1619
+ .adopt-pager-btn svg { width: 13px; height: 13px; }
1620
+ .adopt-row-meta {
1621
+ display: flex;
1622
+ align-items: center;
1623
+ font-size: 11px;
1624
+ color: var(--ink-muted);
1625
+ margin-top: 4px;
1626
+ white-space: nowrap;
1627
+ overflow: hidden;
1628
+ }
1629
+ .adopt-row-path {
1630
+ min-width: 0;
1631
+ overflow: hidden;
1632
+ text-overflow: ellipsis;
1633
+ white-space: nowrap;
1634
+ flex: 0 1 auto;
1635
+ }
1636
+ .adopt-row-dot { margin: 0 8px; color: var(--ink-faint); }
1637
+ .adopt-row-id { color: var(--ink-faint); }
1638
+ .adopt-row-actions {
1639
+ display: flex;
1640
+ align-items: center;
1641
+ gap: 6px;
1642
+ flex: 0 0 auto;
1643
+ }
1644
+ .adopt-row-btn { padding: 6px 14px; font-size: 12px; }
1645
+ .adopt-row-badge {
1646
+ font-size: 11px;
1647
+ color: var(--ink-muted);
1648
+ padding: 5px 12px;
1649
+ border-radius: 999px;
1650
+ background: var(--bg);
1651
+ border: 1px solid var(--border);
1652
+ }
1653
+
1654
+ /* ── Remote page ──────────────────────────────────────────────────
1655
+ Uses the existing .settings-scroll + Section + .config-grid + .field
1656
+ + .chip system from ConfigurePage. Only adds the bits that don't
1657
+ already exist: the inline status line per provider, the token-row
1658
+ input + action cluster, the URL row, the CLI log block, and the
1659
+ bulleted security list. */
1660
+
1661
+ /* Provider picker tiles — large clickable cards with the brand mark
1662
+ front and center, replacing the old chip-row radio pair. Two-wide
1663
+ on desktop, stacks at narrow widths. */
1664
+ .provider-tile-row {
1665
+ display: grid;
1666
+ grid-template-columns: repeat(2, minmax(0, 1fr));
1667
+ gap: var(--s-3);
1668
+ max-width: 560px;
1669
+ }
1670
+ @media (max-width: 560px) {
1671
+ .provider-tile-row { grid-template-columns: 1fr; }
1672
+ }
1673
+ .provider-tile {
1674
+ appearance: none;
1675
+ display: flex;
1676
+ align-items: center;
1677
+ gap: var(--s-3);
1678
+ padding: var(--s-3) var(--s-4);
1679
+ background: var(--bg-elev);
1680
+ border: 1px solid var(--border);
1681
+ border-radius: 10px;
1682
+ cursor: pointer;
1683
+ text-align: left;
1684
+ color: var(--ink);
1685
+ font: inherit;
1686
+ transition: border-color .12s, background-color .12s, box-shadow .12s;
1687
+ }
1688
+ .provider-tile:hover { border-color: var(--border-strong); }
1689
+ .provider-tile.is-selected {
1690
+ border-color: var(--ink);
1691
+ background: var(--bg-elev);
1692
+ box-shadow: 0 0 0 1px var(--ink);
1693
+ }
1694
+ .provider-tile.is-disabled,
1695
+ .provider-tile:disabled {
1696
+ cursor: not-allowed;
1697
+ opacity: 0.55;
1698
+ }
1699
+ .provider-tile.is-disabled:hover,
1700
+ .provider-tile:disabled:hover {
1701
+ border-color: var(--border);
1702
+ }
1703
+ .provider-tile:focus-visible {
1704
+ outline: 2px solid var(--ink);
1705
+ outline-offset: 2px;
1706
+ }
1707
+ .provider-tile-icon {
1708
+ flex: 0 0 32px;
1709
+ width: 32px;
1710
+ height: 32px;
1711
+ display: inline-flex;
1712
+ align-items: center;
1713
+ justify-content: center;
1714
+ }
1715
+ .provider-tile-body {
1716
+ display: flex;
1717
+ flex-direction: column;
1718
+ gap: 2px;
1719
+ min-width: 0;
1720
+ }
1721
+ .provider-tile-label {
1722
+ font-size: 14px;
1723
+ font-weight: 500;
1724
+ letter-spacing: -0.005em;
1725
+ }
1726
+ .provider-tile-hint {
1727
+ font-size: 11.5px;
1728
+ color: var(--ink-muted);
1729
+ }
1730
+ /* ── Provider status row + sign-in card ───────────────────────────
1731
+ Replaces the older devtunnel-login + .remote-status-line inline
1732
+ bag-of-spans with a single composable card vocabulary so the
1733
+ signed-in / signed-out / mid-sign-in states all read as parts of
1734
+ one design rather than three different debug widgets. */
1735
+ .provider-status {
1736
+ display: flex;
1737
+ align-items: center;
1738
+ flex-wrap: wrap;
1739
+ gap: var(--s-2) var(--s-3);
1740
+ }
1741
+ .provider-status.is-stack {
1742
+ flex-direction: column;
1743
+ align-items: stretch;
1744
+ gap: var(--s-2);
1745
+ }
1746
+ .provider-status.is-stack .provider-status-row {
1747
+ display: flex;
1748
+ align-items: center;
1749
+ gap: var(--s-2) var(--s-3);
1750
+ flex-wrap: wrap;
1751
+ }
1752
+ .provider-status-muted { color: var(--ink-muted); font-size: 13px; }
1753
+ .provider-status-state {
1754
+ display: inline-flex;
1755
+ align-items: center;
1756
+ gap: 6px;
1757
+ font-size: 12.5px;
1758
+ font-weight: 500;
1759
+ letter-spacing: -0.003em;
1760
+ color: var(--ink);
1761
+ }
1762
+ .provider-status-state.is-warn { color: #8b3a3a; }
1763
+ .provider-status-state.is-ok { color: #2f6e3a; }
1764
+ .provider-status-dot {
1765
+ width: 7px;
1766
+ height: 7px;
1767
+ border-radius: 50%;
1768
+ background: var(--ink-muted);
1769
+ display: inline-block;
1770
+ }
1771
+ .provider-status-dot.is-ok { background: #4a8a4a; }
1772
+ .provider-status-dot.is-warn { background: #b86a2a; }
1773
+ .provider-status-user {
1774
+ font-family: var(--mono);
1775
+ font-size: 12px;
1776
+ padding: 2px 8px;
1777
+ border-radius: 4px;
1778
+ background: var(--bg);
1779
+ color: var(--ink);
1780
+ border: 1px solid var(--border);
1781
+ max-width: 28ch;
1782
+ overflow: hidden;
1783
+ text-overflow: ellipsis;
1784
+ white-space: nowrap;
1785
+ }
1786
+ .provider-status-version {
1787
+ font-family: var(--mono);
1788
+ font-size: 11px;
1789
+ color: var(--ink-muted);
1790
+ }
1791
+ .provider-status-switch { margin-left: auto; }
1792
+ .provider-status-signin { margin-left: auto; }
1793
+
1794
+ /* DevtunnelTunnelIdRow — shown under the signed-in Microsoft Dev
1795
+ Tunnel status. The tunnel id is the persistent identifier that
1796
+ keeps the public URL stable across `devtunnel host` restarts;
1797
+ surfaced so the user knows what's being reused and can rotate it
1798
+ when they want fresh credentials. */
1799
+ .tunnel-id-row {
1800
+ display: flex;
1801
+ align-items: center;
1802
+ flex-wrap: wrap;
1803
+ gap: var(--s-2);
1804
+ margin-top: var(--s-2);
1805
+ padding: 6px 10px;
1806
+ border: 1px solid var(--border-soft);
1807
+ border-radius: 6px;
1808
+ background: var(--bg);
1809
+ font-size: 12px;
1810
+ color: var(--ink-mid);
1811
+ }
1812
+ .tunnel-id-row.is-empty { color: var(--ink-muted); }
1813
+ .tunnel-id-label {
1814
+ font-size: 10.5px;
1815
+ letter-spacing: 0.16em;
1816
+ text-transform: uppercase;
1817
+ font-weight: 600;
1818
+ color: var(--ink-muted);
1819
+ }
1820
+ .tunnel-id-value {
1821
+ font-family: var(--mono);
1822
+ font-size: 12px;
1823
+ color: var(--ink);
1824
+ user-select: all;
1825
+ padding: 1px 6px;
1826
+ border-radius: 4px;
1827
+ background: var(--bg-elev);
1828
+ border: 1px solid var(--border-soft);
1829
+ }
1830
+ .tunnel-id-value-empty {
1831
+ font-style: italic;
1832
+ color: var(--ink-muted);
1833
+ }
1834
+ .tunnel-id-reset { margin-left: auto; }
1835
+
1836
+ /* ── Tunnel section: hero (idle) + live banner (running) ──────────
1837
+ Idle: a single horizontal card with the headline + start CTA.
1838
+ Running: a status banner (state · provider · uptime · stop link)
1839
+ followed by a copyable share URL block and an optional collapsed
1840
+ CLI log. */
1841
+ .tunnel-autostart {
1842
+ display: flex;
1843
+ flex-direction: column;
1844
+ gap: 6px;
1845
+ margin-bottom: var(--s-4);
1846
+ }
1847
+ .tunnel-autostart-row {
1848
+ display: flex;
1849
+ align-items: center;
1850
+ gap: 9px;
1851
+ cursor: pointer;
1852
+ font-size: 13px;
1853
+ color: var(--ink-mid);
1854
+ }
1855
+ .tunnel-autostart-row input {
1856
+ flex: 0 0 auto;
1857
+ cursor: pointer;
1858
+ }
1859
+ .tunnel-autostart-label {
1860
+ user-select: none;
1861
+ }
1862
+ .tunnel-autostart-hint {
1863
+ /* indent under the checkbox so it lines up with the label text */
1864
+ padding-left: 26px;
1865
+ }
1866
+
1867
+ .tunnel-hero {
1868
+ display: flex;
1869
+ align-items: center;
1870
+ justify-content: space-between;
1871
+ gap: var(--s-4);
1872
+ padding: var(--s-4) var(--s-5);
1873
+ border: 1px solid var(--border);
1874
+ border-radius: 10px;
1875
+ background: var(--bg-elev);
1876
+ }
1877
+ .tunnel-hero-body {
1878
+ display: flex;
1879
+ flex-direction: column;
1880
+ gap: 4px;
1881
+ min-width: 0;
1882
+ }
1883
+ .tunnel-hero-title {
1884
+ font-size: 15px;
1885
+ font-weight: 600;
1886
+ letter-spacing: -0.01em;
1887
+ color: var(--ink);
1888
+ }
1889
+ .tunnel-hero-meta {
1890
+ font-size: 12.5px;
1891
+ color: var(--ink-mid);
1892
+ line-height: 1.5;
1893
+ }
1894
+ .tunnel-hero-meta code {
1895
+ font-family: var(--mono);
1896
+ font-size: 11.5px;
1897
+ padding: 1px 5px;
1898
+ border-radius: 3px;
1899
+ background: var(--bg);
1900
+ border: 1px solid var(--border-soft);
1901
+ }
1902
+ .tunnel-hero-cta {
1903
+ /* Pick up theme accent + match the default size of other `.action`
1904
+ buttons across the app. No `min-width` override (was 140px, too
1905
+ wide compared to the Copy/Open pair). */
1906
+ flex: 0 0 auto;
1907
+ background: var(--accent);
1908
+ border-color: var(--accent);
1909
+ color: #fff;
1910
+ }
1911
+ .tunnel-hero-cta:hover {
1912
+ background: var(--accent-deep, var(--accent));
1913
+ border-color: var(--accent-deep, var(--accent));
1914
+ }
1915
+ .tunnel-hero-cta:disabled {
1916
+ opacity: 0.6;
1917
+ cursor: wait;
1918
+ }
1919
+
1920
+ .tunnel-live {
1921
+ display: flex;
1922
+ flex-direction: column;
1923
+ gap: var(--s-3);
1924
+ }
1925
+ .tunnel-live-head {
1926
+ display: flex;
1927
+ align-items: center;
1928
+ flex-wrap: wrap;
1929
+ gap: 6px 8px;
1930
+ padding: 6px 10px 6px 12px;
1931
+ border-radius: 999px;
1932
+ background: rgba(74, 138, 74, 0.08);
1933
+ border: 1px solid rgba(74, 138, 74, 0.32);
1934
+ font-size: 12.5px;
1935
+ color: var(--ink);
1936
+ width: fit-content;
1937
+ max-width: 100%;
1938
+ }
1939
+ .tunnel-live-state {
1940
+ display: inline-flex;
1941
+ align-items: center;
1942
+ gap: 6px;
1943
+ font-weight: 600;
1944
+ letter-spacing: 0.02em;
1945
+ color: #2f6e3a;
1946
+ }
1947
+ .tunnel-live-dot {
1948
+ width: 8px;
1949
+ height: 8px;
1950
+ border-radius: 50%;
1951
+ background: #4a8a4a;
1952
+ box-shadow: 0 0 0 0 rgba(74, 138, 74, 0.6);
1953
+ animation: tunnel-live-pulse 2s ease-in-out infinite;
1954
+ }
1955
+ @keyframes tunnel-live-pulse {
1956
+ 0% { box-shadow: 0 0 0 0 rgba(74, 138, 74, 0.55); }
1957
+ 70% { box-shadow: 0 0 0 8px rgba(74, 138, 74, 0); }
1958
+ 100% { box-shadow: 0 0 0 0 rgba(74, 138, 74, 0); }
1959
+ }
1960
+ .tunnel-live-divider { color: var(--ink-faint); }
1961
+ .tunnel-live-provider { color: var(--ink); font-weight: 500; }
1962
+ .tunnel-live-meta { color: var(--ink-mid); }
1963
+ .tunnel-stop-link {
1964
+ appearance: none;
1965
+ background: transparent;
1966
+ border: 0;
1967
+ padding: 0 4px 0 10px;
1968
+ margin-left: 4px;
1969
+ display: inline-flex;
1970
+ align-items: center;
1971
+ gap: 4px;
1972
+ font: inherit;
1973
+ font-size: 12px;
1974
+ font-weight: 500;
1975
+ color: #b73f3f;
1976
+ cursor: pointer;
1977
+ border-left: 1px solid rgba(74, 138, 74, 0.25);
1978
+ transition: color .12s;
1979
+ }
1980
+ .tunnel-stop-link:hover { color: #8b2a2a; }
1981
+ .tunnel-stop-link:disabled { opacity: 0.5; cursor: wait; }
1982
+ .tunnel-stop-link svg { width: 11px; height: 11px; }
1983
+
1984
+ .tunnel-share {
1985
+ display: flex;
1986
+ flex-direction: column;
1987
+ gap: 6px;
1988
+ padding: var(--s-3) var(--s-4);
1989
+ border: 1px solid var(--border);
1990
+ border-radius: 10px;
1991
+ background: var(--bg);
1992
+ }
1993
+ .tunnel-share.is-waiting {
1994
+ flex-direction: row;
1995
+ align-items: center;
1996
+ gap: var(--s-2);
1997
+ color: var(--ink-muted);
1998
+ font-size: 13px;
1999
+ }
2000
+ .tunnel-share-label {
2001
+ font-size: 10.5px;
2002
+ letter-spacing: 0.16em;
2003
+ text-transform: uppercase;
2004
+ color: var(--ink-muted);
2005
+ font-weight: 500;
2006
+ }
2007
+ .tunnel-share-url {
2008
+ display: flex;
2009
+ align-items: center;
2010
+ gap: var(--s-3);
2011
+ flex-wrap: wrap;
2012
+ }
2013
+ .tunnel-share-value {
2014
+ flex: 1;
2015
+ min-width: 0;
2016
+ font-family: var(--mono);
2017
+ font-size: 13px;
2018
+ color: var(--ink);
2019
+ padding: 6px 10px;
2020
+ border: 1px solid var(--border-soft);
2021
+ border-radius: 6px;
2022
+ background: var(--bg-elev);
2023
+ overflow: hidden;
2024
+ text-overflow: ellipsis;
2025
+ white-space: nowrap;
2026
+ user-select: all;
2027
+ }
2028
+ .tunnel-share-actions {
2029
+ display: inline-flex;
2030
+ gap: 6px;
2031
+ flex: 0 0 auto;
2032
+ }
2033
+ .tunnel-share-hint {
2034
+ font-size: 11.5px;
2035
+ color: var(--ink-muted);
2036
+ }
2037
+ .tunnel-log { font-size: 12px; }
2038
+ .tunnel-log summary {
2039
+ cursor: pointer;
2040
+ user-select: none;
2041
+ color: var(--ink-mid);
2042
+ padding: 4px 0;
2043
+ }
2044
+ .tunnel-log pre {
2045
+ margin: 6px 0 0;
2046
+ padding: var(--s-2) var(--s-3);
2047
+ background: var(--bg);
2048
+ border: 1px solid var(--border-soft);
2049
+ border-radius: 6px;
2050
+ font-family: var(--mono);
2051
+ font-size: 11.5px;
2052
+ line-height: 1.45;
2053
+ color: var(--ink-mid);
2054
+ max-height: 220px;
2055
+ overflow: auto;
2056
+ white-space: pre-wrap;
2057
+ word-break: break-word;
2058
+ }
2059
+
2060
+ /* Version-update card — Configure → Version field. Idle state is a
2061
+ muted "you're on the latest" pill; update-available flips a subtle
2062
+ blue tint and surfaces a primary upgrade CTA. */
2063
+ .version-card {
2064
+ display: flex;
2065
+ align-items: center;
2066
+ justify-content: space-between;
2067
+ gap: var(--s-4);
2068
+ padding: var(--s-3) var(--s-4);
2069
+ border: 1px solid var(--border);
2070
+ border-radius: 10px;
2071
+ background: var(--bg-elev);
2072
+ flex-wrap: wrap;
2073
+ }
2074
+ .version-card.has-update {
2075
+ border-color: rgba(0, 120, 212, 0.35);
2076
+ background: linear-gradient(180deg, rgba(0, 120, 212, 0.04) 0%, var(--bg-elev) 100%);
2077
+ }
2078
+ .version-card.has-error {
2079
+ border-color: rgba(183, 63, 63, 0.30);
2080
+ background: rgba(183, 63, 63, 0.03);
2081
+ }
2082
+ .version-card-main {
2083
+ display: flex;
2084
+ flex-direction: column;
2085
+ gap: 4px;
2086
+ min-width: 0;
2087
+ flex: 1;
2088
+ }
2089
+ .version-card-current {
2090
+ display: flex;
2091
+ align-items: baseline;
2092
+ gap: 8px;
2093
+ flex-wrap: wrap;
2094
+ }
2095
+ .version-card-label {
2096
+ font-size: 10.5px;
2097
+ letter-spacing: 0.16em;
2098
+ text-transform: uppercase;
2099
+ color: var(--ink-muted);
2100
+ font-weight: 500;
2101
+ }
2102
+ .version-card-version {
2103
+ font-family: var(--mono);
2104
+ font-size: 18px;
2105
+ font-weight: 600;
2106
+ letter-spacing: -0.01em;
2107
+ color: var(--ink);
2108
+ font-variant-numeric: tabular-nums;
2109
+ }
2110
+ .version-card-badge {
2111
+ font-size: 10.5px;
2112
+ letter-spacing: 0.08em;
2113
+ text-transform: uppercase;
2114
+ font-weight: 600;
2115
+ padding: 1px 8px;
2116
+ border-radius: 999px;
2117
+ background: rgba(74, 138, 74, 0.12);
2118
+ color: #2f6e3a;
2119
+ border: 1px solid rgba(74, 138, 74, 0.3);
2120
+ }
2121
+ .version-card.has-update .version-card-badge {
2122
+ background: rgba(0, 120, 212, 0.12);
2123
+ color: #005a9e;
2124
+ border-color: rgba(0, 120, 212, 0.35);
2125
+ }
2126
+ .version-card-meta {
2127
+ font-size: 12.5px;
2128
+ color: var(--ink-mid);
2129
+ line-height: 1.5;
2130
+ }
2131
+ .version-card-meta .mono {
2132
+ font-family: var(--mono);
2133
+ font-size: 12px;
2134
+ color: var(--ink);
2135
+ }
2136
+ .version-card-error {
2137
+ color: #8b3a3a;
2138
+ }
2139
+ .version-card-error code {
2140
+ font-family: var(--mono);
2141
+ font-size: 11px;
2142
+ }
2143
+ .version-card-actions {
2144
+ display: inline-flex;
2145
+ align-items: center;
2146
+ gap: var(--s-2);
2147
+ flex-shrink: 0;
2148
+ flex-wrap: wrap;
2149
+ justify-content: flex-end;
2150
+ }
2151
+ .version-card-check {
2152
+ background: var(--accent);
2153
+ border-color: var(--accent);
2154
+ color: #fff;
2155
+ }
2156
+ .version-card-check:hover {
2157
+ background: var(--accent-deep, var(--accent));
2158
+ border-color: var(--accent-deep, var(--accent));
2159
+ }
2160
+ .version-card-check:disabled { opacity: 0.6; cursor: wait; }
2161
+ .version-card-check svg { stroke: #fff; }
2162
+
2163
+ /* Cards inside the Configure → General config-grid would otherwise
2164
+ stretch full row width (flex column → align-stretch). For the
2165
+ Restart button we still want it to shrink to the text — keep the
2166
+ inline wrapper. The Version card stays full-width to read like the
2167
+ other settings rows. */
2168
+ .config-grid .field .restart-button-wrap {
2169
+ align-self: stretch;
2170
+ }
2171
+ .restart-button-wrap { display: inline-flex; }
2172
+
2173
+ /* Microsoft brand-style sign-in button. Microsoft's published guidance
2174
+ is a white pill with the 4-square logo on the left and "Sign in
2175
+ with Microsoft" in Segoe-ish type. We can't ship Segoe in a web
2176
+ font here so the body family takes over — the visual still reads
2177
+ correctly thanks to the logo + spacing. White surface + thin
2178
+ border keeps it distinct from our own black `.action.primary`
2179
+ slab (which the user found too heavy for an external-auth CTA). */
2180
+ .btn-signin-microsoft {
2181
+ appearance: none;
2182
+ display: inline-flex;
2183
+ align-items: center;
2184
+ gap: 10px;
2185
+ align-self: flex-start;
2186
+ padding: 8px 16px;
2187
+ min-height: 36px;
2188
+ background: #ffffff;
2189
+ color: #1a1815;
2190
+ border: 1px solid #d3d3d3;
2191
+ border-radius: 4px; /* MS guidance: rectangular, ~2-4px radius */
2192
+ font: inherit;
2193
+ font-size: 13.5px;
2194
+ font-weight: 500;
2195
+ letter-spacing: -0.005em;
2196
+ cursor: pointer;
2197
+ transition: background-color .12s, border-color .12s, box-shadow .12s;
2198
+ }
2199
+ .btn-signin-microsoft:hover {
2200
+ background: #f3f3f3;
2201
+ border-color: #b8b8b8;
2202
+ }
2203
+ .btn-signin-microsoft:active { background: #ebebeb; }
2204
+ .btn-signin-microsoft:focus-visible {
2205
+ outline: 2px solid #2f6fa3;
2206
+ outline-offset: 2px;
2207
+ }
2208
+ .btn-signin-microsoft img { display: block; }
2209
+
2210
+ /* The mid-sign-in "card" — replaces .devtunnel-login. Bigger device
2211
+ code, primary CTA, slimmer chrome. */
2212
+ .signin-card {
2213
+ margin-top: var(--s-3);
2214
+ padding: var(--s-5);
2215
+ border: 1px solid var(--border);
2216
+ border-radius: 10px;
2217
+ background: var(--bg-elev);
2218
+ display: flex;
2219
+ flex-direction: column;
2220
+ gap: var(--s-4);
2221
+ font-size: 13px;
2222
+ }
2223
+ .signin-card.is-done { border-color: rgba(74, 138, 74, 0.4); }
2224
+ .signin-card.is-error { border-color: rgba(183, 63, 63, 0.4); }
2225
+ .signin-card-header {
2226
+ display: flex;
2227
+ align-items: center;
2228
+ gap: var(--s-2);
2229
+ color: var(--ink-mid);
2230
+ }
2231
+ .signin-card-cancel {
2232
+ margin-left: auto;
2233
+ appearance: none;
2234
+ display: inline-flex;
2235
+ align-items: center;
2236
+ gap: 4px;
2237
+ padding: 4px 10px;
2238
+ border-radius: 6px;
2239
+ border: 1px solid rgba(183, 63, 63, 0.35);
2240
+ background: transparent;
2241
+ color: #b73f3f;
2242
+ font: inherit;
2243
+ font-size: 12px;
2244
+ font-weight: 500;
2245
+ letter-spacing: 0.02em;
2246
+ cursor: pointer;
2247
+ transition: background-color .12s, border-color .12s, color .12s;
2248
+ }
2249
+ .signin-card-cancel:hover {
2250
+ background: rgba(183, 63, 63, 0.08);
2251
+ border-color: rgba(183, 63, 63, 0.55);
2252
+ color: #8b2a2a;
2253
+ }
2254
+ .signin-card-cancel svg { width: 12px; height: 12px; }
2255
+ .signin-card-eyebrow {
2256
+ font-size: 11px;
2257
+ letter-spacing: 0.14em;
2258
+ text-transform: uppercase;
2259
+ font-weight: 600;
2260
+ }
2261
+ .signin-card-spinner {
2262
+ width: 12px;
2263
+ height: 12px;
2264
+ border-radius: 50%;
2265
+ border: 2px solid var(--border-strong);
2266
+ border-top-color: var(--ink);
2267
+ animation: remote-spin 0.7s linear infinite;
2268
+ }
2269
+ .signin-card-code-block {
2270
+ display: flex;
2271
+ flex-direction: column;
2272
+ gap: 6px;
2273
+ padding: var(--s-3) var(--s-4);
2274
+ background: var(--bg);
2275
+ border: 1px solid var(--border);
2276
+ border-radius: 8px;
2277
+ }
2278
+ .signin-card-code-label {
2279
+ font-size: 10.5px;
2280
+ letter-spacing: 0.16em;
2281
+ text-transform: uppercase;
2282
+ color: var(--ink-muted);
2283
+ }
2284
+ .signin-card-code-row {
2285
+ display: flex;
2286
+ align-items: center;
2287
+ gap: var(--s-2);
2288
+ }
2289
+ .signin-card-code {
2290
+ font-family: var(--mono);
2291
+ font-size: 22px;
2292
+ font-weight: 600;
2293
+ letter-spacing: 0.12em;
2294
+ color: var(--ink);
2295
+ user-select: all;
2296
+ font-variant-numeric: tabular-nums;
2297
+ }
2298
+ .signin-card-code-pending {
2299
+ font-size: 13px;
2300
+ color: var(--ink-muted);
2301
+ font-style: italic;
2302
+ }
2303
+ .signin-card-code-copy { margin-left: 4px; }
2304
+ .signin-card-steps {
2305
+ margin: 0;
2306
+ padding-left: var(--s-5);
2307
+ display: flex;
2308
+ flex-direction: column;
2309
+ gap: 6px;
2310
+ color: var(--ink-mid);
2311
+ font-size: 13px;
2312
+ line-height: 1.5;
2313
+ }
2314
+ .signin-card-steps li::marker {
2315
+ color: var(--ink-faint);
2316
+ font-variant-numeric: tabular-nums;
2317
+ }
2318
+ .signin-card-step-muted { color: var(--ink-muted); }
2319
+ .signin-card-open {
2320
+ display: inline-flex;
2321
+ align-items: center;
2322
+ gap: 6px;
2323
+ color: #0067b8;
2324
+ font-weight: 500;
2325
+ text-decoration: underline;
2326
+ text-decoration-color: rgba(0, 103, 184, 0.4);
2327
+ text-underline-offset: 3px;
2328
+ transition: color .12s, text-decoration-color .12s;
2329
+ }
2330
+ .signin-card-open:hover {
2331
+ color: #005a9e;
2332
+ text-decoration-color: #005a9e;
2333
+ }
2334
+ .signin-card-open svg { width: 13px; height: 13px; }
2335
+ .signin-card-host {
2336
+ font-family: var(--mono);
2337
+ font-size: 12.5px;
2338
+ }
2339
+ .signin-card-actions {
2340
+ display: flex;
2341
+ gap: var(--s-2);
2342
+ flex-wrap: wrap;
2343
+ justify-content: flex-end;
2344
+ }
2345
+ .signin-card-result {
2346
+ display: flex;
2347
+ align-items: flex-start;
2348
+ gap: var(--s-3);
2349
+ padding: var(--s-3) var(--s-4);
2350
+ border-radius: 8px;
2351
+ background: var(--bg);
2352
+ border: 1px solid var(--border);
2353
+ }
2354
+ .signin-card-result.is-ok { border-color: rgba(74, 138, 74, 0.35); background: #f1f6f0; }
2355
+ .signin-card-result.is-error { border-color: rgba(183, 63, 63, 0.35); background: #faf0f0; }
2356
+ .signin-card-result.is-muted { background: var(--bg); }
2357
+ .signin-card-result-icon {
2358
+ flex: 0 0 24px;
2359
+ width: 24px;
2360
+ height: 24px;
2361
+ border-radius: 50%;
2362
+ display: inline-flex;
2363
+ align-items: center;
2364
+ justify-content: center;
2365
+ font-weight: 700;
2366
+ color: #fff;
2367
+ background: var(--ink-muted);
2368
+ font-size: 13px;
2369
+ }
2370
+ .signin-card-result.is-ok .signin-card-result-icon { background: #4a8a4a; }
2371
+ .signin-card-result.is-error .signin-card-result-icon { background: #b73f3f; }
2372
+ .signin-card-result-body {
2373
+ flex: 1;
2374
+ min-width: 0;
2375
+ display: flex;
2376
+ flex-direction: column;
2377
+ gap: 2px;
2378
+ }
2379
+ .signin-card-result-title {
2380
+ font-weight: 600;
2381
+ color: var(--ink);
2382
+ letter-spacing: -0.005em;
2383
+ }
2384
+ .signin-card-result-meta {
2385
+ font-size: 12.5px;
2386
+ color: var(--ink-mid);
2387
+ line-height: 1.45;
2388
+ }
2389
+ .signin-card-result-actions {
2390
+ display: flex;
2391
+ gap: var(--s-2);
2392
+ flex-wrap: wrap;
2393
+ }
2394
+ .signin-card-log {
2395
+ font-size: 11.5px;
2396
+ color: var(--ink-muted);
2397
+ border-top: 1px solid var(--border);
2398
+ padding-top: var(--s-3);
2399
+ }
2400
+ .signin-card-log summary {
2401
+ cursor: pointer;
2402
+ user-select: none;
2403
+ padding: 2px 0;
2404
+ }
2405
+ .signin-card-log pre {
2406
+ margin: var(--s-2) 0 0;
2407
+ padding: var(--s-2) var(--s-3);
2408
+ background: var(--bg);
2409
+ border: 1px solid var(--border-soft);
2410
+ border-radius: 4px;
2411
+ font-family: var(--mono);
2412
+ font-size: 11px;
2413
+ line-height: 1.45;
2414
+ color: var(--ink-mid);
2415
+ max-height: 180px;
2416
+ overflow: auto;
2417
+ white-space: pre-wrap;
2418
+ word-break: break-word;
2419
+ }
2420
+
2421
+ .remote-status-line {
2422
+ display: flex;
2423
+ align-items: center;
2424
+ flex-wrap: wrap;
2425
+ gap: var(--s-2);
2426
+ font-size: 12.5px;
2427
+ color: var(--ink-mid);
2428
+ }
2429
+ .remote-status-line .small-mono { font-size: 11px; }
2430
+ .remote-status-line .warn { color: #b86a2a; font-weight: 500; }
2431
+ .remote-status-line .muted { color: var(--ink-muted); }
2432
+ .remote-status-line code {
2433
+ font-family: var(--mono);
2434
+ font-size: 11.5px;
2435
+ background: var(--bg);
2436
+ padding: 1px 5px;
2437
+ border-radius: 3px;
2438
+ }
2439
+
2440
+ .remote-token-row {
2441
+ display: flex;
2442
+ gap: var(--s-2);
2443
+ align-items: center;
2444
+ flex-wrap: wrap;
2445
+ }
2446
+ .remote-token-input {
2447
+ flex: 1;
2448
+ min-width: 240px;
2449
+ font-family: var(--mono);
2450
+ font-size: 12.5px;
2451
+ padding: 7px 11px;
2452
+ border: 1px solid var(--border-strong);
2453
+ border-radius: var(--r-sm);
2454
+ background: var(--bg-elev);
2455
+ color: var(--ink);
2456
+ }
2457
+ .remote-token-input:focus {
2458
+ outline: none;
2459
+ border-color: var(--ink);
2460
+ box-shadow: 0 0 0 1px var(--ink);
2461
+ }
2462
+
2463
+ .remote-url-line {
2464
+ display: flex;
2465
+ gap: var(--s-2);
2466
+ align-items: center;
2467
+ flex-wrap: wrap;
2468
+ }
2469
+ .remote-url-value {
2470
+ flex: 1;
2471
+ min-width: 0;
2472
+ font-family: var(--mono);
2473
+ font-size: 12px;
2474
+ color: var(--ink);
2475
+ background: var(--bg);
2476
+ padding: 6px 10px;
2477
+ border-radius: 4px;
2478
+ border: 1px solid var(--border);
2479
+ overflow: hidden;
2480
+ text-overflow: ellipsis;
2481
+ white-space: nowrap;
2482
+ }
2483
+
2484
+ .remote-log {
2485
+ font-size: 11.5px;
2486
+ color: var(--ink-mid);
2487
+ }
2488
+ .remote-log summary { cursor: pointer; user-select: none; }
2489
+ .remote-log pre {
2490
+ margin-top: var(--s-2);
2491
+ padding: var(--s-3);
2492
+ background: var(--ink);
2493
+ color: var(--bg-elev);
2494
+ border-radius: var(--r-sm);
2495
+ font-family: var(--mono);
2496
+ font-size: 11px;
2497
+ line-height: 1.5;
2498
+ max-height: 220px;
2499
+ overflow: auto;
2500
+ white-space: pre-wrap;
2501
+ word-break: break-all;
2502
+ }
2503
+
2504
+ .remote-loading {
2505
+ display: flex;
2506
+ flex-direction: column;
2507
+ align-items: center;
2508
+ justify-content: center;
2509
+ gap: var(--s-3);
2510
+ /* Fill the entire scroll container so the spinner sits dead-center
2511
+ of the visible Remote panel — both axes — instead of pinning to a
2512
+ fixed 260px box near the top. flex:1 makes us claim all remaining
2513
+ space inside .settings-scroll (column flex). */
2514
+ flex: 1;
2515
+ min-height: 0;
2516
+ color: var(--ink-muted);
2517
+ font-size: 13px;
2518
+ }
2519
+ .remote-loading p { margin: 0; }
2520
+ .remote-loading-spinner {
2521
+ width: 28px;
2522
+ height: 28px;
2523
+ border-radius: 50%;
2524
+ border: 2px solid var(--border-strong);
2525
+ border-top-color: var(--ink);
2526
+ animation: remote-spin 0.75s linear infinite;
2527
+ }
2528
+ @keyframes remote-spin { to { transform: rotate(360deg); } }
2529
+
2530
+ .remote-empty {
2531
+ margin: 0;
2532
+ font-size: 12.5px;
2533
+ color: var(--ink-muted);
2534
+ padding: var(--s-3);
2535
+ background: var(--bg);
2536
+ border-radius: var(--r-sm);
2537
+ text-align: center;
2538
+ }
2539
+ .remote-devices {
2540
+ display: flex;
2541
+ flex-direction: column;
2542
+ gap: var(--s-4);
2543
+ }
2544
+ .remote-devices-group {
2545
+ display: flex;
2546
+ flex-direction: column;
2547
+ gap: 6px;
2548
+ }
2549
+ .remote-devices-group-head {
2550
+ display: flex;
2551
+ align-items: baseline;
2552
+ gap: var(--s-2);
2553
+ margin-bottom: 2px;
2554
+ }
2555
+ .remote-devices-group-title {
2556
+ font-size: 11px;
2557
+ font-weight: 600;
2558
+ text-transform: uppercase;
2559
+ letter-spacing: 0.06em;
2560
+ color: var(--ink-mid);
2561
+ }
2562
+ .remote-devices-group-count {
2563
+ font-family: var(--mono);
2564
+ font-size: 11px;
2565
+ color: var(--ink-muted);
2566
+ background: var(--bg);
2567
+ padding: 1px 7px;
2568
+ border-radius: 999px;
2569
+ border: 1px solid var(--border);
2570
+ }
2571
+ .remote-devices-group-hint {
2572
+ font-size: 11px;
2573
+ font-style: italic;
2574
+ color: var(--ink-muted);
2575
+ }
2576
+ .remote-device {
2577
+ display: flex;
2578
+ align-items: center;
2579
+ gap: var(--s-3);
2580
+ padding: 10px 12px;
2581
+ background: var(--bg-elev);
2582
+ border: 1px solid var(--border);
2583
+ border-radius: var(--r-sm);
2584
+ }
2585
+ .remote-device.is-pending {
2586
+ border-color: #b86a2a;
2587
+ background: rgba(184, 106, 42, 0.04);
2588
+ }
2589
+ .remote-device.is-rejected {
2590
+ background: var(--bg);
2591
+ opacity: 0.8;
2592
+ }
2593
+ .remote-device-main {
2594
+ flex: 1;
2595
+ min-width: 0;
2596
+ }
2597
+ .remote-device-label {
2598
+ display: flex;
2599
+ align-items: center;
2600
+ gap: 6px;
2601
+ font-size: 13px;
2602
+ font-weight: 500;
2603
+ color: var(--ink);
2604
+ }
2605
+ .remote-device-label .icon-btn {
2606
+ background: transparent;
2607
+ border: 0;
2608
+ padding: 2px;
2609
+ cursor: pointer;
2610
+ color: var(--ink-muted);
2611
+ border-radius: 3px;
2612
+ display: inline-flex;
2613
+ align-items: center;
2614
+ }
2615
+ .remote-device-label .icon-btn:hover { color: var(--ink); background: var(--bg); }
2616
+ /* 4-digit identification code rendered as a small pill before the
2617
+ device label. Distinct background so the operator's eye lands on
2618
+ it first — that's the thing they're cross-referencing against what
2619
+ the requesting user reads off their own screen. */
2620
+ .remote-device-code {
2621
+ font-family: var(--mono);
2622
+ font-size: 12px;
2623
+ font-weight: 600;
2624
+ letter-spacing: 0.08em;
2625
+ padding: 1px 7px;
2626
+ border-radius: 999px;
2627
+ /* Brand-accent chip, not the ink slab. var(--ink) flips to a light cream
2628
+ in dark mode, which made this a glaring white pill; the accent is a
2629
+ saturated mid-tone that's distinct (eye lands on it) and identical in
2630
+ both themes. */
2631
+ background: var(--accent);
2632
+ color: #fff;
2633
+ font-variant-numeric: tabular-nums;
2634
+ }
2635
+ .remote-device-name { min-width: 0; }
2636
+ .remote-device-meta {
2637
+ font-size: 11.5px;
2638
+ color: var(--ink-mid);
2639
+ margin-top: 2px;
2640
+ display: flex;
2641
+ align-items: baseline;
2642
+ flex-wrap: wrap;
2643
+ gap: 4px;
2644
+ }
2645
+ .remote-device-meta .mono { font-family: var(--mono); font-size: 11px; }
2646
+ .remote-device-ua {
2647
+ font-family: var(--mono);
2648
+ font-size: 11px;
2649
+ color: var(--ink-muted);
2650
+ overflow: hidden;
2651
+ text-overflow: ellipsis;
2652
+ max-width: 380px;
2653
+ white-space: nowrap;
2654
+ }
2655
+ .remote-device-actions {
2656
+ display: flex;
2657
+ gap: 6px;
2658
+ flex-shrink: 0;
2659
+ }
2660
+ .remote-device-actions .action.small { padding: 4px 10px; font-size: 11.5px; }
2661
+
2662
+ /* Remote · "How access works" — three fact rows separated by hairlines,
2663
+ inset on the left by a 2px ink bar so the section reads as quiet
2664
+ reference material instead of an alert. */
2665
+ .remote-facts {
2666
+ margin: 0;
2667
+ padding: 0;
2668
+ display: flex;
2669
+ flex-direction: column;
2670
+ }
2671
+ .remote-fact {
2672
+ position: relative;
2673
+ padding: var(--s-3) var(--s-3) var(--s-3) var(--s-5);
2674
+ border-bottom: 1px solid var(--border);
2675
+ }
2676
+ .remote-fact:first-child { padding-top: var(--s-2); }
2677
+ .remote-fact:last-child { border-bottom: 0; padding-bottom: var(--s-2); }
2678
+ .remote-fact::before {
2679
+ content: "";
2680
+ position: absolute;
2681
+ left: 0;
2682
+ top: var(--s-3);
2683
+ bottom: var(--s-3);
2684
+ width: 2px;
2685
+ background: var(--ink);
2686
+ border-radius: 1px;
2687
+ opacity: 0.35;
2688
+ }
2689
+ .remote-fact dt {
2690
+ font-size: 12.5px;
2691
+ font-weight: 600;
2692
+ color: var(--ink);
2693
+ letter-spacing: -0.005em;
2694
+ margin-bottom: 4px;
2695
+ }
2696
+ .remote-fact dd {
2697
+ margin: 0;
2698
+ font-size: 12px;
2699
+ color: var(--ink-mid);
2700
+ line-height: 1.6;
2701
+ }
2702
+ .remote-fact dd code {
2703
+ font-family: var(--mono);
2704
+ font-size: 11px;
2705
+ background: var(--bg);
2706
+ padding: 1px 5px;
2707
+ border-radius: 3px;
2708
+ }
2709
+ .remote-fact dd strong {
2710
+ color: var(--ink);
2711
+ font-weight: 600;
2712
+ }
2713
+ .remote-fact dd em {
2714
+ font-style: italic;
2715
+ color: var(--ink);
2716
+ }
2717
+ .remote-fact-pill {
2718
+ display: inline-block;
2719
+ font-size: 11px;
2720
+ padding: 1px 7px;
2721
+ border-radius: 999px;
2722
+ background: rgba(184, 106, 42, 0.14);
2723
+ color: #8b4f1f;
2724
+ font-weight: 500;
2725
+ }