kanbo-cli 0.3.0 → 0.4.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.
@@ -1,477 +1,1772 @@
1
1
  /*
2
- * The board page's look: a small set of colour and spacing tokens, with
3
- * Tailwind's colour values written out. No web fonts: the page loads nothing
4
- * but itself.
2
+ * The board page's look, as `DIRECTION.md` beside it says: a strip board of
3
+ * paper and ink, orange only for "waiting for you". System fonts, no web font.
4
+ * Layers: tokens, base, components, layout, motion. Raw values live only in
5
+ * the tokens' `:root` blocks (`board-css.test.ts` checks).
6
+ * Breakpoints, mobile first: 40rem (640 px), 56.25rem (900 px).
5
7
  */
6
8
 
9
+ /* ===== tokens ===== */
10
+
7
11
  :root {
8
- --neutral-50: oklch(98.5% 0 0);
9
- --neutral-100: oklch(97% 0 0);
10
- --neutral-400: oklch(70.8% 0 0);
11
- --neutral-500: oklch(55.6% 0 0);
12
- --neutral-800: oklch(26.9% 0 0);
13
- --neutral-950: oklch(14.5% 0 0);
14
- --amber-500: oklch(76.9% 0.188 70.08);
15
- --emerald-500: oklch(69.6% 0.17 162.48);
16
- --blue-500: oklch(62.3% 0.214 259.815);
17
- --red-500: oklch(63.7% 0.237 25.331);
18
-
19
- --radius: 0.625rem;
20
- --topbar-height: 45px;
21
- --background: var(--neutral-50);
22
- --foreground: var(--neutral-800);
23
- --card: #fff;
24
- --primary: var(--neutral-800);
25
- --primary-foreground: var(--neutral-50);
26
- --muted: rgb(0 0 0 / 4%);
27
- --muted-foreground: var(--neutral-500);
28
- --accent: rgb(0 0 0 / 7%);
29
- --border: rgb(0 0 0 / 6%);
30
- --border-strong: rgb(0 0 0 / 14%);
31
- --input: rgb(0 0 0 / 7%);
32
- --ring: var(--neutral-400);
33
- --destructive: var(--red-500);
34
- --info: var(--blue-500);
35
- --success: var(--emerald-500);
36
- --warning: var(--amber-500);
37
- --font-sans: 'Geist Variable', 'Geist', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif;
38
- --font-mono: 'Geist Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
39
12
  color-scheme: light dark;
13
+
14
+ /* colour by job — light: a paper strip board in daylight */
15
+ --color-bg: #F1EFE9;
16
+ --color-surface: #FAF9F6;
17
+ --color-well: #E6E3DB;
18
+ --color-raised: #FFFFFF;
19
+ --color-text: #1B2129;
20
+ --color-text-muted: #59616C;
21
+ --color-border: #DCD8CF;
22
+ --color-border-strong: #8A867D;
23
+ --color-focus: #1B2129;
24
+ --color-primary: #1B2129;
25
+ --color-on-primary: #FFFFFF;
26
+ --color-waiting: #E8590C;
27
+ --color-on-waiting: #1C0D02;
28
+ --color-waiting-wash: #FFF1E5;
29
+ --color-running: #1E5BC6;
30
+ --color-running-wash: #E7EEFB;
31
+ --color-agent: var(--color-running);
32
+ --color-agent-wash: var(--color-running-wash);
33
+ --color-done: #2C7A4B;
34
+ --color-quiet: #8B9098;
35
+ --color-danger: #BF2A2A;
36
+ --color-danger-wash: #FCEBEA;
37
+ --color-tint: rgb(27 33 41 / 6%);
38
+ --color-scrim: rgb(27 33 41 / 28%);
39
+ --color-shadow: rgb(27 33 41 / 7%);
40
+ --color-shadow-strong: rgb(27 33 41 / 14%);
41
+
42
+ /* type */
43
+ --font-text: system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
44
+ --font-mono: ui-monospace, 'SF Mono', SFMono-Regular, Menlo, Consolas, monospace;
45
+ --font-display: var(--font-text);
46
+ --text-xs: 0.6875rem;
47
+ --text-sm: 0.75rem;
48
+ --text-base: 0.8125rem;
49
+ --text-md: 0.875rem;
50
+ --text-lg: 1rem;
51
+ --text-xl: 1.25rem;
52
+ --text-2xl: 1.5rem;
53
+ --text-reading: 0.9375rem;
54
+ --leading-tight: 1.3;
55
+ --leading-normal: 1.5;
56
+ --tracking-caps: 0.06em;
57
+
58
+ /* space, 4 px based */
59
+ --space-1: 0.25rem;
60
+ --space-2: 0.5rem;
61
+ --space-3: 0.75rem;
62
+ --space-4: 1rem;
63
+ --space-5: 1.5rem;
64
+ --space-6: 2rem;
65
+ --space-7: 3rem;
66
+
67
+ /* shape */
68
+ --radius-sm: 0.1875rem;
69
+ --radius-md: 0.375rem;
70
+ --radius-lg: 0.625rem; /* = radius-md + the bay's 4 px padding */
71
+ --edge-width: 3px;
72
+ --shadow-card: 0 1px 0 var(--color-shadow);
73
+ --shadow-lift: 0 1px 0 var(--color-shadow), 0 4px 12px var(--color-shadow-strong);
74
+ --shadow-panel: 0 24px 64px var(--color-shadow-strong);
75
+
76
+ /* sizes: touch first, tightened from 40rem */
77
+ --control-height: 2.5rem;
78
+ --chip-height: 2.5rem;
79
+ --column-width: 15rem;
80
+ --column-max: 20rem;
81
+ --dialog-width: 78rem;
82
+ --dialog-side-width: 21.5rem;
83
+
84
+ /* layers */
85
+ --z-raised: 1;
86
+ --z-panel: 10;
87
+ --z-overlay: 20;
88
+ --z-toast: 30;
89
+
90
+ /* motion */
91
+ --duration-fast: 120ms;
92
+ --duration-base: 200ms;
93
+ --duration-slow: 320ms;
94
+ --duration-loop: 1600ms;
95
+ --ease-out: cubic-bezier(0.2, 0, 0, 1);
96
+ --ease-in-out: cubic-bezier(0.45, 0, 0.55, 1);
97
+ --press-scale: 0.96;
40
98
  }
41
99
 
