@bakapiano/ccsm 0.4.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/public/styles.css CHANGED
@@ -1,136 +1,1639 @@
1
+ /* ─────────────────────────────────────────────────────────────
2
+ ccsm · light cream theme · sidebar nav · v0.6
3
+ ───────────────────────────────────────────────────────────── */
4
+
1
5
  :root {
2
- --bg: #0e1116;
3
- --bg-elev: #161b22;
4
- --bg-elev2: #1c2230;
5
- --border: #2a3240;
6
- --text: #e6edf3;
7
- --text-dim: #8b95a4;
8
- --accent: #c97f5d; /* warm Claude orange */
9
- --primary: #4f8df9;
10
- --success: #3fb950;
11
- --warn: #d29922;
12
- --danger: #f85149;
13
- --row-hover: #1f2530;
14
- --mono: ui-monospace, "Cascadia Mono", "JetBrains Mono", "Fira Code", Consolas, monospace;
15
- }
16
-
17
- * { box-sizing: border-box; }
18
- html, body { margin: 0; padding: 0; background: var(--bg); color: var(--text); font: 14px/1.5 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; }
19
- code, pre, .mono { font-family: var(--mono); font-size: 12.5px; }
20
- a { color: var(--primary); }
21
-
22
- .topbar {
23
- position: sticky; top: 0; z-index: 10;
24
- display: flex; align-items: center; justify-content: space-between;
25
- padding: 10px 18px;
6
+ /* Surfaces — cream with neutral whites */
7
+ --bg: #faf9f5;
8
+ --bg-elev: #ffffff;
9
+ --sidebar-bg: #f3f0e8;
10
+ --sidebar-hover: #ebe7db;
11
+ --sidebar-active: #e3ddca;
12
+
13
+ /* Borders & rules */
14
+ --border: #e8e3d5;
15
+ --border-soft: #ece8da;
16
+ --border-strong: #d4cdb8;
17
+
18
+ /* Ink */
19
+ --ink: #1a1815;
20
+ --ink-mid: #534e44;
21
+ --ink-muted: #8a8475;
22
+ --ink-faint: #b5af9d;
23
+
24
+ /* Accent Claude warm orange/copper */
25
+ --accent: #c45f3f;
26
+ --accent-deep: #a14d33;
27
+ --accent-soft: rgba(196, 95, 63, 0.10);
28
+ --accent-softer: rgba(196, 95, 63, 0.04);
29
+
30
+ /* Status */
31
+ --green: #4a8a4a;
32
+ --yellow: #c4892b;
33
+ --red: #b73f3f;
34
+ --blue: #4a73a5;
35
+
36
+ /* Type */
37
+ --body: "Geist", -apple-system, "Segoe UI", system-ui, sans-serif;
38
+ --mono: "JetBrains Mono", "Cascadia Mono", "Consolas", monospace;
39
+
40
+ /* Scale */
41
+ --s-1: 4px; --s-2: 8px; --s-3: 12px; --s-4: 16px;
42
+ --s-5: 20px; --s-6: 24px; --s-8: 32px; --s-10: 40px;
43
+ --s-12: 48px; --s-16: 64px;
44
+
45
+ /* Radius */
46
+ --r-sm: 6px;
47
+ --r: 8px;
48
+ --r-md: 10px;
49
+ --r-lg: 14px;
50
+
51
+ /* Shadow — soft, like print on cream */
52
+ --shadow-sm: 0 1px 0 rgba(26, 24, 21, 0.04);
53
+ --shadow: 0 1px 2px rgba(26, 24, 21, 0.04),
54
+ 0 1px 0 rgba(26, 24, 21, 0.03);
55
+ --shadow-md: 0 4px 12px -2px rgba(26, 24, 21, 0.08),
56
+ 0 1px 0 rgba(26, 24, 21, 0.04);
57
+
58
+ /* Sidebar geometry */
59
+ --sidebar-w: 232px;
60
+ --sidebar-w-collapsed: 60px;
61
+ }
62
+
63
+ * { box-sizing: border-box; margin: 0; padding: 0; }
64
+ [hidden] { display: none !important; }
65
+
66
+ html, body {
67
+ background: var(--bg);
68
+ color: var(--ink);
69
+ font-family: var(--body);
70
+ font-size: 14px;
71
+ line-height: 1.5;
72
+ font-variant-numeric: tabular-nums;
73
+ min-height: 100vh;
74
+ -webkit-font-smoothing: antialiased;
75
+ -moz-osx-font-smoothing: grayscale;
76
+ }
77
+
78
+ ::selection { background: var(--accent); color: var(--bg-elev); }
79
+
80
+ /* ─────────────────────────────────────────────────────────────
81
+ App layout
82
+ ───────────────────────────────────────────────────────────── */
83
+
84
+ .app {
85
+ display: grid;
86
+ grid-template-columns: var(--sidebar-w) 1fr;
87
+ min-height: 100vh;
88
+ transition: grid-template-columns .25s cubic-bezier(.4, 0, .2, 1);
89
+ }
90
+ .app:has(.sidebar[data-collapsed="true"]) {
91
+ grid-template-columns: var(--sidebar-w-collapsed) 1fr;
92
+ }
93
+
94
+ /* ─────────────────────────────────────────────────────────────
95
+ Sidebar
96
+ ───────────────────────────────────────────────────────────── */
97
+
98
+ .sidebar {
99
+ position: sticky;
100
+ top: 0;
101
+ height: 100vh;
102
+ background: var(--sidebar-bg);
103
+ border-right: 1px solid var(--border);
104
+ display: flex;
105
+ flex-direction: column;
106
+ padding: var(--s-4) var(--s-3);
107
+ overflow: hidden;
108
+ transition: padding .25s cubic-bezier(.4, 0, .2, 1);
109
+ }
110
+ .sidebar[data-collapsed="true"] {
111
+ padding: var(--s-4) var(--s-2);
112
+ }
113
+
114
+ .sidebar-brand {
115
+ display: flex;
116
+ align-items: center;
117
+ gap: var(--s-2);
118
+ padding: var(--s-2) var(--s-2) var(--s-4);
119
+ height: 56px;
120
+ }
121
+ .brand-mark {
122
+ display: inline-flex;
123
+ align-items: center;
124
+ justify-content: center;
125
+ width: 32px;
126
+ height: 32px;
127
+ flex: 0 0 32px;
128
+ background: transparent; /* SVG draws its own terminal window */
129
+ }
130
+ .brand-mark svg { display: block; }
131
+ .brand-name {
132
+ font-size: 19px;
133
+ font-weight: 600;
134
+ letter-spacing: -0.02em;
135
+ color: var(--ink);
136
+ white-space: nowrap;
137
+ opacity: 1;
138
+ transition: opacity .15s ease;
139
+ }
140
+ .brand-dot { color: var(--accent); }
141
+ .sidebar[data-collapsed="true"] .brand-name { opacity: 0; pointer-events: none; }
142
+
143
+ .sidebar-nav {
144
+ display: flex;
145
+ flex-direction: column;
146
+ gap: 2px;
147
+ flex: 0 0 auto;
148
+ }
149
+
150
+ .nav-item, .util-item {
151
+ appearance: none;
152
+ background: transparent;
153
+ border: 0;
154
+ display: flex;
155
+ align-items: center;
156
+ gap: var(--s-3);
157
+ width: 100%;
158
+ padding: 0 10px;
159
+ min-height: 36px; /* uniform across nav + util items */
160
+ border-radius: var(--r-sm);
161
+ cursor: pointer;
162
+ color: var(--ink-mid);
163
+ font-family: var(--body);
164
+ font-size: 13.5px;
165
+ font-weight: 500;
166
+ text-align: left;
167
+ transition: background .12s ease, color .12s ease;
168
+ position: relative;
169
+ }
170
+ .nav-item:hover, .util-item:hover {
171
+ background: var(--sidebar-hover);
172
+ color: var(--ink);
173
+ }
174
+ .nav-item[aria-selected="true"] {
175
+ background: var(--bg-elev);
176
+ color: var(--ink);
177
+ box-shadow: var(--shadow-sm);
178
+ }
179
+ .nav-item[aria-selected="true"]::before {
180
+ content: "";
181
+ position: absolute;
182
+ left: -4px;
183
+ top: 8px;
184
+ bottom: 8px;
185
+ width: 3px;
186
+ background: var(--accent);
187
+ border-radius: 2px;
188
+ }
189
+
190
+ /* "Has unsaved changes" indicator — small accent dot next to the label */
191
+ .nav-item.has-changes::after {
192
+ content: "";
193
+ position: absolute;
194
+ right: 10px;
195
+ top: 50%;
196
+ transform: translateY(-50%);
197
+ width: 7px;
198
+ height: 7px;
199
+ border-radius: 50%;
200
+ background: var(--accent);
201
+ box-shadow: 0 0 0 0 rgba(196, 95, 63, 0.45);
202
+ animation: dirty-pulse 2s ease-in-out infinite;
203
+ }
204
+ @keyframes dirty-pulse {
205
+ 0%, 100% { box-shadow: 0 0 0 0 rgba(196, 95, 63, 0.45); }
206
+ 50% { box-shadow: 0 0 0 5px rgba(196, 95, 63, 0); }
207
+ }
208
+ .sidebar[data-collapsed="true"] .nav-item.has-changes::after {
209
+ right: auto;
210
+ top: 6px;
211
+ left: 28px;
212
+ }
213
+ .nav-icon {
214
+ display: inline-flex;
215
+ width: 18px;
216
+ height: 18px;
217
+ flex: 0 0 18px;
218
+ color: currentColor;
219
+ }
220
+ .nav-label {
221
+ white-space: nowrap;
222
+ opacity: 1;
223
+ transition: opacity .15s ease;
224
+ flex: 1;
225
+ }
226
+ .sidebar[data-collapsed="true"] .nav-label { opacity: 0; pointer-events: none; }
227
+
228
+ .nav-badge {
229
+ font-family: var(--mono);
230
+ font-size: 10.5px;
231
+ background: var(--border-soft);
232
+ color: var(--ink-muted);
233
+ padding: 1px 6px;
234
+ border-radius: 4px;
235
+ font-variant-numeric: tabular-nums;
236
+ opacity: 1;
237
+ transition: opacity .15s ease;
238
+ }
239
+ .sidebar[data-collapsed="true"] .nav-badge { opacity: 0; }
240
+ .nav-item[aria-selected="true"] .nav-badge {
241
+ background: var(--accent-soft);
242
+ color: var(--accent);
243
+ }
244
+
245
+ .sidebar-divider {
246
+ margin: var(--s-3) var(--s-2);
247
+ border-top: 1px solid var(--border);
248
+ }
249
+
250
+ .sidebar-utility {
251
+ display: flex;
252
+ flex-direction: column;
253
+ gap: 2px;
254
+ }
255
+ .util-accent {
256
+ color: var(--accent);
257
+ }
258
+ .util-accent:hover {
259
+ background: var(--accent-soft);
260
+ color: var(--accent);
261
+ }
262
+
263
+ .sidebar-foot {
264
+ margin-top: auto;
265
+ padding: var(--s-2);
266
+ display: flex;
267
+ justify-content: flex-end;
268
+ }
269
+
270
+ .collapse-toggle {
271
+ appearance: none;
272
+ background: transparent;
273
+ border: 1px solid var(--border);
274
+ color: var(--ink-muted);
275
+ width: 26px;
276
+ height: 26px;
277
+ border-radius: var(--r-sm);
278
+ display: inline-flex;
279
+ align-items: center;
280
+ justify-content: center;
281
+ cursor: pointer;
282
+ transition: background .12s ease, color .12s ease, transform .25s cubic-bezier(.4, 0, .2, 1), border-color .12s;
283
+ }
284
+ .collapse-toggle:hover {
26
285
  background: var(--bg-elev);
286
+ color: var(--ink);
287
+ border-color: var(--border-strong);
288
+ }
289
+ .sidebar[data-collapsed="true"] .collapse-toggle {
290
+ transform: rotate(180deg);
291
+ }
292
+ .sidebar[data-collapsed="true"] .sidebar-foot {
293
+ justify-content: center;
294
+ }
295
+
296
+ /* ─────────────────────────────────────────────────────────────
297
+ Main column
298
+ ───────────────────────────────────────────────────────────── */
299
+
300
+ .main {
301
+ display: flex;
302
+ flex-direction: column;
303
+ min-width: 0;
304
+ padding: var(--s-8) var(--s-10) var(--s-6);
305
+ gap: var(--s-6);
306
+ }
307
+
308
+ .page-head {
309
+ display: flex;
310
+ align-items: flex-start;
311
+ justify-content: space-between;
312
+ gap: var(--s-8);
313
+ padding-bottom: var(--s-5);
27
314
  border-bottom: 1px solid var(--border);
28
315
  }
