splitagent 0.0.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. splitagent/__init__.py +8 -0
  2. splitagent/__main__.py +6 -0
  3. splitagent/agents/__init__.py +10 -0
  4. splitagent/agents/base.py +477 -0
  5. splitagent/agents/blue.py +57 -0
  6. splitagent/agents/chat.py +60 -0
  7. splitagent/agents/prompts.py +462 -0
  8. splitagent/agents/red.py +75 -0
  9. splitagent/cli.py +701 -0
  10. splitagent/config.py +697 -0
  11. splitagent/core/__init__.py +19 -0
  12. splitagent/core/bus.py +62 -0
  13. splitagent/core/context.py +587 -0
  14. splitagent/core/context_manager.py +381 -0
  15. splitagent/core/engine.py +424 -0
  16. splitagent/core/models.py +310 -0
  17. splitagent/core/proc.py +73 -0
  18. splitagent/core/sandbox.py +184 -0
  19. splitagent/core/toolbox.py +520 -0
  20. splitagent/core/workspace.py +420 -0
  21. splitagent/desktop/__init__.py +7 -0
  22. splitagent/desktop/api.py +525 -0
  23. splitagent/desktop/app.py +1131 -0
  24. splitagent/desktop/web/app.js +3067 -0
  25. splitagent/desktop/web/assets/Inter.ttf +0 -0
  26. splitagent/desktop/web/assets/JetBrainsMonoNerdFontMono-Regular.woff2 +0 -0
  27. splitagent/desktop/web/index.html +760 -0
  28. splitagent/desktop/web/styles.css +1612 -0
  29. splitagent/errors.py +27 -0
  30. splitagent/llm/__init__.py +8 -0
  31. splitagent/llm/client.py +488 -0
  32. splitagent/llm/types.py +172 -0
  33. splitagent/report/__init__.py +9 -0
  34. splitagent/report/cvss.py +93 -0
  35. splitagent/report/generator.py +733 -0
  36. splitagent/tools/__init__.py +8 -0
  37. splitagent/tools/base.py +135 -0
  38. splitagent/tools/defense.py +475 -0
  39. splitagent/tools/exploit.py +318 -0
  40. splitagent/tools/http_pool.py +109 -0
  41. splitagent/tools/knowledge.py +376 -0
  42. splitagent/tools/recon.py +182 -0
  43. splitagent/tools/registry.py +62 -0
  44. splitagent/tools/validate.py +908 -0
  45. splitagent/tools/web.py +386 -0
  46. splitagent/tools/workspace_tools.py +411 -0
  47. splitagent/ui/__init__.py +5 -0
  48. splitagent/ui/app.py +389 -0
  49. splitagent/ui/stream.py +234 -0
  50. splitagent/ui/theme.py +72 -0
  51. splitagent-0.0.3.dist-info/METADATA +987 -0
  52. splitagent-0.0.3.dist-info/RECORD +56 -0
  53. splitagent-0.0.3.dist-info/WHEEL +5 -0
  54. splitagent-0.0.3.dist-info/entry_points.txt +2 -0
  55. splitagent-0.0.3.dist-info/licenses/LICENSE +21 -0
  56. splitagent-0.0.3.dist-info/top_level.txt +1 -0
