@bakapiano/ccsm 0.22.6 → 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 (58) 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 +154 -154
  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 +546 -546
  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 -0
  42. package/public/js/components/useDragSort.js +67 -67
  43. package/public/js/dialog.js +67 -67
  44. package/public/js/icons.js +212 -212
  45. package/public/js/main.js +296 -296
  46. package/public/js/pages/AboutPage.js +90 -90
  47. package/public/js/pages/ConfigurePage.js +728 -713
  48. package/public/js/pages/LaunchPage.js +421 -421
  49. package/public/js/pages/RemotePage.js +743 -743
  50. package/public/js/pages/SessionsPage.js +53 -53
  51. package/public/js/state.js +335 -335
  52. package/scripts/dev.js +149 -149
  53. package/scripts/install.js +153 -153
  54. package/scripts/restart-helper.js +96 -96
  55. package/scripts/upgrade-helper.js +687 -687
  56. package/server.js +1820 -1807
  57. package/public/manifest.webmanifest +0 -25
  58. package/public/setup/index.html +0 -567
@@ -1,453 +1,453 @@
1
- /* Buttons (.action variants) · inputs · checkbox · chip pills ·
2
- form-row layout · config grid · repos sub-table */
3
-
4
- .action {
5
- appearance: none;
6
- background: var(--bg-elev);
7
- border: 1px solid var(--border-strong);
8
- color: var(--ink);
9
- padding: 7px 14px;
10
- font-family: var(--body);
11
- font-size: 13px;
12
- font-weight: 500;
13
- letter-spacing: -0.005em;
14
- border-radius: 6px;
15
- cursor: pointer;
16
- transition:
17
- background .14s ease,
18
- border-color .14s ease,
19
- color .14s ease,
20
- box-shadow .14s ease,
21
- transform .14s cubic-bezier(.4, 0, .2, 1);
22
- white-space: nowrap;
23
- box-shadow: var(--shadow-sm);
24
- display: inline-flex;
25
- align-items: center;
26
- justify-content: center;
27
- gap: 6px;
28
- text-decoration: none;
29
- position: relative;
30
- }
31
- .action:hover {
32
- background: var(--bg);
33
- border-color: var(--ink-faint);
34
- box-shadow: 0 2px 4px -2px rgba(26, 24, 21, 0.10);
35
- transform: translateY(-0.5px);
36
- }
37
- .action:active { transform: translateY(0.5px); box-shadow: var(--shadow-sm); }
38
- .action:focus-visible {
39
- outline: none;
40
- box-shadow: 0 0 0 3px rgba(26, 24, 21, 0.10);
41
- border-color: var(--ink);
42
- }
43
- .action:disabled { opacity: .5; cursor: not-allowed; pointer-events: none; }
44
- .action.primary {
45
- background: var(--ink);
46
- border-color: var(--ink);
47
- color: var(--bg-elev);
48
- }
49
- .action.primary:hover {
50
- background: #000;
51
- border-color: #000;
52
- box-shadow: 0 4px 12px -4px rgba(26, 24, 21, 0.35);
53
- }
54
- .action.small { font-size: 12px; padding: 4px 10px; }
55
- .action.tiny { font-size: 11px; padding: 3px 8px; }
56
- .action.subtle {
57
- background: transparent;
58
- border-color: var(--border);
59
- box-shadow: none;
60
- color: var(--ink-mid);
61
- }
62
- .action.subtle:hover { background: var(--bg); color: var(--ink); }
63
- .action.danger {
64
- background: var(--red);
65
- border-color: var(--red);
66
- /* Always light text — the danger red is dark in both themes, so it must
67
- NOT follow --bg-elev (which is a dark surface in dark mode and would
68
- render black text on red). In light mode --bg-elev was #fff anyway,
69
- so this is identical there. */
70
- color: #fff;
71
- }
72
- .action.danger:hover {
73
- background: #9a3636;
74
- border-color: #9a3636;
75
- }
76
-
77
- .input, input[type="text"], input[type="number"], select, textarea {
78
- appearance: none;
79
- /* background-COLOR, not the `background` shorthand — the shorthand resets
80
- background-repeat/position/size to their initial values (repeat / 0% 0%
81
- / auto), and since this rule matches <select> via the higher-specificity
82
- `.input` selector, it was overriding the `select` rule's no-repeat +
83
- positioning. Result: the dropdown arrow SVG tiled across the whole
84
- select as a grid of little triangles. Setting only the color leaves the
85
- select rule's background-* longhands intact. */
86
- background-color: var(--bg-elev);
87
- border: 1px solid var(--border-strong);
88
- color: var(--ink);
89
- padding: 8px 12px;
90
- font-family: var(--body);
91
- font-size: 13px;
92
- border-radius: 6px;
93
- transition: border-color .14s ease, box-shadow .14s ease, background .14s ease;
94
- width: 100%;
95
- max-width: 480px;
96
- }
97
- .input.narrow { min-width: 240px; max-width: 320px; }
98
- .input:focus, input:focus, select:focus, textarea:focus {
99
- outline: none;
100
- border-color: var(--ink);
101
- box-shadow: 0 0 0 3px rgba(26, 24, 21, 0.08);
102
- }
103
- select {
104
- /* A single FILLED triangle, not a 2-stroke chevron. Thin strokes alias
105
- into jagged "teeth" at this ~9px size; a solid shape anti-aliases
106
- cleanly and reads as one arrow rather than a pair of serrations. */
107
- background-image: url("data:image/svg+xml;utf8,<svg viewBox='0 0 10 6' xmlns='http://www.w3.org/2000/svg'><path d='M1 1 L5 5 L9 1 Z' fill='%238a8475'/></svg>");
108
- background-repeat: no-repeat;
109
- background-position: right 10px center;
110
- background-size: 10px;
111
- padding-right: 28px;
112
- }
113
- textarea {
114
- font-family: var(--mono);
115
- font-size: 12px;
116
- resize: vertical;
117
- line-height: 1.55;
118
- }
119
-
120
- /* Segmented control — a row of mutually-exclusive pills sharing one
121
- border (used for the Appearance light/dark/system toggle). */
122
- .seg {
123
- display: inline-flex;
124
- padding: 2px;
125
- gap: 2px;
126
- background: var(--ui-bg);
127
- border: 1px solid var(--border-strong);
128
- border-radius: 8px;
129
- }
130
- .seg-btn {
131
- appearance: none;
132
- background: transparent;
133
- border: 0;
134
- color: var(--ink-mid);
135
- font-family: var(--body);
136
- font-size: 12.5px;
137
- font-weight: 500;
138
- padding: 5px 13px;
139
- border-radius: 6px;
140
- cursor: pointer;
141
- transition: background .14s ease, color .14s ease;
142
- display: inline-flex;
143
- align-items: center;
144
- gap: 6px;
145
- }
146
- .seg-btn svg { width: 14px; height: 14px; opacity: 0.85; }
147
- .seg-btn:hover { color: var(--ink); }
148
- .seg-btn.is-active {
149
- background: var(--bg-elev);
150
- color: var(--ink);
151
- box-shadow: var(--shadow-sm);
152
- }
153
-
154
- input[type="checkbox"] {
155
- appearance: none;
156
- width: 16px;
157
- height: 16px;
158
- flex: 0 0 16px;
159
- border: 1px solid var(--border-strong);
160
- background: var(--bg-elev);
161
- border-radius: 4px;
162
- cursor: pointer;
163
- position: relative;
164
- transition: background .12s, border-color .12s;
165
- }
166
- input[type="checkbox"]:checked {
167
- background: var(--ink);
168
- border-color: var(--ink);
169
- }
170
- input[type="checkbox"]:checked::after {
171
- content: "";
172
- position: absolute;
173
- left: 4px; top: 1px;
174
- width: 5px; height: 9px;
175
- border: solid var(--bg-elev);
176
- border-width: 0 1.5px 1.5px 0;
177
- transform: rotate(45deg);
178
- }
179
-
180
- .form-row {
181
- display: flex;
182
- align-items: center;
183
- gap: var(--s-4);
184
- margin-bottom: var(--s-3);
185
- flex-wrap: wrap;
186
- }
187
- .form-row:last-child { margin-bottom: 0; }
188
- .form-label {
189
- font-family: var(--body);
190
- font-size: 12px;
191
- font-weight: 500;
192
- color: var(--ink-mid);
193
- min-width: 96px;
194
- }
195
- .form-actions {
196
- display: flex;
197
- align-items: center;
198
- gap: var(--s-3);
199
- margin-top: var(--s-4);
200
- }
201
-
202
- /* Radio pills — same visual family as chip but exclusive (radio not checkbox) */
203
- .radio-row {
204
- display: flex;
205
- gap: var(--s-2);
206
- flex-wrap: wrap;
207
- }
208
- .radio {
209
- display: inline-flex;
210
- align-items: center;
211
- gap: 6px;
212
- padding: 5px 12px;
213
- border: 1px solid var(--border-strong);
214
- background: var(--bg-elev);
215
- color: var(--ink-mid);
216
- font-family: var(--body);
217
- font-size: 12.5px;
218
- font-weight: 500;
219
- cursor: pointer;
220
- user-select: none;
221
- transition: all .12s ease;
222
- border-radius: 999px;
223
- }
224
- .radio input { display: none; }
225
- .radio:hover { color: var(--ink); border-color: var(--ink-faint); }
226
- .radio::before {
227
- content: "";
228
- width: 7px;
229
- height: 7px;
230
- border: 1px solid var(--ink-faint);
231
- border-radius: 50%;
232
- background: transparent;
233
- }
234
- .radio.is-checked {
235
- background: var(--bg);
236
- border-color: var(--ink);
237
- color: var(--ink);
238
- }
239
- .radio.is-checked::before {
240
- background: var(--ink);
241
- border-color: var(--ink);
242
- box-shadow: inset 0 0 0 2px var(--bg-elev);
243
- }
244
-
245
- /* Chip-style multi-select used for repo picker etc. */
246
- .chip-row {
247
- display: flex;
248
- flex-wrap: wrap;
249
- gap: var(--s-2);
250
- flex: 1;
251
- }
252
- .chip {
253
- display: inline-flex;
254
- align-items: center;
255
- gap: 6px;
256
- padding: 5px 12px;
257
- border: 1px solid var(--border-strong);
258
- background: var(--bg-elev);
259
- color: var(--ink-mid);
260
- font-family: var(--body);
261
- font-size: 12.5px;
262
- font-weight: 500;
263
- cursor: pointer;
264
- user-select: none;
265
- appearance: none;
266
- transition: all .12s ease;
267
- border-radius: 999px;
268
- }
269
- .chip input { display: none; }
270
- .chip:hover {
271
- color: var(--ink);
272
- border-color: var(--ink-faint);
273
- }
274
- .chip::before {
275
- content: "";
276
- width: 7px;
277
- height: 7px;
278
- border: 1px solid var(--ink-faint);
279
- border-radius: 50%;
280
- background: transparent;
281
- }
282
- .chip.checked {
283
- background: var(--bg);
284
- border-color: var(--ink);
285
- color: var(--ink);
286
- }
287
- .chip.checked::before {
288
- background: var(--ink);
289
- border-color: var(--ink);
290
- box-shadow: inset 0 0 0 2px var(--bg-elev);
291
- }
292
-
293
- /* Two-column field grid used inside the Configure card */
294
- .config-grid {
295
- display: grid;
296
- grid-template-columns: 1fr;
297
- gap: var(--s-5) var(--s-6);
298
- align-items: start;
299
- }
300
- .config-grid .field { display: flex; flex-direction: column; gap: 6px; }
301
- .config-grid .field.full { grid-column: 1 / -1; }
302
- .config-grid .field .label {
303
- font-size: 12px;
304
- font-weight: 500;
305
- color: var(--ink-mid);
306
- }
307
- .config-grid .field .hint {
308
- font-size: 11.5px;
309
- color: var(--ink-muted);
310
- font-style: italic;
311
- }
312
- .config-grid .field .hint.inline {
313
- display: inline;
314
- margin-left: 4px;
315
- font-style: italic;
316
- }
317
- .config-grid .field.toggle {
318
- flex-direction: row;
319
- align-items: flex-start;
320
- gap: var(--s-3);
321
- padding-top: var(--s-4);
322
- }
323
- .config-grid .field.toggle .toggle-text {
324
- display: flex;
325
- flex-direction: column;
326
- gap: 2px;
327
- }
328
- .config-grid .field.toggle .label { font-weight: 500; }
329
-
330
- /* Inline editable repo list (Configure tab) */
331
- .repos-head {
332
- display: flex;
333
- justify-content: space-between;
334
- align-items: center;
335
- margin-bottom: var(--s-2);
336
- }
337
- .repos-table thead th, .repos-table tbody td { padding: 8px var(--s-2); }
338
- .repos-table thead th:first-child,
339
- .repos-table tbody td:first-child { padding-left: var(--s-2); }
340
- .repos-table thead th:last-child,
341
- .repos-table tbody td:last-child { padding-right: var(--s-2); }
342
- .repos-table tbody td input { font-size: 12px; max-width: none; }
343
-
344
- /* Theme accent picker (Configure tab). Pill chips with color dot + name;
345
- active chip fills with its accent color. A "Custom" chip toggles an
346
- inline color picker + hex input + reset. */
347
- .accent-picker {
348
- display: flex;
349
- flex-direction: column;
350
- gap: var(--s-3);
351
- }
352
- .accent-chips {
353
- display: flex;
354
- flex-wrap: wrap;
355
- gap: 6px;
356
- }
357
- .accent-chip {
358
- appearance: none;
359
- display: inline-flex;
360
- align-items: center;
361
- gap: 6px;
362
- padding: 5px 11px 5px 9px;
363
- border: 1px solid var(--border);
364
- border-radius: 999px;
365
- background: var(--bg-elev);
366
- color: var(--ink-mid);
367
- font-size: 12px;
368
- font-weight: 500;
369
- letter-spacing: -0.005em;
370
- line-height: 1;
371
- cursor: pointer;
372
- transition: background .12s ease, color .12s ease,
373
- border-color .12s ease, transform .12s ease,
374
- box-shadow .12s ease;
375
- }
376
- .accent-chip:hover {
377
- color: var(--ink);
378
- border-color: var(--ink-faint);
379
- transform: translateY(-1px);
380
- }
381
- .accent-chip-dot {
382
- width: 10px;
383
- height: 10px;
384
- border-radius: 999px;
385
- background: var(--c, var(--ink-faint));
386
- box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.08);
387
- flex: none;
388
- }
389
- .accent-chip-plus {
390
- display: inline-flex;
391
- align-items: center;
392
- justify-content: center;
393
- width: 10px;
394
- height: 10px;
395
- color: var(--ink-mid);
396
- font-size: 14px;
397
- line-height: 1;
398
- }
399
- .accent-chip.is-active {
400
- background: var(--c);
401
- border-color: var(--c);
402
- color: #fff;
403
- box-shadow: 0 1px 0 rgba(0, 0, 0, 0.05);
404
- }
405
- .accent-chip.is-active .accent-chip-dot {
406
- background: rgba(255, 255, 255, 0.85);
407
- box-shadow: none;
408
- }
409
- .accent-chip-custom {
410
- border-style: dashed;
411
- }
412
- .accent-chip-custom.is-open:not(.is-active) {
413
- border-style: solid;
414
- color: var(--ink);
415
- border-color: var(--ink-faint);
416
- }
417
-
418
- .accent-custom {
419
- display: flex;
420
- align-items: center;
421
- gap: var(--s-2);
422
- padding-top: 2px;
423
- }
424
- .accent-custom input[type="color"] {
425
- width: 32px;
426
- height: 28px;
427
- padding: 0;
428
- border: 1px solid var(--border);
429
- border-radius: var(--r-sm);
430
- background: var(--bg-elev);
431
- cursor: pointer;
432
- }
433
- .accent-hex {
434
- font-family: var(--mono);
435
- font-size: 12px;
436
- width: 96px;
437
- padding: 4px 8px;
438
- border: 1px solid var(--border);
439
- border-radius: var(--r-sm);
440
- background: var(--bg-elev);
441
- }
442
- .accent-reset {
443
- appearance: none;
444
- background: transparent;
445
- border: 0;
446
- padding: 4px 6px;
447
- font-size: 12px;
448
- color: var(--ink-faint);
449
- cursor: pointer;
450
- border-radius: 6px;
451
- transition: color .12s ease, background .12s ease;
452
- }
453
- .accent-reset:hover { color: var(--ink-mid); background: var(--bg); }
1
+ /* Buttons (.action variants) · inputs · checkbox · chip pills ·
2
+ form-row layout · config grid · repos sub-table */
3
+
4
+ .action {
5
+ appearance: none;
6
+ background: var(--bg-elev);
7
+ border: 1px solid var(--border-strong);
8
+ color: var(--ink);
9
+ padding: 7px 14px;
10
+ font-family: var(--body);
11
+ font-size: 13px;
12
+ font-weight: 500;
13
+ letter-spacing: -0.005em;
14
+ border-radius: 6px;
15
+ cursor: pointer;
16
+ transition:
17
+ background .14s ease,
18
+ border-color .14s ease,
19
+ color .14s ease,
20
+ box-shadow .14s ease,
21
+ transform .14s cubic-bezier(.4, 0, .2, 1);
22
+ white-space: nowrap;
23
+ box-shadow: var(--shadow-sm);
24
+ display: inline-flex;
25
+ align-items: center;
26
+ justify-content: center;
27
+ gap: 6px;
28
+ text-decoration: none;
29
+ position: relative;
30
+ }
31
+ .action:hover {
32
+ background: var(--bg);
33
+ border-color: var(--ink-faint);
34
+ box-shadow: 0 2px 4px -2px rgba(26, 24, 21, 0.10);
35
+ transform: translateY(-0.5px);
36
+ }
37
+ .action:active { transform: translateY(0.5px); box-shadow: var(--shadow-sm); }
38
+ .action:focus-visible {
39
+ outline: none;
40
+ box-shadow: 0 0 0 3px rgba(26, 24, 21, 0.10);
41
+ border-color: var(--ink);
42
+ }
43
+ .action:disabled { opacity: .5; cursor: not-allowed; pointer-events: none; }
44
+ .action.primary {
45
+ background: var(--ink);
46
+ border-color: var(--ink);
47
+ color: var(--bg-elev);
48
+ }
49
+ .action.primary:hover {
50
+ background: #000;
51
+ border-color: #000;
52
+ box-shadow: 0 4px 12px -4px rgba(26, 24, 21, 0.35);
53
+ }
54
+ .action.small { font-size: 12px; padding: 4px 10px; }
55
+ .action.tiny { font-size: 11px; padding: 3px 8px; }
56
+ .action.subtle {
57
+ background: transparent;
58
+ border-color: var(--border);
59
+ box-shadow: none;
60
+ color: var(--ink-mid);
61
+ }
62
+ .action.subtle:hover { background: var(--bg); color: var(--ink); }
63
+ .action.danger {
64
+ background: var(--red);
65
+ border-color: var(--red);
66
+ /* Always light text — the danger red is dark in both themes, so it must
67
+ NOT follow --bg-elev (which is a dark surface in dark mode and would
68
+ render black text on red). In light mode --bg-elev was #fff anyway,
69
+ so this is identical there. */
70
+ color: #fff;
71
+ }
72
+ .action.danger:hover {
73
+ background: #9a3636;
74
+ border-color: #9a3636;
75
+ }
76
+
77
+ .input, input[type="text"], input[type="number"], select, textarea {
78
+ appearance: none;
79
+ /* background-COLOR, not the `background` shorthand — the shorthand resets
80
+ background-repeat/position/size to their initial values (repeat / 0% 0%
81
+ / auto), and since this rule matches <select> via the higher-specificity
82
+ `.input` selector, it was overriding the `select` rule's no-repeat +
83
+ positioning. Result: the dropdown arrow SVG tiled across the whole
84
+ select as a grid of little triangles. Setting only the color leaves the
85
+ select rule's background-* longhands intact. */
86
+ background-color: var(--bg-elev);
87
+ border: 1px solid var(--border-strong);
88
+ color: var(--ink);
89
+ padding: 8px 12px;
90
+ font-family: var(--body);
91
+ font-size: 13px;
92
+ border-radius: 6px;
93
+ transition: border-color .14s ease, box-shadow .14s ease, background .14s ease;
94
+ width: 100%;
95
+ max-width: 480px;
96
+ }
97
+ .input.narrow { min-width: 240px; max-width: 320px; }
98
+ .input:focus, input:focus, select:focus, textarea:focus {
99
+ outline: none;
100
+ border-color: var(--ink);
101
+ box-shadow: 0 0 0 3px rgba(26, 24, 21, 0.08);
102
+ }
103
+ select {
104
+ /* A single FILLED triangle, not a 2-stroke chevron. Thin strokes alias
105
+ into jagged "teeth" at this ~9px size; a solid shape anti-aliases
106
+ cleanly and reads as one arrow rather than a pair of serrations. */
107
+ background-image: url("data:image/svg+xml;utf8,<svg viewBox='0 0 10 6' xmlns='http://www.w3.org/2000/svg'><path d='M1 1 L5 5 L9 1 Z' fill='%238a8475'/></svg>");
108
+ background-repeat: no-repeat;
109
+ background-position: right 10px center;
110
+ background-size: 10px;
111
+ padding-right: 28px;
112
+ }
113
+ textarea {
114
+ font-family: var(--mono);
115
+ font-size: 12px;
116
+ resize: vertical;
117
+ line-height: 1.55;
118
+ }
119
+
120
+ /* Segmented control — a row of mutually-exclusive pills sharing one
121
+ border (used for the Appearance light/dark/system toggle). */
122
+ .seg {
123
+ display: inline-flex;
124
+ padding: 2px;
125
+ gap: 2px;
126
+ background: var(--ui-bg);
127
+ border: 1px solid var(--border-strong);
128
+ border-radius: 8px;
129
+ }
130
+ .seg-btn {
131
+ appearance: none;
132
+ background: transparent;
133
+ border: 0;
134
+ color: var(--ink-mid);
135
+ font-family: var(--body);
136
+ font-size: 12.5px;
137
+ font-weight: 500;
138
+ padding: 5px 13px;
139
+ border-radius: 6px;
140
+ cursor: pointer;
141
+ transition: background .14s ease, color .14s ease;
142
+ display: inline-flex;
143
+ align-items: center;
144
+ gap: 6px;
145
+ }
146
+ .seg-btn svg { width: 14px; height: 14px; opacity: 0.85; }
147
+ .seg-btn:hover { color: var(--ink); }
148
+ .seg-btn.is-active {
149
+ background: var(--bg-elev);
150
+ color: var(--ink);
151
+ box-shadow: var(--shadow-sm);
152
+ }
153
+
154
+ input[type="checkbox"] {
155
+ appearance: none;
156
+ width: 16px;
157
+ height: 16px;
158
+ flex: 0 0 16px;
159
+ border: 1px solid var(--border-strong);
160
+ background: var(--bg-elev);
161
+ border-radius: 4px;
162
+ cursor: pointer;
163
+ position: relative;
164
+ transition: background .12s, border-color .12s;
165
+ }
166
+ input[type="checkbox"]:checked {
167
+ background: var(--ink);
168
+ border-color: var(--ink);
169
+ }
170
+ input[type="checkbox"]:checked::after {
171
+ content: "";
172
+ position: absolute;
173
+ left: 4px; top: 1px;
174
+ width: 5px; height: 9px;
175
+ border: solid var(--bg-elev);
176
+ border-width: 0 1.5px 1.5px 0;
177
+ transform: rotate(45deg);
178
+ }
179
+
180
+ .form-row {
181
+ display: flex;
182
+ align-items: center;
183
+ gap: var(--s-4);
184
+ margin-bottom: var(--s-3);
185
+ flex-wrap: wrap;
186
+ }
187
+ .form-row:last-child { margin-bottom: 0; }
188
+ .form-label {
189
+ font-family: var(--body);
190
+ font-size: 12px;
191
+ font-weight: 500;
192
+ color: var(--ink-mid);
193
+ min-width: 96px;
194
+ }
195
+ .form-actions {
196
+ display: flex;
197
+ align-items: center;
198
+ gap: var(--s-3);
199
+ margin-top: var(--s-4);
200
+ }
201
+
202
+ /* Radio pills — same visual family as chip but exclusive (radio not checkbox) */
203
+ .radio-row {
204
+ display: flex;
205
+ gap: var(--s-2);
206
+ flex-wrap: wrap;
207
+ }
208
+ .radio {
209
+ display: inline-flex;
210
+ align-items: center;
211
+ gap: 6px;
212
+ padding: 5px 12px;
213
+ border: 1px solid var(--border-strong);
214
+ background: var(--bg-elev);
215
+ color: var(--ink-mid);
216
+ font-family: var(--body);
217
+ font-size: 12.5px;
218
+ font-weight: 500;
219
+ cursor: pointer;
220
+ user-select: none;
221
+ transition: all .12s ease;
222
+ border-radius: 999px;
223
+ }
224
+ .radio input { display: none; }
225
+ .radio:hover { color: var(--ink); border-color: var(--ink-faint); }
226
+ .radio::before {
227
+ content: "";
228
+ width: 7px;
229
+ height: 7px;
230
+ border: 1px solid var(--ink-faint);
231
+ border-radius: 50%;
232
+ background: transparent;
233
+ }
234
+ .radio.is-checked {
235
+ background: var(--bg);
236
+ border-color: var(--ink);
237
+ color: var(--ink);
238
+ }
239
+ .radio.is-checked::before {
240
+ background: var(--ink);
241
+ border-color: var(--ink);
242
+ box-shadow: inset 0 0 0 2px var(--bg-elev);
243
+ }
244
+
245
+ /* Chip-style multi-select used for repo picker etc. */
246
+ .chip-row {
247
+ display: flex;
248
+ flex-wrap: wrap;
249
+ gap: var(--s-2);
250
+ flex: 1;
251
+ }
252
+ .chip {
253
+ display: inline-flex;
254
+ align-items: center;
255
+ gap: 6px;
256
+ padding: 5px 12px;
257
+ border: 1px solid var(--border-strong);
258
+ background: var(--bg-elev);
259
+ color: var(--ink-mid);
260
+ font-family: var(--body);
261
+ font-size: 12.5px;
262
+ font-weight: 500;
263
+ cursor: pointer;
264
+ user-select: none;
265
+ appearance: none;
266
+ transition: all .12s ease;
267
+ border-radius: 999px;
268
+ }
269
+ .chip input { display: none; }
270
+ .chip:hover {
271
+ color: var(--ink);
272
+ border-color: var(--ink-faint);
273
+ }
274
+ .chip::before {
275
+ content: "";
276
+ width: 7px;
277
+ height: 7px;
278
+ border: 1px solid var(--ink-faint);
279
+ border-radius: 50%;
280
+ background: transparent;
281
+ }
282
+ .chip.checked {
283
+ background: var(--bg);
284
+ border-color: var(--ink);
285
+ color: var(--ink);
286
+ }
287
+ .chip.checked::before {
288
+ background: var(--ink);
289
+ border-color: var(--ink);
290
+ box-shadow: inset 0 0 0 2px var(--bg-elev);
291
+ }
292
+
293
+ /* Two-column field grid used inside the Configure card */
294
+ .config-grid {
295
+ display: grid;
296
+ grid-template-columns: 1fr;
297
+ gap: var(--s-5) var(--s-6);
298
+ align-items: start;
299
+ }
300
+ .config-grid .field { display: flex; flex-direction: column; gap: 6px; }
301
+ .config-grid .field.full { grid-column: 1 / -1; }
302
+ .config-grid .field .label {
303
+ font-size: 12px;
304
+ font-weight: 500;
305
+ color: var(--ink-mid);
306
+ }
307
+ .config-grid .field .hint {
308
+ font-size: 11.5px;
309
+ color: var(--ink-muted);
310
+ font-style: italic;
311
+ }
312
+ .config-grid .field .hint.inline {
313
+ display: inline;
314
+ margin-left: 4px;
315
+ font-style: italic;
316
+ }
317
+ .config-grid .field.toggle {
318
+ flex-direction: row;
319
+ align-items: flex-start;
320
+ gap: var(--s-3);
321
+ padding-top: var(--s-4);
322
+ }
323
+ .config-grid .field.toggle .toggle-text {
324
+ display: flex;
325
+ flex-direction: column;
326
+ gap: 2px;
327
+ }
328
+ .config-grid .field.toggle .label { font-weight: 500; }
329
+
330
+ /* Inline editable repo list (Configure tab) */
331
+ .repos-head {
332
+ display: flex;
333
+ justify-content: space-between;
334
+ align-items: center;
335
+ margin-bottom: var(--s-2);
336
+ }
337
+ .repos-table thead th, .repos-table tbody td { padding: 8px var(--s-2); }
338
+ .repos-table thead th:first-child,
339
+ .repos-table tbody td:first-child { padding-left: var(--s-2); }
340
+ .repos-table thead th:last-child,
341
+ .repos-table tbody td:last-child { padding-right: var(--s-2); }
342
+ .repos-table tbody td input { font-size: 12px; max-width: none; }
343
+
344
+ /* Theme accent picker (Configure tab). Pill chips with color dot + name;
345
+ active chip fills with its accent color. A "Custom" chip toggles an
346
+ inline color picker + hex input + reset. */
347
+ .accent-picker {
348
+ display: flex;
349
+ flex-direction: column;
350
+ gap: var(--s-3);
351
+ }
352
+ .accent-chips {
353
+ display: flex;
354
+ flex-wrap: wrap;
355
+ gap: 6px;
356
+ }
357
+ .accent-chip {
358
+ appearance: none;
359
+ display: inline-flex;
360
+ align-items: center;
361
+ gap: 6px;
362
+ padding: 5px 11px 5px 9px;
363
+ border: 1px solid var(--border);
364
+ border-radius: 999px;
365
+ background: var(--bg-elev);
366
+ color: var(--ink-mid);
367
+ font-size: 12px;
368
+ font-weight: 500;
369
+ letter-spacing: -0.005em;
370
+ line-height: 1;
371
+ cursor: pointer;
372
+ transition: background .12s ease, color .12s ease,
373
+ border-color .12s ease, transform .12s ease,
374
+ box-shadow .12s ease;
375
+ }
376
+ .accent-chip:hover {
377
+ color: var(--ink);
378
+ border-color: var(--ink-faint);
379
+ transform: translateY(-1px);
380
+ }
381
+ .accent-chip-dot {
382
+ width: 10px;
383
+ height: 10px;
384
+ border-radius: 999px;
385
+ background: var(--c, var(--ink-faint));
386
+ box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.08);
387
+ flex: none;
388
+ }
389
+ .accent-chip-plus {
390
+ display: inline-flex;
391
+ align-items: center;
392
+ justify-content: center;
393
+ width: 10px;
394
+ height: 10px;
395
+ color: var(--ink-mid);
396
+ font-size: 14px;
397
+ line-height: 1;
398
+ }
399
+ .accent-chip.is-active {
400
+ background: var(--c);
401
+ border-color: var(--c);
402
+ color: #fff;
403
+ box-shadow: 0 1px 0 rgba(0, 0, 0, 0.05);
404
+ }
405
+ .accent-chip.is-active .accent-chip-dot {
406
+ background: rgba(255, 255, 255, 0.85);
407
+ box-shadow: none;
408
+ }
409
+ .accent-chip-custom {
410
+ border-style: dashed;
411
+ }
412
+ .accent-chip-custom.is-open:not(.is-active) {
413
+ border-style: solid;
414
+ color: var(--ink);
415
+ border-color: var(--ink-faint);
416
+ }
417
+
418
+ .accent-custom {
419
+ display: flex;
420
+ align-items: center;
421
+ gap: var(--s-2);
422
+ padding-top: 2px;
423
+ }
424
+ .accent-custom input[type="color"] {
425
+ width: 32px;
426
+ height: 28px;
427
+ padding: 0;
428
+ border: 1px solid var(--border);
429
+ border-radius: var(--r-sm);
430
+ background: var(--bg-elev);
431
+ cursor: pointer;
432
+ }
433
+ .accent-hex {
434
+ font-family: var(--mono);
435
+ font-size: 12px;
436
+ width: 96px;
437
+ padding: 4px 8px;
438
+ border: 1px solid var(--border);
439
+ border-radius: var(--r-sm);
440
+ background: var(--bg-elev);
441
+ }
442
+ .accent-reset {
443
+ appearance: none;
444
+ background: transparent;
445
+ border: 0;
446
+ padding: 4px 6px;
447
+ font-size: 12px;
448
+ color: var(--ink-faint);
449
+ cursor: pointer;
450
+ border-radius: 6px;
451
+ transition: color .12s ease, background .12s ease;
452
+ }
453
+ .accent-reset:hover { color: var(--ink-mid); background: var(--bg); }