@yemi33/minions 0.1.2100 → 0.1.2102

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.
@@ -0,0 +1,1128 @@
1
+ /* ---------------------------------------------------------------
2
+ Slim UX prototype — gated by the 'slim-ux' feature flag.
3
+ Plain HTML/CSS/vanilla JS so the human can edit this file
4
+ directly. The dashboard reads this from disk on each request,
5
+ so a page refresh shows the latest edit (no server restart).
6
+
7
+ Round-3 layout (W-moxkqfaw): three sections instead of two
8
+ panels — ACTIONS / STATUS / HISTORY. See
9
+ docs/slim-ux/concepts.md for the language we're standardizing
10
+ around, and architecture-suggestions.md for the data-shape
11
+ changes that would make this UX cheaper to maintain.
12
+ --------------------------------------------------------------- */
13
+ :root {
14
+ --bg: #0d1117;
15
+ --surface: #161b22;
16
+ --surface2: #1c2128;
17
+ --border: #30363d;
18
+ --text: #c9d1d9;
19
+ --muted: #8b949e;
20
+ --blue: #58a6ff;
21
+ --green: #3fb950;
22
+ --amber: #d29922;
23
+ --red: #f85149;
24
+ --radius: 6px;
25
+ }
26
+
27
+ * { box-sizing: border-box; }
28
+
29
+ /* Typography baseline (slim UX foundation phase).
30
+ Existing dashboard uses 'Segoe UI' / 14px on body — see styles.css.
31
+ Round-2 bumped to 15px; round-3 bumps once more to 16px because the
32
+ human flagged the slim as still feeling cramped. The scale below is
33
+ proportional to 16px (h1 22, h2 18, label 11). The existing
34
+ dashboard stays untouched. */
35
+ html, body {
36
+ margin: 0;
37
+ padding: 0;
38
+ height: 100vh;
39
+ width: 100%;
40
+ overflow: hidden;
41
+ background: var(--bg);
42
+ color: var(--text);
43
+ font-family: 'Segoe UI', system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
44
+ font-size: 16px;
45
+ line-height: 1.5;
46
+ }
47
+
48
+ /* ── Scrollbars ───────────────────────────────────────────────
49
+ Replace the chunky OS-default bars with slim, theme-matched ones.
50
+ Track is transparent (shows the element background through), and the
51
+ thumb uses a transparent border + background-clip so it reads as a thin
52
+ bar that blends with whatever surface it sits on. Firefox uses the
53
+ scrollbar-width / scrollbar-color shorthands. */
54
+ * { scrollbar-width: thin; scrollbar-color: var(--border) transparent; }
55
+ ::-webkit-scrollbar { width: 10px; height: 10px; }
56
+ ::-webkit-scrollbar-track { background: transparent; }
57
+ ::-webkit-scrollbar-thumb {
58
+ background: var(--border);
59
+ border-radius: 8px;
60
+ border: 2px solid transparent;
61
+ background-clip: padding-box;
62
+ }
63
+ ::-webkit-scrollbar-thumb:hover { background: var(--muted); background-clip: padding-box; }
64
+ ::-webkit-scrollbar-corner { background: transparent; }
65
+
66
+ /* Inside chat responses (code blocks + the tool panel) keep them even more
67
+ discreet: slimmer and a faint muted tint. */
68
+ .chat-msg pre, .chat-tools { scrollbar-color: rgba(139, 148, 158, 0.28) transparent; }
69
+ .chat-msg pre::-webkit-scrollbar, .chat-tools::-webkit-scrollbar { width: 7px; height: 7px; }
70
+ .chat-msg pre::-webkit-scrollbar-thumb, .chat-tools::-webkit-scrollbar-thumb {
71
+ background: rgba(139, 148, 158, 0.28);
72
+ border: none;
73
+ border-radius: 4px;
74
+ }
75
+ .chat-msg pre::-webkit-scrollbar-thumb:hover, .chat-tools::-webkit-scrollbar-thumb:hover {
76
+ background: rgba(139, 148, 158, 0.5);
77
+ }
78
+
79
+ /* ── Top bar ──────────────────────────────────────────────── */
80
+ .topbar {
81
+ display: flex;
82
+ align-items: center;
83
+ justify-content: space-between;
84
+ padding: 8px 18px;
85
+ background: var(--surface);
86
+ border-bottom: 1px solid var(--border);
87
+ height: 46px;
88
+ flex-shrink: 0;
89
+ }
90
+ .topbar-title {
91
+ font-weight: 600;
92
+ font-size: 15px;
93
+ color: var(--text);
94
+ letter-spacing: 0.3px;
95
+ }
96
+ .topbar-title .badge {
97
+ display: inline-block;
98
+ margin-left: 8px;
99
+ padding: 1px 6px;
100
+ font-size: 12px;
101
+ font-weight: 700;
102
+ letter-spacing: 0.5px;
103
+ color: var(--blue);
104
+ border: 1px solid var(--blue);
105
+ border-radius: 3px;
106
+ vertical-align: 2px;
107
+ }
108
+ .topbar-actions { display: flex; align-items: center; gap: 8px; }
109
+ .icon-btn {
110
+ background: none;
111
+ border: none;
112
+ cursor: pointer;
113
+ color: var(--muted);
114
+ font-size: 20px;
115
+ line-height: 1;
116
+ padding: 6px 10px;
117
+ border-radius: var(--radius);
118
+ }
119
+ .icon-btn:hover { color: var(--text); background: var(--surface2); }
120
+
121
+ /* ── Layout grid ──────────────────────────────────────────────
122
+ Left column: ACTIONS (chat + action buttons) — visually dominant.
123
+ Right column: STATUS on top, HISTORY underneath.
124
+ The whole grid is sized to its content (`fit-content`) and centered
125
+ on wide monitors. minmax(0, …) keeps columns from overflowing on
126
+ narrow viewports. */
127
+ .layout {
128
+ display: grid;
129
+ grid-template-columns: minmax(0, 820px) minmax(0, 548px);
130
+ grid-template-rows: 1fr 1fr;
131
+ grid-template-areas:
132
+ "actions status"
133
+ "actions history";
134
+ gap: 10px;
135
+ padding: 10px;
136
+ width: fit-content;
137
+ max-width: 100%;
138
+ margin: 0 auto;
139
+ height: calc(100vh - 46px);
140
+ }
141
+ .panel {
142
+ background: var(--surface);
143
+ border: 1px solid var(--border);
144
+ border-radius: var(--radius);
145
+ display: flex;
146
+ flex-direction: column;
147
+ min-height: 0;
148
+ min-width: 0;
149
+ overflow: hidden;
150
+ }
151
+ .panel-header {
152
+ padding: 9px 14px;
153
+ font-size: 12px;
154
+ font-weight: 700;
155
+ letter-spacing: 0.7px;
156
+ text-transform: uppercase;
157
+ color: var(--muted);
158
+ border-bottom: 1px solid var(--border);
159
+ flex-shrink: 0;
160
+ display: flex;
161
+ align-items: center;
162
+ justify-content: space-between;
163
+ }
164
+ .panel-header .panel-sub {
165
+ text-transform: none;
166
+ letter-spacing: 0;
167
+ font-weight: 400;
168
+ color: var(--muted);
169
+ font-size: 12px;
170
+ }
171
+ .panel-body {
172
+ flex: 1;
173
+ overflow-y: auto;
174
+ padding: 14px;
175
+ min-height: 0;
176
+ }
177
+ .panel-placeholder {
178
+ color: var(--muted);
179
+ font-style: italic;
180
+ font-size: 14px;
181
+ }
182
+
183
+ .panel-actions { grid-area: actions; }
184
+ .panel-status { grid-area: status; }
185
+ .panel-history { grid-area: history; }
186
+
187
+ /* ── Actions panel: chat + action buttons ───────────────────── */
188
+ /* The chat fills the panel above the action button row. Same IDs and
189
+ class names as the previous slim chatbox so the IIFE wiring below
190
+ continues to work without changes. */
191
+ .actions-chat {
192
+ flex: 1;
193
+ display: flex;
194
+ flex-direction: column;
195
+ min-height: 0;
196
+ }
197
+ .chat-messages {
198
+ flex: 1;
199
+ overflow-y: auto;
200
+ padding: 12px;
201
+ display: flex;
202
+ flex-direction: column;
203
+ gap: 10px;
204
+ min-height: 0;
205
+ width: 100%;
206
+ max-width: 800px;
207
+ margin-left: auto;
208
+ margin-right: auto;
209
+ }
210
+ .chat-empty {
211
+ color: var(--muted);
212
+ font-size: 14px;
213
+ font-style: italic;
214
+ text-align: center;
215
+ margin-top: 24px;
216
+ }
217
+ .chat-msg {
218
+ max-width: 90%;
219
+ padding: 10px 14px;
220
+ border-radius: var(--radius);
221
+ white-space: pre-wrap;
222
+ word-wrap: break-word;
223
+ font-size: 16px;
224
+ }
225
+ .chat-msg.user {
226
+ align-self: flex-end;
227
+ background: var(--blue);
228
+ color: #fff;
229
+ }
230
+ .chat-msg.assistant {
231
+ align-self: flex-start;
232
+ background: var(--surface2);
233
+ color: var(--text);
234
+ border: 1px solid var(--border);
235
+ }
236
+ .chat-msg.system {
237
+ align-self: center;
238
+ background: transparent;
239
+ color: var(--muted);
240
+ font-size: 13px;
241
+ font-style: italic;
242
+ }
243
+ .chat-msg.error {
244
+ align-self: flex-start;
245
+ background: rgba(248, 81, 73, 0.1);
246
+ color: var(--red);
247
+ border: 1px solid var(--red);
248
+ font-size: 14px;
249
+ }
250
+ .chat-input-wrap {
251
+ display: flex;
252
+ gap: 8px;
253
+ padding: 10px 12px;
254
+ border-top: 1px solid var(--border);
255
+ flex-shrink: 0;
256
+ background: var(--surface);
257
+ width: 100%;
258
+ max-width: 800px;
259
+ margin-left: auto;
260
+ margin-right: auto;
261
+ }
262
+
263
+ /* "Working in: <project>" strip sits between the message list and the
264
+ input row so the active project is always visible while composing.
265
+ Selection persists in localStorage and is sent to /api/command-center
266
+ so CC can default action.project without the user having to name it. */
267
+ .chat-context-strip {
268
+ display: flex;
269
+ align-items: center;
270
+ gap: 10px;
271
+ padding: 6px 12px;
272
+ border-top: 1px solid var(--border);
273
+ flex-shrink: 0;
274
+ background: var(--surface);
275
+ width: 100%;
276
+ max-width: 800px;
277
+ margin-left: auto;
278
+ margin-right: auto;
279
+ font-size: 12px;
280
+ color: var(--muted);
281
+ }
282
+ .chat-context-strip .context-label {
283
+ text-transform: uppercase;
284
+ letter-spacing: 0.5px;
285
+ font-weight: 700;
286
+ font-size: 12px;
287
+ }
288
+ .chat-context-strip select {
289
+ background: var(--bg);
290
+ color: var(--text);
291
+ border: 1px solid var(--border);
292
+ border-radius: var(--radius);
293
+ padding: 4px 8px;
294
+ font-family: inherit;
295
+ font-size: 12px;
296
+ cursor: pointer;
297
+ }
298
+ .chat-context-strip select:focus { outline: none; border-color: var(--blue); }
299
+ .chat-context-strip .context-static {
300
+ color: var(--text);
301
+ font-weight: 500;
302
+ }
303
+ .chat-context-strip .context-empty {
304
+ font-style: italic;
305
+ }
306
+ .chat-context-strip .context-add {
307
+ margin-left: auto;
308
+ background: none;
309
+ color: var(--blue);
310
+ border: 1px solid var(--border);
311
+ border-radius: var(--radius);
312
+ padding: 3px 9px;
313
+ font-size: 12px;
314
+ cursor: pointer;
315
+ line-height: 1;
316
+ }
317
+ .chat-context-strip .context-add:hover {
318
+ background: var(--surface2);
319
+ border-color: var(--blue);
320
+ }
321
+ .chat-input {
322
+ flex: 1;
323
+ padding: 10px 12px;
324
+ background: var(--bg);
325
+ color: var(--text);
326
+ border: 1px solid var(--border);
327
+ border-radius: var(--radius);
328
+ font-size: 16px;
329
+ font-family: inherit;
330
+ resize: none;
331
+ /* >= 2 lines visible by default. 16px font * 1.5 line-height = 24px/line,
332
+ x 2 = 48px content + 20px vertical padding + 2px border ~= 70px. */
333
+ min-height: 70px;
334
+ max-height: 150px;
335
+ }
336
+ .chat-input:focus { outline: none; border-color: var(--blue); }
337
+ .chat-send {
338
+ padding: 10px 18px;
339
+ background: var(--blue);
340
+ color: #fff;
341
+ border: none;
342
+ border-radius: var(--radius);
343
+ font-size: 14px;
344
+ font-weight: 600;
345
+ cursor: pointer;
346
+ align-self: flex-end;
347
+ }
348
+ .chat-send:hover { filter: brightness(1.1); }
349
+ .chat-send:disabled { opacity: 0.5; cursor: not-allowed; }
350
+ .chat-stop {
351
+ padding: 10px 14px;
352
+ background: var(--surface2);
353
+ color: var(--red);
354
+ border: 1px solid var(--border);
355
+ border-radius: var(--radius);
356
+ font-size: 13px;
357
+ cursor: pointer;
358
+ align-self: flex-end;
359
+ display: none;
360
+ }
361
+ .chat-stop:hover { filter: brightness(1.1); }
362
+
363
+ /* Tool-call progress panel + thinking indicator. While streaming, the
364
+ thinking indicator sits at the bottom-left of the response card and the
365
+ tool panel to its right; on completion the thinking indicator is removed
366
+ and the panel stays put at the bottom of the card. */
367
+ .chat-toolbar {
368
+ display: flex;
369
+ align-items: flex-start;
370
+ gap: 12px;
371
+ margin-top: 14px;
372
+ }
373
+ /* Collapsed tool panel: at most 3 non-wrapping lines, scrolls (newest at
374
+ the bottom) once there are more. Clicking opens the full list in a modal. */
375
+ .chat-tools-panel {
376
+ width: 100%; /* full card width once the response is done */
377
+ min-width: 0;
378
+ background: var(--surface);
379
+ border: 1px solid var(--border);
380
+ border-radius: var(--radius);
381
+ padding: 4px 8px;
382
+ cursor: pointer;
383
+ transition: border-color 0.2s;
384
+ }
385
+ /* While streaming, the panel fills the space remaining to the right of the
386
+ thinking UI (which keeps its natural width). */
387
+ .chat-msg.streaming .chat-tools-panel {
388
+ flex: 1;
389
+ min-width: 0;
390
+ }
391
+ .chat-tools-panel:hover { border-color: var(--blue); }
392
+ .chat-tools-panel:focus-visible { outline: 2px solid var(--blue); outline-offset: 1px; }
393
+ .chat-tools {
394
+ /* Block (not flex): a flex column with max-height shrinks its items to
395
+ fit and they overlap. Block keeps each line's height and the box
396
+ scrolls once there are more than 3. */
397
+ max-height: 54px; /* 3 lines at 12px / 1.5 line-height */
398
+ overflow-y: auto;
399
+ }
400
+ .chat-tool {
401
+ color: var(--muted);
402
+ font-size: 12px;
403
+ line-height: 1.5;
404
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
405
+ white-space: nowrap;
406
+ overflow: hidden;
407
+ text-overflow: ellipsis;
408
+ }
409
+ .chat-tool::before { content: "● "; }
410
+
411
+ /* Tool-calls modal: full list, wrapped so long commands are readable. */
412
+ .tools-modal-line {
413
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
414
+ font-size: 12px;
415
+ color: var(--text);
416
+ padding: 5px 0;
417
+ border-bottom: 1px solid var(--border);
418
+ white-space: pre-wrap;
419
+ word-break: break-word;
420
+ }
421
+ .tools-modal-line::before { content: "● "; color: var(--muted); }
422
+ .tools-modal-line:last-child { border-bottom: none; }
423
+ .tools-modal-empty { color: var(--muted); font-style: italic; font-size: 13px; }
424
+ /* Wide enough to span the Actions + Status columns (820 + 10 gap + 548). */
425
+ #slim-tools-modal .modal {
426
+ width: 1378px;
427
+ max-width: calc(100vw - 32px);
428
+ }
429
+
430
+ /* Cockpit-tile detail modal: list of dispatches / PRs / watches, or a
431
+ key/value engine readout (reuses .agent-detail-row). */
432
+ #slim-tile-modal .modal { width: 720px; max-width: calc(100vw - 32px); }
433
+ .tile-item {
434
+ display: block;
435
+ text-decoration: none;
436
+ color: inherit;
437
+ background: var(--surface2);
438
+ border: 1px solid var(--border);
439
+ border-radius: var(--radius);
440
+ padding: 8px 10px;
441
+ margin-bottom: 8px;
442
+ }
443
+ .tile-item:last-child { margin-bottom: 0; }
444
+ a.tile-item:hover { border-color: var(--blue); }
445
+ .tile-item-top { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
446
+ .tile-item-title {
447
+ font-size: 14px; font-weight: 600; color: var(--text);
448
+ min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
449
+ }
450
+ .tile-item-meta { font-size: 12px; color: var(--muted); margin-top: 3px; word-break: break-word; }
451
+ .tile-chip {
452
+ flex: 0 0 auto;
453
+ font-size: 12px; font-weight: 700; letter-spacing: 0.4px; text-transform: uppercase;
454
+ padding: 1px 7px; border-radius: 10px;
455
+ background: var(--surface); border: 1px solid var(--border); color: var(--muted);
456
+ }
457
+ .tile-chip.green { background: rgba(63, 185, 80, 0.15); color: var(--green); border-color: var(--green); }
458
+ .tile-chip.amber { background: rgba(210, 153, 34, 0.15); color: var(--amber); border-color: var(--amber); }
459
+ .tile-chip.red { background: rgba(248, 81, 73, 0.15); color: var(--red); border-color: var(--red); }
460
+ .tile-chip.blue { background: rgba(88, 166, 255, 0.12); color: var(--blue); border-color: var(--blue); }
461
+ .tile-empty { color: var(--muted); font-style: italic; font-size: 13px; }
462
+
463
+ .chat-thinking {
464
+ color: var(--muted);
465
+ font-size: 13px;
466
+ font-style: italic;
467
+ }
468
+ .chat-thinking-dots {
469
+ display: inline-flex;
470
+ gap: 3px;
471
+ margin-left: 6px;
472
+ vertical-align: middle;
473
+ }
474
+ .chat-thinking-dots > span {
475
+ width: 4px;
476
+ height: 4px;
477
+ background: var(--blue);
478
+ border-radius: 50%;
479
+ animation: dotPulse 1.2s infinite;
480
+ }
481
+ .chat-thinking-dots > span:nth-child(2) { animation-delay: 0.2s; }
482
+ .chat-thinking-dots > span:nth-child(3) { animation-delay: 0.4s; }
483
+ @keyframes dotPulse {
484
+ 0%, 80%, 100% { opacity: 0.3; }
485
+ 40% { opacity: 1; }
486
+ }
487
+
488
+ .chat-action {
489
+ align-self: flex-start;
490
+ padding: 5px 11px;
491
+ border-radius: 4px;
492
+ font-size: 12px;
493
+ border: 1px dashed var(--border);
494
+ color: var(--muted);
495
+ }
496
+ .chat-action.ok { color: var(--green); }
497
+ .chat-action.warn { color: var(--amber); }
498
+ .chat-action.err { color: var(--red); }
499
+
500
+ /* Lightweight markdown styling inside assistant bubbles. */
501
+ .chat-msg.assistant code,
502
+ .chat-msg.assistant pre {
503
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
504
+ }
505
+ .chat-msg.assistant code {
506
+ background: var(--bg);
507
+ padding: 1px 4px;
508
+ border-radius: 3px;
509
+ font-size: 0.9em;
510
+ }
511
+ .chat-msg.assistant pre {
512
+ background: var(--bg);
513
+ padding: 10px;
514
+ border-radius: 4px;
515
+ overflow-x: auto;
516
+ font-size: 14px;
517
+ margin: 6px 0;
518
+ }
519
+ .chat-msg.assistant pre code { background: none; padding: 0; }
520
+ .chat-msg.assistant a { color: var(--blue); }
521
+ .chat-msg.assistant strong { color: var(--text); }
522
+
523
+ /* ── Action footer: square action buttons (one for now: Link PR) ── */
524
+ .actions-buttons {
525
+ flex-shrink: 0;
526
+ display: grid;
527
+ grid-template-columns: repeat(4, 1fr);
528
+ gap: 8px;
529
+ padding: 10px 12px 12px;
530
+ border-top: 1px solid var(--border);
531
+ width: 100%;
532
+ max-width: 800px;
533
+ margin-left: auto;
534
+ margin-right: auto;
535
+ }
536
+ .link-pr-btn {
537
+ background: var(--surface2);
538
+ color: var(--text);
539
+ border: 1px solid var(--border);
540
+ border-radius: var(--radius);
541
+ padding: 10px 12px;
542
+ cursor: pointer;
543
+ font-size: 13px;
544
+ font-family: inherit;
545
+ display: flex;
546
+ flex-direction: column;
547
+ align-items: center;
548
+ gap: 2px;
549
+ text-align: center;
550
+ transition: border-color 0.15s, background 0.15s, color 0.15s;
551
+ }
552
+ .link-pr-btn:hover { border-color: var(--green); background: var(--surface); color: var(--green); }
553
+ .link-pr-btn .link-pr-icon { font-size: 16px; }
554
+ .link-pr-btn .link-pr-label { font-weight: 600; }
555
+ .link-pr-btn .link-pr-sub { font-size: 12px; color: var(--muted); }
556
+
557
+ /* Link-PR dialog fields + the "+ Link PR" chip (tile corner + modal header). */
558
+ .linkpr-label { display: block; color: var(--text); font-size: 13px; margin-bottom: 10px; }
559
+ .linkpr-input {
560
+ display: block; width: 100%; margin-top: 4px; padding: 7px 9px;
561
+ background: var(--bg); border: 1px solid var(--border); border-radius: var(--radius);
562
+ color: var(--text); font-size: 13px; font-family: inherit; resize: vertical;
563
+ }
564
+ .linkpr-input:focus { outline: none; border-color: var(--blue); }
565
+ .linkpr-check { display: flex; align-items: center; gap: 8px; color: var(--text); font-size: 13px; cursor: pointer; margin-bottom: 4px; }
566
+ .linkpr-check input { width: 16px; height: 16px; accent-color: var(--blue); }
567
+ .linkpr-hint-inline { color: var(--muted); font-weight: 400; }
568
+ .linkpr-hint { font-size: 12px; color: var(--muted); padding-left: 24px; }
569
+ .linkpr-warning {
570
+ padding: 8px 12px; margin-bottom: 10px;
571
+ background: rgba(210, 153, 34, 0.15); border: 1px solid rgba(210, 153, 34, 0.3);
572
+ border-radius: var(--radius); font-size: 13px; line-height: 1.5; color: var(--text);
573
+ }
574
+ .linkpr-warning-title { font-weight: 700; margin-bottom: 2px; color: var(--amber); }
575
+ .linkpr-chip {
576
+ font-size: 12px; font-weight: 600;
577
+ padding: 1px 8px; border-radius: 10px;
578
+ background: rgba(63, 185, 80, 0.12); color: var(--green); border: 1px solid var(--green);
579
+ cursor: pointer; font-family: inherit;
580
+ }
581
+ .linkpr-chip:hover { filter: brightness(1.2); }
582
+ .linkpr-chip.on-tile { position: absolute; top: 8px; right: 8px; z-index: 1; }
583
+
584
+ /* ── Status panel: cockpit tiles ─────────────────────────────
585
+ Tiles light up when their value is non-zero or their state is
586
+ 'active'. Dim grey otherwise. The whole panel polls /api/status
587
+ every 5s.
588
+
589
+ Tile state classes drive the colored dot + glow. Adding a new
590
+ indicator: append a tile DOM node + a key in the COCKPIT_TILES
591
+ table inside the IIFE. */
592
+ .cockpit-grid {
593
+ display: grid;
594
+ grid-template-columns: repeat(2, 1fr);
595
+ gap: 8px;
596
+ }
597
+ .cockpit-tile {
598
+ background: var(--surface2);
599
+ border: 1px solid var(--border);
600
+ border-radius: var(--radius);
601
+ padding: 10px 12px;
602
+ display: flex;
603
+ flex-direction: column;
604
+ gap: 4px;
605
+ transition: border-color 0.2s, background 0.2s;
606
+ }
607
+ .cockpit-tile.lit-blue {
608
+ border-color: rgba(88, 166, 255, 0.6);
609
+ background: rgba(88, 166, 255, 0.06);
610
+ }
611
+ .cockpit-tile.lit-green {
612
+ border-color: rgba(63, 185, 80, 0.6);
613
+ background: rgba(63, 185, 80, 0.06);
614
+ }
615
+ .cockpit-tile.lit-amber {
616
+ border-color: rgba(210, 153, 34, 0.6);
617
+ background: rgba(210, 153, 34, 0.06);
618
+ }
619
+ .cockpit-tile.lit-red {
620
+ border-color: rgba(248, 81, 73, 0.6);
621
+ background: rgba(248, 81, 73, 0.08);
622
+ }
623
+ .cockpit-label {
624
+ font-size: 12px;
625
+ font-weight: 700;
626
+ letter-spacing: 0.6px;
627
+ text-transform: uppercase;
628
+ color: var(--muted);
629
+ display: flex;
630
+ align-items: center;
631
+ gap: 6px;
632
+ }
633
+ .cockpit-dot {
634
+ display: inline-block;
635
+ width: 8px;
636
+ height: 8px;
637
+ border-radius: 50%;
638
+ background: var(--border);
639
+ }
640
+ .lit-blue .cockpit-dot { background: var(--blue); box-shadow: 0 0 6px var(--blue); }
641
+ .lit-green .cockpit-dot { background: var(--green); box-shadow: 0 0 6px var(--green); }
642
+ .lit-amber .cockpit-dot { background: var(--amber); box-shadow: 0 0 6px var(--amber); }
643
+ .lit-red .cockpit-dot { background: var(--red); box-shadow: 0 0 6px var(--red); }
644
+ .cockpit-value {
645
+ font-size: 22px;
646
+ font-weight: 700;
647
+ color: var(--text);
648
+ line-height: 1;
649
+ }
650
+ .cockpit-value.dim { color: var(--muted); }
651
+ .cockpit-detail {
652
+ font-size: 12px;
653
+ color: var(--muted);
654
+ line-height: 1.3;
655
+ min-height: 14px;
656
+ }
657
+ /* Cockpit tiles are clickable -> detail modal. */
658
+ .cockpit-tile { cursor: pointer; position: relative; }
659
+ .cockpit-tile:hover { border-color: var(--blue); }
660
+ .cockpit-tile:focus-visible { outline: 2px solid var(--blue); outline-offset: 1px; }
661
+
662
+ /* ── Status panel sub-divisions: Team cards over System tiles,
663
+ separated by a divider line (no text headers). ──── */
664
+ .team-section { margin-bottom: 14px; }
665
+ .cockpit-section { padding-top: 14px; border-top: 1px solid var(--border); }
666
+
667
+ /* Square member cards. Auto-fill so the column count adapts to the
668
+ panel width; aspect-ratio keeps each card square regardless. */
669
+ .member-grid {
670
+ display: grid;
671
+ grid-template-columns: repeat(auto-fill, minmax(96px, 1fr));
672
+ gap: 8px;
673
+ }
674
+ .member-empty {
675
+ grid-column: 1 / -1;
676
+ color: var(--muted);
677
+ font-size: 13px;
678
+ font-style: italic;
679
+ }
680
+ .member-card {
681
+ aspect-ratio: 1 / 1;
682
+ background: var(--surface2);
683
+ border: 1px solid var(--border);
684
+ border-radius: var(--radius);
685
+ padding: 8px 6px;
686
+ display: flex;
687
+ flex-direction: column;
688
+ align-items: center;
689
+ justify-content: center;
690
+ gap: 3px;
691
+ text-align: center;
692
+ cursor: pointer;
693
+ transition: border-color 0.2s, background 0.2s, transform 0.2s;
694
+ min-width: 0;
695
+ }
696
+ .member-card:hover { border-color: var(--blue); transform: translateY(-1px); }
697
+ .member-card:focus-visible { outline: 2px solid var(--blue); outline-offset: 1px; }
698
+ .member-card.working { border-color: rgba(210, 153, 34, 0.6); }
699
+ .member-card.done { border-color: rgba(63, 185, 80, 0.6); }
700
+ .member-card.error { border-color: rgba(248, 81, 73, 0.6); }
701
+ .member-emoji { font-size: 24px; line-height: 1; }
702
+ .member-name {
703
+ font-size: 13px;
704
+ font-weight: 600;
705
+ line-height: 1.2;
706
+ color: var(--text);
707
+ max-width: 100%;
708
+ overflow: hidden;
709
+ text-overflow: ellipsis;
710
+ white-space: nowrap;
711
+ }
712
+ .member-role {
713
+ font-size: 12px;
714
+ line-height: 1.2;
715
+ color: var(--muted);
716
+ max-width: 100%;
717
+ overflow: hidden;
718
+ text-overflow: ellipsis;
719
+ white-space: nowrap;
720
+ }
721
+ /* Status chip — pill, colored by status. Mirrors the old dashboard's
722
+ status-badge but tuned to the slim token palette. */
723
+ .member-status {
724
+ margin-top: 2px;
725
+ font-size: 12px;
726
+ font-weight: 700;
727
+ letter-spacing: 0.5px;
728
+ text-transform: uppercase;
729
+ padding: 2px 8px;
730
+ border-radius: 10px;
731
+ border: 1px solid var(--border);
732
+ background: var(--surface);
733
+ color: var(--muted);
734
+ }
735
+ .member-status.working {
736
+ background: rgba(210, 153, 34, 0.15);
737
+ color: var(--amber);
738
+ border-color: var(--amber);
739
+ animation: slim-pulse 1.6s ease-in-out infinite;
740
+ }
741
+ .member-status.done {
742
+ background: rgba(63, 185, 80, 0.15);
743
+ color: var(--green);
744
+ border-color: var(--green);
745
+ }
746
+ .member-status.error {
747
+ background: rgba(248, 81, 73, 0.15);
748
+ color: var(--red);
749
+ border-color: var(--red);
750
+ }
751
+ @keyframes slim-pulse {
752
+ 0%, 100% { opacity: 1; }
753
+ 50% { opacity: 0.55; }
754
+ }
755
+
756
+ /* Agent detail modal body */
757
+ .agent-detail-head {
758
+ display: flex;
759
+ align-items: center;
760
+ gap: 12px;
761
+ margin-bottom: 14px;
762
+ }
763
+ .agent-detail-emoji { font-size: 34px; line-height: 1; }
764
+ .agent-detail-name { font-size: 17px; font-weight: 600; color: var(--text); }
765
+ .agent-detail-role { font-size: 13px; color: var(--muted); }
766
+ .agent-detail-row { margin-bottom: 12px; }
767
+ .agent-detail-key {
768
+ font-size: 12px;
769
+ font-weight: 700;
770
+ letter-spacing: 0.5px;
771
+ text-transform: uppercase;
772
+ color: var(--muted);
773
+ margin-bottom: 3px;
774
+ }
775
+ .agent-detail-val { font-size: 13px; color: var(--text); white-space: pre-wrap; word-break: break-word; }
776
+ .agent-detail-val.muted { color: var(--muted); font-style: italic; }
777
+
778
+ /* ── History panel: event log ─────────────────────────────── */
779
+ .history-list {
780
+ display: flex;
781
+ flex-direction: column;
782
+ gap: 6px;
783
+ }
784
+ .history-item {
785
+ background: var(--surface2);
786
+ border: 1px solid var(--border);
787
+ border-radius: var(--radius);
788
+ padding: 8px 10px;
789
+ display: flex;
790
+ flex-direction: column;
791
+ gap: 3px;
792
+ }
793
+ .history-item.kind-completion { border-left: 3px solid var(--green); }
794
+ .history-item.kind-dispatch { border-left: 3px solid var(--blue); }
795
+ .history-item.kind-pr { border-left: 3px solid var(--amber); }
796
+ .history-item.kind-failure { border-left: 3px solid var(--red); }
797
+ .history-head {
798
+ display: flex;
799
+ justify-content: space-between;
800
+ align-items: baseline;
801
+ gap: 8px;
802
+ font-size: 13px;
803
+ }
804
+ .history-kind {
805
+ font-weight: 700;
806
+ letter-spacing: 0.4px;
807
+ text-transform: uppercase;
808
+ font-size: 12px;
809
+ color: var(--muted);
810
+ }
811
+ .history-time {
812
+ font-size: 12px;
813
+ color: var(--muted);
814
+ white-space: nowrap;
815
+ }
816
+ .history-title {
817
+ font-size: 13px;
818
+ color: var(--text);
819
+ word-break: break-word;
820
+ }
821
+ .history-meta {
822
+ font-size: 12px;
823
+ color: var(--muted);
824
+ word-break: break-word;
825
+ }
826
+ .history-meta a { color: var(--blue); }
827
+ .history-empty {
828
+ color: var(--muted);
829
+ font-style: italic;
830
+ font-size: 13px;
831
+ }
832
+
833
+ /* ╔══════════════════════════════════════════════════════════════════╗
834
+ ║ COMPLETIONS CARD (W-betterHistory) ║
835
+ ╚══════════════════════════════════════════════════════════════════╝
836
+ One of the History Panel's card components. The panel renders
837
+ different card types side-by-side; each type shares the .history-item
838
+ base class (background, border, hover, .kind-* left-stripe color)
839
+ and adds its own `.<name>-card` namespace for sub-elements. New
840
+ sibling cards (e.g. Dispatch Card, PR Card) should follow the same
841
+ convention: a top-level `.foo-card` class on the .history-item, with
842
+ sub-elements named `.foo-card-<part>`.
843
+
844
+ Completions Card structure (2×2 grid; rail uses subgrid so its rows
845
+ lock onto the body rows):
846
+ ┌─────────────────┬─────────────────────────────────────┐
847
+ │ rail-top │ body-top │
848
+ │ (type emoji) │ title + optional failure line │
849
+ ├─────────────────┼─────────────────────────────────────┤
850
+ │ rail-bottom │ lineage │
851
+ │ ✓ · 8h ago │ [WI:…] [Plan:…] [PR:…] │
852
+ └─────────────────┴─────────────────────────────────────┘
853
+ Clicking the card opens the completions-details modal; clicking the
854
+ PR chip opens the PR URL in a new tab (only chip with its own click
855
+ handler, the rest fall through to the card click). */
856
+ .history-item.completions-card {
857
+ display: grid;
858
+ grid-template-columns: 80px 1fr;
859
+ grid-template-rows: 1fr auto;
860
+ gap: 10px;
861
+ padding: 8px 10px;
862
+ cursor: pointer;
863
+ }
864
+ .history-item.completions-card:hover {
865
+ background: #1f242c;
866
+ }
867
+ .completions-card-rail {
868
+ grid-column: 1;
869
+ grid-row: 1 / -1; /* span both rows of the parent grid */
870
+ display: grid;
871
+ grid-template-rows: subgrid; /* inherit parent's row tracks */
872
+ border-right: 1px solid var(--border);
873
+ padding-right: 8px;
874
+ min-height: 60px;
875
+ }
876
+ .completions-card-rail-top {
877
+ /* row 1 of the subgrid — vertically centers the type emoji
878
+ against the title + failure block in body-top */
879
+ display: flex;
880
+ align-items: center;
881
+ justify-content: center;
882
+ }
883
+ .completions-card-rail-bottom {
884
+ /* row 2 of the subgrid — shares the row with .completions-card-lineage
885
+ so the status·time line sits on the same horizontal baseline
886
+ as the chip row */
887
+ display: flex;
888
+ align-items: center;
889
+ justify-content: center;
890
+ gap: 4px;
891
+ color: var(--muted);
892
+ font-size: 12px;
893
+ }
894
+ .completions-card-body-top {
895
+ /* parent grid cell (col 2, row 1) — wraps title and optional
896
+ failure line so they form a single sized block the rail-top
897
+ can center against */
898
+ display: flex;
899
+ flex-direction: column;
900
+ gap: 3px;
901
+ min-width: 0;
902
+ }
903
+ /* The success/failure signal lives primarily on the card's left-border
904
+ stripe (kind-completion green / kind-failure red). The status-icon
905
+ glyph here is a secondary textual cue — same size and color as the
906
+ relative time so the rail's bottom row reads as a single quiet line:
907
+ `✓ · 8h ago`. */
908
+ .completions-card-status-icon {
909
+ font-size: 12px;
910
+ line-height: 1;
911
+ color: var(--muted);
912
+ }
913
+ .completions-card-rail-sep {
914
+ color: var(--muted);
915
+ line-height: 1;
916
+ }
917
+ /* Type indicator — a single emoji glyph at 28px (alone on the rail's
918
+ top row). The full c.type string is exposed via the `title`
919
+ attribute so hovering reveals it. */
920
+ .completions-card-type-chip {
921
+ font-size: 28px;
922
+ line-height: 1;
923
+ cursor: help;
924
+ white-space: nowrap;
925
+ }
926
+ .completions-card-time {
927
+ font-size: 12px;
928
+ color: var(--muted);
929
+ white-space: nowrap;
930
+ }
931
+ .completions-card-title {
932
+ font-size: 16px;
933
+ color: var(--text);
934
+ line-height: 1.35;
935
+ /* Always reserve two lines so cards have a consistent vertical
936
+ rhythm regardless of title length. Combined with -webkit-line-clamp,
937
+ the title is exactly 2 lines max + 2 lines min. */
938
+ min-height: 2.7em;
939
+ display: -webkit-box;
940
+ -webkit-line-clamp: 2;
941
+ -webkit-box-orient: vertical;
942
+ overflow: hidden;
943
+ word-break: break-word;
944
+ }
945
+ .completions-card-fail-line {
946
+ font-size: 12px;
947
+ color: var(--red);
948
+ word-break: break-word;
949
+ }
950
+ .completions-card-fail-class {
951
+ font-weight: 700;
952
+ text-transform: lowercase;
953
+ }
954
+ /* Lineage row — fixed 3-column grid (WI / Plan / PR) so cells line up
955
+ between cards. No wrapping; long values ellipsis-truncate inside
956
+ their cell while the kind label stays visible. Vertical spacing
957
+ above the chips is supplied by the parent card grid's row gap. */
958
+ .completions-card-lineage {
959
+ grid-column: 2; /* cell 2,2 of the parent card grid */
960
+ font-size: 12px;
961
+ color: var(--muted);
962
+ display: grid;
963
+ grid-template-columns: 1fr 1fr 1fr;
964
+ gap: 6px;
965
+ align-items: stretch;
966
+ }
967
+ .completions-card-chip {
968
+ font-family: 'Consolas', 'Courier New', monospace;
969
+ font-size: 12px;
970
+ background: var(--bg);
971
+ border: 1px solid var(--border);
972
+ border-radius: 3px;
973
+ padding: 1px 5px;
974
+ color: var(--muted);
975
+ display: flex;
976
+ align-items: baseline;
977
+ gap: 4px;
978
+ overflow: hidden;
979
+ min-width: 0;
980
+ }
981
+ .completions-card-chip-label {
982
+ flex: 0 0 auto;
983
+ font-weight: 700;
984
+ }
985
+ .completions-card-chip-value {
986
+ flex: 1 1 auto;
987
+ overflow: hidden;
988
+ text-overflow: ellipsis;
989
+ white-space: nowrap;
990
+ min-width: 0;
991
+ }
992
+ .completions-card-chip-pr {
993
+ cursor: pointer;
994
+ text-decoration: none;
995
+ }
996
+ .completions-card-chip-pr:hover { filter: brightness(1.2); }
997
+
998
+ /* Completion details modal — uses .modal-bg / .modal base styles but
999
+ widens the inner modal so report contents are readable. */
1000
+ #slim-completions-modal .modal { width: 640px; }
1001
+ .completions-modal-section { margin-bottom: 14px; }
1002
+ .completions-modal-section:last-child { margin-bottom: 0; }
1003
+ .completions-modal-label {
1004
+ font-size: 12px;
1005
+ font-weight: 700;
1006
+ letter-spacing: 0.4px;
1007
+ text-transform: uppercase;
1008
+ color: var(--muted);
1009
+ margin-bottom: 4px;
1010
+ }
1011
+ .completions-modal-value {
1012
+ font-size: 13px;
1013
+ color: var(--text);
1014
+ word-break: break-word;
1015
+ white-space: pre-wrap;
1016
+ }
1017
+ .completions-modal-report {
1018
+ font-family: 'Consolas', 'Courier New', monospace;
1019
+ font-size: 12px;
1020
+ background: var(--bg);
1021
+ border: 1px solid var(--border);
1022
+ border-radius: var(--radius);
1023
+ padding: 8px 10px;
1024
+ max-height: 280px;
1025
+ overflow: auto;
1026
+ white-space: pre-wrap;
1027
+ word-break: break-all;
1028
+ }
1029
+
1030
+ /* ── Modals (settings + action prompt) ──────────────────── */
1031
+ .modal-bg {
1032
+ position: fixed;
1033
+ inset: 0;
1034
+ background: rgba(0, 0, 0, 0.55);
1035
+ display: none;
1036
+ align-items: center;
1037
+ justify-content: center;
1038
+ z-index: 100;
1039
+ }
1040
+ .modal-bg.open { display: flex; }
1041
+ .modal {
1042
+ background: var(--surface);
1043
+ border: 1px solid var(--border);
1044
+ border-radius: 8px;
1045
+ width: 480px;
1046
+ max-width: calc(100vw - 32px);
1047
+ max-height: calc(100vh - 64px);
1048
+ display: flex;
1049
+ flex-direction: column;
1050
+ overflow: hidden;
1051
+ }
1052
+ .modal-header {
1053
+ display: flex;
1054
+ align-items: center;
1055
+ justify-content: space-between;
1056
+ padding: 12px 16px;
1057
+ border-bottom: 1px solid var(--border);
1058
+ }
1059
+ .modal-header h3 { margin: 0; font-size: 16px; color: var(--blue); }
1060
+ .modal-body { padding: 14px 18px; overflow-y: auto; }
1061
+ .modal-body p { color: var(--muted); margin: 4px 0 12px; font-size: 13px; }
1062
+ .modal-footer {
1063
+ padding: 10px 16px;
1064
+ border-top: 1px solid var(--border);
1065
+ display: flex;
1066
+ justify-content: flex-end;
1067
+ gap: 8px;
1068
+ }
1069
+ .btn-primary {
1070
+ padding: 8px 16px;
1071
+ background: var(--blue);
1072
+ color: #fff;
1073
+ border: none;
1074
+ border-radius: var(--radius);
1075
+ cursor: pointer;
1076
+ font-size: 13px;
1077
+ font-weight: 600;
1078
+ }
1079
+ .btn-secondary {
1080
+ padding: 8px 16px;
1081
+ background: var(--surface2);
1082
+ color: var(--text);
1083
+ border: 1px solid var(--border);
1084
+ border-radius: var(--radius);
1085
+ cursor: pointer;
1086
+ font-size: 13px;
1087
+ }
1088
+ .btn-primary:hover, .btn-secondary:hover { filter: brightness(1.1); }
1089
+
1090
+ .flag-row {
1091
+ display: flex;
1092
+ align-items: center;
1093
+ justify-content: space-between;
1094
+ padding: 10px 0;
1095
+ border-bottom: 1px solid var(--border);
1096
+ }
1097
+ .flag-row:last-child { border-bottom: none; }
1098
+ .flag-name { font-size: 14px; font-weight: 600; }
1099
+ .flag-desc { font-size: 12px; color: var(--muted); margin-top: 2px; }
1100
+ .flag-toggle { display: flex; align-items: center; gap: 8px; font-size: 13px; }
1101
+ .flag-toggle input { cursor: pointer; }
1102
+ .settings-link {
1103
+ display: block;
1104
+ margin-top: 14px;
1105
+ padding: 10px 12px;
1106
+ background: var(--surface2);
1107
+ border: 1px solid var(--border);
1108
+ border-radius: var(--radius);
1109
+ color: var(--blue);
1110
+ text-decoration: none;
1111
+ font-size: 13px;
1112
+ text-align: center;
1113
+ }
1114
+ .settings-link:hover { filter: brightness(1.1); }
1115
+
1116
+ .modal-textarea {
1117
+ width: 100%;
1118
+ min-height: 96px;
1119
+ padding: 10px 12px;
1120
+ background: var(--bg);
1121
+ color: var(--text);
1122
+ border: 1px solid var(--border);
1123
+ border-radius: var(--radius);
1124
+ font-size: 14px;
1125
+ font-family: inherit;
1126
+ resize: vertical;
1127
+ }
1128
+ .modal-textarea:focus { outline: none; border-color: var(--blue); }