29
- .brand { display: flex; align-items: baseline; gap: 10px; font-weight: 600; font-size: 16px; }
30
- .brand .logo { color: var(--accent); font-size: 18px; }
31
- .brand small { color: var(--text-dim); font-weight: 400; font-size: 11px; }
32
- .topbar-actions { display: flex; gap: 8px; align-items: center; }
33
- .toggle { display: flex; align-items: center; gap: 5px; color: var(--text-dim); font-size: 12px; cursor: pointer; user-select: none; }
316
+ .page-head-inner { min-width: 0; }
34
317
 
35
- main { max-width: 1400px; margin: 16px auto; padding: 0 18px; display: grid; gap: 14px; }
318
+ .page-title {
319
+ font-size: 26px;
320
+ font-weight: 600;
321
+ letter-spacing: -0.024em;
322
+ color: var(--ink);
323
+ line-height: 1.1;
324
+ }
325
+ .page-subtitle {
326
+ margin-top: 4px;
327
+ font-size: 13.5px;
328
+ color: var(--ink-mid);
329
+ }
36
330
 
37
- .panel { background: var(--bg-elev); border: 1px solid var(--border); border-radius: 8px; overflow: hidden; }
38
- .panel-header { display: flex; align-items: baseline; gap: 12px; padding: 10px 14px; border-bottom: 1px solid var(--border); background: var(--bg-elev2); }
39
- .panel-header h2 { margin: 0; font-size: 13px; font-weight: 600; letter-spacing: .04em; text-transform: uppercase; color: var(--text-dim); }
40
- .panel-body { padding: 12px 14px; border-bottom: 1px solid var(--border); }
41
- .panel-body:last-child { border-bottom: 0; }
331
+ .page-head-meta {
332
+ display: flex;
333
+ align-items: baseline;
334
+ gap: var(--s-3);
335
+ flex-shrink: 0;
336
+ white-space: nowrap;
337
+ font-family: var(--mono);
338
+ font-size: 11px;
339
+ color: var(--ink-muted);
340
+ }
341
+ .ph-stat { display: inline-flex; gap: 6px; align-items: baseline; }
342
+ .ph-key {
343
+ font-family: var(--body);
344
+ font-size: 10.5px;
345
+ letter-spacing: 0.06em;
346
+ text-transform: uppercase;
347
+ color: var(--ink-faint);
348
+ }
349
+ .ph-val { color: var(--ink-mid); }
350
+ .ph-divider { color: var(--ink-faint); }
42
351
 
43
- .muted { color: var(--text-dim); }
44
- .small { font-size: 12px; }
352
+ /* Server status pill — "● online v0.5.0" / "● offline" */
353
+ .server-status {
354
+ display: inline-flex;
355
+ align-items: center;
356
+ gap: 6px;
357
+ padding: 2px 9px 2px 7px;
358
+ border-radius: 999px;
359
+ background: var(--bg);
360
+ border: 1px solid var(--border);
361
+ font-family: var(--mono);
362
+ font-size: 10.5px;
363
+ letter-spacing: 0.02em;
364
+ color: var(--ink-mid);
365
+ transition: background .15s ease, border-color .15s ease, color .15s ease;
366
+ cursor: default;
367
+ }
368
+ .server-status .status-pulse {
369
+ width: 6px;
370
+ height: 6px;
371
+ border-radius: 50%;
372
+ background: var(--ink-faint);
373
+ flex: 0 0 6px;
374
+ position: relative;
375
+ }
376
+ .server-status[data-state="online"] {
377
+ border-color: rgba(74, 138, 74, 0.35);
378
+ background: rgba(74, 138, 74, 0.06);
379
+ color: var(--green);
380
+ }
381
+ .server-status[data-state="online"] .status-pulse {
382
+ background: var(--green);
383
+ animation: server-pulse 2.2s ease-in-out infinite;
384
+ }
385
+ .server-status[data-state="offline"] {
386
+ border-color: rgba(183, 63, 63, 0.4);
387
+ background: rgba(183, 63, 63, 0.06);
388
+ color: var(--red);
389
+ }
390
+ .server-status[data-state="offline"] .status-pulse {
391
+ background: var(--red);
392
+ }
393
+ .server-status[data-state="connecting"] {
394
+ border-color: rgba(196, 137, 43, 0.4);
395
+ background: rgba(196, 137, 43, 0.06);
396
+ color: var(--yellow);
397
+ }
398
+ .server-status[data-state="connecting"] .status-pulse {
399
+ background: var(--yellow);
400
+ animation: server-pulse 1s ease-in-out infinite;
401
+ }
402
+ @keyframes server-pulse {
403
+ 0%, 100% { box-shadow: 0 0 0 0 currentColor; }
404
+ 50% { box-shadow: 0 0 0 4px transparent; }
405
+ }
45
406
 
46
- .row { display: flex; align-items: center; }
47
- .row.gap { gap: 8px; flex-wrap: wrap; }
407
+ .content {
408
+ flex: 1;
409
+ display: flex;
410
+ flex-direction: column;
411
+ }
48
412
 
