@worca/app 0.0.1

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 (114) hide show
  1. package/README.md +403 -0
  2. package/agents/clarify.meta.json +19 -0
  3. package/agents/decomposer.meta.json +21 -0
  4. package/agents/implementer.meta.json +20 -0
  5. package/agents/manualTestsChecklist.meta.json +18 -0
  6. package/agents/manualWebUiTesting.meta.json +18 -0
  7. package/agents/planReviewer.meta.json +19 -0
  8. package/agents/planner.meta.json +20 -0
  9. package/agents/refiner.meta.json +19 -0
  10. package/agents/reviewer.meta.json +19 -0
  11. package/agents/worca-cc-clarify.md +67 -0
  12. package/agents/worca-cc-code-reviewer.md +66 -0
  13. package/agents/worca-cc-decomposer.md +84 -0
  14. package/agents/worca-cc-implementer.md +69 -0
  15. package/agents/worca-cc-manual-tests-checklist.md +63 -0
  16. package/agents/worca-cc-manual-web-ui-testing.md +64 -0
  17. package/agents/worca-cc-plan-refiner.md +69 -0
  18. package/agents/worca-cc-plan-reviewer.md +70 -0
  19. package/agents/worca-cc-planner.md +70 -0
  20. package/agents/worca-cc-workspace-reviewer.md +56 -0
  21. package/agents/worca-cc-workspace-scanner.md +55 -0
  22. package/agents/workspaceReviewer.meta.json +20 -0
  23. package/agents/workspaceScanner.meta.json +18 -0
  24. package/package.json +61 -0
  25. package/scripts/install.mjs +209 -0
  26. package/skills/worca/SKILL.md +66 -0
  27. package/src/cli/worca-cc.mjs +1520 -0
  28. package/src/core/agent-gen.mjs +206 -0
  29. package/src/core/agent-registry.mjs +417 -0
  30. package/src/core/agent-store.mjs +143 -0
  31. package/src/core/artifacts.mjs +2019 -0
  32. package/src/core/channels.mjs +302 -0
  33. package/src/core/chat/allowlist.mjs +27 -0
  34. package/src/core/chat/channel-host.mjs +562 -0
  35. package/src/core/chat/channel-protocol.mjs +117 -0
  36. package/src/core/chat/channel-worker-child.mjs +211 -0
  37. package/src/core/chat/chat-context.mjs +66 -0
  38. package/src/core/chat/command-router.mjs +343 -0
  39. package/src/core/chat/notifier.mjs +120 -0
  40. package/src/core/chat/parser.mjs +30 -0
  41. package/src/core/chat/rate-limiter.mjs +133 -0
  42. package/src/core/chat/redact.mjs +27 -0
  43. package/src/core/chat/renderers.mjs +136 -0
  44. package/src/core/claude-runner.mjs +1356 -0
  45. package/src/core/config.mjs +882 -0
  46. package/src/core/cost-budget.mjs +103 -0
  47. package/src/core/db.mjs +864 -0
  48. package/src/core/fanout.mjs +48 -0
  49. package/src/core/folder-dialog.mjs +138 -0
  50. package/src/core/fs-browse.mjs +49 -0
  51. package/src/core/git-info.mjs +200 -0
  52. package/src/core/guardrail-store.mjs +204 -0
  53. package/src/core/guardrails.mjs +302 -0
  54. package/src/core/marketplaces.mjs +267 -0
  55. package/src/core/migrate-fs-to-db.mjs +612 -0
  56. package/src/core/model-env.mjs +74 -0
  57. package/src/core/orchestrator.mjs +4279 -0
  58. package/src/core/overview-agent.mjs +124 -0
  59. package/src/core/phases.mjs +1279 -0
  60. package/src/core/pipeline-delete.mjs +428 -0
  61. package/src/core/plugin-api.mjs +13 -0
  62. package/src/core/plugin-config.mjs +100 -0
  63. package/src/core/plugin-inventory.mjs +50 -0
  64. package/src/core/plugin-manifest.mjs +447 -0
  65. package/src/core/plugin-models.mjs +130 -0
  66. package/src/core/plugin-repo.mjs +303 -0
  67. package/src/core/plugin-shim-child.mjs +76 -0
  68. package/src/core/plugin-shim.mjs +197 -0
  69. package/src/core/plugin-store.mjs +485 -0
  70. package/src/core/plugin-workflows.mjs +179 -0
  71. package/src/core/plugins-lock.mjs +49 -0
  72. package/src/core/preflight-node.mjs +122 -0
  73. package/src/core/preflight.mjs +341 -0
  74. package/src/core/projects.mjs +157 -0
  75. package/src/core/protocol.mjs +257 -0
  76. package/src/core/recoverable-error.mjs +51 -0
  77. package/src/core/results.mjs +188 -0
  78. package/src/core/run-context.mjs +1375 -0
  79. package/src/core/run-log.mjs +64 -0
  80. package/src/core/run-manifest.mjs +317 -0
  81. package/src/core/runners.mjs +167 -0
  82. package/src/core/settings.mjs +682 -0
  83. package/src/core/skills.mjs +210 -0
  84. package/src/core/sources.mjs +232 -0
  85. package/src/core/stats.mjs +182 -0
  86. package/src/core/store.mjs +67 -0
  87. package/src/core/title.mjs +64 -0
  88. package/src/core/workflow-validator.mjs +185 -0
  89. package/src/core/workflows.mjs +568 -0
  90. package/src/core/workspace-scan.mjs +420 -0
  91. package/src/core/workspaces.mjs +353 -0
  92. package/src/core/worktree.mjs +708 -0
  93. package/src/feature.mjs +9 -0
  94. package/ui/public/app.js +10647 -0
  95. package/ui/public/assets/worca-favicon.png +0 -0
  96. package/ui/public/assets/worca-logo.png +0 -0
  97. package/ui/public/chat-settings-view.mjs +89 -0
  98. package/ui/public/composer-core.mjs +211 -0
  99. package/ui/public/fonts/jetbrains-mono-latin-400-normal.woff2 +0 -0
  100. package/ui/public/fonts/poppins-latin-400-normal.woff2 +0 -0
  101. package/ui/public/fonts/poppins-latin-500-normal.woff2 +0 -0
  102. package/ui/public/fonts/poppins-latin-600-normal.woff2 +0 -0
  103. package/ui/public/fonts/poppins-latin-700-normal.woff2 +0 -0
  104. package/ui/public/guardrails-view.mjs +244 -0
  105. package/ui/public/index.html +1145 -0
  106. package/ui/public/log-filter.mjs +81 -0
  107. package/ui/public/log-line.mjs +86 -0
  108. package/ui/public/models-view.mjs +433 -0
  109. package/ui/public/plugins-view.mjs +430 -0
  110. package/ui/public/results-view.mjs +121 -0
  111. package/ui/public/source-pane.mjs +156 -0
  112. package/ui/public/stats-view.mjs +523 -0
  113. package/ui/public/style.css +1557 -0
  114. package/ui/server.mjs +3573 -0