@@ -0,0 +1,1612 @@
1
+ /* SplitAgent desktop — dark design language built on OpenCode v2 tokens. */
2
+
3
+ /* ── Bundled fonts (same faces OpenCode ships) ────────────────────────── */
4
+ @font-face {
5
+ font-family: "Inter";
6
+ src: url("assets/Inter.ttf") format("truetype");
7
+ font-weight: 100 900;
8
+ font-style: normal;
9
+ font-display: swap;
10
+ }
11
+ @font-face {
12
+ font-family: "JetBrainsMono Nerd Font Mono";
13
+ src: url("assets/JetBrainsMonoNerdFontMono-Regular.woff2") format("woff2");
14
+ font-weight: normal;
15
+ font-style: normal;
16
+ font-display: swap;
17
+ }
18
+
19
+ :root {
20
+ /* Surfaces: deeper floor, subtle elevation steps */
21
+ --bg-deep: #0f0f10;
22
+ --bg-base: #1a1a1c;
23
+ --layer-01: #232326;
24
+ --layer-02: #2c2c30;
25
+ --layer-03: #3a3a3f;
26
+ --overlay-hover: rgba(255, 255, 255, 0.055);
27
+ --overlay-pressed: rgba(255, 255, 255, 0.095);
28
+
29
+ /* Text: warmer, higher contrast at the top */
30
+ --text: #f5f5f7;
31
+ --text-muted: #a8a8b0;
32
+ --text-faint: #6f6f78;
33
+ --text-inverse: #1a1a1c;
34
+
35
+ --border: rgba(255, 255, 255, 0.09);
36
+ --border-muted: rgba(255, 255, 255, 0.06);
37
+ --border-strong: rgba(255, 255, 255, 0.18);
38
+
39
+ /* Accent */
40
+ --accent: #5b76ff;
41
+ --accent-hover: #4a63f0;
42
+ --accent-soft: rgba(91, 118, 255, 0.13);
43
+ --accent-text: #b3c2ff;
44
+ --accent-glow: rgba(91, 118, 255, 0.28);
45
+
46
+ /* Semantic */
47
+ --red: #f17471;
48
+ --red-strong: #f1484f;
49
+ --blue: #7698fd;
50
+ --blue-strong: #5b76ff;
51
+ --green: #57cf7d;
52
+ --orange: #ff9a5c;
53
+ --yellow: #f6c96b;
54
+ --cyan: #3fc9e0;
55
+ --purple: #9d8cf9;
56
+
57
+ /* Radii + motion */
58
+ --radius-sm: 5px;
59
+ --radius: 8px;
60
+ --radius-lg: 12px;
61
+ --ease: cubic-bezier(0.22, 1, 0.36, 1);
62
+ --ease-spring: cubic-bezier(0.34, 1.2, 0.64, 1);
63
+ --dur: 160ms;
64
+
65
+ /* Elevation */
66
+ --shadow-1: 0 1px 2px rgba(0, 0, 0, 0.4);
67
+ --shadow-2: 0 6px 20px rgba(0, 0, 0, 0.45);
68
+ --shadow-3: 0 24px 64px rgba(0, 0, 0, 0.6);
69
+
70
+ /* Fonts */
71
+ --font: "Inter", "Segoe UI", system-ui, -apple-system, sans-serif;
72
+ --mono: "JetBrainsMono Nerd Font Mono", "JetBrains Mono", "Cascadia Code",
73
+ Consolas, "SFMono-Regular", monospace;
74
+ }
75
+
76
+ * { box-sizing: border-box; margin: 0; padding: 0; }
77
+
78
+ html, body, #app { height: 100%; }
79
+
80
+ body {
81
+ font-family: var(--font);
82
+ font-size: 13px;
83
+ line-height: 20px;
84
+ font-feature-settings: "cv05" 1, "cv08" 1, "ss03" 1;
85
+ color: var(--text);
86
+ background:
87
+ radial-gradient(1100px 620px at 12% -8%, rgba(91, 118, 255, 0.055), transparent 62%),
88
+ radial-gradient(900px 520px at 100% 0%, rgba(157, 140, 249, 0.045), transparent 58%),
89
+ var(--bg-deep);
90
+ overflow: hidden;
91
+ user-select: none;
92
+ -webkit-font-smoothing: antialiased;
93
+ text-rendering: optimizeLegibility;
94
+ }
95
+
96
+ #app {
97
+ display: grid;
98
+ grid-template-rows: 42px 1fr 28px;
99
+ height: 100vh;
100
+ width: 100vw;
101
+ overflow: hidden;
102
+ }
103
+
104
+ /* Every panel manages its own scrolling; nothing may widen the window. */
105
+ .body > * { min-width: 0; }
106
+ .sidebar, .review { overflow: hidden; }
107
+
108
+ /* Focus rings only for keyboard users. */
109
+ :focus-visible {
110
+ outline: 2px solid var(--accent);
111
+ outline-offset: 1px;
112
+ border-radius: var(--radius-sm);
113
+ }
114
+
115
+ ::-webkit-scrollbar { width: 11px; height: 11px; }
116
+ ::-webkit-scrollbar-thumb {
117
+ background: rgba(255, 255, 255, 0.11);
118
+ border-radius: 8px;
119
+ border: 3px solid transparent;
120
+ background-clip: content-box;
121
+ transition: background var(--dur) var(--ease);
122
+ }
123
+ ::-webkit-scrollbar-thumb:hover { background: rgba(255, 255, 255, 0.24); background-clip: content-box; }
124
+ ::-webkit-scrollbar-track { background: transparent; }
125
+ ::-webkit-scrollbar-corner { background: transparent; }
126
+
127
+ ::selection { background: var(--accent-soft); color: var(--text); }
128
+
129
+ @media (prefers-reduced-motion: reduce) {
130
+ *, *::before, *::after {
131
+ animation-duration: 0.001ms !important;
132
+ animation-iteration-count: 1 !important;
133
+ transition-duration: 0.001ms !important;
134
+ }
135
+ }
136
+
137
+ /* ── Titlebar ─────────────────────────────────────────────── */
138
+ .titlebar {
139
+ display: flex;
140
+ align-items: center;
141
+ justify-content: space-between;
142
+ padding: 0 4px 0 14px;
143
+ background: color-mix(in srgb, var(--bg-deep) 82%, transparent);
144
+ backdrop-filter: blur(14px) saturate(140%);
145
+ border-bottom: 1px solid var(--border-muted);
146
+ position: relative;
147
+ z-index: 20;
148
+ }
149
+ .tb-left { display: flex; align-items: center; gap: 18px; min-width: 0; flex: 1; }
150
+ .tb-right { display: flex; align-items: center; gap: 2px; }
151
+
152
+ .brand { display: flex; align-items: center; gap: 9px; }
153
+ .brand-mark {
154
+ width: 19px; height: 19px; color: var(--accent-text);
155
+ filter: drop-shadow(0 0 8px var(--accent-glow));
156
+ }
157
+ .brand-name {
158
+ font-weight: 650; font-size: 13px; letter-spacing: -0.015em;
159
+ background: linear-gradient(180deg, #ffffff, #b9b9c4);
160
+ -webkit-background-clip: text; background-clip: text;
161
+ -webkit-text-fill-color: transparent;
162
+ }
163
+ .brand-ver {
164
+ color: var(--text-faint); font-size: 10.5px; font-family: var(--mono);
165
+ padding: 1px 6px; border-radius: 999px; background: var(--layer-01);
166
+ border: 1px solid var(--border-muted);
167
+ }
168
+
169
+ /* Mode switch — the app's primary control, so it gets real presence. */
170
+ .mode-switch {
171
+ display: flex; gap: 3px; padding: 3px;
172
+ background: var(--bg-base);
173
+ border: 1px solid var(--border-muted);
174
+ border-radius: var(--radius);
175
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.03);
176
+ }
177
+ .mode-btn {
178
+ display: flex; align-items: center; gap: 7px;
179
+ height: 26px; padding: 0 12px;
180
+ background: transparent; border: 0; border-radius: 6px;
181
+ color: var(--text-faint); font-family: inherit; font-size: 12.5px;
182
+ font-weight: 500; cursor: pointer;
183
+ transition: color var(--dur) var(--ease), background var(--dur) var(--ease);
184
+ }
185
+ .mode-btn svg { width: 13px; height: 13px; flex: none; }
186
+ .mode-btn:hover { color: var(--text-muted); }
187
+ .mode-btn.active {
188
+ background: linear-gradient(180deg, var(--layer-02), var(--layer-01));
189
+ color: var(--text);
190
+ box-shadow: var(--shadow-1), inset 0 1px 0 rgba(255, 255, 255, 0.06);
191
+ }
192
+
193
+ .tabs { display: flex; align-items: center; gap: 2px; min-width: 0; }
194
+ .tab {
195
+ display: flex; align-items: center; gap: 8px;
196
+ height: 28px; padding: 0 12px;
197
+ background: transparent; border: 0; color: var(--text-muted);
198
+ font-family: inherit; font-size: 12px; border-radius: var(--radius);
199
+ cursor: pointer; white-space: nowrap;
200
+ transition: background var(--dur) var(--ease);
201
+ }
202
+ .tab.active { background: var(--layer-01); color: var(--text); }
203
+ .tab-dot {
204
+ width: 7px; height: 7px; border-radius: 50%; background: var(--red);
205
+ box-shadow: 0 0 0 3px rgba(241, 116, 113, 0.16);
206
+ animation: pulse-dot 2.4s ease-in-out infinite;
207
+ }
208
+ @keyframes pulse-dot {
209
+ 0%, 100% { box-shadow: 0 0 0 3px rgba(241, 116, 113, 0.16); }
210
+ 50% { box-shadow: 0 0 0 5px rgba(241, 116, 113, 0.07); }
211
+ }
212
+
213
+ .icon-btn {
214
+ width: 30px; height: 30px; display: grid; place-items: center;
215
+ background: transparent; border: 0; border-radius: var(--radius);
216
+ color: var(--text-muted); cursor: pointer;
217
+ transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
218
+ }
219
+ .icon-btn:hover { background: var(--overlay-hover); color: var(--text); }
220
+ .icon-btn:active { background: var(--overlay-pressed); }
221
+ .icon-btn svg { width: 15px; height: 15px; }
222
+
223
+ .window-controls { display: flex; margin-left: 8px; }
224
+ .wc {
225
+ width: 42px; height: 32px; display: grid; place-items: center;
226
+ background: transparent; border: 0; color: var(--text-muted); cursor: pointer;
227
+ transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
228
+ }
229
+ .wc svg { width: 12px; height: 12px; }
230
+ .wc:hover { background: var(--overlay-hover); color: var(--text); }
231
+ .wc.close:hover { background: #c42b1c; color: #fff; }
232
+
233
+ /* ── Body layout ──────────────────────────────────────────── */
234
+ .body {
235
+ --side-w: 272px;
236
+ --review-w: 384px;
237
+ position: relative;
238
+ display: grid;
239
+ grid-template-columns: var(--side-w) 1fr var(--review-w);
240
+ min-height: 0;
241
+ background: transparent;
242
+ transition: grid-template-columns 220ms var(--ease);
243
+ }
244
+ body.sidebar-collapsed .body { --side-w: 0px; }
245
+ body.review-collapsed .body { --review-w: 0px; }
246
+ body.sidebar-collapsed .sidebar,
247
+ body.review-collapsed .review { opacity: 0; pointer-events: none; visibility: hidden; }
248
+ .body.resizing { transition: none; }
249
+ .body.resizing * { user-select: none; }
250
+
251
+ /* Drag handles sit on top of the column edges instead of taking a grid track,
252
+ so the three-column layout stays exactly as before. */
253
+ .resizer {
254
+ position: absolute; top: 0; bottom: 0; width: 7px; z-index: 6;
255
+ cursor: col-resize; background: transparent;
256
+ }
257
+ .resizer::after {
258
+ content: ""; position: absolute; top: 0; bottom: 0; left: 3px; width: 1px;
259
+ background: transparent; transition: background 140ms var(--ease);
260
+ }
261
+ .resizer:hover::after, .resizer.dragging::after { background: var(--accent); }
262
+ #resize-sidebar { left: calc(var(--side-w) - 3px); }
263
+ #resize-review { right: calc(var(--review-w) - 3px); }
264
+ body.sidebar-collapsed #resize-sidebar,
265
+ body.review-collapsed #resize-review { display: none; }
266
+
267
+ .sidebar {
268
+ display: flex; flex-direction: column; min-height: 0;
269
+ background: color-mix(in srgb, var(--bg-deep) 72%, transparent);
270
+ border-right: 1px solid var(--border-muted);
271
+ padding: 14px 12px;
272
+ gap: 16px;
273
+ }
274
+ .side-block { display: flex; flex-direction: column; gap: 9px; min-height: 0; }
275
+ .side-block.grow { flex: 1; }
276
+ .side-label {
277
+ font-size: 10px; text-transform: uppercase; letter-spacing: 0.1em;
278
+ color: var(--text-faint); padding: 0 4px; font-weight: 650;
279
+ }
280
+
281
+ .target-card {
282
+ background: linear-gradient(180deg, var(--bg-base), color-mix(in srgb, var(--bg-base) 92%, #000));
283
+ border: 1px solid var(--border-muted);
284
+ border-radius: var(--radius-lg); padding: 13px;
285
+ display: flex; flex-direction: column; gap: 9px;
286
+ box-shadow: var(--shadow-1);
287
+ }
288
+ .target-row { display: flex; align-items: center; gap: 8px; }
289
+ .badge {
290
+ font-size: 10px; text-transform: uppercase; letter-spacing: 0.05em;
291
+ padding: 2px 8px; border-radius: 999px; background: var(--layer-01);
292
+ color: var(--text-muted); border: 1px solid var(--border-muted); font-weight: 600;
293
+ }
294
+ .badge.kind {
295
+ background: var(--accent-soft); color: var(--accent-text);
296
+ border-color: color-mix(in srgb, var(--accent) 32%, transparent);
297
+ }
298
+ .target-url {
299
+ font-family: var(--mono); font-size: 12px; color: var(--text);
300
+ overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
301
+ }
302
+ .target-meta { font-size: 11.5px; color: var(--text-faint); line-height: 17px; }
303
+ .target-meta code, code {
304
+ font-family: var(--mono); font-size: 11px; color: var(--text-muted);
305
+ background: var(--layer-01); padding: 1px 5px; border-radius: 4px;
306
+ }
307
+ .target-actions { display: flex; gap: 6px; }
308
+
309
+ .mini-btn {
310
+ flex: 1; height: 28px; border-radius: var(--radius-sm);
311
+ background: var(--overlay-hover); border: 1px solid var(--border-muted);
312
+ color: var(--text-muted); font-family: inherit; font-size: 11.5px;
313
+ font-weight: 500; cursor: pointer;
314
+ transition: background var(--dur) var(--ease), color var(--dur) var(--ease),
315
+ border-color var(--dur) var(--ease);
316
+ }
317
+ .mini-btn:hover { background: var(--overlay-pressed); color: var(--text); border-color: var(--border-strong); }
318
+
319
+ .session-list { display: flex; flex-direction: column; gap: 3px; overflow-y: auto; min-height: 0; }
320
+ .session-item {
321
+ display: flex; flex-direction: column; gap: 2px;
322
+ padding: 8px 10px; border-radius: var(--radius); cursor: pointer;
323
+ border: 1px solid transparent;
324
+ transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease);
325
+ }
326
+ .session-item:hover { background: var(--overlay-hover); border-color: var(--border-muted); }
327
+ .session-item .sid { font-family: var(--mono); font-size: 11.5px; color: var(--text); }
328
+ .session-item .smeta { font-size: 10.5px; color: var(--text-faint); }
329
+ .session-empty { color: var(--text-faint); font-size: 11.5px; padding: 4px; }
330
+
331
+ .side-footer { border-top: 1px solid var(--border-muted); padding-top: 10px; }
332
+ .dot {
333
+ width: 7px; height: 7px; border-radius: 50%; background: var(--text-faint);
334
+ flex: none; transition: box-shadow var(--dur) var(--ease);
335
+ }
336
+ .dot.ok { background: var(--green); box-shadow: 0 0 0 3px rgba(87, 207, 125, 0.16); }
337
+ .dot.bad { background: var(--red); box-shadow: 0 0 0 3px rgba(241, 72, 79, 0.14); }
338
+ .model-name {
339
+ font-family: var(--mono); font-size: 11.5px; color: var(--text-muted);
340
+ overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
341
+ }
342
+
343
+ /* ── Center ───────────────────────────────────────────────── */
344
+ .center { display: flex; flex-direction: column; min-height: 0; background: transparent; }
345
+ .stream { flex: 1; overflow-y: auto; padding: 26px 30px 8px; user-select: text; }
346
+ .stream > * { animation: rise 260ms var(--ease) both; }
347
+ @keyframes rise {
348
+ from { opacity: 0; transform: translateY(5px); }
349
+ to { opacity: 1; transform: none; }
350
+ }
351
+
352
+ .empty-state { max-width: 580px; margin: 9vh auto 0; text-align: center; color: var(--text-muted); }
353
+ .empty-mark {
354
+ width: 58px; height: 58px; margin: 0 auto 22px; color: var(--accent-text);
355
+ filter: drop-shadow(0 0 24px var(--accent-glow));
356
+ animation: float 5s ease-in-out infinite;
357
+ }
358
+ @keyframes float {
359
+ 0%, 100% { transform: translateY(0); }
360
+ 50% { transform: translateY(-6px); }
361
+ }
362
+ .empty-mark svg { width: 100%; height: 100%; }
363
+ .empty-state h1 {
364
+ font-size: 23px; font-weight: 650; margin-bottom: 14px; letter-spacing: -0.025em;
365
+ background: linear-gradient(180deg, #ffffff, #a9a9b6);
366
+ -webkit-background-clip: text; background-clip: text;
367
+ -webkit-text-fill-color: transparent;
368
+ }
369
+ .empty-state p { font-size: 13.5px; line-height: 22px; margin-bottom: 11px; }
370
+ .empty-state .muted { color: var(--text-faint); }
371
+ .red { color: var(--red); }
372
+ .blue { color: var(--blue); }
373
+
374
+ /* Messages */
375
+ .msg { max-width: 780px; margin: 0 auto 22px; }
376
+ .msg-head { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; }
377
+ .msg-name.accent { color: var(--accent-text); }
378
+ .msg-name.core { color: var(--text-muted); }
379
+ .msg-name { font-size: 12px; font-weight: 600; letter-spacing: 0.02em; }
380
+ .msg-name.red { color: var(--red); }
381
+ .msg-name.blue { color: var(--blue); }
382
+ .msg-time { font-size: 10.5px; color: var(--text-faint); font-family: var(--mono); }
383
+ .msg-timer {
384
+ margin-left: auto; flex: none; font-family: var(--mono); font-size: 10.5px;
385
+ color: var(--text-faint); font-variant-numeric: tabular-nums;
386
+ }
387
+ .msg-timer.running {
388
+ color: var(--accent-text);
389
+ animation: timer-pulse 1.6s ease-in-out infinite;
390
+ }
391
+ @keyframes timer-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.55; } }
392
+ .msg-body { font-size: 13.5px; line-height: 22px; color: var(--text); }
393
+ .msg-body p { margin: 0 0 8px; }
394
+ .msg-body h1, .msg-body h2, .msg-body h3 { font-size: 14px; font-weight: 600; margin: 12px 0 6px; }
395
+ .msg-body ul { margin: 6px 0 10px 18px; list-style: disc; }
396
+ .msg-body li { margin: 2px 0; }
397
+ .msg-body code { font-family: var(--mono); font-size: 12px; background: var(--layer-01); padding: 1px 5px; border-radius: 4px; color: var(--accent-text); }
398
+ .msg-body pre {
399
+ background: color-mix(in srgb, var(--bg-deep) 80%, #000);
400
+ border: 1px solid var(--border-muted);
401
+ border-radius: var(--radius); padding: 13px 15px; overflow-x: auto;
402
+ font-family: var(--mono); font-size: 12px; line-height: 18.5px;
403
+ margin: 10px 0 14px; color: #d6d6d6;
404
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.025);
405
+ }
406
+ .msg-body pre code { background: none; padding: 0; color: inherit; }
407
+ .msg-body a { color: var(--accent-text); }
408
+ .msg-body strong { font-weight: 600; }
409
+
410
+ .divider {
411
+ display: flex; align-items: center; gap: 10px; max-width: 780px;
412
+ margin: 6px auto 20px; color: var(--text-faint); font-size: 11px;
413
+ text-transform: uppercase; letter-spacing: 0.08em;
414
+ }
415
+ .divider::before, .divider::after { content: ""; height: 1px; background: var(--border-muted); flex: 1; }
416
+ .divider .tag { display: flex; align-items: center; gap: 6px; font-weight: 600; }
417
+ .divider.red .tag { color: var(--red); }
418
+ .divider.blue .tag { color: var(--blue); }
419
+
420
+ /* Tool calls */
421
+ .tool {
422
+ max-width: 780px; margin: 0 auto 12px;
423
+ background: linear-gradient(180deg, var(--bg-base), color-mix(in srgb, var(--bg-base) 95%, #000));
424
+ border: 1px solid var(--border-muted); border-radius: var(--radius);
425
+ overflow: hidden; user-select: text;
426
+ box-shadow: var(--shadow-1);
427
+ }
428
+ .tool.hidden { display: none; }
429
+ .tool.open { border-color: var(--border-strong); }
430
+ .tool-head {
431
+ display: flex; align-items: center; gap: 8px; padding: 9px 12px;
432
+ cursor: pointer; color: var(--text-muted); font-size: 12px;
433
+ transition: background var(--dur) var(--ease);
434
+ }
435
+ .tool-head:hover { background: var(--overlay-hover); }
436
+ .tool-name { font-family: var(--mono); color: var(--accent-text); }
437
+ .tool-args { font-family: var(--mono); font-size: 11px; color: var(--text-faint); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1; }
438
+ .tool-status { width: 14px; height: 14px; flex: none; }
439
+ .tool-status.running { border: 2px solid rgba(162, 188, 255, 0.3); border-top-color: var(--accent-text); border-radius: 50%; animation: spin 0.7s linear infinite; }
440
+ .tool-status.done { color: var(--green); }
441
+ .tool-status.error { color: var(--red); }
442
+ @keyframes spin { to { transform: rotate(360deg); } }
443
+ .tool-body { display: none; border-top: 1px solid var(--border-muted); }
444
+ .tool.open .tool-body { display: block; }
445
+ .tool-body pre {
446
+ margin: 0; padding: 10px 12px; font-family: var(--mono); font-size: 11.5px;
447
+ line-height: 17px; color: var(--text-muted); white-space: pre-wrap;
448
+ word-break: break-word; max-height: 320px; overflow-y: auto;
449
+ }
450
+
451
+ /* Inline finding cards */
452
+ .inline-finding {
453
+ max-width: 780px; margin: 0 auto 12px; border-radius: var(--radius);
454
+ background: linear-gradient(180deg, var(--bg-base), color-mix(in srgb, var(--bg-base) 94%, #000));
455
+ border: 1px solid var(--border-muted);
456
+ border-left: 3px solid var(--text-faint); padding: 12px 14px;
457
+ box-shadow: var(--shadow-1);
458
+ }
459
+ .inline-finding.critical { box-shadow: var(--shadow-1), 0 0 0 1px rgba(241, 72, 79, 0.12); }
460
+ .inline-finding.critical { border-left-color: var(--red-strong); }
461
+ .inline-finding.high { border-left-color: var(--orange); }
462
+ .inline-finding.medium { border-left-color: var(--yellow); }
463
+ .inline-finding.low { border-left-color: var(--green); }
464
+ .inline-finding.info { border-left-color: var(--cyan); }
465
+ .if-head { display: flex; align-items: center; gap: 8px; margin-bottom: 4px; }
466
+ .if-title { font-weight: 600; font-size: 13px; }
467
+ .if-meta { font-family: var(--mono); font-size: 11px; color: var(--text-faint); }
468
+
469
+ /* ── Composer ─────────────────────────────────────────────── */
470
+ .composer { padding: 10px 30px 22px; }
471
+ .composer-card {
472
+ max-width: 840px; margin: 0 auto;
473
+ background: linear-gradient(180deg, var(--bg-base), color-mix(in srgb, var(--bg-base) 94%, #000));
474
+ border: 1px solid var(--border); border-radius: var(--radius-lg);
475
+ padding: 12px 14px 10px;
476
+ box-shadow: var(--shadow-2);
477
+ transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
478
+ }
479
+ .composer-card:focus-within {
480
+ border-color: color-mix(in srgb, var(--accent) 55%, transparent);
481
+ box-shadow: var(--shadow-2), 0 0 0 3px var(--accent-soft);
482
+ }
483
+ #objective,
484
+ #chat-input {
485
+ width: 100%; background: transparent; border: 0; resize: none;
486
+ color: var(--text); font-family: inherit; font-size: 13.5px; line-height: 21px;
487
+ outline: none; max-height: 160px; padding: 2px 2px 8px;
488
+ appearance: none; -webkit-appearance: none;
489
+ }
490
+ #objective::placeholder,
491
+ #chat-input::placeholder { color: var(--text-faint); }
492
+ .composer-bar { display: flex; align-items: center; gap: 8px; }
493
+ .spacer { flex: 1; }
494
+
495
+ .pill {
496
+ display: flex; align-items: center; gap: 7px; height: 28px; padding: 0 10px;
497
+ background: var(--overlay-hover); border: 1px solid var(--border-muted);
498
+ border-radius: var(--radius); color: var(--text-muted);
499
+ font-family: var(--mono); font-size: 11.5px; cursor: pointer; max-width: 260px;
500
+ }
501
+ .pill:hover { background: var(--overlay-pressed); color: var(--text); }
502
+ .pill .chev { width: 12px; height: 12px; opacity: 0.7; }
503
+ .pill span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
504
+
505
+ .chip {
506
+ display: flex; align-items: center; gap: 6px; height: 28px; padding: 0 10px;
507
+ background: transparent; border: 1px solid var(--border-muted);
508
+ border-radius: var(--radius); color: var(--text-muted); font-size: 11.5px; cursor: pointer;
509
+ }
510
+ .chip:hover { background: var(--overlay-hover); }
511
+ .chip input[type="checkbox"] { accent-color: var(--accent); width: 13px; height: 13px; }
512
+ .chip.num input {
513
+ width: 34px; background: transparent; border: 0; color: var(--text);
514
+ font-family: var(--mono); font-size: 12px; outline: none; text-align: center;
515
+ }
516
+
517
+ .btn {
518
+ height: 30px; padding: 0 14px; border-radius: var(--radius); border: 1px solid transparent;
519
+ font-family: inherit; font-size: 12.5px; font-weight: 550; cursor: pointer;
520
+ display: inline-flex; align-items: center; gap: 6px;
521
+ transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease),
522
+ color var(--dur) var(--ease), box-shadow var(--dur) var(--ease), transform 80ms var(--ease);
523
+ }
524
+ .btn:active:not(:disabled) { transform: translateY(0.5px); }
525
+ .btn.primary {
526
+ background: linear-gradient(180deg, color-mix(in srgb, var(--accent) 92%, #fff), var(--accent));
527
+ color: #fff;
528
+ box-shadow: 0 1px 0 rgba(255, 255, 255, 0.14) inset, 0 3px 12px var(--accent-glow);
529
+ }
530
+ .btn.primary:hover {
531
+ background: linear-gradient(180deg, var(--accent), var(--accent-hover));
532
+ box-shadow: 0 1px 0 rgba(255, 255, 255, 0.18) inset, 0 5px 18px var(--accent-glow);
533
+ }
534
+ .btn.ghost { background: var(--overlay-hover); border-color: var(--border-muted); color: var(--text-muted); }
535
+ .btn.ghost:hover { background: var(--overlay-pressed); color: var(--text); border-color: var(--border-strong); }
536
+ .btn.danger { background: rgba(241, 72, 79, 0.14); color: #ff9ea1; border-color: rgba(241, 72, 79, 0.32); }
537
+ .btn.danger:hover { background: rgba(241, 72, 79, 0.24); border-color: rgba(241, 72, 79, 0.5); }
538
+ .btn:disabled { opacity: 0.42; cursor: not-allowed; }
539
+ .hidden { display: none !important; }
540
+
541
+ /* ── Review panel ─────────────────────────────────────────── */
542
+ .review {
543
+ display: flex; flex-direction: column; min-height: 0;
544
+ background: color-mix(in srgb, var(--bg-deep) 72%, transparent);
545
+ border-left: 1px solid var(--border-muted);
546
+ }
547
+ .review-tabs {
548
+ display: flex; gap: 2px; padding: 12px 12px 0;
549
+ border-bottom: 1px solid var(--border-muted);
550
+ /* The strip scrolls instead of pushing the panel wider than its column. */
551
+ overflow-x: auto; overflow-y: hidden;
552
+ scrollbar-width: none;
553
+ }
554
+ .review-tabs::-webkit-scrollbar { display: none; }
555
+ .rtab {
556
+ display: flex; align-items: center; gap: 6px; height: 32px; padding: 0 10px;
557
+ background: transparent; border: 0; border-bottom: 2px solid transparent;
558
+ color: var(--text-faint); font-family: inherit; font-size: 12px;
559
+ font-weight: 500; cursor: pointer; flex: none; white-space: nowrap;
560
+ transition: color var(--dur) var(--ease), border-color var(--dur) var(--ease);
561
+ }
562
+ .rtab:hover { color: var(--text-muted); }
563
+ .rtab.active { color: var(--text); border-bottom-color: var(--accent); }
564
+ .count {
565
+ font-family: var(--mono); font-size: 10px; background: var(--layer-01);
566
+ padding: 1px 6px; border-radius: 999px; color: var(--text-muted);
567
+ border: 1px solid var(--border-muted);
568
+ }
569
+ .rtab.active .count { background: var(--accent-soft); color: var(--accent-text); border-color: transparent; }
570
+ .review-body { flex: 1; overflow-y: auto; padding: 12px; }
571
+ .rpanel { display: none; flex-direction: column; gap: 10px; }
572
+ .rpanel.active { display: flex; }
573
+ .panel-empty { color: var(--text-faint); font-size: 12px; padding: 8px 4px; }
574
+
575
+ .finding {
576
+ background: var(--bg-base); border: 1px solid var(--border-muted);
577
+ border-left: 3px solid var(--text-faint); border-radius: var(--radius);
578
+ padding: 10px 12px; cursor: pointer;
579
+ }
580
+ .finding:hover { border-color: var(--border-strong); }
581
+ .finding.critical { border-left-color: var(--red-strong); }
582
+ .finding.high { border-left-color: var(--orange); }
583
+ .finding.medium { border-left-color: var(--yellow); }
584
+ .finding.low { border-left-color: var(--green); }
585
+ .finding.info { border-left-color: var(--cyan); }
586
+ .finding .f-top { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
587
+ .finding .f-title { font-weight: 600; font-size: 12.5px; }
588
+ .finding .f-sub { font-family: var(--mono); font-size: 11px; color: var(--text-faint); margin-top: 3px; }
589
+ .sev { font-size: 10px; font-weight: 700; letter-spacing: 0.04em; padding: 2px 6px; border-radius: 999px; }
590
+ .sev.critical { background: rgba(241, 72, 79, 0.18); color: #ff9ea1; }
591
+ .sev.high { background: rgba(255, 134, 72, 0.18); color: var(--orange); }
592
+ .sev.medium { background: rgba(246, 194, 81, 0.18); color: var(--yellow); }
593
+ .sev.low { background: rgba(73, 201, 112, 0.18); color: var(--green); }
594
+ .sev.info { background: rgba(0, 171, 207, 0.18); color: var(--cyan); }
595
+
596
+ .mitigation {
597
+ background: var(--bg-base); border: 1px solid var(--border-muted);
598
+ border-radius: var(--radius); padding: 10px 12px;
599
+ }
600
+ .mitigation .m-top { display: flex; align-items: center; gap: 8px; margin-bottom: 4px; }
601
+ .mitigation .m-title { font-weight: 600; font-size: 12.5px; }
602
+ .mitigation pre {
603
+ background: var(--bg-deep); border: 1px solid var(--border-muted);
604
+ border-radius: var(--radius-sm); padding: 8px 10px; margin-top: 6px;
605
+ font-family: var(--mono); font-size: 11px; line-height: 16px; color: var(--text-muted);
606
+ white-space: pre-wrap; word-break: break-word; max-height: 240px; overflow-y: auto;
607
+ }
608
+ .mitigation .m-sub { font-size: 11.5px; color: var(--text-muted); }
609
+
610
+ .activity-line {
611
+ font-family: var(--mono); font-size: 11.5px; color: var(--text-muted);
612
+ padding: 3px 0; border-bottom: 1px solid var(--border-muted);
613
+ white-space: pre-wrap; word-break: break-word;
614
+ }
615
+ .activity-line.err { color: #ff9ea1; }
616
+
617
+ .review-footer {
618
+ display: flex; gap: 8px; padding: 10px 12px;
619
+ border-top: 1px solid var(--border-muted);
620
+ }
621
+ .review-footer .btn { flex: 1; justify-content: center; }
622
+
623
+ /* ── Statusbar ────────────────────────────────────────────── */
624
+ .statusbar {
625
+ display: flex; align-items: center; gap: 9px; padding: 0 16px;
626
+ background: color-mix(in srgb, var(--bg-deep) 82%, transparent);
627
+ backdrop-filter: blur(14px) saturate(140%);
628
+ border-top: 1px solid var(--border-muted);
629
+ font-size: 11px; color: var(--text-faint); font-family: var(--mono);
630
+ position: relative; z-index: 20;
631
+ }
632
+ .statusbar #st-mode {
633
+ color: var(--accent-text); font-weight: 600; text-transform: uppercase;
634
+ letter-spacing: 0.06em; font-size: 10px;
635
+ }
636
+ .statusbar .sep { opacity: 0.5; }
637
+ .statusbar .spacer { flex: 1; }
638
+ .statusbar .phase { color: var(--accent-text); }
639
+ .resilience { display: flex; align-items: center; gap: 7px; color: var(--text-muted); }
640
+ .resilience .bar { width: 90px; height: 5px; border-radius: 999px; background: var(--layer-01); overflow: hidden; }
641
+ .resilience .bar i { display: block; height: 100%; background: var(--green); transition: width 300ms ease; }
642
+
643
+ /* ── Modals ───────────────────────────────────────────────── */
644
+ .overlay {
645
+ position: fixed; inset: 0; background: rgba(6, 6, 8, 0.62);
646
+ display: flex; align-items: flex-start; justify-content: center;
647
+ padding-top: 8vh; z-index: 100;
648
+ backdrop-filter: blur(6px) saturate(120%);
649
+ animation: overlay-in 160ms var(--ease) both;
650
+ }
651
+ @keyframes overlay-in { from { opacity: 0; } to { opacity: 1; } }
652
+ .dialog {
653
+ width: 560px; max-width: calc(100vw - 48px);
654
+ background: linear-gradient(180deg, var(--bg-base), color-mix(in srgb, var(--bg-base) 95%, #000));
655
+ border: 1px solid var(--border); border-radius: 14px; padding: 22px;
656
+ box-shadow: var(--shadow-3), inset 0 1px 0 rgba(255, 255, 255, 0.04);
657
+ animation: dialog-in 220ms var(--ease-spring) both;
658
+ }
659
+ @keyframes dialog-in {
660
+ from { opacity: 0; transform: translateY(-10px) scale(0.985); }
661
+ to { opacity: 1; transform: none; }
662
+ }
663
+ .dialog.wide { width: 620px; }
664
+ .dialog-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 6px; }
665
+ .dialog-head h2 { font-size: 15px; font-weight: 600; }
666
+ .dialog-sub { font-size: 12px; color: var(--text-faint); margin-bottom: 16px; line-height: 18px; }
667
+ .form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
668
+ .field { display: flex; flex-direction: column; gap: 5px; }
669
+ .field.span2 { grid-column: span 2; }
670
+ .field.check { flex-direction: row; align-items: center; gap: 8px; }
671
+ .field > span { font-size: 11px; color: var(--text-faint); text-transform: uppercase; letter-spacing: 0.05em; }
672
+ .field input, .field select {
673
+ height: 34px; padding: 0 11px;
674
+ background: color-mix(in srgb, var(--bg-deep) 70%, #000);
675
+ border: 1px solid var(--border); border-radius: var(--radius);
676
+ color: var(--text); font-family: var(--font); font-size: 12.5px; outline: none;
677
+ transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
678
+ }
679
+ .field select {
680
+ appearance: none;
681
+ background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'><path d='M3 5l3 3 3-3' fill='none' stroke='%23a8a8b0' stroke-width='1.3' stroke-linecap='round'/></svg>");
682
+ background-repeat: no-repeat;
683
+ background-position: right 10px center;
684
+ padding-right: 30px;
685
+ }
686
+ .field input:focus, .field select:focus {
687
+ border-color: color-mix(in srgb, var(--accent) 60%, transparent);
688
+ box-shadow: 0 0 0 3px var(--accent-soft);
689
+ }
690
+ .field input::placeholder { color: var(--text-faint); }
691
+ .field input[type="checkbox"] { height: 14px; width: 14px; accent-color: var(--accent); }
692
+
693
+ .test-row { display: flex; align-items: center; gap: 12px; margin-top: 16px; }
694
+ .test-result { font-size: 12px; color: var(--text-muted); font-family: var(--mono); }
695
+ .test-result.ok { color: var(--green); }
696
+ .test-result.bad { color: #ff9ea1; }
697
+ .dialog-foot { display: flex; justify-content: flex-end; gap: 8px; margin-top: 20px; }
698
+ .dialog-foot .spacer { flex: 1; }
699
+
700
+ .dialog.palette { width: 560px; padding: 0; overflow: hidden; }
701
+ #command-input {
702
+ width: 100%; height: 46px; padding: 0 16px; background: transparent;
703
+ border: 0; border-bottom: 1px solid var(--border-muted); color: var(--text);
704
+ font-family: var(--font); font-size: 14px; outline: none;
705
+ }
706
+ .command-list { max-height: 320px; overflow-y: auto; padding: 6px; }
707
+ .command-item {
708
+ display: flex; align-items: center; gap: 10px; padding: 9px 12px;
709
+ border-radius: var(--radius); cursor: pointer; font-size: 13px; color: var(--text-muted);
710
+ }
711
+ .command-item.active, .command-item:hover { background: var(--overlay-hover); color: var(--text); }
712
+ .command-item .kbd { margin-left: auto; font-family: var(--mono); font-size: 10.5px; color: var(--text-faint); }
713
+
714
+ /* ── Toast ────────────────────────────────────────────────── */
715
+ .toast {
716
+ position: fixed; bottom: 46px; left: 50%;
717
+ background: linear-gradient(180deg, var(--layer-02), var(--layer-01));
718
+ border: 1px solid var(--border-strong);
719
+ color: var(--text); padding: 10px 18px; border-radius: 999px;
720
+ font-size: 12.5px; font-weight: 500; z-index: 200;
721
+ box-shadow: var(--shadow-3), inset 0 1px 0 rgba(255, 255, 255, 0.06);
722
+ animation: toast-in 260ms var(--ease-spring) both;
723
+ max-width: min(560px, calc(100vw - 48px));
724
+ }
725
+ @keyframes toast-in {
726
+ from { opacity: 0; transform: translate(-50%, 12px) scale(0.96); }
727
+ to { opacity: 1; transform: translate(-50%, 0) scale(1); }
728
+ }
729
+ .toast:not(.hidden) { transform: translateX(-50%); }
730
+ .toast.err { border-color: rgba(241, 72, 79, 0.5); color: #ff9ea1; }
731
+
732
+ .view { display: flex; flex-direction: column; flex: 1; min-height: 0; }
733
+ .view.hidden { display: none; }
734
+ .btn.big {
735
+ height: 36px; padding: 0 20px; font-size: 13.5px; margin: 10px 0 6px;
736
+ box-shadow: 0 6px 20px var(--accent-glow), inset 0 1px 0 rgba(255, 255, 255, 0.15);
737
+ }
738
+
739
+ /* Sidebar model chip, rendered as a full-width control. */
740
+ .model-chip {
741
+ display: flex; align-items: center; gap: 8px;
742
+ width: 100%; background: transparent; border: 1px solid transparent;
743
+ border-radius: var(--radius); padding: 8px 10px; cursor: pointer; text-align: left;
744
+ transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease);
745
+ }
746
+ .model-chip:hover { background: var(--overlay-hover); border-color: var(--border-muted); }
747
+ .model-chip .chev { width: 12px; height: 12px; margin-left: auto; color: var(--text-faint); }
748
+
749
+ /* ── Model picker popover (OpenCode-style) ────────────────── */
750
+ .model-popover {
751
+ position: fixed; width: 288px; z-index: 150;
752
+ background: linear-gradient(180deg, var(--layer-01), color-mix(in srgb, var(--layer-01) 95%, #000));
753
+ border: 1px solid var(--border);
754
+ border-radius: var(--radius-lg); box-shadow: var(--shadow-3);
755
+ display: flex; flex-direction: column; overflow: hidden;
756
+ animation: pop-in 140ms var(--ease) both;
757
+ transform-origin: bottom left;
758
+ }
759
+ @keyframes pop-in {
760
+ from { opacity: 0; transform: translateY(4px) scale(0.98); }
761
+ to { opacity: 1; transform: none; }
762
+ }
763
+ .mp-search { display: flex; align-items: center; gap: 8px; height: 34px; padding: 0 12px; color: var(--text-faint); }
764
+ .mp-search svg { width: 14px; height: 14px; flex: none; }
765
+ .mp-search input {
766
+ flex: 1; min-width: 0; height: 34px; border: 0; background: transparent;
767
+ color: var(--text); font-family: inherit; font-size: 13px; outline: none;
768
+ }
769
+ .mp-search input::placeholder { color: var(--text-faint); }
770
+ .mp-clear {
771
+ width: 20px; height: 20px; display: grid; place-items: center; border: 0;
772
+ background: transparent; color: var(--text-faint); border-radius: 4px; cursor: pointer; font-size: 11px;
773
+ }
774
+ .mp-clear:hover { background: var(--overlay-hover); color: var(--text); }
775
+ .mp-divider { height: 1px; background: var(--border-muted); }
776
+ .mp-list { max-height: 240px; overflow-y: auto; padding: 2px; }
777
+ .mp-group-label {
778
+ position: sticky; top: 0; z-index: 1; background: var(--layer-01);
779
+ padding: 6px 12px 4px; font-size: 10.5px; text-transform: uppercase;
780
+ letter-spacing: 0.06em; color: var(--text-faint); font-weight: 600;
781
+ }
782
+ .mp-item {
783
+ display: flex; align-items: center; gap: 8px; width: 100%; padding: 6px 12px;
784
+ background: transparent; border: 0; border-radius: 4px; color: var(--text-muted);
785
+ font-family: inherit; font-size: 13px; text-align: left; cursor: pointer;
786
+ }
787
+ .mp-item:hover, .mp-item.active { background: var(--overlay-hover); color: var(--text); }
788
+ .mp-item .mp-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1; }
789
+ .mp-item.selected { color: var(--text); }
790
+ .mp-item .check { color: var(--accent-text); flex: none; }
791
+ .mp-tag {
792
+ font-size: 9.5px; font-weight: 700; letter-spacing: 0.04em; padding: 1px 6px;
793
+ border-radius: 999px; background: var(--layer-02); color: var(--text-muted); flex: none;
794
+ }
795
+ .mp-tag.free { background: rgba(73, 201, 112, 0.16); color: var(--green); }
796
+ .mp-empty { padding: 14px 12px; color: var(--text-faint); font-size: 12.5px; }
797
+ .mp-manage {
798
+ display: flex; align-items: center; gap: 8px; padding: 9px 12px; cursor: pointer;
799
+ color: var(--text-muted); font-size: 12.5px;
800
+ }
801
+ .mp-manage:hover { background: var(--overlay-hover); color: var(--text); }
802
+ .mp-manage svg { width: 14px; height: 14px; }
803
+
804
+ /* ── Chat ─────────────────────────────────────────────────── */
805
+ .suggestions { display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; margin-top: 18px; max-width: 560px; }
806
+ .suggestion {
807
+ padding: 7px 12px; background: var(--bg-base); border: 1px solid var(--border-muted);
808
+ border-radius: 999px; color: var(--text-muted); font-family: inherit; font-size: 12px; cursor: pointer;
809
+ transition: background var(--dur) var(--ease), color var(--dur) var(--ease),
810
+ border-color var(--dur) var(--ease), transform 140ms var(--ease);
811
+ }
812
+ .suggestion:hover {
813
+ background: var(--overlay-hover); color: var(--text);
814
+ border-color: var(--border-strong); transform: translateY(-1px);
815
+ }
816
+
817
+ /* The chat mirror of an assistant/user turn: keep one consistent rhythm. */
818
+ #view-chat .stream { padding: 26px 30px 8px; }
819
+ #chat-stream .msg { max-width: 780px; }
820
+
821
+ .thinking {
822
+ max-width: 780px; margin: 0 auto 10px; border-left: 2px solid var(--border-strong);
823
+ padding: 4px 12px; color: var(--text-faint); font-size: 12px; line-height: 18px;
824
+ white-space: pre-wrap; user-select: text; display: none;
825
+ }
826
+ .thinking.show { display: block; }
827
+ .thinking-toggle {
828
+ max-width: 780px; margin: 0 auto 8px; font-size: 11px; color: var(--text-faint);
829
+ cursor: pointer; user-select: none; font-family: var(--mono);
830
+ }
831
+ .thinking-toggle:hover { color: var(--text-muted); }
832
+
833
+ /* ── Guided wizard ────────────────────────────────────────── */
834
+ .dialog.wizard { width: 640px; }
835
+ .wizard-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
836
+ .wizard-progress { display: flex; gap: 6px; margin: 14px 0 4px; }
837
+ .wdot { width: 100%; height: 3px; border-radius: 999px; background: var(--layer-02); transition: background 150ms ease; }
838
+ .wdot.active { background: var(--accent); }
839
+ .wdot.done { background: var(--accent-hover); }
840
+ .wizard-body { min-height: 260px; padding: 16px 2px 4px; }
841
+ .wstep { display: none; flex-direction: column; gap: 14px; }
842
+ .wstep.active { display: flex; }
843
+ .wizard-foot { display: flex; align-items: center; gap: 8px; margin-top: 18px; }
844
+ .wizard-foot .spacer { flex: 1; }
845
+ .wiz-note { font-size: 12px; color: var(--text-faint); line-height: 18px; }
846
+
847
+ .kind-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
848
+ .kind-card {
849
+ display: flex; flex-direction: column; align-items: flex-start; gap: 3px;
850
+ padding: 14px; background: var(--bg-deep); border: 1px solid var(--border);
851
+ border-radius: var(--radius); color: var(--text-muted); font-family: inherit;
852
+ text-align: left; cursor: pointer;
853
+ }
854
+ .kind-card svg { width: 22px; height: 22px; margin-bottom: 6px; color: var(--text-faint); }
855
+ .kind-card b { color: var(--text); font-size: 13px; font-weight: 600; }
856
+ .kind-card span { font-size: 11.5px; color: var(--text-faint); }
857
+ .kind-card:hover { border-color: var(--border-strong); }
858
+ .kind-card.active { border-color: var(--accent); background: rgba(59, 92, 246, 0.10); }
859
+ .kind-card.active svg { color: var(--accent-text); }
860
+
861
+ .choice-list { display: flex; flex-direction: column; gap: 10px; }
862
+ .choice {
863
+ display: flex; gap: 12px; padding: 14px; background: var(--bg-deep);
864
+ border: 1px solid var(--border); border-radius: var(--radius); cursor: pointer;
865
+ }
866
+ .choice:hover { border-color: var(--border-strong); }
867
+ .choice input { margin-top: 3px; accent-color: var(--accent); }
868
+ .choice b { display: block; color: var(--text); font-size: 13px; }
869
+ .choice span { font-size: 11.5px; color: var(--text-faint); line-height: 16px; }
870
+ .choice:has(input:checked) { border-color: var(--accent); background: rgba(59, 92, 246, 0.08); }
871
+
872
+ .depth-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
873
+ .depth-card {
874
+ display: flex; flex-direction: column; gap: 3px; padding: 14px; background: var(--bg-deep);
875
+ border: 1px solid var(--border); border-radius: var(--radius); color: var(--text-muted);
876
+ font-family: inherit; cursor: pointer; text-align: left;
877
+ }
878
+ .depth-card b { color: var(--text); font-size: 13px; }
879
+ .depth-card span { font-size: 11px; color: var(--text-faint); font-family: var(--mono); }
880
+ .depth-card em { font-size: 10.5px; color: var(--text-faint); font-style: normal; }
881
+ .depth-card.active { border-color: var(--accent); background: rgba(59, 92, 246, 0.10); }
882
+
883
+ .preset-row { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
884
+ .preset-label { font-size: 11px; color: var(--text-faint); }
885
+ .preset-row .mini-btn { flex: none; padding: 0 10px; }
886
+
887
+ .wiz-summary {
888
+ background: var(--bg-deep); border: 1px solid var(--border-muted);
889
+ border-radius: var(--radius); padding: 12px 14px; font-size: 12px; color: var(--text-muted);
890
+ font-family: var(--mono); line-height: 19px; white-space: pre-wrap;
891
+ }
892
+
893
+ .form-grid .field textarea {
894
+ background: color-mix(in srgb, var(--bg-deep) 70%, #000);
895
+ border: 1px solid var(--border); border-radius: var(--radius);
896
+ color: var(--text); font-family: var(--font); font-size: 12.5px; padding: 9px 11px;
897
+ outline: none; resize: vertical; min-height: 64px; line-height: 19px;
898
+ transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
899
+ }
900
+ .form-grid .field textarea:focus {
901
+ border-color: color-mix(in srgb, var(--accent) 60%, transparent);
902
+ box-shadow: 0 0 0 3px var(--accent-soft);
903
+ }
904
+ .mini-btn.accent {
905
+ background: rgba(59, 92, 246, 0.16); border-color: rgba(59, 92, 246, 0.4); color: var(--accent-text);
906
+ }
907
+ .mini-btn.accent:hover { background: rgba(59, 92, 246, 0.26); color: #fff; }
908
+
909
+ /* ── Settings (OpenCode-style) ───────────────────────────── */
910
+ .dialog.settings {
911
+ width: 720px; height: 620px; max-height: 86vh; padding: 0;
912
+ display: flex; flex-direction: column; overflow: hidden;
913
+ }
914
+ .settings-head {
915
+ display: flex; align-items: center; justify-content: space-between;
916
+ padding: 10px 12px 0 16px; border-bottom: 1px solid var(--border-muted);
917
+ }
918
+ .settings-tabs { display: flex; gap: 2px; }
919
+ .stab {
920
+ height: 32px; padding: 0 12px; background: transparent; border: 0;
921
+ border-bottom: 2px solid transparent; color: var(--text-faint);
922
+ font-family: inherit; font-size: 12.5px; cursor: pointer;
923
+ }
924
+ .stab:hover { color: var(--text-muted); }
925
+ .stab.active { color: var(--text); border-bottom-color: var(--accent); }
926
+
927
+ .spanel { display: none; flex-direction: column; flex: 1; min-height: 0; }
928
+ .spanel.active { display: flex; }
929
+ .spanel-head {
930
+ display: flex; align-items: center; justify-content: space-between;
931
+ padding: 16px 20px 10px;
932
+ }
933
+ .spanel-title { font-size: 15px; font-weight: 600; }
934
+ .spanel-body { flex: 1; min-height: 0; overflow-y: auto; padding: 0 20px 20px; }
935
+
936
+ .ssearch {
937
+ display: flex; align-items: center; gap: 8px; margin: 0 20px 4px;
938
+ height: 32px; padding: 0 10px; background: var(--bg-deep);
939
+ border: 1px solid var(--border); border-radius: var(--radius); color: var(--text-faint);
940
+ }
941
+ .ssearch svg { width: 14px; height: 14px; flex: none; }
942
+ .ssearch input {
943
+ flex: 1; min-width: 0; height: 30px; border: 0; background: transparent;
944
+ color: var(--text); font-family: inherit; font-size: 12.5px; outline: none;
945
+ }
946
+ .ssearch input::placeholder { color: var(--text-faint); }
947
+ .ssearch:focus-within { border-color: var(--accent); }
948
+
949
+ .s-section { margin-top: 18px; }
950
+ .s-section-title {
951
+ font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.07em;
952
+ color: var(--text-faint); font-weight: 600; margin-bottom: 8px;
953
+ }
954
+ .s-list { display: flex; flex-direction: column; gap: 2px; }
955
+
956
+ .s-group { margin-bottom: 14px; }
957
+ .s-group-header {
958
+ display: flex; align-items: center; gap: 8px; padding: 6px 4px;
959
+ border-bottom: 1px solid var(--border-muted); margin-bottom: 2px;
960
+ }
961
+ .s-group-trigger {
962
+ display: flex; align-items: center; gap: 8px; flex: 1; min-width: 0;
963
+ background: transparent; border: 0; color: var(--text); font-family: inherit;
964
+ font-size: 12.5px; font-weight: 600; cursor: pointer; text-align: left; padding: 0;
965
+ }
966
+ .s-chev { width: 16px; height: 16px; color: var(--text-faint); flex: none; display: grid; place-items: center; }
967
+ .s-chev svg { width: 10px; height: 10px; }
968
+ .s-provider-dot {
969
+ width: 16px; height: 16px; border-radius: 4px; flex: none;
970
+ background: var(--layer-02); color: var(--text-muted);
971
+ display: grid; place-items: center; font-size: 9px; font-weight: 700;
972
+ text-transform: uppercase;
973
+ }
974
+ .s-group-count { color: var(--text-faint); font-size: 11px; font-family: var(--mono); }
975
+
976
+ .s-row {
977
+ display: flex; align-items: center; gap: 10px; padding: 7px 8px;
978
+ border-radius: var(--radius-sm);
979
+ }
980
+ .s-row:hover { background: var(--overlay-hover); }
981
+ .s-row .s-name { flex: 1; min-width: 0; font-size: 12.5px; color: var(--text); }
982
+ .s-row.hidden-model .s-name { color: var(--text-faint); }
983
+ .s-row .s-sub { font-family: var(--mono); font-size: 10.5px; color: var(--text-faint); }
984
+ .s-active-dot {
985
+ width: 6px; height: 6px; border-radius: 50%; background: var(--green); flex: none;
986
+ }
987
+ .s-remove {
988
+ width: 22px; height: 22px; border: 0; background: transparent; color: var(--text-faint);
989
+ border-radius: 4px; cursor: pointer; opacity: 0; font-size: 11px;
990
+ }
991
+ .s-row:hover .s-remove { opacity: 1; }
992
+ .s-remove:hover { background: rgba(241, 72, 79, 0.2); color: #ff9ea1; }
993
+
994
+ /* switch */
995
+ .switch {
996
+ position: relative; width: 30px; height: 17px; flex: none; cursor: pointer;
997
+ background: var(--layer-02); border: 1px solid var(--border); border-radius: 999px;
998
+ transition: background 120ms ease;
999
+ }
1000
+ .switch::after {
1001
+ content: ""; position: absolute; top: 1px; left: 1px; width: 13px; height: 13px;
1002
+ border-radius: 50%; background: var(--text-muted); transition: transform 120ms ease, background 120ms ease;
1003
+ }
1004
+ .switch.on { background: var(--accent); border-color: var(--accent); }
1005
+ .switch.on::after { transform: translateX(13px); background: #fff; }
1006
+
1007
+ /* ── Pinned activity feed ─────────────────────────────────── */
1008
+ /* Thinking / Exploring / working lines are hoisted into this container so they
1009
+ stay at the very bottom of the stream, under the latest content, instead of
1010
+ scrolling away above a long message. */
1011
+ .activity-host {
1012
+ position: sticky;
1013
+ bottom: 0;
1014
+ z-index: 5;
1015
+ padding-bottom: 6px;
1016
+ margin-top: 2px;
1017
+ background: linear-gradient(
1018
+ 180deg,
1019
+ transparent,
1020
+ color-mix(in srgb, var(--bg-deep) 88%, transparent) 42%
1021
+ );
1022
+ backdrop-filter: blur(3px);
1023
+ }
1024
+
1025
+ /* ── OpenCode-style grouped tool surface ──────────────────── */
1026
+ .run-summary {
1027
+ display: flex; align-items: center; gap: 8px; max-width: 780px;
1028
+ margin: 3px auto 7px; padding: 5px 4px; cursor: pointer;
1029
+ font-size: 14px; font-weight: 500; color: var(--text);
1030
+ border-radius: var(--radius-sm);
1031
+ transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
1032
+ }
1033
+ .run-summary:hover { background: var(--overlay-hover); color: #fff; }
1034
+ .run-summary .rs-title { display: flex; align-items: baseline; gap: 0; min-width: 0; }
1035
+ .run-summary .rs-label { flex: none; }
1036
+ .run-summary.busy .rs-label {
1037
+ color: var(--text-muted);
1038
+ background-image: linear-gradient(
1039
+ 90deg,
1040
+ transparent calc(50% - 5.2ch),
1041
+ var(--text) 50%,
1042
+ transparent calc(50% + 5.2ch)
1043
+ );
1044
+ background-size: 360% 100%;
1045
+ background-position: 100% 0;
1046
+ background-repeat: no-repeat;
1047
+ -webkit-background-clip: text;
1048
+ background-clip: text;
1049
+ -webkit-text-fill-color: transparent;
1050
+ animation: text-shimmer 1.2s linear infinite;
1051
+ }
1052
+ @keyframes text-shimmer {
1053
+ 0% { background-position: 100% 0; }
1054
+ 100% { background-position: 0% 0; }
1055
+ }
1056
+ .run-summary .rs-counts {
1057
+ min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
1058
+ font-weight: 400; color: var(--text-base, var(--text));
1059
+ }
1060
+ .run-summary .rs-chevron {
1061
+ color: var(--text-faint); flex: none; font-size: 13px;
1062
+ transition: transform 0.15s ease;
1063
+ }
1064
+ .run-summary.open .rs-chevron { transform: rotate(90deg); }
1065
+ .rs-log {
1066
+ display: none; max-width: 780px; margin: 0 auto 10px; padding-left: 4px;
1067
+ border-left: 1px solid var(--border-muted);
1068
+ }
1069
+ .rs-log.show { display: block; }
1070
+
1071
+ /* Each action is its own collapsed row (OpenCode BasicTool pattern):
1072
+ title · subtitle · args, chevron on the right, details on demand. */
1073
+ .rs-log-item { padding: 0; }
1074
+ .rs-log-row {
1075
+ display: flex; align-items: baseline; gap: 8px; padding: 4px 6px;
1076
+ cursor: pointer; border-radius: var(--radius-sm); min-width: 0;
1077
+ }
1078
+ .rs-log-row:hover { background: var(--overlay-hover); }
1079
+ .rs-log-row .tool-status { align-self: center; }
1080
+ .rs-log-name {
1081
+ flex: none; font-family: var(--font); font-size: 13px; font-weight: 500;
1082
+ color: var(--text);
1083
+ }
1084
+ .rs-log-args {
1085
+ flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis;
1086
+ white-space: nowrap; font-size: 13px; color: var(--text-muted);
1087
+ font-variant-numeric: tabular-nums;
1088
+ }
1089
+ .rs-log-chevron {
1090
+ flex: none; color: var(--text-faint); font-size: 12px; opacity: 0;
1091
+ transition: transform 0.15s ease, opacity 0.15s ease;
1092
+ }
1093
+ .rs-log-row:hover .rs-log-chevron,
1094
+ .rs-log-item.open .rs-log-chevron { opacity: 1; }
1095
+ .rs-log-item.open .rs-log-chevron { transform: rotate(90deg); }
1096
+ .rs-log-item.error .rs-log-name { color: #ff9ea1; }
1097
+ .rs-log-detail { display: none; padding: 2px 0 6px 14px; }
1098
+ .rs-log-detail.show { display: block; }
1099
+ .rs-log-detail .tool {
1100
+ margin: 0 0 6px; border: 1px solid var(--border-muted);
1101
+ background: var(--bg-deep); border-radius: var(--radius-sm);
1102
+ }
1103
+ .rs-log-detail .tool-body { display: block; }
1104
+
1105
+ /* ── Thinking: one shimmering line, detail on demand ──────── */
1106
+ .thinking-line {
1107
+ display: flex; align-items: baseline; gap: 8px; max-width: 780px;
1108
+ margin: 3px auto 7px; padding: 5px 4px; cursor: pointer;
1109
+ font-size: 14px; font-weight: 500; color: var(--text);
1110
+ border-radius: var(--radius-sm);
1111
+ transition: background var(--dur) var(--ease);
1112
+ }
1113
+ .thinking-line:hover { background: var(--overlay-hover); }
1114
+ .thinking-line .tl-label { flex: none; color: var(--text-muted); }
1115
+ .thinking-line .tl-text {
1116
+ min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
1117
+ font-weight: 400; color: var(--text-base, var(--text));
1118
+ }
1119
+ .thinking-line .tl-text.shimmer {
1120
+ background-image: linear-gradient(
1121
+ 90deg,
1122
+ transparent calc(50% - 5.2ch),
1123
+ var(--text) 50%,
1124
+ transparent calc(50% + 5.2ch)
1125
+ );
1126
+ background-size: 360% 100%;
1127
+ background-position: 100% 0;
1128
+ background-repeat: no-repeat;
1129
+ -webkit-background-clip: text;
1130
+ background-clip: text;
1131
+ -webkit-text-fill-color: transparent;
1132
+ animation: text-shimmer 1.2s linear infinite;
1133
+ }
1134
+ .thinking-line .tl-chevron { color: var(--text-faint); flex: none; font-size: 13px; }
1135
+ .thinking-body {
1136
+ display: none; max-width: 780px; margin: 0 auto 12px; padding: 8px 12px;
1137
+ border-left: 2px solid var(--border-strong); color: var(--text-faint);
1138
+ font-size: 12px; line-height: 18px; white-space: pre-wrap; user-select: text;
1139
+ max-height: 260px; overflow-y: auto;
1140
+ }
1141
+ .thinking-body.show { display: block; }
1142
+
1143
+ /* ── Workspace card ──────────────────────────────────────── */
1144
+ .ws-label { margin-top: 10px; }
1145
+ .workspace-card {
1146
+ display: flex; align-items: center; gap: 8px; width: 100%;
1147
+ padding: 8px 10px; background: var(--bg-base);
1148
+ border: 1px solid var(--border-muted); border-radius: var(--radius);
1149
+ color: var(--text-muted); font-family: inherit; font-size: 11.5px;
1150
+ cursor: pointer; text-align: left;
1151
+ }
1152
+ .workspace-card:hover { background: var(--overlay-hover); color: var(--text); border-color: var(--border-strong); }
1153
+ .workspace-card svg { width: 13px; height: 13px; flex: none; color: var(--text-faint); }
1154
+ .workspace-card .ws-name {
1155
+ flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis;
1156
+ white-space: nowrap; font-family: var(--mono); font-size: 11px;
1157
+ }
1158
+ .workspace-card .ws-badge {
1159
+ flex: none; font-family: var(--mono); font-size: 10px; padding: 1px 6px;
1160
+ border-radius: 999px; background: var(--layer-02); color: var(--text-faint);
1161
+ }
1162
+
1163
+ /* ── Dashboard (post-audit summary) ───────────────────────── */
1164
+ .dev-only-inline { display: inline-flex; align-items: center; gap: 8px; }
1165
+
1166
+ .dash-hero {
1167
+ border-radius: var(--radius-lg); padding: 16px;
1168
+ border: 1px solid var(--border-muted);
1169
+ background: linear-gradient(180deg, var(--bg-base), color-mix(in srgb, var(--bg-base) 94%, #000));
1170
+ margin-bottom: 16px;
1171
+ }
1172
+ .dash-hero .dh-risk { font-size: 15px; font-weight: 650; margin-bottom: 12px; }
1173
+ .dash-hero.ok { border-color: rgba(87, 207, 125, 0.4); }
1174
+ .dash-hero.warn { border-color: rgba(255, 154, 92, 0.4); }
1175
+ .dash-hero.bad { border-color: rgba(241, 72, 79, 0.4); }
1176
+ .dh-metrics { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; }
1177
+ .dh-metric { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
1178
+ .dh-metric b { font-size: 20px; font-weight: 700; line-height: 1; font-variant-numeric: tabular-nums; }
1179
+ .dh-metric b small { font-size: 11px; color: var(--text-faint); font-weight: 500; }
1180
+ .dh-metric span { font-size: 9.5px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-faint); }
1181
+
1182
+ .dash-section { margin-bottom: 18px; }
1183
+ .dash-title {
1184
+ font-size: 11px; text-transform: uppercase; letter-spacing: 0.07em;
1185
+ color: var(--text-faint); font-weight: 650; margin-bottom: 10px;
1186
+ }
1187
+
1188
+ .sev-row { display: grid; grid-template-columns: 88px 1fr 26px; align-items: center; gap: 10px; margin-bottom: 7px; }
1189
+ .sev-name { display: flex; align-items: center; gap: 7px; font-size: 12px; color: var(--text-muted); }
1190
+ .sev-dot { width: 8px; height: 8px; border-radius: 50%; flex: none; display: inline-block; }
1191
+ .sev-bar { height: 6px; border-radius: 999px; background: var(--layer-02); overflow: hidden; }
1192
+ .sev-bar i { display: block; height: 100%; border-radius: 999px; transition: width var(--dur) var(--ease); }
1193
+ .sev-count { text-align: right; font-size: 12px; font-variant-numeric: tabular-nums; color: var(--text); }
1194
+
1195
+ .dash-finding {
1196
+ display: grid; grid-template-columns: 10px 1fr auto; align-items: center;
1197
+ gap: 4px 8px; padding: 8px 10px; border: 1px solid var(--border-muted);
1198
+ border-radius: var(--radius); margin-bottom: 6px; background: var(--bg-base);
1199
+ }
1200
+ .dash-finding .sev-dot { grid-row: 1 / 3; align-self: center; }
1201
+ .dash-finding .df-title {
1202
+ grid-column: 2; font-size: 12.5px; color: var(--text);
1203
+ overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
1204
+ }
1205
+ .dash-finding .df-where {
1206
+ grid-column: 2 / 4; font-family: var(--mono); font-size: 10.5px; color: var(--text-faint);
1207
+ overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
1208
+ }
1209
+ .dash-finding .df-where:empty { display: none; }
1210
+ .dash-finding .df-cvss { grid-column: 3; text-align: right; font-family: var(--mono); font-size: 11px; color: var(--text-muted); }
1211
+
1212
+ .dash-round {
1213
+ padding: 9px 11px; border: 1px solid var(--border-muted); border-radius: var(--radius);
1214
+ margin-bottom: 6px; background: var(--bg-base);
1215
+ }
1216
+ .dash-round .dr-head { display: flex; justify-content: space-between; gap: 8px; font-size: 12px; color: var(--text); }
1217
+ .dash-round .dr-head span { color: var(--text-faint); font-size: 11px; }
1218
+ /* ── Toolbox setup ───────────────────────────────────────── */
1219
+ .setup-box {
1220
+ display: flex; flex-direction: column; gap: 1px; margin-bottom: 14px;
1221
+ background: var(--bg-deep); border: 1px solid var(--border-muted);
1222
+ border-radius: var(--radius); overflow: hidden;
1223
+ }
1224
+ .setup-row {
1225
+ display: flex; align-items: center; justify-content: space-between;
1226
+ padding: 8px 12px; font-size: 12.5px;
1227
+ }
1228
+ .setup-row span { color: var(--text-faint); }
1229
+ .setup-row b { color: var(--text); font-weight: 500; font-family: var(--mono); font-size: 12px; }
1230
+ .setup-row b.ok { color: var(--green); }
1231
+ .setup-row b.bad { color: var(--orange); }
1232
+
1233
+ .workspace-card .ws-badge.on { background: rgba(73, 201, 112, 0.16); color: var(--green); }
1234
+ .workspace-card .ws-badge.off { background: rgba(255, 134, 72, 0.16); color: var(--orange); }
1235
+
1236
+ /* ── Todo dock (OpenCode SessionTodoDock) ─────────────────── */
1237
+ .todo-dock {
1238
+ max-width: 820px; margin: 0 auto 8px; background: var(--bg-base);
1239
+ border: 1px solid var(--border); border-radius: 12px; overflow: hidden;
1240
+ }
1241
+ .todo-dock.hidden { display: none; }
1242
+ .td-head {
1243
+ display: flex; align-items: center; gap: 8px; height: 42px; padding: 0 10px 0 16px;
1244
+ cursor: pointer; user-select: none;
1245
+ }
1246
+ .td-head:hover { background: var(--overlay-hover); }
1247
+ .td-progress {
1248
+ flex: none; font-size: 13px; font-weight: 440; letter-spacing: -0.04px;
1249
+ color: var(--text-muted); white-space: pre;
1250
+ }
1251
+ .td-progress b { font-weight: 600; color: var(--text); font-variant-numeric: tabular-nums; }
1252
+ .td-preview {
1253
+ flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis;
1254
+ white-space: nowrap; font-size: 13px; font-weight: 440; color: var(--text-faint);
1255
+ margin-left: 4px;
1256
+ }
1257
+ .td-chevron {
1258
+ flex: none; width: 14px; height: 14px; color: var(--text-faint);
1259
+ transition: transform 0.3s cubic-bezier(0.34, 1, 0.64, 1);
1260
+ }
1261
+ .todo-dock.collapsed .td-chevron { transform: rotate(-90deg); }
1262
+ .todo-dock.collapsed .td-list { display: none; }
1263
+ .td-list {
1264
+ display: flex; flex-direction: column; gap: 6px; padding: 0 12px 14px;
1265
+ max-height: 240px; overflow-y: auto;
1266
+ }
1267
+ .todo-item {
1268
+ display: flex; align-items: flex-start; gap: 12px;
1269
+ opacity: 0.94; transition: opacity 220ms cubic-bezier(0.22, 1, 0.36, 1);
1270
+ }
1271
+ .todo-box {
1272
+ position: relative; width: 16px; height: 16px; flex: none; margin-top: 1px;
1273
+ border: 1px solid var(--border-strong); border-radius: 4px;
1274
+ display: grid; place-items: center;
1275
+ transition: border-color 220ms cubic-bezier(0.22, 1, 0.36, 1),
1276
+ background-color 220ms cubic-bezier(0.22, 1, 0.36, 1);
1277
+ }
1278
+ .todo-item[data-state="completed"] .todo-box,
1279
+ .todo-item[data-state="cancelled"] .todo-box { background: var(--layer-02); }
1280
+ .todo-tick { color: var(--text); opacity: 0; transform: scale(0.9); transition: opacity 180ms, transform 220ms; }
1281
+ .todo-item[data-state="completed"] .todo-tick { opacity: 1; transform: scale(1); }
1282
+ .todo-spinner { color: var(--accent-text); }
1283
+ .todo-spinner circle { animation: pulse-scale 1.2s ease-in-out infinite; transform-origin: center; transform-box: fill-box; }
1284
+ .todo-item[data-state="in_progress"] .todo-box { border-color: var(--accent); }
1285
+ .todo-text {
1286
+ min-width: 0; font-size: 13.5px; line-height: 20px; color: var(--text);
1287
+ word-break: break-word; position: relative;
1288
+ }
1289
+ .todo-item[data-state="pending"] .todo-text { opacity: 0.92; }
1290
+ .todo-item[data-state="completed"] .todo-text,
1291
+ .todo-item[data-state="cancelled"] .todo-text { color: var(--text-faint); }
1292
+ .todo-item[data-state="completed"] .todo-text::after,
1293
+ .todo-item[data-state="cancelled"] .todo-text::after {
1294
+ content: ""; position: absolute; left: 0; top: 50%; height: 1px;
1295
+ width: 100%; background: var(--text-faint);
1296
+ animation: todo-strike 260ms cubic-bezier(0.22, 1, 0.36, 1) both;
1297
+ }
1298
+ @keyframes todo-strike { from { transform: scaleX(0); transform-origin: left; } to { transform: scaleX(1); transform-origin: left; } }
1299
+
1300
+ /* dynamic exploration line */
1301
+ @keyframes pulse-scale {
1302
+ 0%, 100% { transform: scale(1); }
1303
+ 50% { transform: scale(0.6666667); }
1304
+ }
1305
+
1306
+ @media (prefers-reduced-motion: reduce) {
1307
+ .run-summary.busy .rs-label,
1308
+ .thinking-line .tl-text.shimmer {
1309
+ animation: none; -webkit-text-fill-color: currentColor;
1310
+ color: var(--text-muted); background-image: none;
1311
+ }
1312
+ }
1313
+
1314
+ .tool-count { font-family: var(--mono); font-size: 10.5px; color: var(--text-faint); flex: none; }
1315
+ .tool-chevron { color: var(--text-faint); flex: none; font-size: 13px; transition: transform 120ms ease; }
1316
+ .tool.open .tool-chevron { transform: rotate(90deg); }
1317
+
1318
+ /* ── Compaction checkpoint card ───────────────────────────── */
1319
+ .compaction {
1320
+ max-width: 780px; margin: 0 auto 14px; background: var(--bg-base);
1321
+ border: 1px solid var(--border); border-left: 3px solid var(--purple);
1322
+ border-radius: var(--radius); padding: 12px 14px;
1323
+ }
1324
+ .compaction .cp-head { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; }
1325
+ .compaction .cp-badge {
1326
+ font-size: 9.5px; font-weight: 700; letter-spacing: 0.06em;
1327
+ padding: 2px 7px; border-radius: 999px; background: rgba(130, 113, 248, 0.18); color: #b9b8f5;
1328
+ }
1329
+ .compaction .cp-meta { font-family: var(--mono); font-size: 11px; color: var(--text-faint); }
1330
+ .compaction .cp-summary {
1331
+ margin: 0; padding: 0; background: none; border: 0; font-family: var(--mono);
1332
+ font-size: 11.5px; line-height: 17px; color: var(--text-muted);
1333
+ white-space: pre-wrap; word-break: break-word; max-height: 180px; overflow-y: auto;
1334
+ }
1335
+ .compaction .cp-note { margin-top: 8px; font-size: 11px; color: var(--text-faint); }
1336
+
1337
+ /* ── Trace panel ──────────────────────────────────────────── */
1338
+ .trace-head {
1339
+ display: flex; flex-direction: column; gap: 8px; padding: 4px 2px 10px;
1340
+ font-size: 11.5px; color: var(--text-faint); line-height: 17px;
1341
+ border-bottom: 1px solid var(--border-muted); margin-bottom: 8px;
1342
+ }
1343
+ .trace-head .mini-btn { align-self: flex-start; padding: 0 10px; }
1344
+ .trace-empty { color: var(--text-faint); font-size: 12px; padding: 8px 4px; }
1345
+ .trace-item {
1346
+ border-left: 2px solid var(--border); padding: 6px 0 6px 10px; margin-bottom: 6px;
1347
+ font-size: 11.5px; color: var(--text-muted);
1348
+ }
1349
+ .trace-item.kind-tool_call { border-left-color: var(--cyan); }
1350
+ .trace-item.kind-tool_result { border-left-color: var(--green); }
1351
+ .trace-item.kind-prune { border-left-color: var(--orange); }
1352
+ .trace-item.kind-compaction { border-left-color: var(--purple); }
1353
+ .trace-item.kind-usage { border-left-color: var(--accent); }
1354
+ .trace-item.kind-context { border-left-color: var(--yellow); }
1355
+ .trace-item .ti-head {
1356
+ display: flex; align-items: center; gap: 8px; font-family: var(--mono); font-size: 10.5px;
1357
+ }
1358
+ .trace-item .ti-kind { color: var(--text); font-weight: 600; }
1359
+ .trace-item .ti-time { color: var(--text-faint); }
1360
+ .trace-item pre {
1361
+ margin: 5px 0 0; padding: 6px 8px; background: var(--bg-deep);
1362
+ border: 1px solid var(--border-muted); border-radius: 4px;
1363
+ font-family: var(--mono); font-size: 10.5px; line-height: 15px; color: var(--text-muted);
1364
+ white-space: pre-wrap; word-break: break-word; max-height: 220px; overflow-y: auto;
1365
+ }
1366
+
1367
+ .statusbar .st.mid { color: var(--yellow); }
1368
+ .statusbar .st.warn { color: var(--orange); }
1369
+
1370
+ .s-connected-empty, .settings-hint {
1371
+ color: var(--text-faint); font-size: 11.5px; padding: 6px 4px; line-height: 17px;
1372
+ }
1373
+ .settings-hint { border-top: 1px solid var(--border-muted); padding: 10px 20px; margin: 0; }
1374
+
1375
+ .provider-row {
1376
+ display: flex; align-items: center; gap: 10px; padding: 9px 8px;
1377
+ border-radius: var(--radius-sm);
1378
+ }
1379
+ .provider-row:hover { background: var(--overlay-hover); }
1380
+ .provider-main { flex: 1; min-width: 0; display: flex; align-items: center; gap: 8px; }
1381
+ .provider-name { font-size: 12.5px; color: var(--text); }
1382
+ .provider-sub { font-family: var(--mono); font-size: 10.5px; color: var(--text-faint); }
1383
+ .tag-rec {
1384
+ font-size: 9.5px; font-weight: 700; letter-spacing: 0.04em; padding: 1px 6px;
1385
+ border-radius: 999px; background: rgba(130, 113, 248, 0.18); color: #b9b8f5;
1386
+ }
1387
+ .tag-custom {
1388
+ font-size: 9.5px; font-weight: 700; letter-spacing: 0.04em; padding: 1px 6px;
1389
+ border-radius: 999px; background: var(--layer-02); color: var(--text-muted);
1390
+ }
1391
+
1392
+ .config-row { display: flex; align-items: center; gap: 10px; }
1393
+ .config-row code {
1394
+ flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
1395
+ background: var(--bg-deep); border: 1px solid var(--border-muted);
1396
+ border-radius: var(--radius-sm); padding: 7px 10px; color: var(--text-muted);
1397
+ }
1398
+ .settings-foot {
1399
+ display: flex; align-items: center; gap: 8px; padding: 12px 16px;
1400
+ border-top: 1px solid var(--border-muted);
1401
+ }
1402
+ .settings-foot .spacer { flex: 1; }
1403
+ .settings-status { font-size: 11.5px; color: var(--text-faint); font-family: var(--mono); }
1404
+ .settings-status.ok { color: var(--green); }
1405
+ .settings-status.bad { color: #ff9ea1; }
1406
+
1407
+ /* ── Responsive ───────────────────────────────────────────── */
1408
+ /* Only the variables change; the grid always reads them, so dragging the
1409
+ dividers keeps working at every width. */
1410
+ @media (max-width: 1280px) {
1411
+ .body { --side-w: 232px; --review-w: 336px; }
1412
+ }
1413
+ @media (max-width: 1080px) {
1414
+ .body { --side-w: 208px; --review-w: 296px; }
1415
+ .brand-name { display: none; }
1416
+ }
1417
+ @media (max-width: 980px) {
1418
+ .body { --side-w: 0px; }
1419
+ .sidebar { display: none; }
1420
+ body.sidebar-collapsed #resize-sidebar { display: none; }
1421
+ }
1422
+ @media (max-width: 820px) {
1423
+ .body { --review-w: 0px; }
1424
+ .review, #resize-review { display: none; }
1425
+ .st#st-round, .st#st-events { display: none; }
1426
+ }
1427
+ @media (max-height: 620px) {
1428
+ .empty-state { margin-top: 4vh; }
1429
+ }
1430
+
1431
+ /* ── Futuristic effects ───────────────────────────────────── */
1432
+ /* A slow scan line and ambient glow make the cockpit feel alive without
1433
+ stealing attention from the work. */
1434
+ .brand-mark { animation: mark-float 6s ease-in-out infinite; }
1435
+ @keyframes mark-float {
1436
+ 0%, 100% { filter: drop-shadow(0 0 6px var(--accent-glow)); }
1437
+ 50% { filter: drop-shadow(0 0 16px var(--accent-glow)); }
1438
+ }
1439
+
1440
+ /* Panels rise into place. */
1441
+ .constellation, .rpanel.active, .empty-state, .review-tabs {
1442
+ animation: rise-in 420ms var(--ease) both;
1443
+ }
1444
+ @keyframes rise-in {
1445
+ from { opacity: 0; transform: translateY(10px); }
1446
+ to { opacity: 1; transform: translateY(0); }
1447
+ }
1448
+
1449
+ /* Reveal for newly streamed messages and cards. */
1450
+ .msg, .inline-finding, .finding, .mitigation, .dash-section, .dash-hero, .tool, .run-summary, .thinking-line {
1451
+ animation: reveal-in 340ms var(--ease) both;
1452
+ }
1453
+ @keyframes reveal-in {
1454
+ from { opacity: 0; transform: translateY(6px) scale(0.995); }
1455
+ to { opacity: 1; transform: none; }
1456
+ }
1457
+
1458
+ /* Buttons and interactive rows get a subtle lift. */
1459
+ .btn { transition: transform 140ms var(--ease), box-shadow 200ms var(--ease), background var(--dur) var(--ease); }
1460
+ .btn.primary:hover { box-shadow: 0 0 0 1px var(--accent), 0 8px 26px -8px var(--accent-glow); }
1461
+ .btn.primary:active { transform: translateY(1px) scale(0.99); }
1462
+ .icon-btn:active, .wc:active { transform: scale(0.92); }
1463
+
1464
+ /* ── Boot intro ───────────────────────────────────────────── */
1465
+ .intro {
1466
+ position: fixed; inset: 0; z-index: 100; display: grid; place-items: center;
1467
+ background:
1468
+ radial-gradient(700px 460px at 50% 42%, rgba(91, 118, 255, 0.16), transparent 66%),
1469
+ radial-gradient(520px 360px at 50% 42%, rgba(157, 140, 249, 0.10), transparent 70%),
1470
+ var(--bg-deep);
1471
+ transition: opacity 620ms var(--ease), transform 620ms var(--ease), visibility 620ms;
1472
+ }
1473
+ .intro.done { opacity: 0; transform: scale(1.04); visibility: hidden; pointer-events: none; }
1474
+ .intro-canvas { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0.55; }
1475
+ .intro-inner {
1476
+ position: relative; display: flex; flex-direction: column; align-items: center;
1477
+ gap: 6px; text-align: center;
1478
+ }
1479
+ .intro-mark {
1480
+ width: 66px; height: 66px; color: var(--accent-text);
1481
+ filter: drop-shadow(0 0 22px var(--accent-glow));
1482
+ stroke-dasharray: 120; stroke-dashoffset: 120;
1483
+ animation: intro-draw 1.35s var(--ease) 0.15s forwards, mark-float 5s ease-in-out 1.5s infinite;
1484
+ }
1485
+ @keyframes intro-draw { to { stroke-dashoffset: 0; } }
1486
+ .intro-title {
1487
+ font-size: 40px; font-weight: 750; letter-spacing: -0.03em; margin-top: 14px;
1488
+ background: linear-gradient(180deg, #ffffff, #a9b4e6);
1489
+ -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent;
1490
+ opacity: 0; animation: intro-up 700ms var(--ease) 0.35s forwards;
1491
+ }
1492
+ .intro-sub {
1493
+ font-family: var(--mono); font-size: 11.5px; letter-spacing: 0.22em; text-transform: uppercase;
1494
+ color: var(--text-faint); opacity: 0; animation: intro-up 700ms var(--ease) 0.55s forwards;
1495
+ }
1496
+ @keyframes intro-up { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: none; } }
1497
+ .intro-scan {
1498
+ width: 240px; height: 2px; margin-top: 22px; border-radius: 999px; overflow: hidden;
1499
+ background: var(--layer-02); opacity: 0; animation: intro-up 500ms ease 0.8s forwards;
1500
+ }
1501
+ .intro-scan span {
1502
+ display: block; height: 100%; width: 40%; border-radius: 999px;
1503
+ background: linear-gradient(90deg, transparent, var(--accent), var(--cyan));
1504
+ animation: intro-scan 1.1s ease-in-out infinite;
1505
+ }
1506
+ @keyframes intro-scan { 0% { transform: translateX(-110%); } 100% { transform: translateX(310%); } }
1507
+ .intro-lines {
1508
+ margin-top: 18px; min-height: 54px; display: flex; flex-direction: column; gap: 4px;
1509
+ font-family: var(--mono); font-size: 11px; color: var(--text-muted);
1510
+ }
1511
+ .intro-lines div { opacity: 0; animation: intro-up 300ms ease forwards; }
1512
+ .intro-lines b { color: var(--green); font-weight: 600; }
1513
+
1514
+ /* ── Copilot proposed-engagement card ─────────────────────── */
1515
+ .chat-plan {
1516
+ max-width: 780px; margin: 4px auto 18px; padding: 16px 18px;
1517
+ background: linear-gradient(180deg, var(--bg-base), color-mix(in srgb, var(--bg-base) 94%, #000));
1518
+ border: 1px solid var(--border); border-left: 3px solid var(--accent);
1519
+ border-radius: var(--radius-lg); box-shadow: var(--shadow-2);
1520
+ animation: reveal-in 340ms var(--ease) both;
1521
+ }
1522
+ .chat-plan .cp-head { display: flex; flex-direction: column; gap: 4px; margin-bottom: 12px; }
1523
+ .chat-plan .cp-badge {
1524
+ align-self: flex-start; font-size: 9.5px; text-transform: uppercase; letter-spacing: 0.08em;
1525
+ color: var(--accent-text); background: var(--accent-soft); padding: 2px 8px; border-radius: 999px;
1526
+ font-weight: 650;
1527
+ }
1528
+ .chat-plan .cp-title { font-size: 15px; font-weight: 650; }
1529
+ .chat-plan .cp-row { display: flex; gap: 10px; align-items: baseline; margin-bottom: 6px; font-size: 12.5px; }
1530
+ .chat-plan .cp-row span { flex: none; width: 92px; color: var(--text-faint); font-size: 11px; text-transform: uppercase; letter-spacing: 0.05em; }
1531
+ .chat-plan .cp-row code { font-family: var(--mono); font-size: 11.5px; color: var(--text); word-break: break-all; }
1532
+ .chat-plan .cp-phases { margin: 10px 0 4px; }
1533
+ .chat-plan .cp-sub { font-size: 10px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-faint); margin-bottom: 5px; font-weight: 650; }
1534
+ .chat-plan .cp-phases ol { margin: 0 0 0 18px; font-size: 12.5px; line-height: 20px; color: var(--text-muted); }
1535
+ .chat-plan .cp-foot { display: flex; align-items: center; gap: 10px; margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--border-muted); }
1536
+ .chat-plan .cp-note { flex: 1; font-size: 11.5px; color: var(--text-faint); }
1537
+
1538
+ /* ── Audit brief: mini-chat + pending plan ─────────────────── */
1539
+ .brief-refine {
1540
+ margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--border-muted);
1541
+ }
1542
+ .brief-refine-head { font-size: 11.5px; color: var(--text-faint); margin-bottom: 8px; }
1543
+ .brief-refine-row, .ap-refine-row {
1544
+ display: flex; gap: 8px; align-items: center;
1545
+ }
1546
+ .brief-refine-row input, .ap-refine-row input {
1547
+ flex: 1; min-width: 0; height: 32px; padding: 0 10px;
1548
+ background: var(--bg-deep); border: 1px solid var(--border); border-radius: var(--radius);
1549
+ color: var(--text); font-family: inherit; font-size: 12.5px; outline: none;
1550
+ }
1551
+ .brief-refine-row input:focus, .ap-refine-row input:focus { border-color: var(--accent); }
1552
+ .brief-refine-log, .ap-refine-log {
1553
+ margin-top: 10px; display: flex; flex-direction: column; gap: 6px;
1554
+ max-height: 220px; overflow-y: auto;
1555
+ }
1556
+ .ap-refine-log:empty { display: none; }
1557
+ .ap-msg { font-size: 12.5px; line-height: 19px; padding: 7px 10px; border-radius: var(--radius); }
1558
+ .ap-msg.user { background: var(--accent-soft); color: var(--text); align-self: flex-end; max-width: 90%; }
1559
+ .ap-msg.bot { background: var(--bg-deep); border: 1px solid var(--border-muted); color: var(--text-muted); }
1560
+ .ap-msg.bot p { margin: 0 0 6px; }
1561
+ .ap-msg.bot p:last-child { margin: 0; }
1562
+
1563
+ .plan-pending {
1564
+ display: flex; align-items: center; gap: 10px; max-width: 780px; margin: 18px auto;
1565
+ padding: 14px 16px; border: 1px solid var(--border); border-radius: var(--radius-lg);
1566
+ background: var(--bg-base); color: var(--text-muted); font-size: 13px;
1567
+ animation: reveal-in 300ms var(--ease) both;
1568
+ }
1569
+ .plan-pending .spinner {
1570
+ width: 14px; height: 14px; flex: none; border-radius: 50%;
1571
+ border: 2px solid var(--border-strong); border-top-color: var(--accent);
1572
+ animation: spin 0.8s linear infinite;
1573
+ }
1574
+ @keyframes spin { to { transform: rotate(360deg); } }
1575
+ .audit-plan .cp-phases ul { margin: 0 0 0 18px; font-size: 12.5px; line-height: 20px; color: var(--text-muted); }
1576
+
1577
+ /* ── Plan chat panel (right side) ──────────────────────────── */
1578
+ /* The review-body is the scroll container for most panels, but the chat needs
1579
+ its own scroll, so this panel fills the available height without relying on
1580
+ a percentage of an auto-height parent. */
1581
+ #panel-plan { display: none; flex-direction: column; min-height: 0; }
1582
+ #panel-plan.active { display: flex; flex: 1; }
1583
+ .review-body:has(#panel-plan.active) { overflow: hidden; display: flex; }
1584
+ .plan-chat-log {
1585
+ flex: 1; overflow-y: auto; display: flex; flex-direction: column; gap: 8px;
1586
+ padding: 2px 0 10px;
1587
+ }
1588
+ .plan-chat-row { display: flex; gap: 8px; align-items: center; padding-top: 8px; border-top: 1px solid var(--border-muted); }
1589
+ .plan-chat-row input {
1590
+ flex: 1; min-width: 0; height: 32px; padding: 0 10px;
1591
+ background: var(--bg-deep); border: 1px solid var(--border); border-radius: var(--radius);
1592
+ color: var(--text); font-family: inherit; font-size: 12.5px; outline: none;
1593
+ }
1594
+ .plan-chat-row input:focus { border-color: var(--accent); }
1595
+ .planner-thinking { color: var(--text-faint); font-style: italic; }
1596
+
1597
+ /* ── Scope document upload ─────────────────────────────────── */
1598
+ .scope-doc-row {
1599
+ display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
1600
+ margin-bottom: 14px; padding: 10px 12px; border: 1px dashed var(--border);
1601
+ border-radius: var(--radius); background: var(--bg-deep);
1602
+ }
1603
+ .scope-doc-name { font-size: 12px; color: var(--text-muted); }
1604
+ .mini-btn.ghostish { background: transparent; border-color: var(--border-muted); color: var(--text-muted); }
1605
+
1606
+ /* ── Audit bar (no free-text objective; planning lives in Plan chat) ── */
1607
+ .composer-card.audit-bar { padding: 8px 12px; }
1608
+ #btn-objective {
1609
+ max-width: 320px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
1610
+ font-weight: 500;
1611
+ }
1612
+ #btn-objective.muted { color: var(--text-faint); }