42
100
  @media (prefers-color-scheme: dark) {
43
101
  :root {
44
- --background: color-mix(in srgb, var(--neutral-950) 94%, #fff);
45
- --foreground: var(--neutral-100);
46
- --card: color-mix(in srgb, var(--background) 98%, #fff);
47
- --primary: var(--neutral-100);
48
- --primary-foreground: var(--neutral-800);
49
- --muted: rgb(255 255 255 / 4%);
50
- --muted-foreground: color-mix(in srgb, var(--neutral-500) 90%, #fff);
51
- --accent: rgb(255 255 255 / 8%);
52
- --border: rgb(255 255 255 / 5%);
53
- --border-strong: rgb(255 255 255 / 12%);
54
- --input: rgb(255 255 255 / 7%);
55
- --ring: var(--neutral-500);
56
- --destructive: color-mix(in srgb, var(--red-500) 90%, #fff);
57
- }
58
- }
59
-
60
- * {
102
+ /* dark: the same board under a desk lamp — ink ground, warm signal */
103
+ --color-bg: #13161A;
104
+ --color-surface: #181C21;
105
+ --color-well: #0E1013;
106
+ --color-raised: #1F242B;
107
+ --color-text: #E6E8EB;
108
+ --color-text-muted: #9AA2AD;
109
+ --color-border: #2B3139;
110
+ --color-border-strong: #6B7480;
111
+ --color-focus: #E6E8EB;
112
+ --color-primary: #E6E8EB;
113
+ --color-on-primary: #13161A;
114
+ --color-waiting: #FF8A3D;
115
+ --color-on-waiting: #1C0D02;
116
+ --color-waiting-wash: #2E2119;
117
+ --color-running: #7AA7FF;
118
+ --color-running-wash: #1B2740;
119
+ --color-done: #5DC58A;
120
+ --color-quiet: #727B86;
121
+ --color-danger: #FF6F6A;
122
+ --color-danger-wash: #3A1D1D;
123
+ --color-tint: rgb(230 232 235 / 8%);
124
+ --color-scrim: rgb(0 0 0 / 50%);
125
+ --color-shadow: rgb(0 0 0 / 30%);
126
+ --color-shadow-strong: rgb(0 0 0 / 45%);
127
+ }
128
+ }
129
+
130
+ @media (min-width: 40rem) {
131
+ :root {
132
+ --control-height: 1.875rem;
133
+ --chip-height: 1.5rem;
134
+ }
135
+ }
136
+
137
+ /* Reduced motion: final states only. */
138
+ @media (prefers-reduced-motion: reduce) {
139
+ :root {
140
+ --duration-fast: 0ms;
141
+ --duration-base: 0ms;
142
+ --duration-slow: 0ms;
143
+ --press-scale: 1;
144
+ }
145
+ }
146
+
147
+ /* ===== base ===== */
148
+
149
+ *,
150
+ *::before,
151
+ *::after {
61
152
  box-sizing: border-box;
62
153
  }
63
154
 
155
+ html {
156
+ -webkit-text-size-adjust: 100%;
157
+ }
158
+
64
159
  body {
65
160
  margin: 0;
66
- background: var(--background);
67
- color: var(--foreground);
68
- font-family: var(--font-sans);
69
- font-size: 14px;
161
+ background: var(--color-bg);
162
+ color: var(--color-text);
163
+ font-family: var(--font-text);
164
+ font-size: var(--text-base);
165
+ line-height: var(--leading-normal);
70
166
  -webkit-font-smoothing: antialiased;
71
167
  }
72
168
 
73
- :focus-visible {
74
- outline: 2px solid var(--ring);
75
- outline-offset: 2px;
169
+ button,
170
+ input,
171
+ select,
172
+ textarea {
173
+ font: inherit;
174
+ color: inherit;
76
175
  }
77
176
 
78
177
  button {
79
- font: inherit;
80
- color: inherit;
81
178
  cursor: pointer;
179
+ }
180
+
181
+ :focus-visible {
182
+ outline: 2px solid var(--color-focus);
183
+ outline-offset: 2px;
184
+ }
185
+
186
+ ::selection {
187
+ background: var(--color-running-wash);
188
+ }
189
+
190
+ [hidden] {
191
+ display: none !important;
192
+ }
193
+
194
+ .visually-hidden {
195
+ position: absolute;
196
+ width: 1px;
197
+ height: 1px;
198
+ overflow: hidden;
199
+ clip-path: inset(50%);
200
+ white-space: nowrap;
201
+ }
202
+
203
+ /* ===== components ===== */
204
+
205
+ /* Buttons */
206
+
207
+ .primary,
208
+ .secondary,
209
+ .ghost {
210
+ display: inline-flex;
211
+ align-items: center;
212
+ justify-content: center;
213
+ gap: var(--space-2);
214
+ min-height: var(--control-height);
215
+ padding: 0 var(--space-3);
82
216
  border: 0;
83
- border-radius: calc(var(--radius) * 0.8);
84
- padding: 4px 10px;
85
- font-size: 12px;
86
- font-weight: 500;
217
+ border-radius: var(--radius-md);
218
+ font-size: var(--text-sm);
219
+ font-weight: 600;
220
+ white-space: nowrap;
221
+ transition:
222
+ transform var(--duration-fast) var(--ease-out),
223
+ background-color var(--duration-fast) var(--ease-out),
224
+ color var(--duration-fast) var(--ease-out);
225
+ }
226
+
227
+ .primary:active,
228
+ .secondary:active,
229
+ .ghost:active {
230
+ transform: scale(var(--press-scale));
87
231
  }
88
232
 
89
233
  .primary {
90
- background: var(--primary);
91
- color: var(--primary-foreground);
234
+ background: var(--color-primary);
235
+ color: var(--color-on-primary);
92
236
  }
93
237
 
94
238
  .secondary {
95
- background: var(--card);
96
- box-shadow: inset 0 0 0 1px var(--border-strong);
239
+ background: var(--color-raised);
240
+ box-shadow: inset 0 0 0 1px var(--color-border-strong);
97
241
  }
98
242
 
99
243
  .ghost {
100
244
  background: transparent;
101
- color: var(--muted-foreground);
245
+ color: var(--color-text-muted);
102
246
  }
103
247
 
104
248
  .ghost:hover,
105
249
  .secondary:hover {
106
- background: var(--accent);
250
+ background: var(--color-tint);
251
+ color: var(--color-text);
107
252
  }
108
253
 
254
+ /* Fields */
255
+
109
256
  .field {
110
- font: inherit;
111
- font-size: 13px;
112
- color: inherit;
113
257
  width: 100%;
114
- background: var(--card);
115
- border: 1px solid var(--input);
116
- border-radius: calc(var(--radius) * 0.8);
117
- padding: 6px 8px;
118
- resize: vertical;
258
+ min-height: var(--control-height);
259
+ padding: var(--space-1) var(--space-2);
260
+ border: 0;
261
+ border-radius: var(--radius-md);
262
+ background: var(--color-raised);
263
+ box-shadow: inset 0 0 0 1px var(--color-border-strong);
264
+ font-size: var(--text-md);
265
+ line-height: var(--leading-normal);
119
266
  }
120
267
 
121
- .row {
122
- display: flex;
123
- gap: 6px;
124
- margin-top: 6px;
268
+ textarea.field {
269
+ display: block;
270
+ resize: vertical;
125
271
  }
126
272
 
127
- /* The top bar */
273
+ .field::placeholder {
274
+ color: var(--color-text-muted);
275
+ }
128
276
 
129
- .topbar {
130
- display: flex;
131
- align-items: center;
132
- gap: 12px;
133
- height: var(--topbar-height);
134
- padding: 0 16px;
135
- border-bottom: 1px solid var(--border);
277
+ select.field {
278
+ width: auto;
279
+ max-width: 100%;
280
+ cursor: pointer;
136
281
  }
137
282
 
138
- .topbar-title {
139
- margin: 0;
140
- font-size: 14px;
141
- font-weight: 600;
283
+ /* A select's chevron, drawn by its wrapper in currentColor. */
284
+ .select-wrap select.field {
285
+ appearance: none;
286
+ width: 100%;
287
+ padding: 0 calc(var(--space-6) - var(--space-1)) 0 var(--space-3);
288
+ font-size: var(--text-sm);
289
+ font-weight: 500;
290
+ text-overflow: ellipsis;
142
291
  }
143
292
 
144
- .workspace {
145
- font-family: var(--font-mono);
146
- font-size: 12px;
147
- color: var(--muted-foreground);
293
+ .select-wrap {
294
+ position: relative;
295
+ display: inline-flex;
296
+ min-width: 0;
148
297
  }
149
298
 
150
- .token-form {
151
- margin-left: auto;
152
- display: flex;
153
- align-items: center;
154
- gap: 6px;
299
+ .select-wrap::after {
300
+ content: '';
301
+ position: absolute;
302
+ top: 50%;
303
+ right: var(--space-3);
304
+ width: 0.375rem;
305
+ height: 0.375rem;
306
+ border-right: 1.5px solid currentColor;
307
+ border-bottom: 1.5px solid currentColor;
308
+ transform: translateY(-70%) rotate(45deg);
309
+ pointer-events: none;
155
310
  }
156
311
 
157
- .token-label {
158
- display: flex;
312
+ /* Filter toggles and chips */
313
+
314
+ .filter-toggle,
315
+ .filter-chip {
316
+ display: inline-flex;
317
+ flex: 0 0 auto;
159
318
  align-items: center;
160
- gap: 6px;
161
- font-size: 12px;
162
- color: var(--muted-foreground);
319
+ gap: var(--space-2);
320
+ border: 0;
321
+ background: var(--color-raised);
322
+ box-shadow: inset 0 0 0 1px var(--color-border-strong);
323
+ font-size: var(--text-sm);
324
+ font-weight: 500;
325
+ white-space: nowrap;
326
+ transition:
327
+ transform var(--duration-fast) var(--ease-out),
328
+ background-color var(--duration-fast) var(--ease-out),
329
+ color var(--duration-fast) var(--ease-out);
163
330
  }
164
331
 
165
- .token-input {
166
- width: 180px;
167
- padding: 3px 8px;
332
+ .filter-toggle {
333
+ min-height: var(--control-height);
334
+ padding: 0 var(--space-3);
335
+ border-radius: var(--radius-md);
168
336
  }
169
337
 
170
- .notice {
171
- margin: 8px 16px 0;
172
- padding: 6px 10px;
173
- border-radius: calc(var(--radius) * 0.8);
174
- font-size: 12px;
175
- background: var(--muted);
338
+ .filter-chip {
339
+ min-height: var(--chip-height);
340
+ padding: 0 var(--space-2);
341
+ border-radius: var(--radius-sm);
176
342
  }
177
343
 
178
- .notice[data-kind='error'] {
179
- color: var(--destructive);
180
- box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--destructive) 40%, transparent);
344
+ .filter-toggle:active,
345
+ .filter-chip:active {
346
+ transform: scale(var(--press-scale));
181
347
  }
182
348
 
183
- /* The board */
349
+ .filter-toggle:hover,
350
+ .filter-chip:hover {
351
+ background: var(--color-tint);
352
+ }
184
353
 
185
- .board {
186
- display: flex;
187
- gap: 12px;
188
- align-items: flex-start;
189
- padding: 12px 16px 24px;
190
- overflow-x: auto;
191
- min-height: calc(100vh - var(--topbar-height));
354
+ .filter-toggle[aria-pressed='true'],
355
+ .filter-chip[aria-pressed='true'] {
356
+ background: var(--color-primary);
357
+ color: var(--color-on-primary);
358
+ box-shadow: none;
192
359
  }
193
360
 
194
- .column {
195
- flex: 0 0 280px;
196
- display: flex;
197
- flex-direction: column;
198
- gap: 8px;
199
- padding: 6px;
200
- border-radius: var(--radius);
201
- min-height: 120px;
361
+ .filter-toggle[data-filter]::before {
362
+ content: '';
363
+ width: 0.5rem;
364
+ height: 0.5rem;
365
+ border-radius: 50%;
202
366
  }
203
367
 
204
- .column.drop-target {
205
- background: var(--muted);
206
- box-shadow: inset 0 0 0 1px var(--border-strong);
368
+ .filter-toggle[data-filter='waiting']::before {
369
+ border-radius: var(--radius-sm);
370
+ background: var(--color-waiting);
207
371
  }
208
372
 
209
- .column-head {
210
- display: flex;
211
- align-items: center;
212
- gap: 6px;
213
- padding: 2px 4px;
214
- font-size: 13px;
215
- font-weight: 500;
373
+ .filter-toggle[data-filter='running']::before {
374
+ background: var(--color-running);
216
375
  }
217
376
 
377
+ /* Small marks on cards and in the panel */
378
+
379
+ .card-key,
380
+ .attempt-chip,
381
+ .workspace,
382
+ .history-time,
218
383
  .column-count {
219
- color: var(--muted-foreground);
384
+ font-family: var(--font-mono);
220
385
  font-variant-numeric: tabular-nums;
221
- font-size: 12px;
222
386
  }
223
387
 
224
- .column-add {
225
- margin-left: auto;
388
+ .card-key {
389
+ min-width: 0;
390
+ overflow: hidden;
391
+ color: var(--color-text-muted);
392
+ font-size: var(--text-xs);
393
+ letter-spacing: 0.01em;
394
+ white-space: nowrap;
395
+ text-overflow: ellipsis;
226
396
  }
227
397
 
228
- .column-cards {
229
- display: flex;
230
- flex-direction: column;
231
- gap: 8px;
398
+ .waiting-badge {
399
+ display: inline-flex;
400
+ flex: 0 0 auto;
401
+ align-items: center;
402
+ height: 1.25rem;
403
+ padding: 0 var(--space-2);
404
+ border-radius: var(--radius-sm);
405
+ background: var(--color-waiting);
406
+ color: var(--color-on-waiting);
407
+ font-size: var(--text-sm);
408
+ font-weight: 650;
409
+ white-space: nowrap;
232
410
  }
233
411
 
234
- .draft {
235
- padding: 8px;
236
- background: var(--card);
237
- border-radius: var(--radius);
238
- box-shadow: inset 0 0 0 1px var(--border-strong);
412
+ .run-state {
413
+ display: inline-flex;
414
+ align-items: center;
415
+ gap: var(--space-2);
416
+ min-width: 0;
417
+ overflow: hidden;
418
+ color: var(--color-running);
419
+ font-size: var(--text-sm);
420
+ font-weight: 600;
421
+ white-space: nowrap;
422
+ text-overflow: ellipsis;
239
423
  }
240
424
 
241
- /* A card */
242
-
243
- .card {
425
+ .run-dot {
244
426
  position: relative;
245
- display: flex;
246
- flex-direction: column;
247
- gap: 6px;
248
- padding: 10px 12px;
249
- background: var(--card);
250
- border-radius: var(--radius);
251
- box-shadow: inset 0 0 0 1px var(--border);
252
- transition: box-shadow 150ms cubic-bezier(0.22, 1, 0.36, 1);
427
+ flex: 0 0 auto;
428
+ width: 0.5rem;
429
+ height: 0.5rem;
430
+ border-radius: 50%;
431
+ background: var(--color-running);
253
432
  }
254
433
 
255
- .card:hover {
256
- box-shadow: inset 0 0 0 1px var(--border-strong);
434
+ /* The ping ring; the dot stays solid. */
435
+ .run-dot::after {
436
+ content: '';
437
+ position: absolute;
438
+ inset: 0;
439
+ border-radius: 50%;
440
+ background: var(--color-running);
441
+ opacity: 0;
257
442
  }
258
443
 
259
- .card.dragging {
260
- opacity: 0.4;
444
+ .attempt-chip {
445
+ flex: 0 0 auto;
446
+ margin-left: auto;
447
+ padding: 0 var(--space-1);
448
+ border-radius: var(--radius-sm);
449
+ box-shadow: inset 0 0 0 1px var(--color-border-strong);
450
+ color: var(--color-text-muted);
451
+ font-size: var(--text-xs);
452
+ line-height: 1.125rem;
261
453
  }
262
454
 
263
- .card-head {
264
- display: flex;
455
+ /* Who works it: blue square an agent, ink circle you. */
456
+ .worker {
457
+ display: inline-flex;
265
458
  align-items: center;
266
- justify-content: space-between;
267
- gap: 8px;
268
- }
269
-
270
- .card-key {
271
- font-family: var(--font-mono);
272
- font-size: 10px;
273
- color: var(--muted-foreground);
274
- font-variant-numeric: tabular-nums;
275
- }
276
-
277
- .card-title {
278
- all: unset;
279
- font-size: 13px;
280
- font-weight: 500;
281
- line-height: 1.375;
282
- text-wrap: pretty;
283
- overflow-wrap: anywhere;
284
- cursor: pointer;
459
+ gap: var(--space-1);
460
+ min-width: 0;
461
+ overflow: hidden;
462
+ color: var(--color-text-muted);
463
+ font-size: var(--text-sm);
464
+ white-space: nowrap;
465
+ text-overflow: ellipsis;
285
466
  }
286
467
 
287
- /* The title is the card's one button, stretched over the whole card. */
288
- .card-title::after {
468
+ .worker::before {
289
469
  content: '';
290
- position: absolute;
291
- inset: 0;
292
- border-radius: var(--radius);
470
+ flex: 0 0 auto;
471
+ width: 0.4375rem;
472
+ height: 0.4375rem;
293
473
  }
294
474
 
295
- .card-title:focus-visible::after {
296
- outline: 2px solid var(--ring);
297
- outline-offset: 2px;
475
+ .worker[data-kind='agent']::before {
476
+ border-radius: 1px;
477
+ background: var(--color-agent);
298
478
  }
299
479
 
300
- .card-status {
301
- display: flex;
302
- align-items: center;
303
- gap: 6px;
304
- min-width: 0;
480
+ .worker[data-kind='user']::before {
481
+ border-radius: 50%;
482
+ background: var(--color-text);
305
483
  }
306
484
 
307
- .status-line {
308
- flex: 1;
309
- min-width: 0;
310
- margin: 0;
311
- padding-left: 8px;
312
- border-left: 2px solid var(--border);
313
- font-size: 11px;
314
- line-height: 1.375;
315
- color: var(--muted-foreground);
316
- white-space: nowrap;
485
+ .priority,
486
+ .label {
487
+ display: inline-block;
488
+ max-width: 100%;
489
+ height: 1.125rem;
490
+ padding: 0 var(--space-1);
317
491
  overflow: hidden;
492
+ border-radius: var(--radius-sm);
493
+ font-size: var(--text-xs);
494
+ font-weight: 600;
495
+ line-height: 1.125rem;
496
+ white-space: nowrap;
318
497
  text-overflow: ellipsis;
498
+ vertical-align: middle;
319
499
  }
320
500
 
321
- .status-line[data-category='triage'] {
322
- border-left-color: color-mix(in srgb, var(--info) 60%, transparent);
501
+ .priority {
502
+ text-transform: capitalize;
323
503
  }
324
504
 
325
- .status-line[data-category='started'] {
326
- border-left-color: color-mix(in srgb, var(--warning) 60%, transparent);
505
+ .priority[data-priority='urgent'] {
506
+ background: var(--color-primary);
507
+ color: var(--color-on-primary);
327
508
  }
328
509
 
329
- .status-line[data-category='completed'] {
330
- border-left-color: color-mix(in srgb, var(--success) 60%, transparent);
510
+ .priority[data-priority='high'] {
511
+ box-shadow: inset 0 0 0 1px var(--color-text);
512
+ color: var(--color-text);
331
513
  }
332
514
 
333
- .waiting-badge {
334
- flex-shrink: 0;
335
- display: inline-flex;
336
- align-items: center;
337
- height: 20px;
338
- padding: 0 6px;
339
- border: 1px solid color-mix(in srgb, var(--warning) 50%, transparent);
340
- border-radius: calc(var(--radius) * 0.6);
341
- font-size: 11px;
515
+ .priority[data-priority='medium'],
516
+ .priority[data-priority='low'] {
517
+ box-shadow: inset 0 0 0 1px var(--color-border-strong);
518
+ color: var(--color-text-muted);
342
519
  font-weight: 500;
343
- color: var(--warning);
344
520
  }
345
521
 
346
- .attempt-chip {
347
- flex-shrink: 0;
348
- font-family: var(--font-mono);
349
- font-size: 10px;
350
- color: var(--muted-foreground);
351
- font-variant-numeric: tabular-nums;
522
+ .label {
523
+ background: var(--color-tint);
524
+ color: var(--color-text-muted);
525
+ font-weight: 500;
352
526
  }
353
527
 
354
- .run-dot {
355
- width: 6px;
356
- height: 6px;
357
- border-radius: 50%;
358
- background: var(--info);
359
- animation: run-pulse 1.4s ease-in-out infinite;
528
+ .status-line {
529
+ display: -webkit-box;
530
+ margin: 0;
531
+ padding-left: var(--space-2);
532
+ overflow: hidden;
533
+ border-left: 2px solid var(--color-border);
534
+ color: var(--color-text-muted);
535
+ font-size: var(--text-sm);
536
+ line-height: var(--leading-tight);
537
+ overflow-wrap: anywhere;
538
+ -webkit-box-orient: vertical;
539
+ -webkit-line-clamp: 2;
360
540
  }
361
541
 
362
- @keyframes run-pulse {
363
- 50% {
364
- opacity: 0.35;
365
- }
542
+ /* A card: a strip in its holder. The left edge says its state. */
543
+
544
+ .card {
545
+ --card-edge: transparent;
546
+ --card-ring: var(--color-border);
547
+ position: relative;
548
+ display: flex;
549
+ flex: 0 0 auto;
550
+ flex-direction: column;
551
+ gap: var(--space-2);
552
+ min-width: 0;
553
+ padding: var(--space-3) var(--space-3) var(--space-3) calc(var(--space-3) + var(--edge-width));
554
+ border-radius: var(--radius-md);
555
+ background: var(--color-raised);
556
+ box-shadow:
557
+ inset var(--edge-width) 0 0 var(--card-edge),
558
+ 0 0 0 1px var(--card-ring),
559
+ var(--shadow-card);
560
+ transition: box-shadow var(--duration-fast) var(--ease-out);
366
561
  }
367
562
 
368
- @media (prefers-reduced-motion: reduce) {
369
- .run-dot {
370
- animation: none;
371
- }
563
+ /* Hover is colour only, never movement. */
564
+ .card:hover {
565
+ --card-ring: var(--color-border-strong);
372
566
  }
373
567
 
374
- /* The side panel, below the top bar so the token stays in reach */
568
+ .card[data-state='waiting'] {
569
+ --card-edge: var(--color-waiting);
570
+ --card-ring: color-mix(in srgb, var(--color-waiting) 45%, transparent);
571
+ background: var(--color-waiting-wash);
572
+ }
375
573
 
376
- .panel {
377
- position: fixed;
378
- top: var(--topbar-height);
379
- right: 0;
380
- bottom: 0;
381
- width: min(440px, 100vw);
382
- overflow-y: auto;
383
- padding: 14px 18px 24px;
384
- background: var(--card);
385
- border-left: 1px solid var(--border-strong);
574
+ .card[data-state='running'] {
575
+ --card-edge: var(--color-running);
386
576
  }
387
577
 
388
- .panel-head {
389
- display: flex;
390
- align-items: center;
391
- justify-content: space-between;
578
+ .card[data-state='done'] {
579
+ --card-edge: var(--color-done);
580
+ box-shadow:
581
+ inset var(--edge-width) 0 0 var(--card-edge),
582
+ 0 0 0 1px var(--card-ring);
392
583
  }
393
584
 
394
- .panel-title {
395
- margin: 8px 0 4px;
396
- font-size: 16px;
397
- font-weight: 600;
398
- overflow-wrap: anywhere;
585
+ .card[data-state='quiet'] {
586
+ --card-edge: var(--color-quiet);
399
587
  }
400
588
 
401
- .panel-facts {
402
- margin: 0 0 8px;
403
- display: flex;
404
- align-items: center;
405
- gap: 8px;
406
- font-size: 12px;
407
- color: var(--muted-foreground);
589
+ .card[data-state='quiet'] .card-title {
590
+ color: var(--color-text-muted);
591
+ text-decoration: line-through;
408
592
  }
409
593
 
410
- .panel .status-line {
411
- white-space: normal;
594
+ /* Open: a flush ink ring and a lift, unlike the focus ring. */
595
+ .card[data-open] {
596
+ box-shadow:
597
+ inset var(--edge-width) 0 0 var(--card-edge),
598
+ 0 0 0 2px var(--color-text),
599
+ var(--shadow-lift);
412
600
  }
413
601
 
414
- .panel-notice {
415
- margin: 10px 0;
416
- padding: 6px 10px;
417
- border-radius: calc(var(--radius) * 0.8);
418
- font-size: 12px;
419
- color: var(--destructive);
420
- box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--destructive) 40%, transparent);
602
+ .card.dragging {
603
+ opacity: 0.45;
421
604
  }
422
605
 
423
- .panel-section {
424
- margin-top: 18px;
606
+ .card-state {
607
+ display: flex;
608
+ align-items: center;
609
+ gap: var(--space-2);
610
+ min-width: 0;
425
611
  }
426
612
 
427
- .panel-section h3 {
428
- margin: 0 0 6px;
429
- font-size: 12px;
613
+ .card-title {
614
+ all: unset;
615
+ display: -webkit-box;
616
+ overflow: hidden;
617
+ font-size: var(--text-md);
430
618
  font-weight: 600;
431
- color: var(--muted-foreground);
619
+ line-height: var(--leading-tight);
620
+ overflow-wrap: anywhere;
621
+ text-wrap: pretty;
622
+ cursor: pointer;
623
+ -webkit-box-orient: vertical;
624
+ -webkit-line-clamp: 3;
432
625
  }
433
626
 
434
- .description {
435
- font-size: 13px;
436
- line-height: 1.5;
437
- white-space: pre-wrap;
438
- overflow-wrap: anywhere;
627
+ /* The title is the card's one button, stretched over the whole card. */
628
+ .card-title::after {
629
+ content: '';
630
+ position: absolute;
631
+ inset: 0;
632
+ border-radius: var(--radius-md);
439
633
  }
440
634
 
441
- .empty,
442
- .hint {
443
- margin: 0;
444
- font-size: 12px;
445
- color: var(--muted-foreground);
635
+ .card-title:focus-visible {
636
+ outline: 0;
446
637
  }
447
638
 
448
- .entries {
449
- list-style: none;
450
- margin: 0 0 8px;
451
- padding: 0;
452
- display: flex;
453
- flex-direction: column;
454
- gap: 8px;
639
+ .card-title:focus-visible::after {
640
+ outline: 2px solid var(--color-focus);
641
+ outline-offset: 2px;
455
642
  }
456
643
 
457
- .entry-meta {
644
+ .card-meta {
458
645
  display: flex;
459
- gap: 8px;
460
- font-size: 11px;
461
- color: var(--muted-foreground);
646
+ align-items: center;
647
+ gap: var(--space-3);
648
+ min-width: 0;
462
649
  }
463
650
 
464
- .entry-author {
465
- font-weight: 500;
466
- color: var(--foreground);
651
+ .card-tags {
652
+ display: flex;
653
+ flex-wrap: wrap;
654
+ gap: var(--space-1);
655
+ min-width: 0;
467
656
  }
468
657
 
469
- .entry-text {
470
- font-size: 13px;
471
- white-space: pre-wrap;
472
- overflow-wrap: anywhere;
473
- }
658
+ /* A sub-card names its parent; a parent says how far its parts are. */
474
659
 
475
- [hidden] {
476
- display: none !important;
660
+ .parent-link {
661
+ all: unset;
662
+ position: relative;
663
+ z-index: var(--z-raised);
664
+ display: flex;
665
+ align-items: center;
666
+ gap: var(--space-1);
667
+ box-sizing: border-box;
668
+ min-width: 0;
669
+ color: var(--color-text-muted);
670
+ font-size: var(--text-sm);
671
+ }
672
+
673
+ button.parent-link {
674
+ min-height: var(--chip-height);
675
+ cursor: pointer;
676
+ }
677
+
678
+ button.parent-link:hover .parent-title {
679
+ color: var(--color-text);
680
+ text-decoration: underline;
681
+ }
682
+
683
+ .parent-title,
684
+ .link-title,
685
+ .subcard-title {
686
+ min-width: 0;
687
+ overflow: hidden;
688
+ text-overflow: ellipsis;
689
+ white-space: nowrap;
690
+ }
691
+
692
+ .subcard-chip {
693
+ flex: 0 0 auto;
694
+ margin-left: auto;
695
+ padding: 0 var(--space-1);
696
+ border-radius: var(--radius-sm);
697
+ background: var(--color-tint);
698
+ color: var(--color-text-muted);
699
+ font-size: var(--text-xs);
700
+ line-height: 1.125rem;
701
+ white-space: nowrap;
702
+ }
703
+
704
+ /* The new-card form */
705
+
706
+ .draft {
707
+ flex: 0 0 auto;
708
+ padding: var(--space-2);
709
+ border-radius: var(--radius-md);
710
+ background: var(--color-raised);
711
+ box-shadow: 0 0 0 1px var(--color-border-strong), var(--shadow-card);
712
+ }
713
+
714
+ /* A column: a bay the strips rest in */
715
+
716
+ .column {
717
+ display: flex;
718
+ flex: 0 0 86%;
719
+ flex-direction: column;
720
+ min-width: 0;
721
+ max-width: var(--column-max);
722
+ min-height: 0;
723
+ border-radius: var(--radius-lg);
724
+ background: var(--color-well);
725
+ scroll-snap-align: start;
726
+ transition:
727
+ background-color var(--duration-fast) var(--ease-out),
728
+ box-shadow var(--duration-fast) var(--ease-out);
729
+ }
730
+
731
+ .column.drop-target {
732
+ background: color-mix(in srgb, var(--color-well) 60%, var(--color-raised));
733
+ box-shadow: inset 0 0 0 2px var(--color-border-strong);
734
+ }
735
+
736
+ .column-head {
737
+ display: flex;
738
+ flex: 0 0 auto;
739
+ align-items: center;
740
+ gap: var(--space-2);
741
+ min-width: 0;
742
+ padding: var(--space-2) var(--space-2) var(--space-2) var(--space-3);
743
+ }
744
+
745
+ .column-name {
746
+ min-width: 0;
747
+ overflow: hidden;
748
+ font-family: var(--font-display);
749
+ font-size: var(--text-sm);
750
+ font-weight: 700;
751
+ letter-spacing: var(--tracking-caps);
752
+ text-transform: uppercase;
753
+ white-space: nowrap;
754
+ text-overflow: ellipsis;
755
+ }
756
+
757
+ .column-count {
758
+ flex: 0 0 auto;
759
+ min-width: 1.25rem;
760
+ padding: 0 var(--space-1);
761
+ border-radius: var(--radius-sm);
762
+ background: var(--color-tint);
763
+ color: var(--color-text-muted);
764
+ font-size: var(--text-xs);
765
+ line-height: 1.125rem;
766
+ text-align: center;
767
+ }
768
+
769
+ .column-add {
770
+ margin-left: auto;
771
+ }
772
+
773
+ .column-cards {
774
+ display: flex;
775
+ flex: 1;
776
+ flex-direction: column;
777
+ gap: var(--space-2);
778
+ min-height: 0;
779
+ padding: var(--space-1) var(--space-1) var(--space-3);
780
+ overflow-y: auto;
781
+ overscroll-behavior: contain;
782
+ }
783
+
784
+ /* Notices */
785
+
786
+ .notice {
787
+ margin: 0;
788
+ padding: var(--space-2) var(--space-4);
789
+ border-bottom: 1px solid var(--color-border);
790
+ background: var(--color-surface);
791
+ font-size: var(--text-sm);
792
+ }
793
+
794
+ .notice[data-kind='error'],
795
+ .panel-notice {
796
+ background: var(--color-danger-wash);
797
+ color: var(--color-danger);
798
+ }
799
+
800
+ .panel-notice {
801
+ margin: var(--space-4) 0 0;
802
+ padding: var(--space-2) var(--space-3);
803
+ border-radius: var(--radius-md);
804
+ font-size: var(--text-sm);
805
+ }
806
+
807
+ /* Top bar */
808
+
809
+ .topbar-title {
810
+ margin: 0;
811
+ font-family: var(--font-display);
812
+ font-size: var(--text-lg);
813
+ font-weight: 750;
814
+ letter-spacing: -0.01em;
815
+ line-height: 1;
816
+ text-transform: lowercase;
817
+ }
818
+
819
+ .project-switcher select.field {
820
+ font-size: var(--text-md);
821
+ font-weight: 600;
822
+ }
823
+
824
+ .workspace {
825
+ min-width: 0;
826
+ overflow: hidden;
827
+ color: var(--color-text-muted);
828
+ font-size: var(--text-xs);
829
+ white-space: nowrap;
830
+ text-overflow: ellipsis;
831
+ }
832
+
833
+ .where-key {
834
+ color: var(--color-text);
835
+ font-weight: 600;
836
+ }
837
+
838
+ .token-form {
839
+ display: flex;
840
+ align-items: center;
841
+ gap: var(--space-2);
842
+ }
843
+
844
+ .token-label {
845
+ display: flex;
846
+ align-items: center;
847
+ gap: var(--space-2);
848
+ color: var(--color-text-muted);
849
+ font-size: var(--text-sm);
850
+ }
851
+
852
+ .token-input {
853
+ width: 7rem;
854
+ font-size: var(--text-sm);
855
+ }
856
+
857
+ /* Narrow: a working token's form folds into its button. */
858
+ .token-toggle {
859
+ display: none;
860
+ }
861
+
862
+ .topbar[data-token] .token-toggle {
863
+ display: inline-flex;
864
+ }
865
+
866
+ .topbar[data-token='folded'] .token-form {
867
+ display: none;
868
+ }
869
+
870
+ .token-toggle[aria-expanded='true'] {
871
+ background: var(--color-tint);
872
+ color: var(--color-text);
873
+ }
874
+
875
+ /* Filter bar */
876
+
877
+ .filter-search {
878
+ flex: 0 0 8rem;
879
+ font-size: var(--text-sm);
880
+ }
881
+
882
+ .filter-group {
883
+ display: flex;
884
+ flex-wrap: wrap;
885
+ gap: var(--space-2);
886
+ }
887
+
888
+ .filter-labels {
889
+ max-height: calc(var(--control-height) * 2);
890
+ font-size: var(--text-sm);
891
+ }
892
+
893
+ .filter-count {
894
+ flex: 0 0 auto;
895
+ color: var(--color-text-muted);
896
+ font-size: var(--text-sm);
897
+ font-variant-numeric: tabular-nums;
898
+ white-space: nowrap;
899
+ }
900
+
901
+ /* Groups in the bar are told apart by space. */
902
+ .select-wrap + .filter-toggle,
903
+ .filter-toggle + .filter-group,
904
+ .filter-group + .filter-group,
905
+ .filter-group + .filter-labels {
906
+ margin-left: var(--space-3);
907
+ }
908
+
909
+ /* Side panel */
910
+
911
+ .panel-head {
912
+ display: flex;
913
+ align-items: center;
914
+ gap: var(--space-3);
915
+ min-height: 3rem;
916
+ padding: 0 var(--space-3) 0 var(--space-4);
917
+ border-bottom: 1px solid var(--color-border);
918
+ color: var(--color-text-muted);
919
+ font-family: var(--font-mono);
920
+ font-size: var(--text-sm);
921
+ }
922
+
923
+ .panel-head .card-key {
924
+ color: var(--color-text);
925
+ font-weight: 600;
926
+ }
927
+
928
+ .panel-head .spacer {
929
+ flex: 1;
930
+ }
931
+
932
+ .icon-button {
933
+ display: inline-grid;
934
+ place-items: center;
935
+ width: var(--control-height);
936
+ height: var(--control-height);
937
+ border: 0;
938
+ border-radius: var(--radius-md);
939
+ background: transparent;
940
+ color: var(--color-text-muted);
941
+ font: inherit;
942
+ font-size: var(--text-lg);
943
+ cursor: pointer;
944
+ }
945
+
946
+ .icon-button:hover {
947
+ background: var(--color-tint);
948
+ color: var(--color-text);
949
+ }
950
+
951
+ .panel-scroll {
952
+ overflow: auto;
953
+ overscroll-behavior: contain;
954
+ }
955
+
956
+ .panel-top {
957
+ padding: var(--space-4);
958
+ }
959
+
960
+ .panel-title {
961
+ margin: 0 0 var(--space-3);
962
+ font-family: var(--font-display);
963
+ font-size: var(--text-xl);
964
+ font-weight: 650;
965
+ line-height: var(--leading-tight);
966
+ overflow-wrap: anywhere;
967
+ text-wrap: balance;
968
+ }
969
+
970
+ .state-row {
971
+ display: flex;
972
+ flex-wrap: wrap;
973
+ align-items: center;
974
+ gap: var(--space-2) var(--space-3);
975
+ }
976
+
977
+ .column-pill {
978
+ display: inline-flex;
979
+ align-items: center;
980
+ height: 1.625rem;
981
+ padding: 0 var(--space-3);
982
+ border: 1px solid var(--color-border-strong);
983
+ border-radius: var(--radius-lg);
984
+ font-size: var(--text-sm);
985
+ font-weight: 600;
986
+ }
987
+
988
+ .panel-body {
989
+ display: grid;
990
+ grid-template-columns: minmax(0, 1fr);
991
+ gap: var(--space-5);
992
+ padding: 0 var(--space-4) var(--space-6);
993
+ }
994
+
995
+ .panel-main {
996
+ min-width: 0;
997
+ }
998
+
999
+ .panel-side {
1000
+ display: grid;
1001
+ gap: var(--space-4);
1002
+ order: -1;
1003
+ }
1004
+
1005
+ .facts {
1006
+ display: grid;
1007
+ grid-template-columns: 6.5rem minmax(0, 1fr);
1008
+ gap: var(--space-3);
1009
+ margin: 0;
1010
+ font-size: var(--text-base);
1011
+ }
1012
+
1013
+ .facts dt {
1014
+ color: var(--color-text-muted);
1015
+ line-height: 1.25rem;
1016
+ }
1017
+
1018
+ .facts dd {
1019
+ display: flex;
1020
+ flex-wrap: wrap;
1021
+ align-items: center;
1022
+ gap: var(--space-1) var(--space-2);
1023
+ min-width: 0;
1024
+ margin: 0;
1025
+ line-height: 1.25rem;
1026
+ }
1027
+
1028
+ .muted {
1029
+ color: var(--color-text-muted);
1030
+ }
1031
+
1032
+ .panel-top .status-line {
1033
+ flex-basis: 100%;
1034
+ margin: var(--space-3) 0 0;
1035
+ font-size: var(--text-md);
1036
+ -webkit-line-clamp: unset;
1037
+ }
1038
+
1039
+ .facts .link {
1040
+ all: unset;
1041
+ display: inline-flex;
1042
+ align-items: center;
1043
+ gap: var(--space-2);
1044
+ box-sizing: border-box;
1045
+ min-width: 0;
1046
+ max-width: 100%;
1047
+ min-height: var(--chip-height);
1048
+ cursor: pointer;
1049
+ }
1050
+
1051
+ .facts .link:hover .link-title {
1052
+ text-decoration: underline;
1053
+ }
1054
+
1055
+ .parent-link:focus-visible,
1056
+ .facts .link:focus-visible,
1057
+ .subcard:focus-visible {
1058
+ outline: 2px solid var(--color-focus);
1059
+ outline-offset: 2px;
1060
+ }
1061
+
1062
+ .subcards {
1063
+ display: flex;
1064
+ flex-direction: column;
1065
+ gap: var(--space-1);
1066
+ margin: 0;
1067
+ padding: 0;
1068
+ list-style: none;
1069
+ }
1070
+
1071
+ .subcard {
1072
+ all: unset;
1073
+ display: flex;
1074
+ flex-direction: column;
1075
+ gap: var(--space-1);
1076
+ box-sizing: border-box;
1077
+ width: 100%;
1078
+ min-height: var(--control-height);
1079
+ padding: var(--space-2) var(--space-3);
1080
+ border-radius: var(--radius-md);
1081
+ box-shadow: 0 0 0 1px var(--color-border);
1082
+ cursor: pointer;
1083
+ }
1084
+
1085
+ .subcard:hover {
1086
+ background: var(--color-tint);
1087
+ }
1088
+
1089
+ .subcard-head {
1090
+ display: flex;
1091
+ align-items: baseline;
1092
+ gap: var(--space-2);
1093
+ min-width: 0;
1094
+ font-weight: 600;
1095
+ }
1096
+
1097
+ .subcard-meta {
1098
+ display: flex;
1099
+ flex-wrap: wrap;
1100
+ align-items: center;
1101
+ gap: var(--space-1) var(--space-2);
1102
+ color: var(--color-text-muted);
1103
+ font-size: var(--text-sm);
1104
+ }
1105
+
1106
+ .subcard[data-done='true'] .subcard-head {
1107
+ color: var(--color-text-muted);
1108
+ font-weight: 400;
1109
+ }
1110
+
1111
+ .panel-section {
1112
+ margin-top: var(--space-5);
1113
+ padding-top: var(--space-4);
1114
+ border-top: 1px solid var(--color-border);
1115
+ }
1116
+
1117
+ .panel-section h3 {
1118
+ margin: 0 0 var(--space-3);
1119
+ color: var(--color-text-muted);
1120
+ font-family: var(--font-display);
1121
+ font-size: var(--text-sm);
1122
+ font-weight: 700;
1123
+ letter-spacing: var(--tracking-caps);
1124
+ text-transform: uppercase;
1125
+ }
1126
+
1127
+ .panel-main > .panel-section,
1128
+ .tab-panel > .panel-section {
1129
+ margin: 0 0 var(--space-5);
1130
+ padding: 0;
1131
+ border: 0;
1132
+ }
1133
+
1134
+ /* Decision and Details: boxes beside the reading column; the decision turns orange while the card waits. */
1135
+ .panel-side > .panel-section {
1136
+ margin: 0;
1137
+ padding: var(--space-4);
1138
+ border: 1px solid var(--color-border);
1139
+ border-radius: var(--radius-lg);
1140
+ background: var(--color-raised);
1141
+ }
1142
+
1143
+ .panel-side > .panel-section[data-waiting] {
1144
+ border-color: var(--color-waiting);
1145
+ background: var(--color-waiting-wash);
1146
+ box-shadow: inset var(--edge-width) 0 0 var(--color-waiting);
1147
+ }
1148
+
1149
+ .panel-side > .panel-section[data-waiting] h3 {
1150
+ color: var(--color-text);
1151
+ }
1152
+
1153
+ /* Tabs */
1154
+ .tabs {
1155
+ display: flex;
1156
+ gap: var(--space-1);
1157
+ margin: 0 0 var(--space-4);
1158
+ overflow-x: auto;
1159
+ border-bottom: 1px solid var(--color-border);
1160
+ }
1161
+
1162
+ .tab {
1163
+ display: inline-flex;
1164
+ align-items: center;
1165
+ gap: var(--space-2);
1166
+ height: var(--control-height);
1167
+ margin-bottom: -1px;
1168
+ padding: 0 var(--space-3);
1169
+ border: 0;
1170
+ border-bottom: 2px solid transparent;
1171
+ background: transparent;
1172
+ color: var(--color-text-muted);
1173
+ font: inherit;
1174
+ font-size: var(--text-md);
1175
+ font-weight: 600;
1176
+ cursor: pointer;
1177
+ }
1178
+
1179
+ .tab:hover {
1180
+ color: var(--color-text);
1181
+ }
1182
+
1183
+ .tab[aria-selected='true'] {
1184
+ border-bottom-color: var(--color-text);
1185
+ color: var(--color-text);
1186
+ }
1187
+
1188
+ .tab .count {
1189
+ min-width: 1.25rem;
1190
+ padding: 0 var(--space-1);
1191
+ border-radius: var(--radius-sm);
1192
+ background: var(--color-tint);
1193
+ font-family: var(--font-mono);
1194
+ font-size: var(--text-xs);
1195
+ font-variant-numeric: tabular-nums;
1196
+ text-align: center;
1197
+ }
1198
+
1199
+ .tab-panel[hidden] {
1200
+ display: none;
1201
+ }
1202
+
1203
+ .tab-panel > .panel-section > h3 {
1204
+ display: none;
1205
+ }
1206
+
1207
+ .tab-panel .comment-form {
1208
+ margin: 0 0 var(--space-5);
1209
+ }
1210
+
1211
+ .tab-panel .comment-form textarea {
1212
+ min-height: 5.5rem;
1213
+ font-size: var(--text-md);
1214
+ }
1215
+
1216
+ .tab-panel ul.entries > li {
1217
+ padding: var(--space-3) var(--space-4);
1218
+ border: 1px solid var(--color-border);
1219
+ border-radius: var(--radius-md);
1220
+ background: var(--color-raised);
1221
+ }
1222
+
1223
+ .tab-panel .entry-text {
1224
+ max-width: 46rem;
1225
+ font-size: var(--text-reading);
1226
+ line-height: 1.6;
1227
+ }
1228
+
1229
+ .description {
1230
+ max-width: 46rem;
1231
+ font-size: var(--text-reading);
1232
+ line-height: 1.65;
1233
+ overflow-wrap: anywhere;
1234
+ white-space: pre-wrap;
1235
+ }
1236
+
1237
+ .row {
1238
+ display: flex;
1239
+ flex-wrap: wrap;
1240
+ gap: var(--space-2);
1241
+ margin-top: var(--space-2);
1242
+ }
1243
+
1244
+ .hint,
1245
+ .empty {
1246
+ margin: var(--space-2) 0 0;
1247
+ color: var(--color-text-muted);
1248
+ font-size: var(--text-sm);
1249
+ }
1250
+
1251
+ .empty {
1252
+ margin-top: 0;
1253
+ }
1254
+
1255
+ .hint:empty {
1256
+ display: none;
1257
+ }
1258
+
1259
+ .entries {
1260
+ display: flex;
1261
+ flex-direction: column;
1262
+ gap: var(--space-3);
1263
+ margin: 0 0 var(--space-3);
1264
+ padding: 0;
1265
+ list-style: none;
1266
+ }
1267
+
1268
+ .entry-meta {
1269
+ display: flex;
1270
+ flex-wrap: wrap;
1271
+ align-items: center;
1272
+ gap: var(--space-2);
1273
+ margin-bottom: var(--space-1);
1274
+ color: var(--color-text-muted);
1275
+ font-size: var(--text-xs);
1276
+ }
1277
+
1278
+ .entry-text {
1279
+ font-size: var(--text-md);
1280
+ overflow-wrap: anywhere;
1281
+ white-space: pre-wrap;
1282
+ }
1283
+
1284
+ /* A run's end as a dot, beside the word. */
1285
+ [data-run-state] > .entry-text::before {
1286
+ content: '';
1287
+ display: inline-block;
1288
+ width: 0.5rem;
1289
+ height: 0.5rem;
1290
+ margin-right: var(--space-2);
1291
+ border-radius: 50%;
1292
+ background: var(--color-quiet);
1293
+ }
1294
+
1295
+ [data-run-state='running'] > .entry-text::before {
1296
+ background: var(--color-running);
1297
+ }
1298
+
1299
+ [data-run-state='finished'] > .entry-text::before {
1300
+ background: var(--color-done);
1301
+ }
1302
+
1303
+ [data-run-state='failed'] > .entry-text::before {
1304
+ background: var(--color-danger);
1305
+ }
1306
+
1307
+ .comment-form {
1308
+ display: flex;
1309
+ flex-direction: column;
1310
+ align-items: flex-start;
1311
+ gap: var(--space-2);
1312
+ }
1313
+
1314
+ /* Who did it: blue an agent, ink you, an outline kanbo. */
1315
+
1316
+ .actor-chip {
1317
+ display: inline-flex;
1318
+ flex: 0 0 auto;
1319
+ align-items: center;
1320
+ gap: var(--space-1);
1321
+ height: 1.25rem;
1322
+ padding: 0 var(--space-2);
1323
+ border-radius: var(--radius-sm);
1324
+ background: var(--color-tint);
1325
+ color: var(--color-text);
1326
+ font-size: var(--text-sm);
1327
+ font-weight: 600;
1328
+ white-space: nowrap;
1329
+ }
1330
+
1331
+ .actor-chip[data-kind='agent'] {
1332
+ background: var(--color-agent-wash);
1333
+ color: var(--color-agent);
1334
+ }
1335
+
1336
+ .actor-chip[data-kind='system'] {
1337
+ background: transparent;
1338
+ box-shadow: inset 0 0 0 1px var(--color-quiet);
1339
+ color: var(--color-text-muted);
1340
+ }
1341
+
1342
+ .actor-label {
1343
+ color: var(--color-text-muted);
1344
+ font-size: var(--text-xs);
1345
+ font-weight: 500;
1346
+ }
1347
+
1348
+ /* History: a ruled timeline, a dot per actor kind. */
1349
+
1350
+ .history-day + .history-day {
1351
+ margin-top: var(--space-4);
1352
+ }
1353
+
1354
+ .history-day h4 {
1355
+ margin: 0 0 var(--space-2);
1356
+ font-size: var(--text-sm);
1357
+ font-weight: 650;
1358
+ }
1359
+
1360
+ .history-list {
1361
+ margin: 0 0 0 var(--space-1);
1362
+ padding: 0 0 0 var(--space-4);
1363
+ border-left: 1px solid color-mix(in srgb, var(--color-border-strong) 55%, transparent);
1364
+ list-style: none;
1365
+ }
1366
+
1367
+ .history-entry {
1368
+ --dot: var(--color-text);
1369
+ position: relative;
1370
+ display: grid;
1371
+ grid-template-columns: minmax(0, 1fr) auto;
1372
+ gap: var(--space-1) var(--space-2);
1373
+ padding-bottom: var(--space-3);
1374
+ font-size: var(--text-base);
1375
+ }
1376
+
1377
+ .history-entry:last-child {
1378
+ padding-bottom: 0;
1379
+ }
1380
+
1381
+ .history-entry::before {
1382
+ content: '';
1383
+ position: absolute;
1384
+ top: 0.375rem;
1385
+ left: calc(-1 * var(--space-4) - 0.25rem - 0.5px);
1386
+ width: 0.5rem;
1387
+ height: 0.5rem;
1388
+ border-radius: 50%;
1389
+ background: var(--dot);
1390
+ box-shadow: 0 0 0 3px var(--color-surface);
1391
+ }
1392
+
1393
+ .history-entry[data-kind='agent'] {
1394
+ --dot: var(--color-agent);
1395
+ }
1396
+
1397
+ .history-entry[data-kind='system']::before {
1398
+ background: var(--color-surface);
1399
+ box-shadow: inset 0 0 0 1.5px var(--color-quiet), 0 0 0 3px var(--color-surface);
1400
+ }
1401
+
1402
+ .history-what {
1403
+ display: flex;
1404
+ flex-wrap: wrap;
1405
+ align-items: center;
1406
+ gap: var(--space-1) var(--space-2);
1407
+ min-width: 0;
1408
+ }
1409
+
1410
+ .history-field {
1411
+ font-weight: 600;
1412
+ }
1413
+
1414
+ .history-time {
1415
+ color: var(--color-text-muted);
1416
+ font-size: var(--text-xs);
1417
+ line-height: 1.25rem;
1418
+ white-space: nowrap;
1419
+ }
1420
+
1421
+ .history-change {
1422
+ grid-column: 1 / -1;
1423
+ min-width: 0;
1424
+ overflow-wrap: anywhere;
1425
+ }
1426
+
1427
+ .value-from {
1428
+ color: var(--color-text-muted);
1429
+ text-decoration: line-through;
1430
+ text-decoration-thickness: 1px;
1431
+ }
1432
+
1433
+ .value-to {
1434
+ font-weight: 600;
1435
+ text-decoration: none;
1436
+ }
1437
+
1438
+ .value-from + .value-to::before {
1439
+ content: '→';
1440
+ margin: 0 var(--space-2);
1441
+ color: var(--color-text-muted);
1442
+ font-weight: 400;
1443
+ }
1444
+
1445
+ .history-text {
1446
+ grid-column: 1 / -1;
1447
+ }
1448
+
1449
+ .history-text summary {
1450
+ width: fit-content;
1451
+ font-size: var(--text-sm);
1452
+ font-weight: 600;
1453
+ text-decoration: underline dotted var(--color-border-strong);
1454
+ text-underline-offset: 3px;
1455
+ cursor: pointer;
1456
+ }
1457
+
1458
+ .history-text-pair {
1459
+ display: grid;
1460
+ gap: var(--space-2);
1461
+ margin-top: var(--space-2);
1462
+ }
1463
+
1464
+ .history-text-block {
1465
+ margin: 0;
1466
+ padding: var(--space-2) var(--space-3);
1467
+ border-radius: var(--radius-md);
1468
+ background: var(--color-raised);
1469
+ box-shadow: inset 0 0 0 1px var(--color-border);
1470
+ font-size: var(--text-base);
1471
+ overflow-wrap: anywhere;
1472
+ white-space: pre-wrap;
1473
+ }
1474
+
1475
+ .history-text-block[data-side='before'] {
1476
+ color: var(--color-text-muted);
1477
+ }
1478
+
1479
+ .history-text-block b {
1480
+ display: block;
1481
+ margin-bottom: var(--space-1);
1482
+ color: var(--color-text-muted);
1483
+ font-size: var(--text-xs);
1484
+ font-weight: 700;
1485
+ letter-spacing: var(--tracking-caps);
1486
+ text-transform: uppercase;
1487
+ }
1488
+
1489
+ /* ===== layout ===== */
1490
+
1491
+ /* Top bar, notice, filter bar, board; the panel beside or over them. */
1492
+ .app {
1493
+ display: grid;
1494
+ grid-template-rows: auto auto auto minmax(0, 1fr);
1495
+ grid-template-columns: minmax(0, 1fr);
1496
+ height: 100vh;
1497
+ height: 100dvh;
1498
+ }
1499
+
1500
+ .topbar {
1501
+ display: flex;
1502
+ flex-wrap: wrap;
1503
+ grid-row: 1;
1504
+ grid-column: 1 / -1;
1505
+ align-items: center;
1506
+ gap: var(--space-2) var(--space-3);
1507
+ padding: var(--space-2) var(--space-3);
1508
+ border-bottom: 1px solid var(--color-border);
1509
+ background: var(--color-surface);
1510
+ }
1511
+
1512
+ .project-slot {
1513
+ display: flex;
1514
+ flex: 1 1 12rem;
1515
+ min-width: 0;
1516
+ }
1517
+
1518
+ .project-slot:empty {
1519
+ display: none;
1520
+ }
1521
+
1522
+ .project-switcher {
1523
+ flex: 1 1 auto;
1524
+ }
1525
+
1526
+ .workspace {
1527
+ flex: 1 1 10rem;
1528
+ }
1529
+
1530
+ .notice {
1531
+ grid-row: 2;
1532
+ grid-column: 1;
1533
+ }
1534
+
1535
+ .filter-slot {
1536
+ grid-row: 3;
1537
+ grid-column: 1;
1538
+ min-width: 0;
1539
+ }
1540
+
1541
+ .filter-bar {
1542
+ display: flex;
1543
+ align-items: center;
1544
+ gap: var(--space-2);
1545
+ padding: var(--space-2) var(--space-3);
1546
+ overflow-x: auto;
1547
+ border-bottom: 1px solid var(--color-border);
1548
+ background: var(--color-surface);
1549
+ scrollbar-width: none;
1550
+ }
1551
+
1552
+ /* Phone: the bar scrolls sideways; search, the count and Clear come first. */
1553
+ .filter-bar > * {
1554
+ flex-shrink: 0;
1555
+ }
1556
+
1557
+ .filter-search {
1558
+ order: -3;
1559
+ }
1560
+
1561
+ .filter-count {
1562
+ order: -2;
1563
+ }
1564
+
1565
+ .filter-clear {
1566
+ order: -1;
1567
+ }
1568
+
1569
+ /* The height left under the bars, whatever theirs; columns scroll alone. */
1570
+ .board {
1571
+ display: flex;
1572
+ grid-row: 4;
1573
+ grid-column: 1;
1574
+ align-items: stretch;
1575
+ gap: var(--space-2);
1576
+ min-height: 0;
1577
+ padding: var(--space-3);
1578
+ overflow-x: auto;
1579
+ overflow-y: hidden;
1580
+ scroll-padding: var(--space-3);
1581
+ scroll-snap-type: x mandatory;
1582
+ }
1583
+
1584
+ .panel-host {
1585
+ position: fixed;
1586
+ inset: 0;
1587
+ z-index: var(--z-overlay);
1588
+ display: grid;
1589
+ place-items: center;
1590
+ background: var(--color-scrim);
1591
+ }
1592
+
1593
+ .panel-host:empty {
1594
+ display: none;
1595
+ }
1596
+
1597
+ .panel {
1598
+ display: grid;
1599
+ grid-template-rows: auto minmax(0, 1fr);
1600
+ width: 100%;
1601
+ height: 100%;
1602
+ overflow: hidden;
1603
+ background: var(--color-surface);
1604
+ }
1605
+
1606
+ @media (min-width: 40rem) {
1607
+ .topbar {
1608
+ flex-wrap: nowrap;
1609
+ gap: var(--space-4);
1610
+ padding: var(--space-2) var(--space-4);
1611
+ }
1612
+
1613
+ .project-slot {
1614
+ flex: 0 1 auto;
1615
+ }
1616
+
1617
+ .workspace {
1618
+ flex: 1 1 auto;
1619
+ }
1620
+
1621
+ .token-form {
1622
+ margin-left: auto;
1623
+ }
1624
+
1625
+ .token-input {
1626
+ width: 9rem;
1627
+ }
1628
+
1629
+ .topbar[data-token] .token-toggle {
1630
+ display: none;
1631
+ }
1632
+
1633
+ .topbar[data-token='folded'] .token-form {
1634
+ display: flex;
1635
+ }
1636
+
1637
+ .filter-bar {
1638
+ flex-wrap: wrap;
1639
+ padding: var(--space-2) var(--space-4);
1640
+ overflow: visible;
1641
+ }
1642
+
1643
+ .filter-search {
1644
+ flex-basis: 13rem;
1645
+ }
1646
+
1647
+ .filter-group {
1648
+ flex-shrink: 1;
1649
+ min-width: 0;
1650
+ }
1651
+
1652
+ .filter-search,
1653
+ .filter-count,
1654
+ .filter-clear {
1655
+ order: 0;
1656
+ }
1657
+
1658
+ .filter-count {
1659
+ margin-left: auto;
1660
+ }
1661
+
1662
+ .board {
1663
+ padding: var(--space-3) var(--space-4);
1664
+ scroll-snap-type: none;
1665
+ }
1666
+
1667
+ .column {
1668
+ flex: 1 0 var(--column-width);
1669
+ }
1670
+ }
1671
+
1672
+ /* Wide: the card is a dialog over the dimmed board; the decision and details stay beside the text. */
1673
+ @media (min-width: 56.25rem) {
1674
+ .panel-host {
1675
+ padding: var(--space-6);
1676
+ }
1677
+
1678
+ .panel {
1679
+ width: min(var(--dialog-width), 100%);
1680
+ height: min(100%, 58rem);
1681
+ border: 1px solid var(--color-border);
1682
+ border-radius: var(--radius-lg);
1683
+ box-shadow: var(--shadow-panel);
1684
+ }
1685
+
1686
+ .panel-head {
1687
+ padding-left: var(--space-6);
1688
+ }
1689
+
1690
+ .panel-top {
1691
+ padding: var(--space-5) var(--space-6) var(--space-4);
1692
+ }
1693
+
1694
+ .panel-title {
1695
+ max-width: 48rem;
1696
+ font-size: var(--text-2xl);
1697
+ }
1698
+
1699
+ .panel-body {
1700
+ grid-template-columns: minmax(0, 1fr) var(--dialog-side-width);
1701
+ align-items: start;
1702
+ gap: var(--space-6);
1703
+ padding: 0 var(--space-6) var(--space-7);
1704
+ }
1705
+
1706
+ .panel-side {
1707
+ position: sticky;
1708
+ top: var(--space-4);
1709
+ order: 0;
1710
+ }
1711
+ }
1712
+
1713
+ /* ===== motion =====
1714
+ * Only: the panel's first opening, a card new or moved since the last render,
1715
+ * the drop target, a press, the run dot, a badge once when a card starts
1716
+ * waiting. `data-enter` and `.panel--opening` are set only then: a poll moves nothing.
1717
+ */
1718
+
1719
+ @media (prefers-reduced-motion: no-preference) {
1720
+ .panel--opening {
1721
+ animation: panel-in var(--duration-slow) var(--ease-out);
1722
+ }
1723
+
1724
+ .card[data-enter] {
1725
+ animation: card-in var(--duration-base) var(--ease-out);
1726
+ }
1727
+
1728
+ .waiting-badge[data-enter='waiting'] {
1729
+ animation: waiting-call var(--duration-loop) var(--ease-out) 1;
1730
+ }
1731
+
1732
+ .run-dot::after {
1733
+ animation: run-ping var(--duration-loop) var(--ease-in-out) infinite;
1734
+ }
1735
+ }
1736
+
1737
+ @keyframes panel-in {
1738
+ from {
1739
+ opacity: 0;
1740
+ transform: scale(0.98);
1741
+ }
1742
+ }
1743
+
1744
+ @keyframes card-in {
1745
+ from {
1746
+ opacity: 0;
1747
+ transform: translateY(var(--space-1));
1748
+ }
1749
+ }
1750
+
1751
+ @keyframes waiting-call {
1752
+ from {
1753
+ box-shadow: 0 0 0 0 color-mix(in srgb, var(--color-waiting) 70%, transparent);
1754
+ }
1755
+
1756
+ to {
1757
+ box-shadow: 0 0 0 var(--space-2) color-mix(in srgb, var(--color-waiting) 0%, transparent);
1758
+ }
1759
+ }
1760
+
1761
+ @keyframes run-ping {
1762
+ 0% {
1763
+ opacity: 0.55;
1764
+ transform: scale(1);
1765
+ }
1766
+
1767
+ 70%,
1768
+ 100% {
1769
+ opacity: 0;
1770
+ transform: scale(2.75);
1771
+ }
477
1772
  }