@@ -0,0 +1,1557 @@
1
+ /* worca-cc UI — "Refined" design system. Warm off-white, white panels. No framework, no build step. */
2
+
3
+ /* ---------- self-hosted webfonts ---------- */
4
+ @font-face{font-family:'Poppins';font-style:normal;font-weight:400;font-display:swap;src:url('/fonts/poppins-latin-400-normal.woff2') format('woff2');}
5
+ @font-face{font-family:'Poppins';font-style:normal;font-weight:500;font-display:swap;src:url('/fonts/poppins-latin-500-normal.woff2') format('woff2');}
6
+ @font-face{font-family:'Poppins';font-style:normal;font-weight:600;font-display:swap;src:url('/fonts/poppins-latin-600-normal.woff2') format('woff2');}
7
+ @font-face{font-family:'Poppins';font-style:normal;font-weight:700;font-display:swap;src:url('/fonts/poppins-latin-700-normal.woff2') format('woff2');}
8
+ @font-face{font-family:'JetBrains Mono';font-style:normal;font-weight:400;font-display:swap;src:url('/fonts/jetbrains-mono-latin-400-normal.woff2') format('woff2');}
9
+
10
+ :root{
11
+ --bg:#F1F1EF;
12
+ --panel:#FFFFFF;
13
+ --ink:#19191B;
14
+ --ink-2:#5C5C63;
15
+ --ink-3:#9A9AA1;
16
+ --line:#ECECEA;
17
+ --line-2:#E3E3E0;
18
+ --field:#F6F6F4;
19
+
20
+ --green-bg:#E2F3DF; --green:#5BAE5B; --green-ink:#2F7A38;
21
+ --peach-bg:#FCEEDA; --peach:#EFA63C; --peach-ink:#B5751A;
22
+ --red-bg:#FBE3E0; --red:#E76A5A; --red-ink:#C5483A;
23
+ --blue-bg:#DEEFF7; --blue:#5BA6CC; --blue-ink:#3782A8;
24
+ --violet-bg:#EAE6F8; --violet:#8C7FD6; --violet-ink:#6353B8;
25
+ --amber-bg:#FCE8C8; --amber:#E6962A; --amber-ink:#A66510;
26
+ --seq:#B7B7BC;
27
+
28
+ --r-card:24px;
29
+ --r-ctrl:14px;
30
+ --shadow:0 6px 28px rgba(25,25,27,.05), 0 1px 2px rgba(25,25,27,.04);
31
+ --shadow-soft:0 2px 12px rgba(25,25,27,.04);
32
+
33
+ --sans:'Poppins',system-ui,-apple-system,BlinkMacSystemFont,sans-serif;
34
+ --mono:'JetBrains Mono',ui-monospace,SFMono-Regular,Menlo,monospace;
35
+ }
36
+
37
+ /* ---------- base reset ---------- */
38
+ *{box-sizing:border-box;}
39
+ html,body{margin:0;padding:0;height:100%;overflow:hidden;}
40
+ body{
41
+ background:var(--bg);
42
+ color:var(--ink);
43
+ font-family:var(--sans);
44
+ font-size:14px;
45
+ line-height:1.5;
46
+ -webkit-font-smoothing:antialiased;
47
+ }
48
+ .hidden{display:none !important;}
49
+
50
+ /* ---------- App shell ---------- */
51
+ .app{display:flex;height:100vh;}
52
+
53
+ /* ---------- Sidebar ---------- */
54
+ .sidebar{
55
+ width:298px;flex:0 0 298px;
56
+ background:var(--panel);
57
+ padding:26px 18px 22px;
58
+ display:flex;flex-direction:column;
59
+ border-right:1px solid var(--line);
60
+ overflow-y:auto;
61
+ }
62
+ .brand{display:flex;align-items:center;padding:0 8px;margin-bottom:24px;}
63
+ .brand .logo{height:36px;width:auto;display:block;}
64
+
65
+ .nav{display:flex;flex-direction:column;gap:4px;flex:1 1 auto;}
66
+ .nav button{
67
+ display:flex;align-items:center;gap:13px;width:100%;margin:0;
68
+ padding:11px 13px;border:0;border-radius:13px;
69
+ background:transparent;color:var(--ink-2);
70
+ font-family:inherit;font-size:inherit;line-height:inherit;font-weight:500;
71
+ text-align:left;cursor:pointer;
72
+ transition:background .15s,color .15s;
73
+ }
74
+ .nav button svg{width:19px;height:19px;flex:0 0 auto;stroke-width:1.9;}
75
+ .nav button:hover{background:var(--field);color:var(--ink);}
76
+ .nav button.active{background:var(--ink);color:#fff;}
77
+ .nav button.active svg{stroke:#fff;}
78
+ .nav button:focus-visible{outline:2px solid var(--ink);outline-offset:2px;}
79
+ .nav-sect{font-size:10.5px;font-weight:600;letter-spacing:.11em;text-transform:uppercase;
80
+ color:var(--ink-3);padding:14px 13px 2px;user-select:none;}
81
+ .nav-sep{margin-top:auto;border-top:1px solid var(--line);}
82
+ /* Primary action: outlined at rest so it doesn't fight the dark current-view
83
+ fill; border thickness is absorbed into padding to keep row height equal. */
84
+ .nav button.nav-cta{border:1.5px solid var(--ink);color:var(--ink);font-weight:600;
85
+ padding:9.5px 11.5px;}
86
+ .nav button.nav-cta:hover{background:var(--field);}
87
+ .nav button.nav-cta.active{background:var(--ink);border-color:var(--ink);color:#fff;}
88
+ .nav-count{margin-left:auto;min-width:22px;height:22px;padding:0 7px;border-radius:999px;
89
+ display:grid;place-items:center;font-size:11.5px;font-weight:700;}
90
+ .nav-count.n-amber{background:var(--amber);color:#fff;}
91
+ .nav-count.n-grey{background:var(--field);color:var(--ink-3);}
92
+ .nav button.active .nav-count{background:rgba(255,255,255,.18);color:#fff;}
93
+ /* Running split-badges: green = work in flight, amber = paused count. Green is
94
+ applied by app.js ONLY while the count is >0 — at zero the badge falls back to
95
+ n-grey, the inert-inventory treatment History/Projects/Workspaces use, so a
96
+ permanently green pill cannot dilute the green that should catch the eye.
97
+ Both keep their colour on the dark active fill (the generic active rule above
98
+ would wash them into translucent white). */
99
+ .nav-count.n-run{background:var(--green);color:#fff;}
100
+ .nav-count.n-paused{background:var(--amber);color:#fff;position:relative;margin-left:6px;}
101
+ .nav-count[hidden]{display:none;} /* author display:grid beats the UA [hidden] rule */
102
+ .nav button.active .nav-count.n-run{background:var(--green);color:#fff;}
103
+ .nav button.active .nav-count.n-paused{background:var(--amber);color:#fff;}
104
+ /* Tiny pause flag pinned at the badge's top-right corner. Scoped under
105
+ .nav-count so it outranks the generic `.nav button svg` sizing rule. */
106
+ .nav-count .pause-flag{position:absolute;top:-5px;right:-6px;width:13px;height:13px;padding:2px;
107
+ border-radius:50%;background:var(--amber-ink);border:1.5px solid var(--panel);fill:#fff;}
108
+
109
+ /* Parent roll-up "needs you" dot on the Running nav item (sidebar + topnav) */
110
+ .nav-rollup {
111
+ width: 8px; height: 8px; border-radius: 50%;
112
+ background: var(--amber); margin-left: 6px; flex: 0 0 auto;
113
+ animation: pulse 1.3s ease-in-out infinite;
114
+ }
115
+ .nav button.active .nav-rollup { background: #fff; }
116
+
117
+ /* Child pipeline rows nested under Running — tree-connector style (mirrors the
118
+ sub-agents tree: a vertical spine on the left with a branch into each dot). */
119
+ .nav-children { display: flex; flex-direction: column; gap: 2px; margin: 2px 0 6px 0; }
120
+ .nav-children.hidden, .nav-children.collapsed { display: none; }
121
+ /* Scoped `.nav .nav-child` so these rows outrank the generic `.nav button` rule
122
+ (padding:11px 13px / gap:13px), which otherwise flattens the left inset and
123
+ parks the dot on top of the elbow connector. */
124
+ .nav .nav-child {
125
+ position: relative;
126
+ display: flex; align-items: center; gap: 9px;
127
+ padding: 6px 10px 6px 28px; border-radius: 9px;
128
+ color: var(--ink-2);
129
+ min-width: 0;
130
+ }
131
+ /* Rounded elbow: vertical run from the top of the row down to the dot center,
132
+ then curving right toward the dot (stops 7px short of it). */
133
+ .nav-child::before {
134
+ content: ""; position: absolute;
135
+ left: 9px; top: -2px;
136
+ width: 12px; height: calc(50% + 2px);
137
+ border-left: 1.5px solid var(--line-2);
138
+ border-bottom: 1.5px solid var(--line-2);
139
+ border-bottom-left-radius: 7px;
140
+ pointer-events: none;
141
+ }
142
+ /* Continuation: keeps the spine unbroken between rows (not after the last). */
143
+ .nav-child:not(:last-child)::after {
144
+ content: ""; position: absolute;
145
+ left: 9px; top: 50%; bottom: -4px;
146
+ width: 1.5px; background: var(--line-2);
147
+ pointer-events: none;
148
+ }
149
+ .nav .nav-child:hover { background: var(--field); color: var(--ink); }
150
+ /* Selected: gentle tint + soft ring, not a heavy dark fill.
151
+ Scoped under .nav to outrank the global `.nav button.active` dark-fill rule. */
152
+ .nav .nav-child.active { background: var(--field); color: var(--ink); box-shadow: inset 0 0 0 1px var(--line-2); }
153
+ .nav-child.lingering { color: var(--ink-3); } /* greyed finished-unread */
154
+
155
+ .child-body { display: flex; flex-direction: column; gap: 1px; min-width: 0; flex: 1 1 auto; }
156
+ /* Up to two lines, then ellipsis — one line rarely fits a run title. */
157
+ .child-title { font-size: 13.5px; font-weight: 700; line-height: 1.3; overflow: hidden;
158
+ display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2;
159
+ overflow-wrap: anywhere; }
160
+ /* Single project → one name; workspace runs list every member. Wraps up to
161
+ three lines, then ellipsis. */
162
+ .child-proj { font-family: 'JetBrains Mono', monospace; font-size: 11px; font-weight: 500; color: var(--ink-3);
163
+ overflow: hidden; display: -webkit-box; -webkit-box-orient: vertical;
164
+ -webkit-line-clamp: 3; line-clamp: 3; overflow-wrap: anywhere; }
165
+ .nav-child.active .child-proj { color: var(--ink-3); }
166
+
167
+ /* Status dot (left). Color matches the current running agent/phase
168
+ (violet=plan, peach=refine/review/running, blue=implement, red=clarify),
169
+ grey-pulse=starting/pausing, green=done, red=error/stopped. */
170
+ .child-dot { width: 9px; height: 9px; border-radius: 50%; flex: 0 0 auto; }
171
+ /* Running states: colour + scale/halo pulse (currentColor drives the halo hue). */
172
+ .child-dot.peach { color: var(--peach); background: currentColor; animation: dotpulse 1.3s ease-in-out infinite; }
173
+ .child-dot.blue { color: var(--blue); background: currentColor; animation: dotpulse 1.3s ease-in-out infinite; }
174
+ .child-dot.violet { color: var(--violet); background: currentColor; animation: dotpulse 1.3s ease-in-out infinite; }
175
+ .child-dot.amber { color: var(--amber); background: currentColor; animation: dotpulse 1.3s ease-in-out infinite; }
176
+ .child-dot.grey-pulse { color: var(--ink-3); background: currentColor; animation: dotpulse 1.3s ease-in-out infinite; }
177
+ .child-dot.green { background: var(--green); }
178
+ .child-dot.red { background: var(--red); }
179
+ .child-dot.paused { background: var(--amber); } /* parked + resumable: static, no pulse */
180
+
181
+ /* Awaiting-input marker: a pulsing yellow "?" pinned at the end of the row. */
182
+ .child-q {
183
+ flex: 0 0 auto; margin-left: 6px;
184
+ color: var(--amber); font-weight: 800; font-size: 15px; line-height: 1;
185
+ animation: pulse 1.3s ease-in-out infinite;
186
+ }
187
+ /* Finished-but-unseen marker: static green/red "●" in the same end slot (no pulse). */
188
+ .child-q.ok { color: var(--green); font-size: 12px; animation: none; }
189
+ .child-q.bad { color: var(--red); font-size: 12px; animation: none; }
190
+
191
+ /* Overview cards are clickable to focus */
192
+ #run-list .run-card .run-top { cursor: pointer; }
193
+
194
+ .side-project{margin:0 4px 22px;padding-bottom:22px;border-bottom:1px solid var(--line);}
195
+ .side-project .sp-label{display:block;font-size:11px;font-weight:600;letter-spacing:.08em;
196
+ text-transform:uppercase;color:var(--ink-3);margin:0 4px 8px;}
197
+ .side-project .sp-select{padding:11px 38px 11px 13px;font-size:13.5px;font-weight:600;border-radius:12px;}
198
+ .nav-label{font-size:11px;font-weight:600;letter-spacing:.08em;text-transform:uppercase;
199
+ color:var(--ink-3);padding:8px 12px 6px;}
200
+ .side-foot{margin-top:auto;display:flex;flex-direction:column;gap:14px;padding-top:14px;}
201
+ .user{display:flex;align-items:center;gap:11px;padding:6px 8px;}
202
+ .user .ava{width:36px;height:36px;border-radius:50%;flex:0 0 auto;
203
+ background:linear-gradient(135deg,#cfcfca,#a8a8a2);}
204
+ .user .who{font-weight:600;line-height:1.2;}
205
+ .user .who small{display:block;color:var(--ink-3);font-weight:500;font-size:11.5px;}
206
+
207
+ /* Generic status dot (pill-status, subs-step-head, sub-agent groups) */
208
+ .dot{width:8px;height:8px;border-radius:50%;display:inline-block;}
209
+
210
+ /* ---------- Main ---------- */
211
+ .main{flex:1;min-width:0;padding:26px 32px 40px;overflow-y:auto;}
212
+ /* History view drops the scroll container's TOP padding so the sticky pills
213
+ toolbar + per-project headers can pin flush to the very top of the scroll
214
+ area. Without this, .main's 26px top padding leaves a band above the stuck
215
+ header where scrolled cards peek through (the reported bug). The inset is
216
+ re-applied inside the view (below) so the unscrolled layout is unchanged. */
217
+ body.view-history .main{padding-top:0;}
218
+ .topbar{display:flex;align-items:flex-start;justify-content:space-between;
219
+ gap:24px;margin-bottom:22px;}
220
+ .topbar h1{font-size:26px;font-weight:700;letter-spacing:-.025em;margin:0 0 4px;}
221
+ .topbar .sub{color:var(--ink-2);font-size:13.5px;}
222
+ .run-state{display:flex;align-items:center;gap:10px;}
223
+ .pill-status{display:inline-flex;align-items:center;gap:8px;background:var(--panel);
224
+ border:1px solid var(--line-2);padding:9px 15px;border-radius:999px;
225
+ font-weight:600;font-size:12.5px;color:var(--ink-2);box-shadow:var(--shadow-soft);}
226
+ .pill-status .dot{width:8px;height:8px;border-radius:50%;background:var(--ink-3);}
227
+ .btn-stop{display:inline-flex;align-items:center;gap:8px;background:var(--red-bg);
228
+ color:var(--red-ink);border:none;padding:11px 19px;border-radius:999px;
229
+ font-family:inherit;font-weight:600;font-size:13px;cursor:pointer;transition:filter .15s;}
230
+ .btn-stop:hover{filter:brightness(.97);}
231
+ .btn-stop:focus-visible{outline:2px solid var(--ink);outline-offset:2px;}
232
+ .btn-pause{display:inline-flex;align-items:center;gap:8px;background:var(--amber-bg);
233
+ color:var(--amber-ink);border:none;padding:11px 19px;border-radius:999px;
234
+ font-family:inherit;font-weight:600;font-size:13px;cursor:pointer;transition:filter .15s;}
235
+ .btn-pause:hover{filter:brightness(.97);}
236
+ .btn-pause:focus-visible{outline:2px solid var(--ink);outline-offset:2px;}
237
+ .btn-resume{display:inline-flex;align-items:center;gap:8px;background:var(--green-bg);
238
+ color:var(--green-ink);border:none;padding:11px 19px;border-radius:999px;
239
+ font-family:inherit;font-weight:600;font-size:13px;cursor:pointer;transition:filter .15s;}
240
+ .btn-resume:hover{filter:brightness(.97);}
241
+ .btn-resume:focus-visible{outline:2px solid var(--ink);outline-offset:2px;}
242
+ /* [hidden] must beat the author display rules above (author origin outranks the
243
+ UA [hidden]{display:none} rule — same footgun as .questions-toggle[hidden]). */
244
+ .btn-pause[hidden],.btn-resume[hidden]{display:none;}
245
+
246
+ /* ---------- Views ---------- */
247
+ .view{display:block;}
248
+
249
+ /* number-disc tint utilities */
250
+ .n-green{background:var(--green-bg);color:var(--green-ink);}
251
+ .n-peach{background:var(--peach-bg);color:var(--peach-ink);}
252
+ .n-red{background:var(--red-bg);color:var(--red-ink);}
253
+ .n-blue{background:var(--blue-bg);color:var(--blue-ink);}
254
+ .n-violet{background:var(--violet-bg);color:var(--violet-ink);}
255
+ .n-amber{background:var(--amber);color:#fff;}
256
+ .n-grey{background:var(--field);color:var(--ink-3);}
257
+
258
+ /* ---------- Grid ---------- */
259
+ .grid{display:grid;grid-template-columns:minmax(360px,1fr) minmax(420px,1.25fr);gap:22px;align-items:start;}
260
+ .grid.single{grid-template-columns:minmax(0,864px);justify-content:center;}
261
+ .view[data-view="new"] .topbar{justify-content:center;text-align:center;}
262
+ .col{display:flex;flex-direction:column;gap:22px;}
263
+ .card{background:var(--panel);border:1px solid var(--line);border-radius:var(--r-card);
264
+ box-shadow:var(--shadow);padding:24px;}
265
+ .card-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:18px;}
266
+ .card-head h2{font-size:17px;font-weight:700;letter-spacing:-.015em;margin:0;}
267
+ .card h2{font-size:17px;font-weight:700;letter-spacing:-.015em;margin:0 0 18px;}
268
+
269
+ /* ---------- Form ---------- */
270
+ .field{margin-bottom:18px;}
271
+ .field > label,.field .label{display:block;font-weight:600;font-size:13px;margin-bottom:8px;}
272
+ .field > label .opt,.field .opt{color:var(--ink-3);font-weight:500;font-style:normal;}
273
+ .hint{display:block;color:var(--ink-3);font-size:12px;margin-top:7px;line-height:1.45;}
274
+ .hint.err{color:var(--red-ink);}
275
+
276
+ .input,.select,.textarea,
277
+ input[type="text"],input[type="number"],textarea,select{
278
+ width:100%;font-family:inherit;font-size:14px;color:var(--ink);
279
+ background:var(--field);border:1.5px solid transparent;border-radius:var(--r-ctrl);
280
+ padding:13px 15px;transition:border-color .15s,background .15s;
281
+ }
282
+ .input::placeholder,.textarea::placeholder,
283
+ input[type="text"]::placeholder,input[type="number"]::placeholder,textarea::placeholder{color:var(--ink-3);}
284
+ .input:focus,.select:focus,.textarea:focus,
285
+ input[type="text"]:focus,input[type="number"]:focus,textarea:focus,select:focus{outline:none;background:#fff;border-color:var(--ink);}
286
+ .input:focus-visible,.select:focus-visible,.textarea:focus-visible,
287
+ input[type="text"]:focus-visible,input[type="number"]:focus-visible,textarea:focus-visible,select:focus-visible{outline:2px solid var(--ink);outline-offset:2px;}
288
+ .textarea,textarea{resize:vertical;min-height:120px;line-height:1.5;}
289
+ input[type="file"]{font-size:12.5px;color:var(--ink-3);background:transparent;border:none;padding:0;}
290
+
291
+ .select-wrap{position:relative;}
292
+ .select,select{appearance:none;-webkit-appearance:none;padding-right:40px;cursor:pointer;}
293
+ .select-wrap::after{content:"";position:absolute;right:15px;top:50%;width:9px;height:9px;
294
+ border-right:2px solid var(--ink-2);border-bottom:2px solid var(--ink-2);
295
+ transform:translateY(-65%) rotate(45deg);pointer-events:none;}
296
+
297
+ /* ---------- Info tooltips (settings) ---------- */
298
+ /* Label + ⓘ ride together; the row replaces the label's own bottom margin. */
299
+ .label-row{display:flex;align-items:center;gap:7px;margin-bottom:8px;}
300
+ .label-row > label{display:inline-block;font-weight:600;font-size:13px;margin-bottom:0;}
301
+ /* `.card h2` (later in the file) wins its tie with `.card-head h2` and re-adds an
302
+ 18px bottom margin; centered flex would sink the ⓘ below the heading text. */
303
+ .label-row > h2{margin:0;}
304
+ .card-head .label-row{margin-bottom:0;}
305
+ .info-tip{position:relative;width:16px;height:16px;flex:0 0 16px;padding:0;
306
+ border:1.5px solid var(--ink-3);border-radius:50%;background:transparent;color:var(--ink-3);
307
+ font-family:inherit;font-size:10px;font-weight:700;line-height:1;
308
+ display:inline-flex;align-items:center;justify-content:center;cursor:help;
309
+ transition:color .15s,border-color .15s;}
310
+ .info-tip:hover{border-color:var(--ink);color:var(--ink);}
311
+ .info-tip:focus-visible{outline:2px solid var(--ink);outline-offset:2px;}
312
+ /* The shared floating bubble (created once by app.js, filled per icon). */
313
+ .info-bubble{position:fixed;z-index:70;background:var(--ink);color:#fff;border-radius:10px;
314
+ padding:10px 13px;font-size:12px;line-height:1.5;max-width:340px;box-shadow:var(--shadow);
315
+ pointer-events:none;}
316
+ .info-bubble code{font-family:var(--mono);font-size:11px;background:rgba(255,255,255,.14);
317
+ border-radius:4px;padding:1px 4px;}
318
+ .info-bubble .tip-desc{display:block;}
319
+ .info-bubble .tip-line{display:block;margin-top:6px;font-family:var(--mono);font-size:10.5px;letter-spacing:.02em;opacity:.75;}
320
+
321
+ .row-2,.grid-2{display:flex;gap:11px;}
322
+ .grid-2{display:grid;grid-template-columns:1fr 1fr;}
323
+ .row-2 .with-x{flex:1;}
324
+ .icon-btn{width:48px;flex:0 0 48px;border-radius:var(--r-ctrl);border:1.5px solid var(--line-2);
325
+ background:var(--field);cursor:pointer;display:grid;place-items:center;color:var(--ink-2);
326
+ font-size:18px;transition:background .15s,color .15s;}
327
+ .icon-btn:hover{background:#fff;color:var(--ink);}
328
+
329
+ /* project selector row */
330
+ .project-row{display:flex;gap:11px;align-items:center;}
331
+ .project-row select{flex:1 1 auto;min-width:0;}
332
+
333
+ /* inline add-project form */
334
+ .add-project{margin-top:10px;display:flex;flex-direction:column;gap:9px;padding:14px;
335
+ border:1.5px solid var(--line-2);border-radius:var(--r-ctrl);background:var(--field);}
336
+ .add-project-actions{display:flex;gap:9px;justify-content:flex-end;}
337
+ /* path row (input + trailing button) — shared by add-project, project modal, plugin add */
338
+ .path-row{display:flex;gap:9px;align-items:center;}
339
+ .path-row input{flex:1 1 auto;min-width:0;}
340
+ .path-row .btn{flex:0 0 auto;white-space:nowrap;}
341
+
342
+ /* segmented toggle */
343
+ .seg{display:inline-flex;background:var(--field);border-radius:12px;padding:4px;gap:4px;}
344
+ .seg button{font-family:inherit;font-weight:600;font-size:13px;color:var(--ink-2);
345
+ background:transparent;border:none;padding:8px 20px;border-radius:9px;cursor:pointer;transition:.15s;}
346
+ .seg button.on{background:#fff;color:var(--ink);box-shadow:var(--shadow-soft);}
347
+ .seg button:focus-visible{outline:2px solid var(--ink);outline-offset:2px;}
348
+
349
+ /* task-source fieldset (old markup) */
350
+ fieldset.source{border:1.5px solid var(--line);border-radius:var(--r-ctrl);padding:16px;margin:0 0 18px;}
351
+ fieldset.source legend{font-weight:600;font-size:13px;padding:0 6px;color:var(--ink);}
352
+ .radio-row{display:flex;gap:18px;margin-bottom:12px;}
353
+ .radio,.check{display:inline-flex;align-items:center;gap:8px;font-size:13px;font-weight:500;cursor:pointer;user-select:none;}
354
+ .check{margin-bottom:12px;}
355
+ .check-inline{margin-bottom:0;font-size:12.5px;color:var(--ink-2);}
356
+
357
+ /* file picker */
358
+ .file{display:flex;align-items:center;gap:13px;background:var(--field);border:1.5px dashed var(--line-2);
359
+ border-radius:var(--r-ctrl);padding:13px 15px;}
360
+ .file .pick{background:#fff;border:1px solid var(--line-2);border-radius:9px;padding:8px 14px;
361
+ font-family:inherit;font-weight:600;font-size:12.5px;cursor:pointer;color:var(--ink);white-space:nowrap;}
362
+ .file .state{color:var(--ink-3);font-size:12.5px;}
363
+ .file-load{display:inline-block;margin-top:8px;}
364
+
365
+ /* switch */
366
+ .switch-row{display:flex;align-items:center;gap:12px;}
367
+ .switch{width:44px;height:26px;border-radius:999px;background:var(--line-2);position:relative;
368
+ cursor:pointer;flex:0 0 auto;transition:background .18s;}
369
+ .switch::after{content:"";position:absolute;top:3px;left:3px;width:20px;height:20px;border-radius:50%;
370
+ background:#fff;box-shadow:0 1px 3px rgba(0,0,0,.18);transition:left .18s;}
371
+ .switch.on{background:var(--green);}
372
+ .switch.on::after{left:21px;}
373
+ .switch:focus-visible{outline:2px solid var(--ink);outline-offset:2px;}
374
+ .switch-row .txt{font-weight:500;}
375
+
376
+ /* ---------- buttons ---------- */
377
+ .actions{display:flex;align-items:center;justify-content:space-between;gap:14px;margin-top:22px;}
378
+ .btn-ghost{background:#fff;border:1.5px solid var(--line-2);color:var(--ink);font-family:inherit;
379
+ font-weight:600;font-size:13.5px;padding:13px 20px;border-radius:999px;cursor:pointer;transition:.15s;}
380
+ .btn-ghost:hover{background:var(--field);}
381
+ .btn-go{display:inline-flex;align-items:center;gap:9px;background:var(--ink);color:#fff;border:none;
382
+ font-family:inherit;font-weight:600;font-size:14px;padding:14px 28px;border-radius:999px;cursor:pointer;
383
+ transition:transform .15s,filter .15s;}
384
+ .btn-go:hover{transform:translateY(-1px);filter:brightness(1.08);}
385
+ .btn-go:focus-visible{outline:2px solid var(--ink);outline-offset:2px;}
386
+
387
+ /* generic .btn / .btn-primary (question + gate JS, old markup) restyled to pills */
388
+ .btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;
389
+ background:#fff;border:1.5px solid var(--line-2);color:var(--ink);font-family:inherit;
390
+ font-weight:600;font-size:13.5px;padding:13px 20px;border-radius:999px;cursor:pointer;
391
+ transition:background .15s,filter .15s,transform .15s,border-color .15s;}
392
+ .btn:hover:not(:disabled){background:var(--field);}
393
+ .btn:disabled{opacity:.45;cursor:not-allowed;}
394
+ .btn:focus-visible{outline:2px solid var(--ink);outline-offset:2px;}
395
+ .btn-primary{background:var(--ink);border-color:var(--ink);color:#fff;}
396
+ .btn-primary:hover:not(:disabled){background:var(--ink);transform:translateY(-1px);filter:brightness(1.08);}
397
+ .btn-danger{background:var(--red-bg);border-color:transparent;color:var(--red-ink);}
398
+ .btn-danger:hover:not(:disabled){background:var(--red-bg);filter:brightness(.97);}
399
+ .btn-mini{padding:8px 14px;font-size:12.5px;}
400
+ .btn-block{width:100%;}
401
+
402
+ /* form message */
403
+ .form-msg{margin:12px 0 0;font-size:12.5px;min-height:16px;}
404
+ .form-msg.ok{color:var(--green-ink);}
405
+ .form-msg.err{color:var(--red-ink);}
406
+
407
+ /* ---------- Pipeline config ---------- */
408
+ /* The always-open .stage-cfg card is gone: every per-agent control now lives in
409
+ an accordion row below (newpipeline-ux-design.md §4.7). Only the colour
410
+ swatch classes survive — the run-graph and the accordion head share them. */
411
+ .acc.violet{background:var(--violet);} .acc.green{background:var(--green);}
412
+ .acc.peach{background:var(--peach);} .acc.blue{background:var(--blue);}
413
+ .acc.amber{background:var(--amber);} .acc.red{background:var(--red);}
414
+
415
+ /* ---------- Agents accordion (New pipeline) ----------
416
+ One collapsed row per agent showing its effective config; the controls only
417
+ exist once a row is opened, so the page height no longer grows with the
418
+ workflow. (newpipeline-ux-design.md §4.2) */
419
+ .agents-cfg{margin:6px 0 18px;border:1px solid var(--line);border-radius:14px;overflow:hidden;background:var(--field);}
420
+ .agents-head{display:flex;align-items:center;gap:10px;padding:11px 14px;border-bottom:1px solid var(--line);}
421
+ .agents-title{font-weight:700;font-size:13px;}
422
+ .agents-wf{flex:0 0 auto;font-size:11.5px;font-weight:600;color:var(--ink-2);
423
+ background:#fff;border:1px solid var(--line-2);border-radius:999px;padding:2px 9px;
424
+ max-width:180px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
425
+ .agents-wf:empty{display:none;}
426
+ .agents-summary{color:var(--ink-3);font-size:12px;flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
427
+ .agents-summary.muted{font-style:italic;}
428
+ /* Read-only accordion (no project selected): the rows still show what the
429
+ workflow will do, but nothing in them can be edited. */
430
+ .agent-row-body select:disabled,.agent-row-body input:disabled{opacity:.55;cursor:not-allowed;}
431
+ .agent-row-body .fanout-toggle:has(input:disabled){opacity:.6;cursor:not-allowed;}
432
+ .agents-actions{display:flex;gap:6px;flex:0 0 auto;}
433
+ .agents-actions .btn-mini{font-size:11.5px;padding:5px 10px;}
434
+
435
+ .agent-row{border-top:1px solid var(--line);background:#fff;}
436
+ .agent-row:first-child{border-top:none;}
437
+ .agent-row-head{display:flex;align-items:center;gap:10px;width:100%;padding:10px 14px;
438
+ background:none;border:none;font-family:inherit;font-size:13px;text-align:left;cursor:pointer;color:inherit;}
439
+ .agent-row-head:hover{background:var(--field);}
440
+ .agent-row-head:focus-visible{outline:2px solid var(--violet);outline-offset:-2px;}
441
+ .agent-chev{flex:0 0 auto;width:0;height:0;border-left:5px solid var(--ink-3);
442
+ border-top:4px solid transparent;border-bottom:4px solid transparent;transition:transform .15s;}
443
+ .agent-row.open .agent-chev{transform:rotate(90deg);}
444
+ /* Sizing only — the colour comes from the shared .acc.<name> classes below, which
445
+ would otherwise be tied on specificity and lose to a background set here. */
446
+ .agent-row-head .acc{width:8px;height:20px;border-radius:4px;flex:0 0 auto;}
447
+ .acc.neutral{background:var(--line-2);}
448
+ /* The agent name stays on one line and ellipsizes when a display name is long;
449
+ its full blurb is in .agent-desc inside the opened body, where it can wrap. */
450
+ .agent-name{font-weight:600;flex:0 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
451
+ .agent-step{color:var(--ink-3);font-size:11px;flex:0 0 auto;}
452
+ .agent-sum{color:var(--ink-3);font-size:12px;margin-left:auto;text-align:right;
453
+ overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;}
454
+ .agent-mod{color:var(--violet);font-size:9px;flex:0 0 auto;line-height:1;}
455
+ .agent-row-body{padding:4px 14px 14px 37px;}
456
+ .agent-desc{display:block;margin-bottom:9px;color:var(--ink-3);font-size:12px;line-height:1.45;overflow-wrap:anywhere;}
457
+ .agent-row-body .picks{display:flex;flex-wrap:wrap;align-items:center;gap:8px 10px;}
458
+ .agent-row-body .select-wrap{width:180px;}
459
+ .agent-row-body .select{padding:10px 36px 10px 13px;font-size:13px;border-radius:11px;background:#fff;border-color:var(--line-2);}
460
+ .agent-origin{display:block;margin-top:4px;color:var(--ink-3);font-size:11.5px;}
461
+ .fb-field{margin-bottom:10px;}
462
+ .fb-field:last-child{margin-bottom:0;}
463
+
464
+ /* A segmented switch + the picker it qualifies, on one row: Target/Project and
465
+ Task source/Workflow share this proportion. The switch column sizes to itself
466
+ but may shrink (a plugin task source adds buttons); the picker keeps at least
467
+ 200px so a long project path or workflow name never squeezes it away. */
468
+ .split-row{display:grid;grid-template-columns:minmax(0,auto) minmax(200px,1fr);column-gap:18px;align-items:start;}
469
+ .split-row > *{min-width:0;}
470
+ .split-row .seg{flex-wrap:wrap;}
471
+ .target-panes{min-width:0;}
472
+ @media (max-width:760px){ .split-row{grid-template-columns:1fr;} }
473
+
474
+ /* Two fields sharing one row (New pipeline: source + feature branch). Equal
475
+ columns with min-width:0 so a long branch name ellipsizes inside its own
476
+ column instead of widening it; stacks below the narrow breakpoint. */
477
+ .field-grid-2{display:grid;grid-template-columns:1fr 1fr;column-gap:18px;}
478
+ .field-grid-2 > .field{min-width:0;}
479
+ @media (max-width:760px){ .field-grid-2{grid-template-columns:1fr;} }
480
+
481
+ /* Compact rhythm for the run-detail fields promoted out of Advanced (title,
482
+ extra files, the branch pair). They are frequent enough to stay visible but
483
+ secondary to the task box, so they get tighter labels, shorter controls and
484
+ less breathing room — full-size fields would have cost ~340px of page. */
485
+ .field-compact{margin-bottom:12px;}
486
+ .field-compact > label{font-size:12px;margin-bottom:5px;}
487
+ .field-compact .input,.field-compact .select{padding:11px 14px;font-size:13px;}
488
+ .field-compact .select{padding-right:36px;}
489
+ .field-compact .file{padding:9px 13px;gap:11px;}
490
+ .field-compact .file .pick{padding:6px 12px;font-size:12px;}
491
+ .field-compact .file .state{font-size:12px;}
492
+ .field-compact .hint{margin-top:5px;font-size:11.5px;}
493
+
494
+ /* ---------- Advanced disclosure (New pipeline) ---------- */
495
+ .advanced{margin-top:18px;border-top:1px solid var(--line);padding-top:14px;}
496
+ .advanced>summary{display:flex;align-items:center;gap:9px;cursor:pointer;list-style:none;
497
+ font-weight:600;font-size:13px;padding:2px 0;}
498
+ .advanced>summary::-webkit-details-marker{display:none;}
499
+ .advanced>summary:focus-visible{outline:2px solid var(--violet);outline-offset:3px;border-radius:6px;}
500
+ .adv-chev{width:0;height:0;border-left:5px solid var(--ink-3);
501
+ border-top:4px solid transparent;border-bottom:4px solid transparent;transition:transform .15s;}
502
+ .advanced[open] .adv-chev{transform:rotate(90deg);}
503
+ .advanced-body{padding-top:12px;}
504
+ .advanced-body .switch-row{margin-top:4px;}
505
+
506
+ /* per-step model/effort controls (app.js: .step-config / .step-model / .step-effort / .step-current) */
507
+ .step-config{display:flex;flex-wrap:wrap;gap:8px;align-items:center;margin-top:8px;}
508
+ .step-config select{width:auto;font-size:12.5px;padding:8px 30px 8px 11px;border-radius:10px;background:#fff;border-color:var(--line-2);}
509
+ .step-config select:disabled{opacity:.6;cursor:not-allowed;}
510
+ .step-current{flex-basis:100%;width:100%;text-align:right;margin-top:2px;color:var(--ink-3);font-size:11.5px;}
511
+
512
+ /* ---------- Live log ---------- */
513
+ .log-card .card-head{margin-bottom:14px;}
514
+ .log-tools,.log-controls{display:flex;align-items:center;gap:14px;}
515
+ .log-tools .switch-row .txt{font-size:13px;font-weight:600;color:var(--ink-2);}
516
+ .btn-clear{background:var(--field);border:none;border-radius:10px;padding:8px 15px;font-family:inherit;
517
+ font-weight:600;font-size:12.5px;cursor:pointer;color:var(--ink-2);transition:.15s;}
518
+ .btn-clear:hover{background:var(--line-2);}
519
+ .log{background:#fff;border:1px solid var(--line);border-radius:16px;min-height:260px;max-height:380px;overflow-y:auto;
520
+ padding:18px 20px;font-family:var(--mono);font-size:12.5px;line-height:1.85;color:var(--ink-2);
521
+ white-space:pre-wrap;word-break:break-word;}
522
+ .log .t{color:var(--ink-3);}
523
+ .log .ok{color:var(--green-ink);} .log .run{color:var(--peach-ink);} .log .info{color:var(--blue-ink);}
524
+ .log .cur{display:inline-block;width:7px;height:14px;background:var(--ink);vertical-align:-2px;animation:blink 1.1s steps(1) infinite;}
525
+ @keyframes blink{50%{opacity:0;}}
526
+
527
+ /* log lines emitted by app.js: .log-line / .log-ts / .log-src / .log-msg + level variants */
528
+ .log-line{display:flex;gap:10px;padding:1px 0;}
529
+ .log-ts{color:var(--ink-3);flex:0 0 auto;}
530
+ .log-src{font-weight:600;color:var(--ink-2);flex:0 0 auto;}
531
+ .log-msg{color:var(--ink-2);flex:1;}
532
+ .lvl-phase .log-msg{color:var(--green-ink);font-weight:600;}
533
+ .lvl-artifact .log-msg{color:var(--blue-ink);}
534
+ .lvl-error .log-msg{color:var(--red-ink);}
535
+ .lvl-warn .log-msg{color:var(--amber-ink);}
536
+ .lvl-system .log-msg{color:var(--ink-3);font-style:italic;}
537
+
538
+ /* sub-agent lines: nested under their parent agent (fan-out) */
539
+ .log-line.sub-agent{padding-left:1.6em;opacity:.72;}
540
+ .log-line.sub-agent .log-src{color:var(--peach-ink);}
541
+
542
+ /* cycle separator: where a feedback loop rewound and re-ran the same steps */
543
+ .log-sep{display:flex;align-items:center;gap:8px;margin:6px 0 4px;
544
+ color:var(--ink-3);font-size:11px;letter-spacing:.08em;text-transform:uppercase;}
545
+ .log-sep::before,.log-sep::after{content:"";flex:1;height:1px;background:var(--line);}
546
+
547
+ /* ---------- Running ---------- */
548
+ .run-list{display:flex;flex-direction:column;gap:18px;}
549
+ .run-card{padding:22px 24px;}
550
+ .run-top{display:flex;align-items:flex-start;justify-content:space-between;gap:16px;margin-bottom:18px;}
551
+ .run-title{font-weight:700;font-size:16px;letter-spacing:-.01em;display:flex;align-items:center;gap:10px;}
552
+ .run-title .hash{font-family:var(--mono);font-size:11.5px;color:var(--ink-3);font-weight:500;}
553
+ .run-title.title-provisional{opacity:.65;font-style:italic;}
554
+ .run-meta{display:flex;align-items:center;gap:10px;color:var(--ink-3);font-size:12.5px;margin-top:4px;}
555
+ .pill-run{display:inline-flex;align-items:center;gap:8px;padding:8px 14px;border-radius:999px;
556
+ font-weight:600;font-size:12.5px;white-space:nowrap;}
557
+ .pill-run .pdot{width:7px;height:7px;border-radius:50%;animation:pulse 1.3s ease-in-out infinite;}
558
+ .pill-run.peach{background:var(--peach-bg);color:var(--peach-ink);} .pill-run.peach .pdot{background:var(--peach);}
559
+ .pill-run.blue{background:var(--blue-bg);color:var(--blue-ink);} .pill-run.blue .pdot{background:var(--blue);}
560
+ .pill-run.amber{background:var(--amber-bg);color:var(--amber-ink);} .pill-run.amber .pdot{background:var(--amber);}
561
+ .pill-run.violet{background:var(--violet-bg);color:var(--violet-ink);} .pill-run.violet .pdot{background:var(--violet);}
562
+ .pill-run.green{background:var(--green-bg);color:var(--green-ink);} .pill-run.green .pdot{background:var(--green);}
563
+ .pill-run.red{background:var(--red-bg);color:var(--red-ink);} .pill-run.red .pdot{background:var(--red);}
564
+ @keyframes pulse{0%,100%{opacity:1;}50%{opacity:.3;}}
565
+ /* Stronger "alive" pulse for the leading run dots: scale + expanding halo so a
566
+ live run reads as actively working, not a faint blink. currentColor halo so
567
+ each colour variant glows in its own hue. */
568
+ @keyframes dotpulse{
569
+ 0%{transform:scale(1);box-shadow:0 0 0 0 color-mix(in srgb, currentColor 55%, transparent);}
570
+ 70%{transform:scale(1.18);box-shadow:0 0 0 5px color-mix(in srgb, currentColor 0%, transparent);}
571
+ 100%{transform:scale(1);box-shadow:0 0 0 0 color-mix(in srgb, currentColor 0%, transparent);}
572
+ }
573
+
574
+ /* empty state for the running list */
575
+ .run-empty{color:var(--ink-3);padding:24px;text-align:center;}
576
+
577
+ .run-foot{display:flex;align-items:center;gap:10px;}
578
+ .chip{background:var(--field);color:var(--ink-2);font-weight:600;font-size:12px;padding:7px 13px;border-radius:999px;}
579
+ .chip.qcount{background:var(--amber-bg);color:var(--amber-ink);}
580
+ .btn-stop.sm{margin-left:auto;padding:8px 15px;font-size:12px;}
581
+ .btn-pause.sm{margin-left:auto;padding:8px 15px;font-size:12px;}
582
+ .btn-resume.sm{margin-left:auto;padding:8px 15px;font-size:12px;}
583
+ .btn-pause.sm + .btn-stop.sm{margin-left:0;}
584
+
585
+ /* expand to live log */
586
+ .btn-expand{margin-left:auto;display:inline-flex;align-items:center;gap:7px;background:var(--field);
587
+ border:none;border-radius:999px;padding:8px 15px;font-family:inherit;font-weight:600;font-size:12px;
588
+ color:var(--ink-2);cursor:pointer;transition:background .15s;}
589
+ .btn-expand:hover{background:var(--line-2);}
590
+ .btn-expand + .btn-stop.sm{margin-left:0;}
591
+ .btn-expand .chev{transition:transform .2s;}
592
+ .btn-expand[aria-expanded="true"] .chev{transform:rotate(180deg);}
593
+ .run-log{margin-top:16px;}
594
+ .run-log[hidden]{display:none;}
595
+ .run-log .log{min-height:210px;max-height:320px;overflow-y:auto;}
596
+ .run-log-head{display:flex;align-items:center;justify-content:space-between;gap:8px 10px;flex-wrap:wrap;margin-bottom:10px;}
597
+ .run-log-head .ll-label{font-weight:700;font-size:13px;}
598
+ .run-log-head .switch-row .txt{font-size:12.5px;font-weight:600;color:var(--ink-2);}
599
+
600
+ /* log filter dropdowns (source / level / step) — run cards + history panel;
601
+ one row always: nowrap bar, content-sized shrinkable pills (width:auto beats
602
+ the global 100%-width select rule; min-width:0 lets bar and pills shrink) */
603
+ .log-filters{display:flex;gap:6px;align-items:center;flex-wrap:nowrap;min-width:0;}
604
+ .log-filters .log-f{font:inherit;font-size:12px;padding:4px 6px;border:1px solid var(--line);border-radius:8px;
605
+ background:#fff;color:var(--ink-2);max-width:150px;width:auto;min-width:0;}
606
+ /* search is the only pill that grows (own max-width beats the pill cap above);
607
+ copy pins to the bar's right edge via the auto margin */
608
+ .log-filters .log-search{flex:1 1 160px;max-width:340px;}
609
+ .log-filters .log-copy{flex:0 0 auto;margin-left:auto;cursor:pointer;}
610
+ .log-filters .log-copy:hover{background:var(--line);}
611
+ /* run card: pills drop to a full-width second row under "Live log" (order puts
612
+ the bar after the autoscroll switch so row 1 stays label ⟷ switch) */
613
+ .run-log-head .log-filters{order:1;flex-basis:100%;}
614
+ .logs-panel .log-filters{margin-top:8px;}
615
+
616
+ /* needs-attention card + paused stage */
617
+ .run-card.attention{border:1.5px solid var(--amber);box-shadow:0 0 0 4px var(--amber-bg),var(--shadow);}
618
+ .attn-flag{display:inline-flex;align-items:center;gap:5px;margin-left:10px;background:var(--amber-bg);
619
+ color:var(--amber-ink);font-size:11px;font-weight:700;padding:3px 9px;border-radius:999px;vertical-align:middle;}
620
+ .attn-flag svg{stroke:var(--amber-ink);}
621
+
622
+ /* ---------- Questions panel ---------- */
623
+ .qpanel,.question-card{margin-top:18px;border:1.5px solid var(--amber-bg);background:#FFFDF8;border-radius:18px;padding:20px 22px;}
624
+ .qpanel-head{display:flex;align-items:center;gap:10px;margin-bottom:6px;}
625
+ .qpanel-head svg{stroke:var(--amber-ink);flex:0 0 auto;}
626
+ .qpanel-head b{font-size:15px;font-weight:700;}
627
+ .qpanel-head .qcount{margin-left:auto;background:var(--amber-bg);color:var(--amber-ink);
628
+ font-weight:700;font-size:11.5px;padding:5px 11px;border-radius:999px;}
629
+ .qblock,.q-block{padding:18px 0;border-top:1px solid var(--line);}
630
+ .qblock:first-of-type,.q-block:first-of-type{border-top:none;}
631
+ .qtext,.q-question{font-weight:600;font-size:14px;margin:0 0 12px;display:flex;align-items:flex-start;gap:10px;line-height:1.45;}
632
+ .qtext .qn{flex:0 0 auto;width:22px;height:22px;border-radius:50%;background:var(--ink);color:#fff;
633
+ font-size:11.5px;font-weight:700;display:grid;place-items:center;margin-top:1px;}
634
+ .qopts,.q-options{display:flex;flex-direction:column;align-items:stretch;gap:9px;margin-bottom:11px;}
635
+ .qopt,.q-option{font-family:inherit;font-weight:600;font-size:13px;color:var(--ink);background:#fff;
636
+ border:1.5px solid var(--line-2);border-radius:11px;padding:12px 16px;cursor:pointer;transition:.14s;text-align:left;width:100%;}
637
+ .qopt:hover,.q-option:hover{border-color:var(--ink-3);}
638
+ .qopt.sel,.q-option.selected{background:var(--ink);color:#fff;border-color:var(--ink);}
639
+ .qopt:focus-visible,.q-option:focus-visible{outline:2px solid var(--ink);outline-offset:2px;}
640
+ .qfree,.q-free input{width:100%;font-family:inherit;font-size:13.5px;color:var(--ink);background:var(--field);
641
+ border:1.5px solid transparent;border-radius:11px;padding:11px 14px;transition:.14s;}
642
+ .qfree::placeholder,.q-free input::placeholder{color:var(--ink-3);}
643
+ .qfree:focus,.q-free input:focus{outline:none;background:#fff;border-color:var(--ink);}
644
+ .qfree.has{background:#fff;border-color:var(--ink);}
645
+ .q-free{display:flex;gap:8px;align-items:stretch;}
646
+ .q-free-label{display:block;font-size:12px;color:var(--ink-3);margin:4px 0;line-height:1.45;}
647
+ .qpanel-foot,.q-submit-row{margin-top:18px;padding-top:18px;border-top:1px solid var(--line);display:flex;justify-content:flex-end;}
648
+
649
+ /* ---------- Gate (cycle gate) ---------- */
650
+ .gate-intro{font-size:13px;color:var(--ink-2);margin:0 0 14px;line-height:1.5;}
651
+ .issues{list-style:none;margin:0 0 16px;padding:0;display:flex;flex-direction:column;gap:9px;}
652
+ .issue{background:#fff;border:1px solid var(--line);border-left-width:3px;border-radius:11px;padding:12px 14px;}
653
+ .issue.sev-critical{border-left-color:var(--red);}
654
+ .issue.sev-major{border-left-color:var(--peach);}
655
+ .issue.sev-minor{border-left-color:var(--amber);}
656
+ .issue.sev-suggestion{border-left-color:var(--blue);}
657
+ .issue-head{display:flex;align-items:center;gap:8px;margin-bottom:4px;}
658
+ .issue-sev{font-size:10px;text-transform:uppercase;letter-spacing:.06em;padding:2px 8px;border-radius:999px;font-weight:700;}
659
+ .sev-critical .issue-sev{background:var(--red-bg);color:var(--red-ink);}
660
+ .sev-major .issue-sev{background:var(--peach-bg);color:var(--peach-ink);}
661
+ .sev-minor .issue-sev{background:var(--amber-bg);color:var(--amber-ink);}
662
+ .sev-suggestion .issue-sev{background:var(--blue-bg);color:var(--blue-ink);}
663
+ .issue-title{font-weight:600;font-size:13px;}
664
+ .issue-detail{font-size:12.5px;color:var(--ink-2);margin:2px 0 0;}
665
+ .issue-loc{font-family:var(--mono);font-size:11px;color:var(--ink-3);margin-top:4px;}
666
+ .gate-actions{display:flex;gap:10px;flex-wrap:wrap;}
667
+ .gate-actions .btn{flex:1 1 auto;}
668
+
669
+ /* ---------- History rows ---------- */
670
+ .hist-row{display:flex;align-items:center;gap:14px;padding:15px 4px;border-top:1px solid var(--line);}
671
+ .hist-row:first-child{border-top:none;}
672
+ .hist-row .h-meta{flex:1;min-width:0;}
673
+ .hist-row .h-meta b{display:block;font-weight:600;font-size:14.5px;}
674
+ .hist-row .h-meta small{color:var(--ink-3);font-size:12px;}
675
+ .hist-row .hash{font-family:var(--mono);font-size:11.5px;color:var(--ink-3);}
676
+
677
+ /* status badge — shared family colors (app.js historyBadge: green/red/running) */
678
+ .badge{display:inline-flex;align-items:center;font-size:10.5px;font-weight:700;letter-spacing:.06em;
679
+ text-transform:uppercase;padding:5px 10px;border-radius:8px;flex:0 0 auto;white-space:nowrap;
680
+ background:var(--field);color:var(--ink-3);}
681
+ .badge.green,.badge.done{background:var(--green-bg);color:var(--green-ink);}
682
+ .badge.running{background:var(--peach-bg);color:var(--peach-ink);}
683
+ .badge.red,.badge.error,.badge.stopped{background:var(--red-bg);color:var(--red-ink);}
684
+ .badge.waiting{background:var(--amber-bg);color:var(--amber-ink);}
685
+ .badge.paused{background:var(--amber-bg);color:var(--amber-ink);}
686
+ .badge.hist-retained-badge{background:var(--amber-bg);color:var(--amber-ink);}
687
+ .badge.hist-retained-badge[hidden]{display:none;}
688
+
689
+ /* ---------- History cards (expandable) ---------- */
690
+ .hist-card{padding:18px 22px;}
691
+ .hist-head{display:flex;align-items:center;gap:13px;cursor:pointer;}
692
+ .hist-head:focus-visible{outline:2px solid var(--ink);outline-offset:2px;}
693
+ .hist-head .h-meta{flex:1;min-width:0;}
694
+ .hist-head .h-meta b{display:block;font-weight:600;font-size:14.5px;}
695
+ .hist-head .h-meta small{color:var(--ink-3);font-size:12px;}
696
+ .hist-head .hash{font-family:var(--mono);font-size:11.5px;color:var(--ink-3);}
697
+ .hist-head .chev{color:var(--ink-3);transition:transform .2s;flex:0 0 auto;}
698
+ .hist-head[aria-expanded="true"] .chev{transform:rotate(180deg);}
699
+ .hist-head .h-meta b{cursor:pointer;}
700
+ .hist-head .h-meta b:hover{text-decoration:underline;}
701
+ .hist-detail{margin-top:16px;padding-top:16px;border-top:1px solid var(--line);}
702
+ .hist-detail[hidden]{display:none;}
703
+ .hist-detail .detail-error{color:var(--red-ink);font-size:12.5px;}
704
+ .retained-banner{margin:0 0 18px;padding:16px 18px;border:1.5px solid var(--amber);
705
+ border-radius:14px;background:var(--amber-bg);color:var(--amber-ink);font-size:12.5px;line-height:1.55;}
706
+ .retained-banner[hidden]{display:none;}
707
+ .retained-banner h4{margin:0 0 6px;font-size:14px;color:var(--amber-ink);}
708
+ .retained-banner p{margin:5px 0;}
709
+ .retained-banner ul{margin:9px 0;padding-left:20px;}
710
+ .retained-banner li+li{margin-top:8px;}
711
+ .retained-banner code{display:block;margin-top:4px;padding:7px 9px;border-radius:8px;
712
+ background:rgba(255,255,255,.7);color:var(--ink);font-family:var(--mono);font-size:11.5px;
713
+ white-space:pre-wrap;word-break:break-all;}
714
+ .retained-banner a{color:var(--amber-ink);font-weight:700;}
715
+ .hist-empty{color:var(--ink-3);font-size:13px;padding:22px 4px;text-align:center;}
716
+ .hist-section{margin-top:16px;padding-top:16px;border-top:1px solid var(--line);}
717
+ .hist-section-title{font-size:11px;text-transform:uppercase;letter-spacing:.07em;color:var(--ink-3);font-weight:700;margin-bottom:10px;}
718
+ .hist-answer{font-size:12.5px;color:var(--ink-2);margin-top:6px;}
719
+
720
+ /* ---------- History project-filter pills ---------- */
721
+ /* Re-apply (inside the scrolling view) the top inset that body.view-history
722
+ removed from .main, so the unscrolled layout is unchanged while the scroll
723
+ container itself has no top padding for position:sticky to fight. */
724
+ .view[data-view="history"]{padding-top:26px;}
725
+ /* The project-filter pills become a persistent sticky toolbar pinned to the top
726
+ of the scroll area while the list scrolls underneath. Opaque background +
727
+ z-index above the per-project header (z-index:3) so scrolled cards never
728
+ show through, and the user can switch projects while scrolled. */
729
+ .hist-filter{position:sticky;top:0;z-index:5;display:flex;flex-wrap:wrap;align-items:center;
730
+ gap:8px;margin:0 0 14px;padding:12px 0;background:var(--bg);}
731
+ .hist-pill{display:inline-flex;align-items:center;gap:7px;background:var(--panel);
732
+ border:1.5px solid var(--line-2);border-radius:999px;padding:7px 14px;font-weight:600;
733
+ font-size:12.5px;color:var(--ink-2);cursor:pointer;white-space:nowrap;
734
+ transition:border-color .12s,color .12s,background .12s;}
735
+ .hist-pill:hover{border-color:var(--ink-3);color:var(--ink);}
736
+ .hist-pill.active{background:var(--ink);border-color:var(--ink);color:#fff;}
737
+ .hist-pill .pill-count{font-size:11px;font-weight:600;opacity:.7;}
738
+
739
+ /* ---------- History per-project sticky sections (All Projects view) ---------- */
740
+ .hist-group{display:flex;flex-direction:column;gap:18px;}
741
+ .hist-group + .hist-group{margin-top:18px;}
742
+ .hist-group-head{position:sticky;top:var(--hist-toolbar-h, 58px);z-index:3;display:flex;align-items:center;gap:10px;
743
+ background:var(--bg);padding:10px 2px;margin:0;font-weight:700;font-size:14px;color:var(--ink);}
744
+ .hist-group-head .pill-count{font-size:11.5px;font-weight:600;color:var(--ink-3);}
745
+
746
+ /* ---------- Saved-markdown viewer ---------- */
747
+ .viewer{font-family:var(--mono);font-size:12.5px;line-height:1.7;background:#FBFBF9;border:1px solid var(--line);
748
+ border-radius:16px;padding:18px 20px;max-height:480px;overflow:auto;white-space:pre-wrap;word-break:break-word;margin:0;}
749
+
750
+ /* ---------- scrollbars ---------- */
751
+ ::-webkit-scrollbar{width:10px;height:10px;}
752
+ ::-webkit-scrollbar-thumb{background:var(--line-2);border-radius:6px;}
753
+ ::-webkit-scrollbar-track{background:transparent;}
754
+
755
+ /* ---------- reduced motion ---------- */
756
+ @media (prefers-reduced-motion: reduce){
757
+ .pdot,.cur,.child-dot,.child-q{animation:none;}
758
+ *{transition:none !important;}
759
+ }
760
+
761
+ /* ---------- responsive ---------- */
762
+ @media (max-width:1080px){
763
+ .grid{grid-template-columns:1fr;}
764
+ .sidebar{display:none;}
765
+ }
766
+
767
+ /* ---------- viewer modal + responsive top-nav ---------- */
768
+ /* Structural styles for markup added in the shell rewrite that are not part
769
+ of the (locked) Refined stylesheet: the viewer modal + the responsive
770
+ top-nav shown only when the sidebar is hidden (<1080px). */
771
+ .viewer-modal{position:fixed;inset:0;z-index:50;display:grid;place-items:center;
772
+ padding:24px;background:rgba(25,25,27,.42);}
773
+ /* Confirm dialog must stack ABOVE the plugin/wizard modal (equal .viewer-modal z-index,
774
+ but #confirm-modal precedes #plugin-modal in the DOM). */
775
+ #confirm-modal.viewer-modal{z-index:60;}
776
+ .viewer-modal .card{width:min(860px,100%);max-height:86vh;overflow:auto;}
777
+ /* folder browser modal (native-dialog fallback). Must come AFTER the
778
+ .viewer-modal rules: `.folder-modal .card` ties with `.viewer-modal .card`
779
+ on specificity, so source order is what lets these declarations win. */
780
+ .folder-modal .card{width:min(560px,100%);max-height:80vh;display:flex;flex-direction:column;overflow:hidden;}
781
+ .folder-toolbar{display:flex;gap:9px;align-items:center;margin-top:10px;}
782
+ .folder-current{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
783
+ font-size:12px;color:var(--ink-2);}
784
+ .folder-list{list-style:none;margin:10px 0;padding:0;flex:1 1 auto;overflow:auto;min-height:120px;
785
+ border:1.5px solid var(--line-2);border-radius:var(--r-ctrl);background:var(--field);}
786
+ .folder-list .folder-item{display:block;width:100%;text-align:left;padding:7px 12px;border:0;
787
+ background:transparent;font-family:inherit;font-size:13px;color:var(--ink);cursor:pointer;}
788
+ .folder-list .folder-item:hover{background:var(--line-2);}
789
+ .folder-empty{padding:10px 12px;}
790
+ .topnav{display:none;}
791
+ @media (max-width:1080px){
792
+ .topnav{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:20px;background:var(--panel);
793
+ border:1px solid var(--line);border-radius:14px;padding:5px;}
794
+ .topnav button{flex:1;text-align:center;padding:9px 12px;border:0;border-radius:10px;
795
+ background:transparent;color:var(--ink-2);font-family:inherit;font-weight:600;font-size:13px;
796
+ cursor:pointer;transition:.15s;}
797
+ .topnav button:hover{background:var(--field);color:var(--ink);}
798
+ .topnav button.active{background:var(--ink);color:#fff;}
799
+ .topnav button:focus-visible{outline:2px solid var(--ink);outline-offset:2px;}
800
+ .topnav-sep{flex:0 0 1px;background:var(--line-2);margin:6px 2px;}
801
+ }
802
+
803
+ /* ---------- per-pipeline cost (per-node cost is the graph's .nrun .cost) ---------- */
804
+ .run-meta .run-cost{font-family:var(--mono);font-weight:600;color:var(--ink-2);}
805
+ .run-meta .run-cost:not(:empty)::before{content:'·';margin:0 8px;color:var(--ink-3);}
806
+ .h-meta .hist-total{font-family:var(--mono);font-size:12px;font-weight:600;color:var(--ink-2);margin-left:10px;}
807
+ .h-meta .hist-total:empty{display:none;}
808
+
809
+ /* ---------- per-pipeline duration (twin of cost) ---------- */
810
+ .run-meta .run-time{font-family:var(--mono);font-weight:600;color:var(--ink-2);}
811
+ .run-meta .run-time:not(:empty)::before{content:'·';margin:0 8px;color:var(--ink-3);}
812
+ .h-meta .hist-time{font-family:var(--mono);font-size:12px;font-weight:600;color:var(--ink-2);margin-left:10px;}
813
+ .h-meta .hist-time:empty{display:none;}
814
+
815
+ /* Branch name under the date/cost (left column). */
816
+ .h-meta .hist-branch{display:block;font-family:var(--mono);font-size:12px;font-weight:600;color:var(--ink-2);margin-top:4px;}
817
+ .h-meta .hist-branch:empty{display:none;}
818
+
819
+ /* Right-side cluster, before the chevron: lines changed, merge pill, Create PR. */
820
+ .hist-aside{display:flex;align-items:center;gap:10px;flex:0 0 auto;}
821
+ .hist-diff{display:inline-flex;gap:6px;font-family:var(--mono);font-size:12px;font-weight:700;}
822
+ .hist-diff:empty{display:none;}
823
+ .hist-diff .diff-add{color:var(--green-ink);}
824
+ .hist-diff .diff-del{color:var(--red-ink);}
825
+
826
+ .hist-merge{font-size:10.5px;font-weight:700;letter-spacing:.04em;padding:3px 8px;border-radius:999px;white-space:nowrap;}
827
+ .hist-merge[hidden]{display:none;}
828
+ .hist-merge.ok{background:var(--green-bg);color:var(--green-ink);}
829
+ .hist-merge.bad{background:var(--red-bg);color:var(--red-ink);}
830
+ .hist-merge.unknown{background:var(--amber-bg);color:var(--amber-ink);}
831
+
832
+ .hist-pr{padding:6px 12px;font-size:12px;flex:0 0 auto;}
833
+ .hist-pr[hidden]{display:none;}
834
+ .hist-pr-link{font-size:12px;font-weight:600;color:var(--green-ink);text-decoration:none;white-space:nowrap;}
835
+ .hist-pr-link:hover{text-decoration:underline;}
836
+ .hist-pr-link.merged{color:var(--muted, #888);}
837
+
838
+ /* Delete action under the expanded card's stepper. Filled red to read as the
839
+ single destructive action (scoped to .hist-delete so the existing soft
840
+ .btn-danger rule is left untouched). */
841
+ .hist-actions{display:flex;justify-content:flex-end;gap:9px;margin-top:14px;}
842
+ .hist-discard{display:inline-flex;align-items:center;padding:6px 12px;font-size:12px;
843
+ color:var(--amber-ink);border-color:var(--amber);background:var(--amber-bg);}
844
+ .hist-discard:hover:not(:disabled){background:var(--amber-bg);filter:brightness(.97);}
845
+ .hist-discard:disabled{opacity:.6;cursor:default;}
846
+ .hist-discard[hidden]{display:none;}
847
+ .hist-delete,.pl-remove{display:inline-flex;align-items:center;gap:6px;background:var(--red-ink,#d9534f);
848
+ border:1.5px solid var(--red-ink,#d9534f);color:#fff;font-family:inherit;font-weight:600;
849
+ font-size:12px;padding:6px 12px;border-radius:8px;cursor:pointer;}
850
+ .hist-delete:hover:not(:disabled),.pl-remove:hover:not(:disabled){filter:brightness(0.95);}
851
+ .hist-delete:disabled,.pl-remove:disabled{opacity:.6;cursor:default;}
852
+ .hist-delete[hidden]{display:none;}
853
+ .hist-delete svg,.pl-remove svg{display:block;}
854
+
855
+ /* ========================================================================== */
856
+ /* Pipeline Composer — drag/drop canvas, wires, palette, saved list */
857
+ /* (ported from docs/pipeline-composer/mockups; reuses :root tokens) */
858
+ /* ========================================================================== */
859
+ .builder-card{padding:0;overflow:hidden;}
860
+ /* No top padding: sticky pins to the scrollport's PADDING edge, so a 20px inset
861
+ here would leave a see-through band above the pinned header for cards to
862
+ scroll through. The header row re-applies the inset itself (same fix shape as
863
+ body.view-history .main + .hist-filter). */
864
+ .palette{display:flex;flex-wrap:wrap;gap:10px;align-items:center;padding:0 24px 20px;border-bottom:1px solid var(--line);background:var(--panel);max-height:320px;overflow-y:auto;}
865
+ .palette .p-label{display:flex;align-items:center;gap:8px;font-size:11px;font-weight:600;letter-spacing:.08em;text-transform:uppercase;color:var(--ink-3);width:100%;margin-bottom:-10px;padding-top:20px;padding-bottom:14px;position:sticky;top:0;z-index:2;background:var(--panel);}
866
+ .palette .p-label svg{width:14px;height:14px;stroke:var(--ink-3);stroke-width:2;}
867
+ .pal-filter{margin-left:auto;width:200px;padding:6px 10px;border:1.5px solid transparent;border-radius:10px;background:var(--field);color:var(--ink);font-family:inherit;font-size:12px;font-weight:500;text-transform:none;letter-spacing:normal;}
868
+ .pal-filter::placeholder{color:var(--ink-3);}
869
+ .pal-filter:focus{outline:none;background:#fff;border-color:var(--ink);}
870
+ .pal-filter:focus-visible{outline:2px solid var(--ink);outline-offset:2px;}
871
+ /* min-width:0 lets the grid item shrink under its min-content width and
872
+ overflow:hidden makes the card the last line of defence: without both, a
873
+ single unbroken 100-char description paints across its neighbours. */
874
+ .agent-pill{display:flex;flex-direction:column;align-items:flex-start;gap:6px;min-width:0;overflow:hidden;background:#fff;border:1.5px solid var(--line-2);border-radius:12px;padding:10px 12px;font-weight:600;font-size:12.5px;color:var(--ink);cursor:grab;box-shadow:var(--shadow-soft);transition:transform .12s,box-shadow .12s,border-color .12s;user-select:none;}
875
+ .agent-pill:hover{transform:translateY(-1px);box-shadow:var(--shadow);}
876
+ .agent-pill:active{cursor:grabbing;}
877
+ .agent-pill.dragging{opacity:.35;}
878
+ /* Dot pins to the FIRST name line (flex-start + optical nudge), because the
879
+ name may wrap to a second line — a centered dot would float between them. */
880
+ .agent-pill .pdotc{width:11px;height:11px;border-radius:50%;flex:0 0 auto;margin-top:3px;}
881
+ .agent-pill .phead{display:inline-flex;align-items:flex-start;gap:9px;max-width:100%;min-width:0;overflow-wrap:anywhere;}
882
+ .agent-pill .pname{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;min-width:0;overflow-wrap:anywhere;line-height:1.3;}
883
+ /* align-self:stretch overrides the card's align-items:flex-start — otherwise
884
+ .pdesc shrink-to-fits to the full string width and its own overflow:hidden
885
+ clips against that oversized box instead of the card. */
886
+ .agent-pill .pdesc{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;align-self:stretch;max-width:100%;min-width:0;overflow-wrap:anywhere;font-weight:400;font-size:11.5px;line-height:1.45;color:var(--ink-2);}
887
+ /* 3-line text budget: a name that wrapped to 2 lines (.name-2l, toggled by a
888
+ ResizeObserver in app.js) leaves only 1 line for the description. */
889
+ .agent-pill.name-2l .pdesc{-webkit-line-clamp:1;}
890
+ .agent-pill .pdesc.derived{font-style:italic;}
891
+
892
+ .composer-hint {
893
+ margin: 0 0 10px;
894
+ padding: 8px 12px;
895
+ font-size: 12px;
896
+ color: var(--ink-3);
897
+ background: color-mix(in srgb, var(--blue) 8%, transparent);
898
+ border-radius: 8px;
899
+ }
900
+ .canvas-wrap{position:relative;overflow:auto;background-color:#FBFBF9;min-height:500px;max-height:640px;background-image:radial-gradient(circle, var(--line-2) 1.1px, transparent 1.1px);background-size:22px 22px;}
901
+ .flow{position:relative;display:flex;align-items:center;gap:0;padding:70px 30px 50px;min-height:500px;width:max-content;min-width:100%;}
902
+ .wires{position:absolute;top:0;left:0;overflow:visible;pointer-events:none;}
903
+
904
+ .strip{flex:0 0 16px;align-self:stretch;border-radius:12px;margin:40px 0;position:relative;transition:flex-basis .14s,background .14s;}
905
+ .strip.full{flex:1;}
906
+ .strip.over{flex-basis:78px;background:rgba(140,127,214,.12);outline:2px dashed var(--violet);outline-offset:-5px;}
907
+ .strip.over::after{content:"+ step";position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);font-size:10.5px;font-weight:700;letter-spacing:.05em;color:var(--violet-ink);white-space:nowrap;text-transform:uppercase;}
908
+
909
+ .col{display:flex;flex-direction:column;gap:18px;align-items:center;justify-content:center;align-self:center;padding:14px 10px;border-radius:20px;position:relative;z-index:1;transition:background .14s,outline-color .14s;outline:2px dashed transparent;outline-offset:0;}
910
+ .col.over{background:rgba(91,166,204,.10);outline-color:var(--blue);}
911
+ /* left:10px tracks .col padding:14px 10px — tag left edge lines up with card left edge (was centered, causing feedback arcs to cut through text) */
912
+ .col .col-tag{position:absolute;top:8px;left:10px;transform:translateY(-100%);font-size:10px;font-weight:700;letter-spacing:.07em;color:var(--ink-3);text-transform:uppercase;white-space:nowrap;}
913
+ .col .col-tag em{font-style:normal;color:var(--blue-ink);}
914
+ .col .par-hint{position:absolute;bottom:6px;left:50%;transform:translate(-50%,100%);font-size:10.5px;font-weight:700;letter-spacing:.05em;color:var(--blue-ink);text-transform:uppercase;opacity:0;transition:opacity .14s;white-space:nowrap;}
915
+ .col.over .par-hint{opacity:1;}
916
+
917
+ .node{position:relative;width:230px;background:#fff;border:1.5px solid var(--line-2);border-radius:16px;box-shadow:var(--shadow-soft);padding:13px 14px 13px 18px;display:flex;align-items:center;gap:12px;z-index:2;transition:box-shadow .12s,transform .12s;}
918
+ .node:hover{box-shadow:var(--shadow);}
919
+ .node::before{content:"";position:absolute;left:0;top:11px;bottom:11px;width:5px;border-radius:0 5px 5px 0;background:var(--c,#ccc);}
920
+ .node .nic{width:36px;height:36px;border-radius:11px;display:grid;place-items:center;flex:0 0 auto;}
921
+ .node .nic svg{width:19px;height:19px;stroke-width:1.85;}
922
+ .node .nmeta{min-width:0;flex:1;}
923
+ .node .nmeta b{display:block;font-weight:600;font-size:13.5px;line-height:1.2;letter-spacing:-.01em;}
924
+ .node .nmeta small{display:block;color:var(--ink-3);font-size:11px;margin-top:1px;}
925
+ .flow .node .nmeta small{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;}
926
+ .node .nx,.node .loop,.node .selfloop{position:absolute;border-radius:50%;background:#fff;border:1.5px solid var(--line-2);display:grid;place-items:center;cursor:pointer;opacity:0;transition:.12s;box-shadow:var(--shadow-soft);z-index:3;}
927
+ .node .nx{top:-9px;right:-9px;width:22px;height:22px;color:var(--ink-3);font-size:12px;}
928
+ .node .loop{right:-10px;bottom:-10px;width:25px;height:25px;}
929
+ .node .selfloop{top:-10px;left:-10px;width:25px;height:25px;}
930
+ .node:hover .nx,.node:hover .loop,.node:hover .selfloop{opacity:1;}
931
+ .node .nx:hover{color:var(--red-ink);border-color:var(--red);}
932
+ .node .loop svg{width:13px;height:13px;stroke:var(--ink-2);stroke-width:2;}
933
+ .node .loop:hover{border-color:var(--amber);}
934
+ .node .loop:hover svg{stroke:var(--amber-ink);}
935
+ .node .selfloop svg{width:14px;height:14px;stroke:var(--ink-2);stroke-width:2;}
936
+ .node .selfloop:hover{border-color:var(--violet);}
937
+ .node .selfloop:hover svg{stroke:var(--violet-ink);}
938
+ /* active self-cycle: always visible, violet ring (mirrors the lit toggle in the mockup) */
939
+ .node .selfloop.on{opacity:1;background:var(--violet-bg);border-color:var(--violet);box-shadow:0 0 0 3px var(--violet-bg);}
940
+ .node .selfloop.on svg{stroke:var(--violet-ink);}
941
+ .node.linking{outline:2px solid var(--amber);outline-offset:3px;}
942
+ .node.linking .loop{opacity:1;border-color:var(--amber);background:var(--amber-bg);}
943
+ .node.link-target{outline:2px dashed var(--amber);outline-offset:3px;cursor:pointer;}
944
+ .node.link-target:hover{background:var(--amber-bg);}
945
+
946
+ .builder-foot{display:flex;align-items:center;gap:14px;padding:16px 24px;border-top:1px solid var(--line);background:var(--panel);flex-wrap:wrap;}
947
+ .legend{display:flex;align-items:center;gap:20px;font-size:12px;color:var(--ink-2);font-weight:600;}
948
+ .legend .lg{display:flex;align-items:center;gap:8px;}
949
+ .legend .ll{width:12px;height:12px;border-radius:50%;background:var(--seq);display:inline-block;flex:none;}
950
+ .legend .ll.fb{background:var(--amber);}
951
+ .legend .ll.sl{background:var(--violet);}
952
+ .builder-foot .sp{flex:1;}
953
+ .link-banner{display:inline-flex;align-items:center;gap:11px;background:var(--amber-bg);color:var(--amber-ink);font-weight:600;font-size:12.5px;padding:8px 9px 8px 15px;border-radius:999px;}
954
+ .link-banner[hidden]{display:none;}
955
+ .link-banner button{background:#fff;border:none;border-radius:999px;padding:5px 12px;font-family:inherit;font-weight:600;font-size:11.5px;color:var(--amber-ink);cursor:pointer;}
956
+ .empty-flow{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:8px;color:var(--ink-3);font-weight:600;font-size:14px;pointer-events:none;text-align:center;}
957
+ .empty-flow svg{width:36px;height:36px;stroke:var(--line-2);stroke-width:1.6;}
958
+ .empty-flow small{font-weight:500;font-size:12.5px;}
959
+
960
+ .saved-card{margin-top:22px;padding:0;overflow:hidden;}
961
+ .saved-head{display:flex;align-items:center;justify-content:space-between;padding:18px 24px;border-bottom:1px solid var(--line);}
962
+ .saved-head b{font-size:15px;font-weight:600;letter-spacing:-.01em;}
963
+ .saved-head .cnt{color:var(--ink-3);font-size:12.5px;font-weight:600;margin-left:9px;}
964
+ .saved-list{display:flex;flex-direction:column;}
965
+ .pl-empty{padding:34px 24px;text-align:center;color:var(--ink-3);font-size:13px;font-weight:500;}
966
+ .pl-item{border-bottom:1px solid var(--line);}
967
+ .pl-item:last-child{border-bottom:none;}
968
+ .pl-row{display:flex;align-items:center;gap:15px;padding:16px 22px;cursor:pointer;transition:background .12s;}
969
+ .pl-row:hover{background:var(--panel);}
970
+ .pl-caret{width:17px;height:17px;flex:0 0 auto;color:var(--ink-3);transition:transform .18s;margin-top:2px;align-self:flex-start;}
971
+ .pl-item.open .pl-caret{transform:rotate(90deg);}
972
+ .pl-main{flex:1;min-width:0;}
973
+ .pl-name{font-weight:600;font-size:14px;letter-spacing:-.01em;color:var(--ink);}
974
+ .pl-meta{font-size:11px;font-weight:600;color:var(--ink-3);text-transform:uppercase;letter-spacing:.05em;margin-top:5px;}
975
+ .pl-meta em{font-style:normal;color:var(--amber-ink);}
976
+ .pl-chips{display:flex;align-items:center;gap:6px;flex-wrap:wrap;margin-top:9px;}
977
+ .pl-chip{display:inline-flex;align-items:center;gap:6px;font-size:11px;font-weight:600;color:var(--ink-2);background:var(--field);border:1px solid var(--line);border-radius:999px;padding:3px 9px 3px 7px;}
978
+ .pl-chip .d{width:8px;height:8px;border-radius:50%;flex:0 0 auto;}
979
+ .pl-del{flex:0 0 auto;width:34px;height:34px;border-radius:10px;border:1.5px solid var(--line-2);background:#fff;display:grid;place-items:center;cursor:pointer;color:var(--ink-3);transition:.12s;align-self:flex-start;}
980
+ .pl-del:hover{border-color:var(--red);color:var(--red-ink);background:var(--red-bg);}
981
+ .pl-del svg{width:16px;height:16px;stroke-width:1.9;}
982
+ .pl-body{display:none;border-top:1px dashed var(--line-2);}
983
+ .pl-item.open .pl-body{display:block;}
984
+ .pl-readonly-tag{display:flex;align-items:center;gap:8px;padding:9px 24px;background:var(--panel);font-size:11px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--ink-3);border-top:1px dashed var(--line-2);}
985
+ .pl-readonly-tag svg{width:13px;height:13px;stroke:var(--ink-3);stroke-width:2;}
986
+ .ro-scroll{overflow:auto;background-color:#FBFBF9;background-image:radial-gradient(circle, var(--line-2) 1.1px, transparent 1.1px);background-size:22px 22px;max-height:520px;}
987
+ .ro-flow{position:relative;display:flex;align-items:center;padding:26px 30px;min-height:360px;width:max-content;min-width:100%;}
988
+ .ro-flow .strip{flex:0 0 58px;align-self:stretch;margin:40px 0;}
989
+ .ro-flow .col{pointer-events:none;}
990
+ .ro-flow .node{width:218px;}
991
+
992
+ /* Per-agent fan-out toggle in the New Pipeline rows. */
993
+ .fanout-toggle {
994
+ display: inline-flex;
995
+ align-items: center;
996
+ gap: 6px;
997
+ font-size: 12px;
998
+ color: var(--muted, #888);
999
+ white-space: nowrap;
1000
+ cursor: pointer;
1001
+ user-select: none;
1002
+ }
1003
+ .fanout-toggle input { margin: 0; cursor: pointer; }
1004
+
1005
+ /* Per-agent questions toggle shares the fan-out look; [hidden] must win over
1006
+ the inline-flex display when the agent has no questions capability. */
1007
+ .questions-toggle[hidden] { display: none; }
1008
+
1009
+ /* ========================================================================== */
1010
+ /* Workspaces — target selector, management cards, creation wizard, scan loader */
1011
+ /* (reuses :root tokens --field/--line/--ink/--panel/--shadow-soft) */
1012
+ /* ========================================================================== */
1013
+
1014
+ /* New-Pipeline target panes (mutually exclusive). */
1015
+ .target-pane.hidden{display:none;}
1016
+ .ws-members{display:flex;flex-wrap:wrap;gap:7px;margin-top:10px;}
1017
+ /* With no workspace picked the container is empty, but a flex box still holds
1018
+ its margin — 10px of nothing that made the workspace pane taller than the
1019
+ project pane and relaid the form out on every target flip. */
1020
+ .ws-members:empty{display:none;}
1021
+ .ws-members .chip{background:var(--field);color:var(--ink-2);font-weight:600;font-size:12px;padding:6px 12px;border-radius:999px;border:1px solid var(--line);}
1022
+ .ws-members .chip.missing{background:var(--red-bg);color:var(--red-ink);border-color:var(--red);}
1023
+ .ws-source-branches{display:flex;flex-direction:column;gap:12px;margin-top:6px;}
1024
+ .ws-src-row{display:flex;flex-direction:column;gap:6px;}
1025
+ .ws-src-name{font-weight:600;font-size:12.5px;color:var(--ink-2);}
1026
+ .ws-src-row .select-wrap{width:100%;}
1027
+ .ws-src-row select[disabled]{opacity:.55;}
1028
+
1029
+ /* Workspace management cards. */
1030
+ .ws-card{padding:0;overflow:hidden;}
1031
+ .ws-head{display:flex;align-items:center;gap:14px;padding:16px 20px;cursor:pointer;}
1032
+ .ws-head:focus-visible{outline:2px solid var(--ink);outline-offset:-2px;}
1033
+ .ws-h-meta{flex:1;min-width:0;display:flex;flex-wrap:wrap;align-items:center;gap:8px;}
1034
+ .ws-h-meta .ws-name{font-weight:600;font-size:15px;letter-spacing:-.01em;color:var(--ink);}
1035
+ .ws-h-meta .ws-projects{display:block;width:100%;font-family:var(--mono);font-size:12px;color:var(--ink-3);}
1036
+ .ws-stale[hidden]{display:none;}
1037
+ .ws-actions{display:flex;align-items:center;gap:8px;flex:0 0 auto;}
1038
+ .ws-actions .btn-ghost{padding:7px 12px;font-size:12px;}
1039
+ .ws-card .chev{width:15px;height:15px;flex:0 0 auto;color:var(--ink-3);}
1040
+ .ws-detail{padding:0 20px 18px;border-top:1px dashed var(--line-2);}
1041
+ .ws-detail[hidden]{display:none;}
1042
+ .ws-desc-view{margin-top:14px;}
1043
+ .ws-desc-edit[hidden]{display:none;}
1044
+ .ws-delete{display:inline-flex;align-items:center;gap:6px;background:var(--red-ink,#d9534f);border:1.5px solid var(--red-ink,#d9534f);color:#fff;font-family:inherit;font-weight:600;font-size:12px;padding:7px 12px;border-radius:8px;cursor:pointer;}
1045
+ .ws-delete:hover:not(:disabled){filter:brightness(0.95);}
1046
+ .ws-delete:disabled{opacity:.6;cursor:default;}
1047
+
1048
+ /* Wizard step panes. */
1049
+ .wiz-step.hidden{display:none;}
1050
+ .wiz-proj-list{display:flex;flex-direction:column;gap:2px;border:1.5px solid var(--line-2);border-radius:var(--r-ctrl);padding:6px;background:var(--field);}
1051
+ .wiz-proj{display:flex;align-items:center;gap:10px;padding:9px 11px;border-radius:10px;cursor:pointer;font-size:13.5px;color:var(--ink);}
1052
+ .wiz-proj:hover{background:#fff;}
1053
+ .wiz-proj input{margin:0;cursor:pointer;}
1054
+ .wiz-proj.missing{color:var(--ink-3);cursor:not-allowed;}
1055
+
1056
+ /* Live scan loader (role=status aria-live=polite). */
1057
+ .ws-loader{display:flex;flex-direction:column;align-items:center;gap:12px;padding:36px 24px;text-align:center;}
1058
+ .spinner{width:38px;height:38px;border-radius:50%;border:3px solid var(--line-2);border-top-color:var(--ink);animation:ws-spin .9s linear infinite;}
1059
+ @keyframes ws-spin{to{transform:rotate(360deg);}}
1060
+
1061
+ /* Refresh button busy state (History SWR/Phase-2 load); reuses @keyframes ws-spin. */
1062
+ #refresh-history.busy{position:relative;color:transparent;pointer-events:none;}
1063
+ #refresh-history.busy::after{
1064
+ content:"";position:absolute;inset:0;margin:auto;
1065
+ width:14px;height:14px;border-radius:50%;
1066
+ border:2px solid var(--line-2);border-top-color:var(--ink);
1067
+ animation:ws-spin .9s linear infinite;
1068
+ }
1069
+ .status-label{font-weight:600;font-size:14.5px;color:var(--ink);max-width:520px;}
1070
+ .status-sub{font-family:var(--mono);font-size:12px;color:var(--ink-3);}
1071
+
1072
+ /* Phase track: graph → investigate → synthesize. */
1073
+ .wiz-phase-track{display:flex;align-items:center;justify-content:center;gap:10px;margin:6px 0 14px;}
1074
+ .wiz-phase-track [data-phase]{font-size:11px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--ink-3);background:var(--field);border:1px solid var(--line);border-radius:999px;padding:6px 14px;}
1075
+ .wiz-phase-track [data-phase].active{color:#fff;background:var(--ink);border-color:var(--ink);}
1076
+
1077
+ /* History pill "WS" badge for workspace runs. */
1078
+ .hist-pill.ws::before{content:'WS';font-size:9px;font-weight:800;letter-spacing:.06em;background:var(--violet-bg);color:var(--violet-ink);border-radius:5px;padding:2px 5px;margin-right:2px;}
1079
+ .hist-pill.ws.active::before{background:rgba(255,255,255,.22);color:#fff;}
1080
+
1081
+ /* ========================================================================== */
1082
+ /* Run-flow — composer-style node graph for Running + History cards */
1083
+ /* (ported from the mockup; reuses :root tokens. Node base look — accent bar, */
1084
+ /* border, radius, shadow — is inherited from the unscoped `.node` rule. */
1085
+ /* --c is set per-node inline by runNode(); these rules read it via var(--c).) */
1086
+ /* ========================================================================== */
1087
+ .run-flow-wrap{position:relative;margin:0 0 18px;border-radius:18px;border:1px solid var(--line);overflow-x:auto;overflow-y:hidden;background-color:#FBFBF9;background-image:radial-gradient(circle, var(--line-2) 1.1px, transparent 1.1px);background-size:22px 22px;}
1088
+ .run-flow{position:relative;display:flex;align-items:center;gap:44px;padding:66px 30px 52px;width:max-content;min-width:100%;}
1089
+ .run-flow .strip{flex:0 0 44px;align-self:stretch;margin:40px 0;background:none;outline:none;}
1090
+ .run-flow .col{padding:14px 8px;}
1091
+ .run-flow .col .col-tag{color:var(--ink-3);}
1092
+
1093
+ /* Node sizing overrides — base look (accent bar ::before, border, radius,
1094
+ soft shadow, flex layout) is inherited from the unscoped `.node` rule. */
1095
+ .run-flow .node{width:198px;padding:11px 13px 11px 16px;cursor:default;transition:opacity .25s, box-shadow .25s, border-color .25s, transform .25s;}
1096
+ .run-flow .node .nic{width:33px;height:33px;border-radius:10px;}
1097
+ .run-flow .node .nic svg{width:17px;height:17px;}
1098
+ .run-flow .node .nmeta b{font-size:12.5px;}
1099
+ .run-flow .node .nmeta small{font-size:10px;}
1100
+ .run-flow .node:hover{box-shadow:var(--shadow-soft);transform:none;}
1101
+
1102
+ /* Always-visible per-node duration · cost (our decision; not in the mockup). */
1103
+ .run-flow .node .nrun{display:flex;align-items:center;gap:5px;margin-top:3px;font-family:var(--mono);font-size:10px;font-weight:600;color:var(--ink-3);}
1104
+ .run-flow .node .nrun .dur,.run-flow .node .nrun .cost{font-family:var(--mono);color:var(--ink-3);}
1105
+ .run-flow .node .nrun .dur:empty,.run-flow .node .nrun .cost:empty{display:none;}
1106
+ /* Separator rendered only when cost is present, so a lone duration (e.g. "0s") has no dangling "·". */
1107
+ .run-flow .node .nrun .cost:not(:empty)::before{content:"·";margin-right:4px;}
1108
+
1109
+ /* Status badge (top-right pip). */
1110
+ .run-flow .nstat{position:absolute;top:-8px;right:-8px;width:21px;height:21px;border-radius:50%;display:grid;place-items:center;box-shadow:var(--shadow-soft);z-index:3;}
1111
+ .run-flow .nstat svg{width:12px;height:12px;}
1112
+ .run-flow .nstat.done{background:var(--green);} .run-flow .nstat.done svg{stroke:#fff;stroke-width:3;}
1113
+ .run-flow .nstat.paused{background:var(--amber);} .run-flow .nstat.paused svg{fill:#fff;}
1114
+ .run-flow .nstat.stopped{background:var(--red);} .run-flow .nstat.stopped svg{stroke:#fff;stroke-width:3;}
1115
+
1116
+ /* Per-status node states. */
1117
+ .run-flow .node.is-pending{opacity:.5;}
1118
+ .run-flow .node.is-pending .nmeta small{color:var(--ink-3);}
1119
+ .run-flow .node.is-done .nmeta small{color:var(--green-ink);font-weight:600;}
1120
+ .run-flow .node.is-active{border-color:color-mix(in srgb, var(--c) 55%, var(--line-2));animation:nodeGlow 2.2s ease-in-out infinite;}
1121
+ .run-flow .node.is-active .nmeta small{color:var(--c);font-weight:600;}
1122
+ .run-flow .node.is-paused{border-color:color-mix(in srgb, var(--amber) 55%, var(--line-2));animation:nodeGlowAmber 2.2s ease-in-out infinite;}
1123
+ .run-flow .node.is-paused .nmeta small{color:var(--amber-ink);font-weight:600;}
1124
+ .run-flow .node.is-stopped{border-color:color-mix(in srgb, var(--red) 50%, var(--line-2));box-shadow:0 0 0 3px color-mix(in srgb, var(--red) 13%, transparent),var(--shadow-soft);}
1125
+ .run-flow .node.is-stopped .nmeta small{color:var(--red-ink);font-weight:600;}
1126
+ /* Per-node model · effort sub-line: stays neutral grey across all statuses
1127
+ (matches the New-pipeline .step-current caption) and truncates with ellipsis. */
1128
+ .run-flow .node .nmeta small.nmodel{color:var(--ink-3);font-weight:600;margin-top:2px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
1129
+ @keyframes nodeGlow{0%,100%{box-shadow:var(--shadow-soft);}50%{box-shadow:0 0 0 4px color-mix(in srgb, var(--c) 13%, transparent),0 8px 26px color-mix(in srgb, var(--c) 24%, transparent);}}
1130
+ @keyframes nodeGlowAmber{0%,100%{box-shadow:var(--shadow-soft);}50%{box-shadow:0 0 0 4px color-mix(in srgb, var(--amber) 16%, transparent),0 8px 26px color-mix(in srgb, var(--amber) 26%, transparent);}}
1131
+
1132
+ /* Sub-agent square strip on a run-graph node. The node wraps so the strip
1133
+ drops to its own full-width row under the meta/cost block. PULSE LIVES HERE
1134
+ AND NOWHERE ELSE: sqPulse attaches only to .run-flow .node .fan .sq.on, so
1135
+ the tree/legend squares (.led/.sq) never animate and history (terminal
1136
+ statuses -> no .on) never pulses. */
1137
+ .run-flow .node.run-node{flex-wrap:wrap;}
1138
+ .run-flow .node .fan{flex:0 0 100%;display:flex;align-items:center;flex-wrap:wrap;gap:3px;margin-top:9px;padding-top:8px;border-top:1px solid var(--line);}
1139
+ .run-flow .node .fan .sq{width:7px;height:7px;border-radius:2px;background:var(--ink-3);opacity:.5;}
1140
+ .run-flow .node .fan .sq.on{background:var(--blue);opacity:1;animation:sqPulse 1.5s ease-in-out infinite;}
1141
+ .run-flow .node .fan .fl{font-size:9.5px;font-weight:700;color:var(--ink-3);margin-left:5px;letter-spacing:.02em;}
1142
+ .run-flow .node.is-active .fan .fl{color:var(--blue-ink);}
1143
+ @keyframes sqPulse{0%,100%{opacity:1;}50%{opacity:.38;}}
1144
+
1145
+ /* "Sub-agents" disclosure pill + its tree panel (shared by Run + History). */
1146
+ .subs-bar,.clarify-bar,.logs-bar,.diff-bar,.overview-bar{margin-top:14px;}
1147
+ .subs-bar[hidden],.clarify-bar[hidden],.logs-bar[hidden],.diff-bar[hidden],.overview-bar[hidden]{display:none;}
1148
+ /* (.subs-panel rule already covers .clarify-panel/.logs-panel via the shared class) */
1149
+ .logs-panel .log{min-height:0;max-height:340px;margin-top:8px;}
1150
+ .btn-subs{display:inline-flex;align-items:center;gap:9px;background:var(--field);border:none;border-radius:999px;padding:9px 15px 9px 13px;font-family:inherit;font-weight:600;font-size:12.5px;color:var(--ink-2);cursor:pointer;transition:background .15s;}
1151
+ .btn-subs:hover{background:var(--line-2);}
1152
+ .btn-subs .ico{width:15px;height:15px;stroke:var(--ink-2);stroke-width:1.9;}
1153
+ .btn-subs .sb-count{display:inline-flex;align-items:center;gap:6px;background:var(--blue-bg);color:var(--blue-ink);font-weight:700;font-size:11px;padding:3px 9px;border-radius:999px;}
1154
+ .btn-subs .sb-count.grey{background:#fff;color:var(--ink-3);box-shadow:inset 0 0 0 1px var(--line-2);}
1155
+ .btn-subs .chev{transition:transform .2s;stroke:var(--ink-3);}
1156
+ .btn-subs[aria-expanded="true"] .chev{transform:rotate(180deg);}
1157
+ .subs-panel{margin-top:14px;border:1px solid var(--line);border-radius:18px;background:#FBFBF9;padding:8px 20px 16px;}
1158
+ .subs-panel[hidden]{display:none;}
1159
+ .subs-legend{display:flex;align-items:center;gap:18px;padding:12px 0 4px;font-size:11.5px;font-weight:600;color:var(--ink-3);}
1160
+ .subs-legend .lk{display:flex;align-items:center;gap:7px;}
1161
+ .subs-legend .sq{width:9px;height:9px;border-radius:2px;}
1162
+ .subs-legend .sq.on{background:var(--blue);}
1163
+ .subs-legend .sq.off{background:var(--ink-3);opacity:.5;}
1164
+ .subs-step{padding:13px 0;border-top:1px solid var(--line);}
1165
+ .subs-step:first-of-type{border-top:none;}
1166
+ .subs-step-head{display:flex;align-items:center;gap:10px;}
1167
+ .subs-step-head .dot{width:10px;height:10px;border-radius:50%;flex:0 0 auto;}
1168
+ .subs-step-head b{font-size:13.5px;font-weight:600;letter-spacing:-.01em;}
1169
+ .subs-step-head .subs-stat{font-size:10.5px;font-weight:700;padding:3px 9px;border-radius:999px;letter-spacing:.02em;text-transform:uppercase;}
1170
+ .subs-step-head .subs-stat.run{background:var(--blue-bg);color:var(--blue-ink);}
1171
+ .subs-step-head .subs-stat.done{background:var(--green-bg);color:var(--green-ink);}
1172
+ .subs-step-head .subs-stat.stop{background:var(--red-bg);color:var(--red-ink);}
1173
+ .subs-step-head .subs-n{margin-left:auto;font-size:11.5px;font-weight:600;color:var(--ink-3);}
1174
+ .subs-step .subs-empty{margin-top:8px;padding-left:5px;font-size:12px;font-weight:500;color:var(--ink-3);font-style:italic;}
1175
+ .subs-tree{list-style:none;margin:8px 0 0;padding:0 0 0 5px;}
1176
+ .subs-tree li{position:relative;padding:6px 0 6px 28px;font-size:12.5px;font-weight:500;color:var(--ink-2);display:flex;align-items:center;gap:9px;}
1177
+ .subs-tree li::before{content:"";position:absolute;left:5px;top:-3px;height:calc(50% + 3px);width:1.5px;background:var(--line-2);}
1178
+ .subs-tree li::after{content:"";position:absolute;left:5px;top:50%;width:15px;height:1.5px;background:var(--line-2);}
1179
+ .subs-tree li .led{width:7px;height:7px;border-radius:2px;flex:0 0 auto;background:var(--ink-3);opacity:.55;}
1180
+ .subs-tree li .led.on{background:var(--blue);opacity:1;}
1181
+ .subs-tree li .ag-name{min-width:0;}
1182
+ .subs-tree li .st{margin-left:auto;font-family:'JetBrains Mono',monospace;font-size:10px;font-weight:500;padding:2px 8px;border-radius:6px;white-space:nowrap;}
1183
+ .subs-tree li .st.done{background:var(--green-bg);color:var(--green-ink);}
1184
+ .subs-tree li .st.run{background:var(--blue-bg);color:var(--blue-ink);}
1185
+ .subs-tree li .st.stop{background:var(--red-bg);color:var(--red-ink);}
1186
+
1187
+ /* Skill / MCP pills — main-agent group header + per sub-agent row. Flex-wrap so
1188
+ pills reflow onto multiple lines as the window shrinks (cf. .agent-chips, .fan). */
1189
+ .subs-skills{display:flex;flex-wrap:wrap;gap:6px;margin-top:8px;}
1190
+ .subs-tree li{flex-wrap:wrap;} /* let the pill row drop below name/status */
1191
+ .subs-tree li .subs-skills{flex:0 0 100%;margin-top:6px;} /* own full row, aligned under .ag-name */
1192
+ .skill-pill{font-size:10.5px;font-weight:700;letter-spacing:.01em;padding:2px 9px;border-radius:999px;white-space:nowrap;}
1193
+ .skill-pill.is-skill{background:var(--blue-bg);color:var(--blue-ink);}
1194
+ .skill-pill.is-mcp{background:var(--green-bg);color:var(--green-ink);box-shadow:inset 0 0 0 1px color-mix(in srgb, var(--green-ink) 18%, transparent);}
1195
+ /* Three-part MCP label `mcp:<server>:<tool>` (§7.4). A VARIANT of .is-mcp — the
1196
+ green background/ink come from the base rule (class list is "is-mcp is-mcp-tool");
1197
+ this only adds monospace (the tool token is an identifier, not prose) and denser
1198
+ padding, since "<server> · <tool>" is roughly twice as wide as a server alone. */
1199
+ .skill-pill.is-mcp-tool{font-family:var(--mono);font-size:10px;font-weight:600;padding:2px 7px;}
1200
+ /* §7.1's overflow sentinel: "+N more" when the per-agent pill cap binds. Muted on
1201
+ purpose — it is a count of what is NOT shown, so it must not read as a label
1202
+ (blue/green) or a status (red/amber/violet). */
1203
+ .skill-pill.is-overflow{background:var(--field);color:var(--ink-3);font-weight:600;box-shadow:inset 0 0 0 1px var(--line);cursor:help;}
1204
+ /* Sub-agent type pill — the raw Task/Agent subagent_type, inline next to the row
1205
+ name (cf. skill pills). Uses the shared violet token (defined :root, l.24) so it
1206
+ reads as agent metadata, distinct from the skill (blue) / MCP (green) pills. */
1207
+ .subs-tree li .agent-type-pill{font-size:10.5px;font-weight:700;letter-spacing:.01em;padding:2px 9px;border-radius:999px;white-space:nowrap;background:var(--violet-bg);color:var(--violet-ink);}
1208
+ /* graphify-use count badge (amber) — how many times an agent / sub-agent invoked the
1209
+ graphify CLI. Rendered INLINE: in the phase/node header next to the status, and on a
1210
+ sub-agent row right after the violet type pill. inline-block + parent flex `gap` size
1211
+ it to its text; amber keeps it distinct from skill (blue) / MCP (green) / type (violet). */
1212
+ .graphify-pill{display:inline-block;font-size:10.5px;font-weight:700;letter-spacing:.01em;padding:2px 9px;border-radius:999px;white-space:nowrap;background:var(--amber-bg);color:var(--amber-ink);}
1213
+
1214
+ /* Loop-badge cycle-count text (renderer sizes font-size inline). */
1215
+ .run-flow .loop-badge text{font-family:var(--sans);font-weight:700;}
1216
+
1217
+ /* Wires — dimmed by default; the live (originating) loop marches. */
1218
+ .run-flow .wires path.wire-dim{opacity:.26;}
1219
+ .run-flow .wires path.wire-live{opacity:1;stroke-width:2.4;animation:wireFlow .9s linear infinite;}
1220
+ @keyframes wireFlow{to{stroke-dashoffset:-18;}}
1221
+
1222
+ @media (prefers-reduced-motion: reduce){
1223
+ .run-flow .node.is-active,.run-flow .node.is-paused{animation:none;box-shadow:0 0 0 3px color-mix(in srgb, var(--c) 16%, transparent),var(--shadow-soft);}
1224
+ .run-flow .node.is-paused{box-shadow:0 0 0 3px color-mix(in srgb, var(--amber) 18%, transparent),var(--shadow-soft);}
1225
+ .run-flow .wires path.wire-live{animation:none;}
1226
+ .run-flow .node .fan .sq.on{animation:none;}
1227
+ }
1228
+
1229
+ /* ===== Agents view ===== */
1230
+ .agent-card .agent-head { display:flex; align-items:center; gap:14px; cursor:pointer; }
1231
+ .agent-card .agent-h-meta { flex:1; min-width:0; }
1232
+ .agent-io { display:flex; flex-direction:column; gap:6px; margin-top:6px; }
1233
+ .agent-io-row { display:flex; align-items:flex-start; gap:8px; }
1234
+ .agent-io-label { flex:0 0 auto; min-width:52px; font-size:11px; font-weight:700;
1235
+ text-transform:uppercase; letter-spacing:.04em; opacity:.6; line-height:20px; }
1236
+ .agent-chips { display:flex; flex-wrap:wrap; gap:6px; flex:1 1 auto; }
1237
+ .agent-chip { font-size:11px; padding:2px 8px; border:1px solid var(--line); border-radius:999px; }
1238
+ .agent-chip.prod { background:#E2F3DF; }
1239
+ .agent-chip.cons { background:#DEEFF7; }
1240
+ .agent-io-none { font-size:11px; opacity:.45; line-height:20px; }
1241
+
1242
+ /* (2) space between the header pills and the expanded markdown body */
1243
+ .agent-detail { margin-top:14px; }
1244
+ .agent-origin.origin-user { background:#EAE6F8; }
1245
+ .agents-group-label { font-size:12px; font-weight:700; opacity:.65; margin:18px 0 8px; text-transform:uppercase; letter-spacing:.06em; }
1246
+ .agent-actions { display:flex; gap:8px; }
1247
+ .chip-select { display:flex; flex-wrap:wrap; gap:8px; }
1248
+ .chip-select label { display:inline-flex; gap:6px; align-items:center; font-size:12.5px; border:1px solid var(--line); border-radius:999px; padding:4px 10px; cursor:pointer; }
1249
+
1250
+ /* ===== Projects management view ===== */
1251
+ /* Static rows (no expand) — neutralize the pipeline row's pointer cursor. */
1252
+ #projects-list .pl-row{cursor:default;}
1253
+ .proj-path{
1254
+ font-family:var(--mono);font-size:12px;color:var(--ink-2);
1255
+ margin-top:4px;word-break:break-all;
1256
+ }
1257
+ .proj-missing{
1258
+ display:inline-block;margin-left:8px;vertical-align:middle;
1259
+ font-size:10.5px;font-weight:700;text-transform:uppercase;letter-spacing:.05em;
1260
+ color:var(--ink-3);border:1px solid var(--line-2);border-radius:6px;padding:1px 6px;
1261
+ }
1262
+ /* Neutral bin button — same size/shape as .pl-del but stays neutral on hover (no red, ever). */
1263
+ .proj-del{
1264
+ flex:0 0 auto;width:34px;height:34px;border-radius:10px;
1265
+ border:1.5px solid var(--line-2);background:#fff;display:grid;place-items:center;
1266
+ cursor:pointer;color:var(--ink-3);transition:.12s;align-self:center;
1267
+ }
1268
+ .proj-del:hover{border-color:var(--ink-3);color:var(--ink);background:var(--field);}
1269
+ .proj-del:focus-visible{outline:2px solid var(--ink);outline-offset:2px;}
1270
+ .proj-del svg{width:16px;height:16px;stroke-width:1.9;}
1271
+
1272
+ /* Guardrails row editors (used by the Guardrails view) */
1273
+ .gr-list{display:flex;flex-direction:column;margin-bottom:8px;}
1274
+ .gr-row{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:7px 0;border-bottom:1px solid var(--line);font-family:var(--mono);font-size:12.5px;}
1275
+ .gr-row:last-child{border-bottom:none;}
1276
+ .gr-rm{flex:0 0 auto;width:26px;height:26px;border-radius:8px;border:1.5px solid var(--line-2);background:#fff;display:grid;place-items:center;cursor:pointer;color:var(--ink-3);font-size:11px;transition:.12s;}
1277
+ .gr-rm:hover{color:var(--red-ink);border-color:var(--red);background:var(--red-bg);}
1278
+ .gr-empty{color:var(--ink-3);font-size:12px;padding:6px 0;}
1279
+
1280
+ /* ===== Confirm + add-project modals (reuse .viewer-modal shell) ===== */
1281
+ /* MUST come after .viewer-modal .card (style.css:514) — equal specificity, later wins. */
1282
+ .confirm-modal .card{width:min(440px,100%);}
1283
+ .confirm-message{margin:4px 0 18px;color:var(--ink-2);font-size:14px;line-height:1.5;white-space:pre-line;}
1284
+ .confirm-actions{display:flex;gap:9px;justify-content:flex-end;margin-top:14px;}
1285
+
1286
+ /* ── domain tag: palette sections + filter chips, workflow badge + filter ── */
1287
+ .pal-chips{display:flex;flex-wrap:wrap;gap:6px;width:100%;margin-bottom:8px;}
1288
+ .pal-chip{font-size:11px;padding:2px 9px;border-radius:999px;border:1px solid var(--line,#d8d8de);background:var(--card,#fff);cursor:pointer;text-transform:capitalize;}
1289
+ .pal-chip.off{opacity:.45;text-decoration:line-through;}
1290
+ .pal-section{width:100%;display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));gap:10px;}
1291
+ .pal-section .pal-head{grid-column:1/-1;}
1292
+ .pal-section.collapsed .agent-pill,.pal-section.collapsed .pal-head{display:none;}
1293
+ .pal-head{font-size:10px;letter-spacing:.06em;text-transform:uppercase;color:var(--muted,#8a8a92);margin:6px 0 4px;}
1294
+ .pl-domain{font-size:10px;padding:1px 6px;border-radius:999px;background:var(--chip,#eee);color:var(--muted,#777);text-transform:capitalize;vertical-align:middle;}
1295
+ .wf-filter{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:8px;}
1296
+
1297
+ /* Run Results view (Layer 1 mechanical + Layer 2 overview) */
1298
+ .results-section{margin-top:14px;}
1299
+ .results-chips{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:10px;}
1300
+ .results-chip{font-size:12px;background:var(--chip-bg,#f1f1f4);border:1px solid var(--line);border-radius:999px;padding:2px 10px;}
1301
+ .results-clean{color:var(--green-ink,#1a7f37);font-size:13px;padding:6px 0;}
1302
+ .results-files{margin-top:10px;}
1303
+ .results-files-h{font-weight:700;font-size:13px;margin-bottom:4px;}
1304
+ .results-files ul{list-style:none;padding:0;margin:0;font-family:ui-monospace,monospace;font-size:12px;}
1305
+ .results-files li{padding:2px 0;}
1306
+ .results-overview-btn{margin:6px 0;font-size:12px;padding:5px 12px;border:1px solid var(--line);border-radius:8px;background:#fff;cursor:pointer;}
1307
+ .results-overview-btn:disabled{opacity:.6;cursor:default;}
1308
+ .results-narrative{font-size:13px;line-height:1.5;background:var(--chip-bg,#f7f7fa);border-radius:10px;padding:10px 12px;margin:8px 0;}
1309
+ .issue-origin{font-size:10px;text-transform:uppercase;letter-spacing:.05em;padding:1px 6px;border-radius:999px;font-weight:700;}
1310
+ .origin-agent{background:var(--blue-bg);color:var(--blue-ink);}
1311
+ .origin-review{background:var(--chip-bg,#eee);color:#555;}
1312
+ .results-trunc{font-size:11px;color:#946;margin-top:6px;}
1313
+
1314
+ /* ---- Plugins view ---- */
1315
+ /* Available/Marketplaces render as one wrapper div inside the .run-list, so the
1316
+ list's gap doesn't reach the cards — the wrappers repeat it. */
1317
+ .pl-list,.pl-orphans,.pl-available,.pl-mkts{display:flex;flex-direction:column;gap:18px;}
1318
+ .plugin-card{padding:16px 20px;}
1319
+ /* Card actions live top-right of the head row. */
1320
+ .pl-remove{border-radius:999px;} /* pill like the rest of this page's buttons */
1321
+ .pl-mkt-actions{margin-left:auto;display:flex;align-items:center;gap:8px;}
1322
+ .pl-mkt-actions .btn-ghost{display:inline-flex;align-items:center;gap:6px;}
1323
+ .pl-mkt-actions .btn-ghost svg{display:block;}
1324
+ .pl-avail-card .pl-install-avail,.pl-avail-card .pl-installed{margin-left:auto;}
1325
+ .plugin-card.pl-disabled{opacity:.62;}
1326
+ .pl-head{display:flex;align-items:center;gap:10px;flex-wrap:wrap;}
1327
+ .pl-head .pl-name{font-size:14.5px;}
1328
+ .pl-version{color:var(--ink-3);font-size:12px;}
1329
+ .pl-enable{margin-left:auto;display:inline-flex;align-items:center;gap:6px;font-size:12px;color:var(--ink-3);cursor:pointer;}
1330
+ .pl-actions{display:flex;gap:8px;margin-top:10px;flex-wrap:wrap;}
1331
+ /* One button height across the Plugins view, keyed to .btn-mini (Install…/Add). */
1332
+ .pl-actions button,.pl-purge-orphan,.pl-mkt-actions .btn-ghost,.pl-remove{padding:8px 14px;font-size:12.5px;}
1333
+ .pl-pick-row{display:flex;align-items:center;gap:10px;justify-content:space-between;padding:8px 0;border-bottom:1px solid var(--line);}
1334
+ .pl-consent-h{font-weight:700;font-size:12.5px;margin:10px 0 4px;}
1335
+ .pl-consent-row{font-size:12.5px;padding:2px 0;}
1336
+ .pl-secret{display:inline-flex;margin-left:8px;background:var(--red-bg);color:var(--red-ink);font-size:11px;font-weight:700;padding:2px 8px;border-radius:999px;}
1337
+ .pl-setup-cmd{background:var(--chip-bg,#f7f7fa);border-radius:8px;padding:4px 8px;margin-top:3px;}
1338
+ .pl-diffstat{background:var(--chip-bg,#f7f7fa);border-radius:10px;padding:10px 12px;font-size:12px;overflow-x:auto;max-height:220px;}
1339
+ .pl-commit{font-size:12px;padding:2px 0;}
1340
+ .pl-doc-row{display:flex;align-items:baseline;gap:8px;padding:4px 0;font-size:12.5px;}
1341
+ .pl-doc-row .hint{margin-top:0;}
1342
+ .pl-uptodate{display:flex;align-items:baseline;gap:8px;padding:4px 0;}
1343
+ .pl-uptodate .hint{margin-top:0;font-size:13px;}
1344
+ .pl-refs-list{margin:6px 0 0 18px;font-size:12.5px;}
1345
+ .plugin-card .mono,.pl-consent .mono,.pl-update .mono,.pl-doc-row .mono,.pl-refs .mono{font-family:var(--mono);}
1346
+ .pl-manifest-delta{margin:8px 0;}
1347
+ .pl-delta{font-size:12.5px;}
1348
+ .pl-delta-secret{font-size:12.5px;font-weight:700;color:var(--red-ink);background:var(--red-bg);border-radius:8px;padding:3px 8px;margin:2px 0;display:inline-block;}
1349
+ #plugin-modal .card{max-width:640px;width:min(92vw,640px);max-height:80vh;overflow:auto;}
1350
+ .pl-sec-title{margin:22px 0 10px;font-size:13px;text-transform:uppercase;letter-spacing:.06em;opacity:.65;}
1351
+ .pl-provenance{display:block;margin-top:4px;}
1352
+ .pl-mkt-url{display:block;margin-top:2px;}
1353
+ .pl-mkt-sync{display:block;margin-top:2px;}
1354
+ .pl-mkt-warning{margin-top:4px;}
1355
+ .pl-avail-card .pl-mkt-badge{margin-left:6px;}
1356
+ .pl-avail-card .mono,.pl-mkt-row .mono{font-family:var(--mono);}
1357
+
1358
+ /* ---- Pluggable source pane (New Pipeline) ---- */
1359
+ .sp-pane{margin-top:11px;}
1360
+ .sp-results{margin-top:8px;max-height:220px;overflow:auto;border:1px solid var(--line);border-radius:12px;}
1361
+ .sp-row{display:flex;justify-content:space-between;gap:10px;padding:8px 12px;cursor:pointer;border-bottom:1px solid var(--line);font-size:13px;}
1362
+ .sp-row:last-child{border-bottom:none;}
1363
+ .sp-row:hover{background:var(--chip-bg,#f7f7fa);}
1364
+ .sp-row.sel{background:var(--green-bg);color:var(--green-ink);}
1365
+ .sp-row-meta{display:inline-flex;gap:6px;align-items:center;color:var(--ink-3);font-size:11.5px;flex:0 0 auto;}
1366
+ .sp-label{background:var(--chip-bg,#f0f0f4);border-radius:999px;padding:1px 8px;font-weight:600;}
1367
+ .sp-preview{margin-top:8px;max-height:260px;overflow:auto;}
1368
+ .sp-preview .sp-prev-body{white-space:pre-wrap;font-size:12.5px;margin:6px 0 0;}
1369
+ .sp-pane .mono{font-family:var(--mono);}
1370
+ .sp-config-missing{display:flex;flex-direction:column;gap:8px;align-items:flex-start;margin-top:11px;}
1371
+
1372
+ /* ---- Plugin provenance (results header, history cards) ---- */
1373
+ .src-badge{display:inline-flex;gap:6px;align-items:center;font-size:11.5px;background:var(--chip-bg,#f0f0f4);border-radius:999px;padding:2px 10px;}
1374
+ .src-badge-plugin{font-weight:700;}
1375
+ .src-report-wrap{display:inline-flex;gap:8px;align-items:center;margin-left:10px;}
1376
+
1377
+ /* ---- Guardrails view ---- */
1378
+ .badge.violet{background:var(--violet-bg);color:var(--violet-ink);}
1379
+ .grv-list{display:grid;gap:14px;}
1380
+ .grv-card{padding:16px 20px;display:flex;align-items:center;gap:14px;}
1381
+ .grv-body{flex:1 1 auto;min-width:0;}
1382
+ .grv-head{display:flex;align-items:center;gap:10px;flex-wrap:wrap;}
1383
+ .grv-name{font-size:14.5px;}
1384
+ .grv-name-input{flex:1 1 auto;min-width:0;}
1385
+ .grv-summary{display:block;margin:6px 0 0;}
1386
+ .grv-actions{display:flex;gap:8px;margin-top:4px;}
1387
+ .grv-actions .btn-ghost{padding:7px 12px;font-size:12px;}
1388
+ /* Details button on the card's right edge — opens the read-only view (built-ins) or the editor (user sets). */
1389
+ .grv-details{flex:0 0 auto;}
1390
+ .grv-editor{padding:18px 22px;}
1391
+ .grv-editor .grv-head{margin-bottom:16px;}
1392
+ .grv-editor .switch-row{margin-top:12px;}
1393
+ .grv-editor .field{margin-top:12px;}
1394
+ .grv-editor .gr-list .mono,.grv-refs409 .mono{font-family:var(--mono);font-size:12px;}
1395
+ .grv-editor-actions{justify-content:flex-end;margin-top:14px;}
1396
+ /* ---- Guardrail wizard (Step 1 + read-only view) ---- */
1397
+ .grv-wizard .grv-source-list{display:grid;gap:8px;margin:12px 0;max-height:46vh;overflow-y:auto;}
1398
+ .grv-source-row{display:flex;align-items:center;gap:10px;padding:10px 12px;border:1px solid var(--line,#d8d8de);border-radius:10px;cursor:pointer;}
1399
+ .grv-source-row:hover{background:var(--chip-bg,#f7f7fa);}
1400
+ .grv-source-name{flex:1 1 auto;font-size:14px;}
1401
+ .grv-wizard-actions{justify-content:flex-end;margin-top:14px;}
1402
+ .grv-editor .switch.disabled{opacity:.5;pointer-events:none;}
1403
+ /* The editor renders as a .card, so inside #plugin-modal it re-matches the
1404
+ `#plugin-modal .card` rule above (640px + its own overflow:auto/max-height).
1405
+ That pinned it to 640px inside the 900px body AND made it a nested scroll
1406
+ container whose scrollbar clipped the right edge of every row/button. Strip
1407
+ the card chrome AND the width/scroll so it fills the body and the OUTER
1408
+ .card stays the single scroll container. */
1409
+ #plugin-modal-body .grv-editor.card{border:none;box-shadow:none;background:none;padding:0;
1410
+ width:auto;max-width:none;max-height:none;overflow:visible;}
1411
+ /* Hide the empty plugin-modal footer for the wizard (it keeps a margin-top otherwise). */
1412
+ #plugin-modal-actions:empty{display:none;}
1413
+ /* The wizard needs more room than the default plugin modal (640px): the editor's
1414
+ labeled fields with inline "+ add" rows and the two-button footer overflow 640.
1415
+ Scoped via :has() so other #plugin-modal consumers (install/settings/doctor/409)
1416
+ keep their 640px width. 960 = 640 * 1.5. */
1417
+ #plugin-modal .card:has(.grv-wizard),
1418
+ #plugin-modal .card:has(.grv-editor){max-width:960px;width:min(94vw,960px);}
1419
+
1420
+ /* ---------- Statistics view ---------- */
1421
+ .stats-filter{display:flex;margin-bottom:18px;}
1422
+ .stat-row{display:grid;grid-template-columns:repeat(4,1fr);gap:14px;margin-bottom:18px;}
1423
+ .stat-tile{padding:18px 20px;}
1424
+ .stat-label{display:flex;align-items:center;gap:8px;color:var(--ink-2);font-size:12.5px;font-weight:600;}
1425
+ .stat-ico{width:16px;height:16px;color:var(--ink-3);flex:0 0 auto;}
1426
+ .stat-delta{margin-left:auto;background:var(--field);color:var(--ink-2);font-size:11px;font-weight:600;
1427
+ padding:2px 8px;border-radius:999px;}
1428
+ .stat-value{font-family:var(--mono);font-size:26px;font-weight:600;color:var(--ink);margin-top:8px;line-height:1.2;}
1429
+ .stat-frac{font-size:16px;color:var(--ink-3);}
1430
+ .stat-sub{display:block;color:var(--ink-3);font-size:11.5px;margin-top:6px;}
1431
+ .stat-sub b{font-weight:600;color:var(--ink-2);}
1432
+ .stat-meter{display:block;height:6px;border-radius:999px;background:var(--blue-bg);margin-top:10px;overflow:hidden;}
1433
+ .stat-meter .stat-meter-fill{display:block;height:100%;border-radius:999px;background:var(--blue-ink);}
1434
+ .charts-grid{display:grid;grid-template-columns:1fr 1fr;gap:14px;}
1435
+ .chart-card{padding:20px 22px;}
1436
+ .chart-fig{margin:0;}
1437
+ .chart-svg{display:block;width:100%;height:auto;}
1438
+ .chart-empty{display:grid;place-items:center;min-height:180px;}
1439
+ .chart-legend{display:flex;gap:16px;flex-wrap:wrap;margin:-6px 0 10px;font-size:12px;color:var(--ink-2);}
1440
+ .lg-item{display:inline-flex;align-items:center;gap:6px;}
1441
+ .lg-item b{font-family:var(--mono);font-weight:600;color:var(--ink);}
1442
+ .lg-swatch{width:10px;height:10px;border-radius:3px;display:inline-block;}
1443
+ .ch-hit{fill:transparent;}
1444
+ /* hit rect paints above the bars (DOM order) — hover must stay translucent */
1445
+ .ch-hit:hover{fill:var(--ink);fill-opacity:.05;}
1446
+ .ch-hit:focus-visible{outline:2px solid var(--ink);outline-offset:-2px;}
1447
+ .chart-tip{position:fixed;z-index:70;background:var(--ink);color:#fff;border-radius:10px;
1448
+ padding:8px 11px;font-size:12px;line-height:1.45;pointer-events:none;box-shadow:var(--shadow);}
1449
+ .chart-tip .tip-head{font-weight:600;}
1450
+ .chart-tip .tip-val{font-family:var(--mono);}
1451
+ #stats-body.is-loading{opacity:.55;pointer-events:none;transition:opacity .15s;}
1452
+ .sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
1453
+ clip:rect(0 0 0 0);white-space:nowrap;border:0;}
1454
+
1455
+ /* ---------- Sidebar spend indicator ---------- */
1456
+ .spend-ind{display:block;width:100%;text-align:left;border:1px solid var(--line);border-radius:var(--r-ctrl);
1457
+ background:var(--field);padding:10px 12px;cursor:pointer;font-family:inherit;}
1458
+ .spend-ind:hover{background:var(--line);}
1459
+ .spend-ind:focus-visible{outline:2px solid var(--ink);outline-offset:2px;}
1460
+ .spend-ind-row{display:flex;align-items:baseline;justify-content:space-between;gap:8px;}
1461
+ .spend-ind-label{font-size:12px;font-weight:600;color:var(--ink-2);}
1462
+ .spend-ind-amt{font-family:var(--mono);font-size:12px;font-weight:600;color:var(--ink);}
1463
+ .spend-ind-meter{display:block;height:6px;border-radius:999px;background:var(--blue-bg);margin-top:8px;overflow:hidden;}
1464
+ /* meterEl() names the fill "<meter-class>-fill", so: spend-ind-meter-fill */
1465
+ .spend-ind-meter-fill{display:block;height:100%;border-radius:999px;background:var(--blue-ink);}
1466
+ .spend-ind-sub{display:block;font-size:11px;color:var(--ink-3);margin-top:6px;}
1467
+ .spend-ind.warn .spend-ind-meter{background:var(--amber-bg);}
1468
+ .spend-ind.warn .spend-ind-meter-fill{background:var(--amber-ink);}
1469
+ .spend-ind.over .spend-ind-meter{background:var(--red-bg);}
1470
+ .spend-ind.over .spend-ind-meter-fill{background:var(--red-ink);}
1471
+ .spend-ind.over .spend-ind-sub{color:var(--red-ink);}
1472
+ .topnav-amt{margin-left:7px;font-family:var(--mono);font-weight:600;}
1473
+ .topnav-amt.warn{color:var(--amber-ink);}
1474
+ .topnav-amt.over{color:var(--red-ink);}
1475
+ .topnav button.active .topnav-amt{color:inherit;}
1476
+
1477
+ /* ---------- Settings cards ---------- */
1478
+ /* One width/centering/gap rule for all three Settings cards. */
1479
+ .settings-card{max-width:760px;padding:22px;margin-left:auto;margin-right:auto;}
1480
+ .settings-card + .settings-card{margin-top:18px;}
1481
+
1482
+ /* ---------- Budget readout (Settings) ---------- */
1483
+ /* Section gap before the limit fields (the disclaimer hint that used to sit
1484
+ here moved into the card heading's ⓘ tooltip). */
1485
+ .budget-readout{margin-bottom:24px;}
1486
+ .budget-readout .spend-ind-meter{max-width:420px;}
1487
+ .budget-readout-line{font-size:13px;color:var(--ink-2);margin-top:8px;}
1488
+ .budget-readout-line b{font-family:var(--mono);font-weight:600;color:var(--ink);}
1489
+
1490
+ /* ---------- Cost-pause banner ---------- */
1491
+ .cost-banner{border-radius:var(--r-ctrl);padding:12px 14px;margin-top:12px;font-size:13px;}
1492
+ .cost-banner.cb-pipeline{background:var(--amber-bg);color:var(--amber-ink);}
1493
+ .cost-banner.cb-total{background:var(--red-bg);color:var(--red-ink);}
1494
+ .cost-banner b{display:block;margin-bottom:4px;}
1495
+ .cost-banner .cb-text{color:var(--ink-2);}
1496
+ .cost-banner .cb-text .mono{font-family:var(--mono);font-weight:600;color:var(--ink);}
1497
+ .cost-banner .cb-actions{display:flex;gap:8px;justify-content:flex-end;margin-top:10px;}
1498
+ .hist-pausenote{font-size:11.5px;font-weight:600;color:var(--amber-ink);margin-left:10px;}
1499
+ .hist-pausenote.total{color:var(--red-ink);}
1500
+
1501
+ @media (max-width:1080px){
1502
+ .stat-row{grid-template-columns:repeat(2,1fr);}
1503
+ .charts-grid{grid-template-columns:1fr;}
1504
+ }
1505
+
1506
+ /* ── Chat connectivity (chat-connectivity-design.md §4.8) ─────────────────── */
1507
+ .pl-channels { display: flex; gap: 6px; flex-wrap: wrap; margin: 4px 0 8px; }
1508
+ .pl-channel-warn { color: var(--red, #e5484d); font-weight: 600; }
1509
+ .pl-config-h { font-weight: 600; margin: 14px 0 6px; font-size: 13px; }
1510
+ .chat-events, .chat-channels { margin: 8px 0; }
1511
+ .chat-event-row { display: flex; gap: 8px; align-items: center; margin: 4px 0; cursor: pointer; }
1512
+ .chat-event-row .hint { margin-left: 4px; }
1513
+ .chat-channel-row { display: flex; gap: 10px; align-items: center; margin: 6px 0; }
1514
+ .chat-channel-toggle { display: flex; gap: 8px; align-items: center; cursor: pointer; }
1515
+ .chat-state { text-transform: none; }
1516
+
1517
+ /* ---- Models view (configurable-models-design.md §4.10) ---- */
1518
+ .mv-list{display:grid;gap:18px;}
1519
+ .mv-section{display:grid;gap:10px;}
1520
+ .mv-section-title{margin:4px 0 0;font-size:13px;text-transform:uppercase;letter-spacing:.04em;opacity:.75;}
1521
+ .mv-card{padding:16px 20px;display:flex;align-items:center;gap:14px;}
1522
+ .mv-body{flex:1 1 auto;min-width:0;}
1523
+ .mv-head{display:flex;align-items:center;gap:10px;flex-wrap:wrap;}
1524
+ .mv-name{font-size:14.5px;}
1525
+ .mv-summary{display:block;margin:6px 0 0;word-break:break-all;}
1526
+ .mv-card .btn-ghost{flex:0 0 auto;padding:7px 12px;font-size:12px;}
1527
+ .mv-builtin{display:flex;align-items:center;gap:10px;flex-wrap:wrap;padding:8px 12px;border:1px solid var(--line-2,#e6e6ec);border-radius:10px;}
1528
+ .mv-builtin .mv-summary{margin:0;flex:1 1 auto;text-align:right;}
1529
+ .mv-editor{padding:18px 22px;}
1530
+ .mv-editor-title{margin:0 0 14px;font-size:15px;}
1531
+ .mv-editor-grid{display:grid;gap:14px;}
1532
+ .mv-field{display:grid;gap:6px;}
1533
+ .mv-field-label{font-size:12.5px;font-weight:600;}
1534
+ .mv-efforts{display:flex;gap:14px;flex-wrap:wrap;}
1535
+ .mv-effort{display:flex;align-items:center;gap:6px;font-size:13px;cursor:pointer;}
1536
+ .mv-env{display:grid;gap:8px;}
1537
+ .mv-env-row{display:flex;gap:8px;align-items:center;}
1538
+ .mv-env-row .mv-env-key{flex:0 0 34%;font-family:var(--mono);font-size:12.5px;}
1539
+ .mv-env-row .mv-env-val{flex:1 1 auto;font-family:var(--mono);font-size:12.5px;}
1540
+ .mv-env-row .mv-env-rm{flex:0 0 auto;padding:6px 10px;}
1541
+ .mv-env-add{justify-self:start;padding:7px 12px;font-size:12px;}
1542
+ .mv-editor-btns{display:flex;gap:10px;justify-content:flex-end;margin-top:14px;}
1543
+ .mv-env-row .mv-env-copy{flex:0 0 auto;padding:6px 10px;}
1544
+ .mv-env-btns{display:flex;gap:10px;justify-content:flex-start;}
1545
+ .mv-env-btns .btn-ghost{padding:7px 12px;font-size:12px;}
1546
+
1547
+ /* ---- Model plugins (design §9.6): plugin cards + export wizard ---- */
1548
+ .mv-secret{display:block;margin:4px 0 0;}
1549
+ .mv-secret.err{color:var(--red,#c0392b);}
1550
+ .mvx-step{display:grid;gap:8px;margin:0 0 16px;}
1551
+ .mvx-step-title{margin:0;font-size:13px;}
1552
+ .mvx-model{display:flex;align-items:center;gap:8px;font-size:13px;cursor:pointer;}
1553
+ .mvx-env-row{display:flex;align-items:center;gap:10px;flex-wrap:wrap;}
1554
+ .mvx-env-key{flex:0 0 34%;font-size:12.5px;word-break:break-all;}
1555
+ .mvx-env-row .select{flex:0 0 auto;}
1556
+ .mvx-warn{color:var(--red,#c0392b);}
1557
+ .pl-baseurl{word-break:break-all;}