@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.
- package/dashboard/slim/body.html +251 -0
- package/dashboard/slim/js/chat.js +329 -0
- package/dashboard/slim/js/command-send.js +190 -0
- package/dashboard/slim/js/helpers.js +26 -0
- package/dashboard/slim/js/history.js +442 -0
- package/dashboard/slim/js/link-pr.js +83 -0
- package/dashboard/slim/js/members.js +138 -0
- package/dashboard/slim/js/modals-tiles.js +161 -0
- package/dashboard/slim/js/projects.js +209 -0
- package/dashboard/slim/js/settings.js +130 -0
- package/dashboard/slim/js/status.js +122 -0
- package/dashboard/slim/layout.html +21 -0
- package/dashboard/slim/styles.css +1128 -0
- package/dashboard-build.js +33 -1
- package/dashboard.js +11 -10
- package/docs/pr-review-fix-loop.md +2 -2
- package/engine/ado.js +21 -0
- package/engine/github.js +21 -0
- package/engine/lifecycle.js +35 -0
- package/engine/shared.js +9 -11
- package/package.json +1 -1
|
@@ -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); }
|