49
- .btn {
50
- background: var(--bg-elev2); color: var(--text);
51
- border: 1px solid var(--border); border-radius: 6px;
52
- padding: 6px 12px; cursor: pointer; font-size: 13px;
53
- transition: background .12s, border-color .12s;
413
+ .tab-panel {
414
+ display: none;
415
+ flex-direction: column;
416
+ gap: var(--s-6);
417
+ }
418
+ .tab-panel[data-active] {
419
+ display: flex;
420
+ animation: panel-in .35s cubic-bezier(.4, 0, .2, 1);
421
+ }
422
+ @keyframes panel-in {
423
+ from { opacity: 0; transform: translateY(6px); }
424
+ to { opacity: 1; transform: translateY(0); }
425
+ }
426
+
427
+ /* ─────────────────────────────────────────────────────────────
428
+ Cards
429
+ ───────────────────────────────────────────────────────────── */
430
+
431
+ .card {
432
+ background: var(--bg-elev);
433
+ border: 1px solid var(--border);
434
+ border-radius: var(--r-md);
435
+ overflow: hidden;
436
+ box-shadow: var(--shadow);
437
+ }
438
+
439
+ .card-head {
440
+ padding: var(--s-4) var(--s-6) var(--s-3);
441
+ border-bottom: 1px solid var(--border-soft);
442
+ display: flex;
443
+ justify-content: flex-start;
444
+ align-items: center;
445
+ gap: var(--s-3);
446
+ }
447
+ /* Make the whole header clickable to fold (only when card is foldable) */
448
+ .card[data-fold-key] .card-head {
449
+ cursor: pointer;
450
+ user-select: none;
451
+ transition: background .12s ease;
452
+ }
453
+ .card[data-fold-key] .card-head:hover {
454
+ background: var(--bg);
455
+ }
456
+ .card[data-collapsed] .card-head { border-bottom-color: transparent; }
457
+ .card-titles { flex: 1; min-width: 0; }
458
+
459
+ /* Fold toggle button in card head */
460
+ .card-fold {
461
+ appearance: none;
462
+ background: transparent;
463
+ border: 0;
464
+ padding: 4px;
465
+ margin: 0;
466
+ cursor: pointer;
467
+ color: var(--ink-muted);
468
+ display: inline-flex;
469
+ align-items: center;
470
+ justify-content: center;
471
+ border-radius: 4px;
472
+ transition: color .12s ease, background .12s ease, transform .25s cubic-bezier(.4, 0, .2, 1);
473
+ line-height: 0;
474
+ flex: 0 0 auto;
475
+ }
476
+ .card-fold:hover {
477
+ color: var(--ink);
478
+ background: var(--bg);
479
+ }
480
+ .card[data-collapsed] .card-fold {
481
+ transform: rotate(-90deg);
482
+ }
483
+ .card[data-collapsed] .card-body {
484
+ display: none;
485
+ }
486
+ .card-titles { min-width: 0; }
487
+ .card-title {
488
+ font-size: 15.5px;
489
+ font-weight: 600;
490
+ letter-spacing: -0.012em;
491
+ color: var(--ink);
492
+ }
493
+ .card-meta {
494
+ margin-top: 2px;
495
+ font-size: 12.5px;
496
+ color: var(--ink-muted);
497
+ font-family: var(--body);
498
+ }
499
+ .card-meta code {
500
+ font-family: var(--mono);
501
+ font-size: 11.5px;
502
+ color: var(--ink-mid);
503
+ background: var(--bg);
504
+ padding: 1px 5px;
505
+ border-radius: 4px;
506
+ border: 1px solid var(--border-soft);
507
+ }
508
+
509
+ .card-body { padding: var(--s-5) var(--s-6); }
510
+ .card-body-flush { padding: 0; }
511
+
512
+ /* ─────────────────────────────────────────────────────────────
513
+ Page-level inline actions (above the cards on a tab)
514
+ ───────────────────────────────────────────────────────────── */
515
+
516
+ /* CTA banner — visually distinct from the data cards: subtle accent tint,
517
+ no card shadow, dashed-ish bottom rule, no rounded corners as heavy.
518
+ Reads as "tip / shortcut" rather than another data section. */
519
+ .page-actions {
520
+ display: flex;
521
+ align-items: center;
522
+ justify-content: space-between;
523
+ gap: var(--s-4);
524
+ padding: var(--s-3) var(--s-5);
525
+ background: linear-gradient(180deg, rgba(196,95,63,0.06), rgba(196,95,63,0.02));
526
+ border: 1px solid rgba(196,95,63,0.18);
527
+ border-radius: var(--r-sm);
528
+ box-shadow: none;
529
+ position: relative;
530
+ }
531
+ .page-actions::before {
532
+ content: "";
533
+ position: absolute;
534
+ left: 0; top: 8px; bottom: 8px;
535
+ width: 2px;
536
+ background: var(--accent);
537
+ border-radius: 0 2px 2px 0;
538
+ }
539
+ .page-actions-hint {
540
+ font-size: 13px;
541
+ color: var(--accent-deep);
542
+ font-weight: 500;
543
+ padding-left: var(--s-2);
544
+ }
545
+ .page-actions .action svg { stroke-width: 2; }
546
+
547
+ /* ─────────────────────────────────────────────────────────────
548
+ Data table
549
+ ───────────────────────────────────────────────────────────── */
550
+
551
+ .table-scroll {
552
+ overflow-x: auto;
553
+ /* tactile: scroll-padding so the actions column edges aren't flush against
554
+ the viewport when you scroll right to reach the buttons */
555
+ scroll-padding-right: var(--s-6);
556
+ }
557
+ .table-scroll::-webkit-scrollbar { height: 8px; }
558
+ .table-scroll .data {
559
+ min-width: 960px;
560
+ table-layout: auto;
561
+ }
562
+
563
+ .data {
564
+ width: 100%;
565
+ border-collapse: collapse;
566
+ font-family: var(--body);
567
+ font-size: 13.5px;
568
+ }
569
+
570
+ .data thead th {
571
+ padding: 10px var(--s-5) 10px;
572
+ text-align: left;
573
+ font-family: var(--body);
574
+ font-size: 11px;
575
+ font-weight: 600;
576
+ letter-spacing: 0.04em;
577
+ color: var(--ink-muted);
578
+ border-bottom: 1px solid var(--border);
579
+ background: var(--bg);
580
+ vertical-align: bottom;
581
+ white-space: nowrap;
582
+ }
583
+ .data thead th.num { text-align: right; }
584
+ /* shrink-to-fit pattern: width:1% with nowrap → the cell only takes the
585
+ space its content needs, the title / path cells get the remainder */
586
+ .data thead th.col-mark { width: 28px; padding-left: 0; padding-right: 0; }
587
+ .data thead th.col-star { width: 28px; padding-left: 0; padding-right: 0; }
588
+ .data thead th.col-actions { width: 1%; white-space: nowrap; }
589
+ .data thead th.num { width: 1%; white-space: nowrap; }
590
+ .data tbody td.num { white-space: nowrap; }
591
+ .data tbody td:last-child { white-space: nowrap; }
592
+ .data thead th:first-child { padding-left: var(--s-6); }
593
+ .data thead th:last-child { padding-right: var(--s-6); }
594
+
595
+ /* ── Sticky actions column ──
596
+ The last column (Focus/Resume/Continue buttons) stays pinned to the
597
+ right edge of the .table-scroll container while horizontal scroll happens
598
+ underneath. Backgrounds must be solid because sticky cells overlay the
599
+ content scrolling beneath them. */
600
+ .data thead th:last-child,
601
+ .data tbody td:last-child {
602
+ position: sticky;
603
+ right: 0;
604
+ z-index: 1;
605
+ /* fade the seam into the cell so it doesn't look like a hard cut */
606
+ box-shadow: -10px 0 10px -8px rgba(26, 24, 21, 0.08);
607
+ }
608
+ .data thead th:last-child {
609
+ background: var(--bg); /* matches thead bg */
610
+ }
611
+ .data tbody td:last-child {
612
+ background: var(--bg-elev); /* matches card bg */
613
+ }
614
+ .data tbody tr:hover td:last-child {
615
+ background: var(--bg); /* match row hover */
616
+ }
617
+
618
+ .data tbody tr {
619
+ border-bottom: 1px solid var(--border-soft);
620
+ transition: background .12s ease;
621
+ }
622
+ .data tbody tr:last-child { border-bottom: 0; }
623
+ .data tbody tr:hover { background: var(--bg); }
624
+
625
+ .data tbody td {
626
+ padding: 12px var(--s-5);
627
+ vertical-align: middle;
628
+ color: var(--ink);
629
+ }
630
+ .data tbody td:first-child { padding-left: var(--s-6); }
631
+ .data tbody td:last-child { padding-right: var(--s-6); }
632
+ .data tbody td.num {
633
+ text-align: right;
634
+ font-family: var(--mono);
635
+ font-size: 11.5px;
636
+ color: var(--ink-mid);
637
+ }
638
+
639
+ /* Row entry animation: plays once on first render of each tbody. JS adds
640
+ .no-anim after that initial render so subsequent re-renders (auto-refresh
641
+ every 5s) don't restage and flicker. */
642
+ .data tbody:not(.no-anim) tr {
643
+ animation: row-in .3s ease-out backwards;
644
+ }
645
+ .data tbody:not(.no-anim) tr:nth-child(1) { animation-delay: 0ms; }
646
+ .data tbody:not(.no-anim) tr:nth-child(2) { animation-delay: 20ms; }
647
+ .data tbody:not(.no-anim) tr:nth-child(3) { animation-delay: 40ms; }
648
+ .data tbody:not(.no-anim) tr:nth-child(4) { animation-delay: 60ms; }
649
+ .data tbody:not(.no-anim) tr:nth-child(5) { animation-delay: 80ms; }
650
+ .data tbody:not(.no-anim) tr:nth-child(6) { animation-delay: 100ms; }
651
+ .data tbody:not(.no-anim) tr:nth-child(7) { animation-delay: 120ms; }
652
+ .data tbody:not(.no-anim) tr:nth-child(8) { animation-delay: 140ms; }
653
+ .data tbody:not(.no-anim) tr:nth-child(n+9) { animation-delay: 160ms; }
654
+ @keyframes row-in {
655
+ from { opacity: 0; transform: translateY(3px); }
656
+ to { opacity: 1; transform: translateY(0); }
657
+ }
658
+
659
+ /* Status indicator — small dot, claude-like */
660
+ .status-mark {
661
+ display: inline-block;
662
+ width: 8px;
663
+ height: 8px;
664
+ border-radius: 50%;
665
+ background: currentColor;
666
+ vertical-align: middle;
667
+ position: relative;
668
+ }
669
+ .status-mark.busy {
670
+ color: var(--yellow);
671
+ box-shadow: 0 0 0 0 currentColor;
672
+ animation: pulse 1.5s ease-in-out infinite;
673
+ }
674
+ .status-mark.idle { color: var(--green); }
675
+ .status-mark.unknown { color: var(--ink-faint); }
676
+ @keyframes pulse {
677
+ 0% {
678
+ box-shadow: 0 0 0 0 rgba(196, 137, 43, 0.4);
679
+ }
680
+ 70% {
681
+ box-shadow: 0 0 0 7px rgba(196, 137, 43, 0);
682
+ }
683
+ 100% {
684
+ box-shadow: 0 0 0 0 rgba(196, 137, 43, 0);
685
+ }
686
+ }
687
+
688
+ /* Composite cells — title and path are fixed-width with overflow ellipsis
689
+ on the inner spans, so the actions column is always visible without
690
+ horizontal scroll at typical viewport widths. Long titles / paths
691
+ truncate with ellipsis (hover shows full value via title attribute). */
692
+ .title-cell {
693
+ width: 300px;
694
+ max-width: 300px;
695
+ min-width: 0;
696
+ }
697
+ .title-cell .title-row {
698
+ display: flex;
699
+ align-items: center;
700
+ gap: 6px;
701
+ min-width: 0;
702
+ width: 100%;
703
+ }
704
+ .title-cell .primary {
705
+ color: var(--ink);
706
+ font-weight: 500;
707
+ white-space: nowrap;
708
+ overflow: hidden;
709
+ text-overflow: ellipsis;
710
+ font-size: 13.5px;
711
+ min-width: 0;
712
+ flex: 0 1 auto;
713
+ }
714
+ .title-cell .secondary {
715
+ font-family: var(--mono);
716
+ font-size: 10.5px;
717
+ color: var(--ink-muted);
718
+ letter-spacing: 0.02em;
719
+ margin-top: 2px;
720
+ white-space: nowrap;
721
+ overflow: hidden;
722
+ text-overflow: ellipsis;
723
+ }
724
+
725
+ .path-cell {
726
+ font-family: var(--mono);
727
+ font-size: 11.5px;
728
+ color: var(--ink-mid);
729
+ width: 260px;
730
+ max-width: 260px;
731
+ min-width: 0;
732
+ white-space: nowrap;
733
+ overflow: hidden;
734
+ text-overflow: ellipsis;
735
+ }
736
+
737
+ .branch-tag {
738
+ display: inline-block;
739
+ font-family: var(--mono);
740
+ font-size: 11px;
741
+ color: var(--ink-mid);
742
+ background: var(--bg);
743
+ padding: 2px 7px;
744
+ border-radius: 4px;
745
+ border: 1px solid var(--border-soft);
746
+ }
747
+
748
+ .row-actions {
749
+ display: flex;
750
+ gap: var(--s-2);
751
+ justify-content: flex-end;
752
+ }
753
+
754
+ /* Star button (favorite toggle) — sits inline next to the title text.
755
+ Outline by default, brightens on hover, fills with the accent color
756
+ when starred. */
757
+ .star-btn {
758
+ appearance: none;
759
+ background: transparent;
760
+ border: 0;
761
+ padding: 2px;
762
+ margin: 0;
763
+ cursor: pointer;
764
+ color: var(--ink-muted);
765
+ display: inline-flex;
766
+ align-items: center;
767
+ justify-content: center;
768
+ border-radius: 4px;
769
+ transition: color .12s ease, background .12s ease, transform .15s ease;
770
+ line-height: 0;
771
+ flex: 0 0 auto;
772
+ }
773
+ .data tbody tr:hover .star-btn {
774
+ color: var(--ink-mid);
775
+ }
776
+ .star-btn:hover {
777
+ color: var(--accent) !important;
778
+ background: var(--accent-softer);
779
+ }
780
+ .star-btn:active { transform: scale(0.88); }
781
+ .star-btn.is-fav {
782
+ color: var(--accent);
783
+ }
784
+ .star-btn svg { display: block; }
785
+
786
+ /* Rename (pencil) button — inline next to title, only visible on row hover
787
+ so it doesn't compete with the star or distract from the title. When a
788
+ label exists (`has-label`), it stays subtly visible so the user knows
789
+ the title is overridden. */
790
+ .rename-btn {
791
+ appearance: none;
792
+ background: transparent;
793
+ border: 0;
794
+ padding: 2px;
795
+ margin: 0;
796
+ cursor: pointer;
797
+ color: var(--ink-faint);
798
+ opacity: 0;
799
+ display: inline-flex;
800
+ align-items: center;
801
+ justify-content: center;
802
+ border-radius: 4px;
803
+ transition: opacity .12s ease, color .12s ease, background .12s ease, transform .15s ease;
804
+ line-height: 0;
805
+ flex: 0 0 auto;
806
+ }
807
+ .data tbody tr:hover .rename-btn {
808
+ opacity: 1;
809
+ color: var(--ink-muted);
810
+ }
811
+ .rename-btn:hover {
812
+ color: var(--accent) !important;
813
+ background: var(--accent-softer);
814
+ }
815
+ .rename-btn:active { transform: scale(0.88); }
816
+ .rename-btn.has-label {
817
+ opacity: 0.8;
818
+ color: var(--accent);
819
+ }
820
+ .rename-btn svg { display: block; }
821
+
822
+ /* Title with icon glyph */
823
+ .card-title .title-icon {
824
+ color: var(--accent);
825
+ margin-right: 6px;
826
+ vertical-align: -2px;
827
+ }
828
+ .card-title .title-icon-after {
829
+ margin-right: 0;
830
+ margin-left: 6px;
831
+ vertical-align: -1px;
54
832
  }
55
- .btn:hover { background: #232b3a; border-color: #3a455a; }
56
- .btn:active { transform: translateY(1px); }
57
- .btn:disabled { opacity: .5; cursor: not-allowed; }
58
- .btn.small { padding: 3px 8px; font-size: 12px; }
59
- .btn-primary { background: var(--primary); border-color: var(--primary); color: white; }
60
- .btn-primary:hover { background: #6ba1ff; border-color: #6ba1ff; }
61
- .btn-accent { background: var(--accent); border-color: var(--accent); color: white; }
62
- .btn-accent:hover { background: #d99372; border-color: #d99372; }
63
- .btn-danger { background: transparent; border-color: var(--danger); color: var(--danger); }
64
- .btn-danger:hover { background: rgba(248,81,73,.1); }
65
-
66
- .select, input[type=text], input[type=number], textarea {
67
- background: var(--bg); color: var(--text);
68
- border: 1px solid var(--border); border-radius: 6px;
69
- padding: 5px 8px; font-size: 13px; font-family: inherit;
70
- }
71
- input[type=number] { width: 100px; }
72
- textarea { width: 100%; font-family: var(--mono); }
73
-
74
- .data-table { width: 100%; border-collapse: collapse; }
75
- .data-table th, .data-table td { padding: 7px 12px; text-align: left; font-size: 13px; }
76
- .data-table thead th { font-size: 11px; font-weight: 600; color: var(--text-dim); letter-spacing: .04em; text-transform: uppercase; border-bottom: 1px solid var(--border); background: var(--bg-elev2); position: sticky; top: 0; }
77
- .data-table tbody tr { border-bottom: 1px solid var(--border); }
78
- .data-table tbody tr:hover { background: var(--row-hover); }
79
- .data-table tbody tr:last-child { border-bottom: 0; }
80
- .data-table td { vertical-align: top; }
81
- .data-table .ellipsis { max-width: 380px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
82
- .data-table .mono { color: var(--text-dim); }
83
- .table-wrap { overflow-x: auto; }
84
-
85
- .status-dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; vertical-align: middle; }
86
- .status-dot.busy { background: var(--warn); box-shadow: 0 0 8px rgba(210,153,34,.65); animation: pulse 1.2s ease-in-out infinite; }
87
- .status-dot.idle { background: var(--success); }
88
- .status-dot.unknown { background: var(--text-dim); }
89
-
90
- @keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: .35; } }
91
-
92
- .preview { background: var(--bg); border: 1px solid var(--border); border-radius: 6px; padding: 8px; max-height: 280px; overflow: auto; white-space: pre; }
93
-
94
- .grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 10px 14px; align-items: start; }
95
- .grid-2 label { display: flex; flex-direction: column; gap: 4px; font-size: 12px; color: var(--text-dim); }
96
- .grid-2 label.full { grid-column: 1 / -1; }
97
- .grid-2 input, .grid-2 textarea { color: var(--text); font-size: 13px; }
98
-
99
- .workspace-list { display: flex; flex-direction: column; gap: 6px; }
100
- .workspace-card { padding: 8px 10px; border: 1px solid var(--border); border-radius: 6px; background: var(--bg-elev2); display: flex; justify-content: space-between; align-items: center; gap: 12px; }
101
- .workspace-card.in-use { border-color: rgba(210,153,34,.45); }
102
- .workspace-card .name { font-weight: 600; }
103
- .workspace-card .repos { font-family: var(--mono); font-size: 12px; color: var(--text-dim); }
104
- .tag { display: inline-block; padding: 1px 6px; border-radius: 4px; font-size: 11px; background: var(--bg); border: 1px solid var(--border); color: var(--text-dim); }
105
- .tag.warn { color: var(--warn); border-color: rgba(210,153,34,.4); }
106
- .tag.ok { color: var(--success); border-color: rgba(63,185,80,.4); }
107
-
108
- .repo-chip {
109
- display: flex; align-items: center; gap: 6px;
833
+
834
+ /* Favorites empty state — sits inside the card body (not generic table empty) */
835
+ #favoritesEmpty {
836
+ padding: var(--s-6) var(--s-6);
837
+ text-align: center;
838
+ font-size: 12.5px;
839
+ color: var(--ink-muted);
840
+ }
841
+
842
+ .empty {
843
+ padding: var(--s-12) var(--s-6);
844
+ text-align: center;
845
+ font-size: 13px;
846
+ color: var(--ink-muted);
847
+ }
848
+ .empty code {
849
+ font-family: var(--mono);
850
+ font-size: 12px;
851
+ color: var(--ink-mid);
852
+ background: var(--bg);
853
+ padding: 1px 5px;
854
+ border-radius: 4px;
855
+ }
856
+
857
+ /* ─────────────────────────────────────────────────────────────
858
+ Buttons & form
859
+ ───────────────────────────────────────────────────────────── */
860
+
861
+ .action {
862
+ appearance: none;
863
+ background: var(--bg-elev);
864
+ border: 1px solid var(--border-strong);
865
+ color: var(--ink);
866
+ padding: 7px 14px;
867
+ font-family: var(--body);
868
+ font-size: 13px;
869
+ font-weight: 500;
870
+ letter-spacing: -0.005em;
871
+ border-radius: var(--r-sm);
872
+ cursor: pointer;
873
+ transition: background .12s ease, border-color .12s ease, color .12s ease, box-shadow .12s ease;
874
+ white-space: nowrap;
875
+ box-shadow: var(--shadow-sm);
876
+ }
877
+ .action:hover {
878
+ background: var(--bg);
879
+ border-color: var(--ink-faint);
880
+ }
881
+ .action:active { transform: translateY(0.5px); }
882
+ .action:disabled { opacity: .5; cursor: not-allowed; pointer-events: none; }
883
+ .action.primary {
884
+ background: var(--accent);
885
+ border-color: var(--accent);
886
+ color: var(--bg-elev);
887
+ }
888
+ .action.primary:hover {
889
+ background: var(--accent-deep);
890
+ border-color: var(--accent-deep);
891
+ }
892
+ .action.small {
893
+ font-size: 12px;
110
894
  padding: 4px 10px;
111
- border: 1px solid var(--border); border-radius: 999px;
112
- background: var(--bg-elev2);
113
- cursor: pointer; user-select: none;
114
- }
115
- .repo-chip input { margin: 0; }
116
- .repo-chip.checked { border-color: var(--primary); background: rgba(79,141,249,.12); }
117
-
118
- .toast { position: fixed; bottom: 18px; right: 18px; z-index: 100; padding: 10px 14px; background: var(--bg-elev2); border: 1px solid var(--border); border-radius: 6px; box-shadow: 0 4px 18px rgba(0,0,0,.4); opacity: 0; transform: translateY(8px); transition: opacity .18s, transform .18s; pointer-events: none; max-width: 420px; }
119
- .toast.show { opacity: 1; transform: translateY(0); }
120
- .toast.error { border-color: var(--danger); }
121
- .toast.ok { border-color: var(--success); }
122
-
123
- .progress-list { margin-top: 10px; display: flex; flex-direction: column; gap: 8px; }
124
- .progress-item { background: var(--bg); border: 1px solid var(--border); border-radius: 6px; padding: 8px 10px; }
125
- .progress-item .head { display: flex; justify-content: space-between; align-items: center; font-size: 12px; }
126
- .progress-item .head .name { font-weight: 600; color: var(--text); }
127
- .progress-item .head .phase { color: var(--text-dim); font-family: var(--mono); }
128
- .progress-item .head .pct { color: var(--text-dim); font-family: var(--mono); }
129
- .progress-bar { margin-top: 6px; height: 6px; border-radius: 3px; background: var(--bg-elev2); overflow: hidden; position: relative; }
130
- .progress-bar > .fill { height: 100%; background: var(--primary); transition: width .15s; width: 0; }
131
- .progress-bar > .fill.indeterminate { width: 30% !important; animation: indeterm 1.4s ease-in-out infinite; background: linear-gradient(90deg, transparent, var(--primary), transparent); }
132
- .progress-item.ok .fill { background: var(--success); }
133
- .progress-item.error .fill { background: var(--danger); }
134
- .progress-item .detail { margin-top: 4px; font-size: 11px; color: var(--text-dim); font-family: var(--mono); min-height: 14px; }
135
-
136
- @keyframes indeterm { 0% { transform: translateX(-100%); } 100% { transform: translateX(400%); } }
895
+ }
896
+ .action.tiny {
897
+ font-size: 11px;
898
+ padding: 3px 8px;
899
+ }
900
+ .action.subtle {
901
+ background: transparent;
902
+ border-color: var(--border);
903
+ box-shadow: none;
904
+ color: var(--ink-mid);
905
+ }
906
+ .action.subtle:hover { background: var(--bg); color: var(--ink); }
907
+ .action.danger {
908
+ color: var(--red);
909
+ border-color: var(--border);
910
+ }
911
+ .action.danger:hover {
912
+ background: rgba(183, 63, 63, 0.06);
913
+ border-color: var(--red);
914
+ }
915
+
916
+ .input, input[type="text"], input[type="number"], select, textarea {
917
+ appearance: none;
918
+ background: var(--bg-elev);
919
+ border: 1px solid var(--border-strong);
920
+ color: var(--ink);
921
+ padding: 7px 12px;
922
+ font-family: var(--body);
923
+ font-size: 13px;
924
+ border-radius: var(--r-sm);
925
+ transition: border-color .12s ease, box-shadow .12s ease;
926
+ width: 100%;
927
+ max-width: 480px;
928
+ }
929
+ .input.narrow { min-width: 240px; max-width: 320px; }
930
+ .input:focus, input:focus, select:focus, textarea:focus {
931
+ outline: none;
932
+ border-color: var(--accent);
933
+ box-shadow: 0 0 0 3px var(--accent-soft);
934
+ }
935
+ select {
936
+ background-image: url("data:image/svg+xml;utf8,<svg viewBox='0 0 12 8' xmlns='http://www.w3.org/2000/svg' fill='none' stroke='%238a8475' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'><polyline points='1,1 6,7 11,1'/></svg>");
937
+ background-repeat: no-repeat;
938
+ background-position: right 10px center;
939
+ background-size: 10px;
940
+ padding-right: 28px;
941
+ }
942
+ textarea {
943
+ font-family: var(--mono);
944
+ font-size: 12px;
945
+ resize: vertical;
946
+ line-height: 1.55;
947
+ }
948
+ input[type="checkbox"] {
949
+ appearance: none;
950
+ width: 16px;
951
+ height: 16px;
952
+ flex: 0 0 16px;
953
+ border: 1px solid var(--border-strong);
954
+ background: var(--bg-elev);
955
+ border-radius: 4px;
956
+ cursor: pointer;
957
+ position: relative;
958
+ transition: background .12s, border-color .12s;
959
+ }
960
+ input[type="checkbox"]:checked {
961
+ background: var(--accent);
962
+ border-color: var(--accent);
963
+ }
964
+ input[type="checkbox"]:checked::after {
965
+ content: "";
966
+ position: absolute;
967
+ left: 4px; top: 1px;
968
+ width: 5px; height: 9px;
969
+ border: solid var(--bg-elev);
970
+ border-width: 0 1.5px 1.5px 0;
971
+ transform: rotate(45deg);
972
+ }
973
+
974
+ /* Form layout */
975
+ .form-row {
976
+ display: flex;
977
+ align-items: center;
978
+ gap: var(--s-4);
979
+ margin-bottom: var(--s-3);
980
+ flex-wrap: wrap;
981
+ }
982
+ .form-row:last-child { margin-bottom: 0; }
983
+ .form-label {
984
+ font-family: var(--body);
985
+ font-size: 12px;
986
+ font-weight: 500;
987
+ color: var(--ink-mid);
988
+ min-width: 96px;
989
+ }
990
+ .row { display: flex; align-items: center; }
991
+ .gap-row { gap: var(--s-3); flex-wrap: wrap; }
992
+ .divider-dot { color: var(--ink-faint); padding: 0 var(--s-1); }
993
+
994
+ .post-result {
995
+ margin-top: var(--s-3);
996
+ font-family: var(--mono);
997
+ font-size: 11.5px;
998
+ color: var(--ink-muted);
999
+ }
1000
+ .muted-text {
1001
+ color: var(--ink-muted);
1002
+ font-size: 12.5px;
1003
+ }
1004
+ .muted-text strong { color: var(--ink-mid); font-weight: 600; }
1005
+
1006
+ /* Chips */
1007
+ .chip-row {
1008
+ display: flex;
1009
+ flex-wrap: wrap;
1010
+ gap: var(--s-2);
1011
+ flex: 1;
1012
+ }
1013
+ .chip {
1014
+ display: inline-flex;
1015
+ align-items: center;
1016
+ gap: 6px;
1017
+ padding: 5px 12px;
1018
+ border: 1px solid var(--border-strong);
1019
+ background: var(--bg-elev);
1020
+ color: var(--ink-mid);
1021
+ font-family: var(--body);
1022
+ font-size: 12.5px;
1023
+ font-weight: 500;
1024
+ cursor: pointer;
1025
+ user-select: none;
1026
+ transition: all .12s ease;
1027
+ border-radius: 999px;
1028
+ }
1029
+ .chip input { display: none; }
1030
+ .chip:hover {
1031
+ color: var(--ink);
1032
+ border-color: var(--ink-faint);
1033
+ }
1034
+ .chip::before {
1035
+ content: "";
1036
+ width: 7px;
1037
+ height: 7px;
1038
+ border: 1px solid var(--ink-faint);
1039
+ border-radius: 50%;
1040
+ background: transparent;
1041
+ }
1042
+ .chip.checked {
1043
+ background: var(--accent-soft);
1044
+ border-color: var(--accent);
1045
+ color: var(--accent-deep);
1046
+ }
1047
+ .chip.checked::before {
1048
+ background: var(--accent);
1049
+ border-color: var(--accent);
1050
+ box-shadow: inset 0 0 0 2px var(--accent-soft);
1051
+ }
1052
+
1053
+ /* ─────────────────────────────────────────────────────────────
1054
+ Workspace cards
1055
+ ───────────────────────────────────────────────────────────── */
1056
+
1057
+ .workspace-grid {
1058
+ display: grid;
1059
+ grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
1060
+ gap: var(--s-3);
1061
+ }
1062
+ .workspace-card {
1063
+ padding: var(--s-4);
1064
+ border: 1px solid var(--border);
1065
+ background: var(--bg-elev);
1066
+ border-radius: var(--r-md);
1067
+ transition: border-color .12s, box-shadow .12s;
1068
+ }
1069
+ .workspace-card:hover {
1070
+ border-color: var(--border-strong);
1071
+ box-shadow: var(--shadow);
1072
+ }
1073
+ .workspace-card.in-use {
1074
+ background: linear-gradient(180deg, rgba(196, 137, 43, 0.05), var(--bg-elev));
1075
+ border-color: rgba(196, 137, 43, 0.35);
1076
+ }
1077
+ .workspace-card .ws-head {
1078
+ display: flex;
1079
+ align-items: baseline;
1080
+ justify-content: space-between;
1081
+ gap: var(--s-2);
1082
+ margin-bottom: 4px;
1083
+ }
1084
+ .workspace-card .ws-name {
1085
+ font-size: 14.5px;
1086
+ font-weight: 600;
1087
+ letter-spacing: -0.01em;
1088
+ color: var(--ink);
1089
+ }
1090
+ .workspace-card .ws-tag {
1091
+ font-family: var(--mono);
1092
+ font-size: 10px;
1093
+ text-transform: uppercase;
1094
+ letter-spacing: 0.08em;
1095
+ padding: 2px 7px;
1096
+ border-radius: 4px;
1097
+ background: var(--bg);
1098
+ color: var(--ink-muted);
1099
+ border: 1px solid var(--border-soft);
1100
+ }
1101
+ .workspace-card.in-use .ws-tag {
1102
+ background: rgba(196, 137, 43, 0.10);
1103
+ color: var(--yellow);
1104
+ border-color: rgba(196, 137, 43, 0.3);
1105
+ }
1106
+ .workspace-card .ws-path {
1107
+ font-family: var(--mono);
1108
+ font-size: 11px;
1109
+ color: var(--ink-muted);
1110
+ word-break: break-all;
1111
+ margin-bottom: var(--s-3);
1112
+ }
1113
+ .workspace-card .ws-repos {
1114
+ display: flex;
1115
+ flex-wrap: wrap;
1116
+ gap: 4px;
1117
+ }
1118
+ .workspace-card .ws-repo {
1119
+ font-family: var(--mono);
1120
+ font-size: 10.5px;
1121
+ padding: 2px 7px;
1122
+ border-radius: 4px;
1123
+ background: var(--bg);
1124
+ color: var(--ink-muted);
1125
+ border: 1px solid var(--border-soft);
1126
+ }
1127
+ .workspace-card .ws-repo.cloned {
1128
+ color: var(--green);
1129
+ background: rgba(74, 138, 74, 0.06);
1130
+ border-color: rgba(74, 138, 74, 0.25);
1131
+ }
1132
+
1133
+ /* ─────────────────────────────────────────────────────────────
1134
+ Config grid
1135
+ ───────────────────────────────────────────────────────────── */
1136
+
1137
+ .config-grid {
1138
+ display: grid;
1139
+ grid-template-columns: 1fr 1fr;
1140
+ gap: var(--s-5) var(--s-6);
1141
+ align-items: start;
1142
+ }
1143
+ .config-grid .field { display: flex; flex-direction: column; gap: 6px; }
1144
+ .config-grid .field.full { grid-column: 1 / -1; }
1145
+ .config-grid .field .label {
1146
+ font-size: 12px;
1147
+ font-weight: 500;
1148
+ color: var(--ink-mid);
1149
+ }
1150
+ .config-grid .field .hint {
1151
+ font-size: 11.5px;
1152
+ color: var(--ink-muted);
1153
+ font-style: italic;
1154
+ }
1155
+ .config-grid .field .hint.inline {
1156
+ display: inline;
1157
+ margin-left: 4px;
1158
+ font-style: italic;
1159
+ }
1160
+ .config-grid .field.toggle {
1161
+ flex-direction: row;
1162
+ align-items: flex-start;
1163
+ gap: var(--s-3);
1164
+ padding-top: var(--s-4);
1165
+ }
1166
+ .config-grid .field.toggle .toggle-text {
1167
+ display: flex;
1168
+ flex-direction: column;
1169
+ gap: 2px;
1170
+ }
1171
+ .config-grid .field.toggle .label { font-weight: 500; }
1172
+
1173
+ .repos-head {
1174
+ display: flex;
1175
+ justify-content: space-between;
1176
+ align-items: center;
1177
+ margin-bottom: var(--s-2);
1178
+ }
1179
+ .repos-table thead th, .repos-table tbody td {
1180
+ padding: 8px var(--s-2);
1181
+ }
1182
+ .repos-table thead th:first-child,
1183
+ .repos-table tbody td:first-child { padding-left: var(--s-2); }
1184
+ .repos-table thead th:last-child,
1185
+ .repos-table tbody td:last-child { padding-right: var(--s-2); }
1186
+ .repos-table tbody td input { font-size: 12px; max-width: none; }
1187
+
1188
+ .form-actions {
1189
+ display: flex;
1190
+ align-items: center;
1191
+ gap: var(--s-3);
1192
+ margin-top: var(--s-4);
1193
+ }
1194
+
1195
+ /* ─────────────────────────────────────────────────────────────
1196
+ Progress list
1197
+ ───────────────────────────────────────────────────────────── */
1198
+
1199
+ .progress-list {
1200
+ display: flex;
1201
+ flex-direction: column;
1202
+ gap: var(--s-2);
1203
+ margin-top: var(--s-3);
1204
+ }
1205
+ .progress-list:empty { display: none; }
1206
+
1207
+ .progress-item {
1208
+ border: 1px solid var(--border);
1209
+ background: var(--bg);
1210
+ border-radius: var(--r-sm);
1211
+ padding: var(--s-3) var(--s-4);
1212
+ }
1213
+ .progress-item .head {
1214
+ display: grid;
1215
+ grid-template-columns: 1fr auto auto;
1216
+ align-items: baseline;
1217
+ gap: var(--s-3);
1218
+ margin-bottom: var(--s-2);
1219
+ }
1220
+ .progress-item .name {
1221
+ font-family: var(--body);
1222
+ font-size: 12.5px;
1223
+ font-weight: 600;
1224
+ color: var(--ink);
1225
+ }
1226
+ .progress-item .phase {
1227
+ font-family: var(--mono);
1228
+ font-size: 10.5px;
1229
+ color: var(--ink-muted);
1230
+ letter-spacing: 0.04em;
1231
+ }
1232
+ .progress-item .pct {
1233
+ font-family: var(--mono);
1234
+ font-size: 11.5px;
1235
+ color: var(--accent);
1236
+ font-variant-numeric: tabular-nums;
1237
+ }
1238
+ .progress-bar {
1239
+ height: 3px;
1240
+ background: var(--border);
1241
+ position: relative;
1242
+ overflow: hidden;
1243
+ border-radius: 2px;
1244
+ }
1245
+ .progress-bar .fill {
1246
+ height: 100%;
1247
+ width: 0;
1248
+ background: var(--accent);
1249
+ transition: width .2s ease;
1250
+ border-radius: 2px;
1251
+ }
1252
+ .progress-bar .fill.indeterminate {
1253
+ width: 35% !important;
1254
+ animation: indeterm 1.4s ease-in-out infinite;
1255
+ }
1256
+ @keyframes indeterm {
1257
+ from { transform: translateX(-110%); }
1258
+ to { transform: translateX(330%); }
1259
+ }
1260
+ .progress-item.ok .fill { background: var(--green); }
1261
+ .progress-item.error .fill { background: var(--red); }
1262
+ .progress-item .detail {
1263
+ margin-top: 4px;
1264
+ font-family: var(--mono);
1265
+ font-size: 10.5px;
1266
+ color: var(--ink-muted);
1267
+ min-height: 12px;
1268
+ }
1269
+
1270
+ /* ─────────────────────────────────────────────────────────────
1271
+ Pagination (recently closed)
1272
+ ───────────────────────────────────────────────────────────── */
1273
+
1274
+ .pagination {
1275
+ display: flex;
1276
+ align-items: center;
1277
+ gap: var(--s-3);
1278
+ padding: var(--s-3) var(--s-6);
1279
+ border-top: 1px solid var(--border-soft);
1280
+ background: var(--bg);
1281
+ font-size: 12.5px;
1282
+ color: var(--ink-mid);
1283
+ flex-wrap: wrap;
1284
+ }
1285
+ .pagination-info {
1286
+ flex: 1;
1287
+ text-align: center;
1288
+ font-family: var(--mono);
1289
+ font-size: 11.5px;
1290
+ color: var(--ink-muted);
1291
+ }
1292
+ .pagination-info strong {
1293
+ color: var(--ink);
1294
+ font-weight: 600;
1295
+ }
1296
+ .pagination select {
1297
+ font-size: 11.5px;
1298
+ padding: 4px 24px 4px 8px;
1299
+ }
1300
+
1301
+ /* ─────────────────────────────────────────────────────────────
1302
+ Snapshot preview
1303
+ ───────────────────────────────────────────────────────────── */
1304
+
1305
+ .snapshot-detail {
1306
+ margin-top: var(--s-4);
1307
+ }
1308
+ .snapshot-detail summary {
1309
+ cursor: pointer;
1310
+ font-size: 12.5px;
1311
+ color: var(--ink-mid);
1312
+ padding: var(--s-2) 0;
1313
+ user-select: none;
1314
+ font-weight: 500;
1315
+ }
1316
+ .snapshot-detail summary::marker { color: var(--accent); }
1317
+ .snapshot-detail summary:hover { color: var(--ink); }
1318
+ .preview {
1319
+ font-family: var(--mono);
1320
+ font-size: 11.5px;
1321
+ color: var(--ink-mid);
1322
+ background: var(--bg);
1323
+ border: 1px solid var(--border);
1324
+ border-radius: var(--r-sm);
1325
+ padding: var(--s-3);
1326
+ margin-top: var(--s-2);
1327
+ max-height: 280px;
1328
+ overflow: auto;
1329
+ white-space: pre;
1330
+ line-height: 1.55;
1331
+ }
1332
+
1333
+ /* ─────────────────────────────────────────────────────────────
1334
+ Footer status line
1335
+ ───────────────────────────────────────────────────────────── */
1336
+
1337
+ .footer-status {
1338
+ margin-top: auto;
1339
+ padding-top: var(--s-4);
1340
+ border-top: 1px solid var(--border-soft);
1341
+ display: flex;
1342
+ flex-wrap: wrap;
1343
+ align-items: baseline;
1344
+ gap: var(--s-2);
1345
+ font-size: 11px;
1346
+ color: var(--ink-muted);
1347
+ }
1348
+ .footer-status .fs-key {
1349
+ text-transform: uppercase;
1350
+ letter-spacing: 0.08em;
1351
+ font-size: 10px;
1352
+ color: var(--ink-faint);
1353
+ }
1354
+ .footer-status .fs-val {
1355
+ font-family: var(--mono);
1356
+ font-size: 11px;
1357
+ color: var(--ink-mid);
1358
+ }
1359
+ .footer-status .fs-divider { color: var(--ink-faint); margin: 0 var(--s-1); }
1360
+
1361
+ /* ─────────────────────────────────────────────────────────────
1362
+ Toast
1363
+ ───────────────────────────────────────────────────────────── */
1364
+
1365
+ .toast {
1366
+ position: fixed;
1367
+ bottom: var(--s-6);
1368
+ right: var(--s-6);
1369
+ z-index: 100;
1370
+ max-width: 420px;
1371
+ padding: var(--s-3) var(--s-4);
1372
+ background: var(--bg-elev);
1373
+ border: 1px solid var(--border-strong);
1374
+ border-left: 3px solid var(--accent);
1375
+ border-radius: var(--r-sm);
1376
+ font-size: 13px;
1377
+ color: var(--ink);
1378
+ letter-spacing: -0.005em;
1379
+ opacity: 0;
1380
+ transform: translateY(8px);
1381
+ transition: opacity .2s ease, transform .2s ease;
1382
+ pointer-events: none;
1383
+ box-shadow: var(--shadow-md);
1384
+ }
1385
+ .toast.show {
1386
+ opacity: 1;
1387
+ transform: translateY(0);
1388
+ }
1389
+ .toast.error { border-left-color: var(--red); }
1390
+ .toast.ok { border-left-color: var(--green); }
1391
+
1392
+ /* ─────────────────────────────────────────────────────────────
1393
+ FAB · floating action button (bottom-right "+ new session")
1394
+ ───────────────────────────────────────────────────────────── */
1395
+
1396
+ .fab {
1397
+ position: fixed;
1398
+ bottom: var(--s-6);
1399
+ right: var(--s-6);
1400
+ z-index: 90;
1401
+ width: 52px;
1402
+ height: 52px;
1403
+ border-radius: 50%;
1404
+ background: var(--accent);
1405
+ color: var(--bg-elev);
1406
+ border: 0;
1407
+ cursor: pointer;
1408
+ display: inline-flex;
1409
+ align-items: center;
1410
+ justify-content: center;
1411
+ box-shadow:
1412
+ 0 8px 24px -6px rgba(196, 95, 63, 0.5),
1413
+ 0 2px 6px -1px rgba(26, 24, 21, 0.15);
1414
+ transition: background .12s ease, transform .15s ease, box-shadow .15s ease;
1415
+ }
1416
+ .fab:hover {
1417
+ background: var(--accent-deep);
1418
+ transform: translateY(-1px) scale(1.04);
1419
+ box-shadow:
1420
+ 0 12px 28px -6px rgba(196, 95, 63, 0.6),
1421
+ 0 4px 10px -2px rgba(26, 24, 21, 0.2);
1422
+ }
1423
+ .fab:active { transform: scale(0.96); }
1424
+
1425
+ /* ─────────────────────────────────────────────────────────────
1426
+ Modal dialog
1427
+ ───────────────────────────────────────────────────────────── */
1428
+
1429
+ .modal-backdrop {
1430
+ position: fixed;
1431
+ inset: 0;
1432
+ z-index: 200;
1433
+ background: rgba(26, 24, 21, 0.42);
1434
+ backdrop-filter: blur(4px);
1435
+ -webkit-backdrop-filter: blur(4px);
1436
+ display: flex;
1437
+ align-items: center;
1438
+ justify-content: center;
1439
+ padding: var(--s-6);
1440
+ animation: backdrop-in .18s ease;
1441
+ }
1442
+ @keyframes backdrop-in { from { opacity: 0; } to { opacity: 1; } }
1443
+
1444
+ .modal {
1445
+ background: var(--bg-elev);
1446
+ border: 1px solid var(--border);
1447
+ border-radius: var(--r-md);
1448
+ width: min(560px, 100%);
1449
+ max-height: 90vh;
1450
+ display: flex;
1451
+ flex-direction: column;
1452
+ overflow: hidden;
1453
+ box-shadow:
1454
+ 0 24px 64px -16px rgba(26, 24, 21, 0.35),
1455
+ 0 4px 12px -2px rgba(26, 24, 21, 0.15);
1456
+ animation: modal-in .22s cubic-bezier(.4, 0, .2, 1);
1457
+ }
1458
+ @keyframes modal-in {
1459
+ from { opacity: 0; transform: translateY(12px) scale(0.98); }
1460
+ to { opacity: 1; transform: translateY(0) scale(1); }
1461
+ }
1462
+
1463
+ .modal-head {
1464
+ display: flex;
1465
+ align-items: center;
1466
+ justify-content: space-between;
1467
+ padding: var(--s-4) var(--s-6);
1468
+ border-bottom: 1px solid var(--border-soft);
1469
+ }
1470
+ .modal-head h2 {
1471
+ font-size: 16px;
1472
+ font-weight: 600;
1473
+ color: var(--ink);
1474
+ }
1475
+ .modal-close {
1476
+ appearance: none;
1477
+ background: transparent;
1478
+ border: 0;
1479
+ padding: 4px;
1480
+ margin: -4px;
1481
+ cursor: pointer;
1482
+ color: var(--ink-muted);
1483
+ border-radius: 4px;
1484
+ display: inline-flex;
1485
+ transition: color .12s ease, background .12s ease;
1486
+ }
1487
+ .modal-close:hover { color: var(--ink); background: var(--bg); }
1488
+
1489
+ .modal-body {
1490
+ padding: var(--s-5) var(--s-6);
1491
+ overflow-y: auto;
1492
+ flex: 1;
1493
+ }
1494
+ .modal-hint {
1495
+ font-size: 13px;
1496
+ color: var(--ink-muted);
1497
+ margin-bottom: var(--s-4);
1498
+ }
1499
+ .modal-hint code {
1500
+ font-family: var(--mono);
1501
+ font-size: 11.5px;
1502
+ background: var(--bg);
1503
+ padding: 1px 5px;
1504
+ border-radius: 4px;
1505
+ border: 1px solid var(--border-soft);
1506
+ }
1507
+
1508
+ .modal-foot {
1509
+ display: flex;
1510
+ justify-content: flex-end;
1511
+ gap: var(--s-3);
1512
+ padding: var(--s-3) var(--s-6);
1513
+ border-top: 1px solid var(--border-soft);
1514
+ background: var(--bg);
1515
+ }
1516
+
1517
+ .repos-inline-config {
1518
+ margin: var(--s-3) 0;
1519
+ border: 1px solid var(--border);
1520
+ border-radius: var(--r-sm);
1521
+ background: var(--bg);
1522
+ }
1523
+ .repos-inline-config summary {
1524
+ cursor: pointer;
1525
+ padding: 8px var(--s-3);
1526
+ font-size: 12.5px;
1527
+ color: var(--ink-mid);
1528
+ font-weight: 500;
1529
+ user-select: none;
1530
+ }
1531
+ .repos-inline-config summary::marker { color: var(--accent); }
1532
+ .repos-inline-config summary:hover { color: var(--ink); }
1533
+ .repos-inline-config[open] summary { border-bottom: 1px solid var(--border); }
1534
+ .repos-inline-body {
1535
+ padding: var(--s-3);
1536
+ background: var(--bg-elev);
1537
+ border-radius: 0 0 var(--r-sm) var(--r-sm);
1538
+ }
1539
+ .repos-inline-actions {
1540
+ display: flex;
1541
+ gap: var(--s-3);
1542
+ align-items: center;
1543
+ margin-top: var(--s-3);
1544
+ }
1545
+
1546
+ /* Unsaved-changes banner in Configure tab — sticky-ish callout above the
1547
+ settings card. Mirrors the accent CTA banner pattern but louder. */
1548
+ .dirty-banner {
1549
+ display: flex;
1550
+ align-items: center;
1551
+ gap: var(--s-3);
1552
+ padding: var(--s-3) var(--s-5);
1553
+ background: linear-gradient(180deg, rgba(196,95,63,0.12), rgba(196,95,63,0.06));
1554
+ border: 1px solid var(--accent);
1555
+ border-radius: var(--r-sm);
1556
+ color: var(--accent-deep);
1557
+ font-size: 13px;
1558
+ font-weight: 500;
1559
+ position: sticky;
1560
+ top: var(--s-3);
1561
+ z-index: 10;
1562
+ box-shadow: 0 4px 16px -8px rgba(196, 95, 63, 0.4);
1563
+ animation: banner-in .25s cubic-bezier(.4, 0, .2, 1);
1564
+ }
1565
+ @keyframes banner-in {
1566
+ from { opacity: 0; transform: translateY(-6px); }
1567
+ to { opacity: 1; transform: translateY(0); }
1568
+ }
1569
+ .dirty-banner .dirty-dot {
1570
+ width: 8px;
1571
+ height: 8px;
1572
+ border-radius: 50%;
1573
+ background: var(--accent);
1574
+ flex: 0 0 8px;
1575
+ box-shadow: 0 0 0 0 rgba(196, 95, 63, 0.5);
1576
+ animation: dirty-pulse 2s ease-in-out infinite;
1577
+ }
1578
+ .dirty-banner .dirty-text { flex: 1; }
1579
+
1580
+ /* Save button "pulse" when there are unsaved changes */
1581
+ .action.primary.is-dirty {
1582
+ animation: save-pulse 1.6s ease-in-out infinite;
1583
+ }
1584
+ @keyframes save-pulse {
1585
+ 0%, 100% { box-shadow: 0 0 0 0 rgba(196, 95, 63, 0.4); }
1586
+ 50% { box-shadow: 0 0 0 6px rgba(196, 95, 63, 0); }
1587
+ }
1588
+
1589
+ /* Ad-hoc dialog variant (confirm / prompt) — narrower than the main modal */
1590
+ .modal-dialog { width: min(440px, 100%); }
1591
+ .modal-dialog .modal-head { padding: var(--s-4) var(--s-5) var(--s-3); border-bottom: 0; }
1592
+ .modal-dialog .modal-head h2 {
1593
+ font-size: 14.5px;
1594
+ font-weight: 600;
1595
+ color: var(--ink);
1596
+ line-height: 1.4;
1597
+ }
1598
+ .modal-dialog .modal-body { padding: 0 var(--s-5) var(--s-4); }
1599
+ .dialog-msg {
1600
+ font-size: 13.5px;
1601
+ color: var(--ink-mid);
1602
+ line-height: 1.55;
1603
+ }
1604
+ .modal-dialog .modal-foot { padding: var(--s-3) var(--s-5); }
1605
+ .modal-dialog input[type="text"] {
1606
+ width: 100%;
1607
+ max-width: none;
1608
+ margin-top: var(--s-2);
1609
+ }
1610
+
1611
+ /* ─────────────────────────────────────────────────────────────
1612
+ Small utilities
1613
+ ───────────────────────────────────────────────────────────── */
1614
+
1615
+ code, .kbd {
1616
+ font-family: var(--mono);
1617
+ font-size: 11.5px;
1618
+ padding: 1px 5px;
1619
+ background: var(--bg);
1620
+ border: 1px solid var(--border-soft);
1621
+ border-radius: 4px;
1622
+ color: var(--ink-mid);
1623
+ }
1624
+
1625
+ /* Scrollbar */
1626
+ ::-webkit-scrollbar { width: 10px; height: 10px; }
1627
+ ::-webkit-scrollbar-track { background: transparent; }
1628
+ ::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: 8px; border: 2px solid var(--bg); }
1629
+ ::-webkit-scrollbar-thumb:hover { background: var(--ink-faint); }
1630
+
1631
+ /* Responsive — narrow screens collapse sidebar */
1632
+ @media (max-width: 900px) {
1633
+ .app { grid-template-columns: var(--sidebar-w-collapsed) 1fr !important; }
1634
+ .sidebar { padding: var(--s-4) var(--s-2); }
1635
+ .brand-name, .nav-label, .nav-badge { opacity: 0; pointer-events: none; }
1636
+ .main { padding: var(--s-6) var(--s-5) var(--s-5); }
1637
+ .page-head { flex-direction: column; gap: var(--s-3); }
1638
+ .config-grid { grid-template-columns: 1fr; }
1639
+ }