wisp-agents 0.15.0 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. package/CHANGELOG.md +39 -1
  2. package/README.md +28 -12
  3. package/bin/wisp.js +3 -2
  4. package/package.json +3 -3
  5. package/server/adapters/antigravity.js +2 -2
  6. package/server/adapters/claude.js +31 -50
  7. package/server/adapters/codex.js +2 -2
  8. package/server/adapters/common.js +14 -34
  9. package/server/adapters/cursor.js +2 -2
  10. package/server/adapters/grok.js +2 -2
  11. package/server/adapters/index.js +16 -1
  12. package/server/adapters/opencode.js +47 -6
  13. package/server/checkpoint.js +12 -68
  14. package/server/client.js +5 -3
  15. package/server/git.js +9 -4
  16. package/server/handoff.js +70 -0
  17. package/server/http/respond.js +59 -0
  18. package/server/http/router.js +64 -0
  19. package/server/http/static.js +36 -0
  20. package/server/index.js +138 -1216
  21. package/server/machines/bootstrap.js +56 -0
  22. package/server/machines/hosts.js +127 -0
  23. package/server/machines.js +7 -179
  24. package/server/mcp-wisp.js +17 -5
  25. package/server/openapi.js +33 -2
  26. package/server/paths.js +32 -0
  27. package/server/preferences.js +2 -6
  28. package/server/proc.js +54 -0
  29. package/server/recipes.js +2 -4
  30. package/server/remote.js +14 -14
  31. package/server/router.js +7 -3
  32. package/server/routes/auto.js +29 -0
  33. package/server/routes/automations.js +92 -0
  34. package/server/routes/internal.js +56 -0
  35. package/server/routes/machines.js +43 -0
  36. package/server/routes/meta.js +76 -0
  37. package/server/routes/proxy.js +47 -0
  38. package/server/routes/sessions.js +339 -0
  39. package/server/routes/settings.js +144 -0
  40. package/server/routes/ship.js +61 -0
  41. package/server/routes/uploads.js +19 -0
  42. package/server/runner.js +87 -36
  43. package/server/services/auto.js +67 -0
  44. package/server/services/feedback.js +53 -0
  45. package/server/services/install.js +69 -0
  46. package/server/services/launch.js +127 -0
  47. package/server/services/phone.js +65 -0
  48. package/server/services/ship.js +82 -0
  49. package/server/services/telemetry.js +34 -0
  50. package/server/services/uploads.js +59 -0
  51. package/server/services/webhooks.js +28 -0
  52. package/server/store.js +5 -3
  53. package/server/subagents.js +5 -4
  54. package/server/telemetry.js +1 -1
  55. package/server/terminal.js +2 -1
  56. package/server/triggers.js +4 -6
  57. package/server/update.js +4 -3
  58. package/server/util.js +42 -0
  59. package/server/welcome.js +1 -1
  60. package/web/css/auto.css +29 -0
  61. package/web/css/automations.css +71 -0
  62. package/web/css/base.css +83 -0
  63. package/web/css/blocks.css +461 -0
  64. package/web/css/composer.css +62 -0
  65. package/web/css/feed.css +208 -0
  66. package/web/css/launcher.css +204 -0
  67. package/web/css/layout.css +61 -0
  68. package/web/css/machines.css +125 -0
  69. package/web/css/modals.css +176 -0
  70. package/web/css/palette.css +79 -0
  71. package/web/css/responsive.css +35 -0
  72. package/web/css/ship.css +95 -0
  73. package/web/css/subagents.css +130 -0
  74. package/web/css/tokens.css +115 -0
  75. package/web/index.html +16 -1
  76. package/web/js/app.js +28 -5237
  77. package/web/js/core/api.js +25 -0
  78. package/web/js/core/bus.js +28 -0
  79. package/web/js/core/dom.js +7 -0
  80. package/web/js/core/format.js +27 -0
  81. package/web/js/core/state.js +43 -0
  82. package/web/js/features/actions.js +339 -0
  83. package/web/js/features/attachments.js +115 -0
  84. package/web/js/features/auto.js +54 -0
  85. package/web/js/features/automations.js +305 -0
  86. package/web/js/features/commands.js +123 -0
  87. package/web/js/features/compare.js +104 -0
  88. package/web/js/features/composer.js +311 -0
  89. package/web/js/features/feed.js +400 -0
  90. package/web/js/features/feedback.js +127 -0
  91. package/web/js/features/keys.js +83 -0
  92. package/web/js/features/launcher.js +559 -0
  93. package/web/js/features/live.js +91 -0
  94. package/web/js/features/machines.js +313 -0
  95. package/web/js/features/memory.js +154 -0
  96. package/web/js/features/notify.js +36 -0
  97. package/web/js/features/phone.js +124 -0
  98. package/web/js/features/places.js +38 -0
  99. package/web/js/features/projects.js +284 -0
  100. package/web/js/features/runner-picker.js +233 -0
  101. package/web/js/features/runners.js +161 -0
  102. package/web/js/features/scroll.js +75 -0
  103. package/web/js/features/settings.js +390 -0
  104. package/web/js/features/setup.js +94 -0
  105. package/web/js/features/ship.js +122 -0
  106. package/web/js/features/team.js +386 -0
  107. package/web/js/features/turns.js +401 -0
  108. package/web/js/features/update.js +48 -0
  109. package/web/js/features/usage.js +75 -0
  110. package/web/js/ui/kbd.js +46 -0
  111. package/web/js/ui/overlay.js +38 -0
  112. package/web/js/ui/popover.js +52 -0
  113. package/web/js/ui/toast.js +23 -0
  114. package/web/css/app.css +0 -1910
@@ -0,0 +1,461 @@
1
+ /* ---------- presentation blocks ---------- */
2
+ .presentation { display: flex; flex-direction: column; gap: 14px; }
3
+ .blk { animation: rise 0.45s var(--ease) var(--d) both; min-width: 0; }
4
+ @keyframes rise { from { opacity: 0; transform: translateY(6px); } }
5
+ .card { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); }
6
+ .b-title { display: flex; align-items: center; gap: 8px; margin: 0 0 10px; font-size: 13px; font-weight: 600; color: var(--ink); }
7
+ .b-title .count { font-weight: 500; color: var(--faint); }
8
+ .caption { margin: 0; padding: 10px 16px 12px; font-size: 13px; color: var(--muted); border-top: 1px solid var(--line); }
9
+ .fallback-note { display: flex; gap: 8px; align-items: center; font-size: 12.5px; color: var(--muted); }
10
+
11
+ /* hero */
12
+ .b-hero { position: relative; padding: 2px 0 6px; }
13
+ .b-hero .aura { display: none; }
14
+ .hero-top { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
15
+ .hero-top .meta { font-size: 12.5px; color: var(--muted); }
16
+ .hero-top .meta + .meta::before { content: '·'; margin-right: 12px; color: var(--faint); }
17
+ .b-hero h2 { margin: 12px 0 6px; font: 600 26px/1.2 var(--display); letter-spacing: -0.025em; text-wrap: balance; }
18
+ .b-hero p { margin: 0; font-size: 15px; line-height: 1.6; color: var(--ink-2); max-width: 70ch; text-wrap: pretty; }
19
+
20
+ /* markdown */
21
+ .prose { color: var(--ink-2); line-height: 1.65; }
22
+ .prose > :first-child { margin-top: 0; }
23
+ .prose > :last-child { margin-bottom: 0; }
24
+ .prose p, .prose ul, .prose ol, .prose pre, .prose blockquote, .prose .table-wrap { margin: 0 0 12px; }
25
+ .prose h3, .prose h4, .prose h5, .prose h6 { color: var(--ink); margin: 18px 0 8px; font-weight: 600; font-size: 15px; }
26
+ .prose h3 { font: 600 17px/1.3 var(--display); letter-spacing: -0.015em; }
27
+ .prose ul, .prose ol { padding-left: 20px; }
28
+ .prose li { margin: 3px 0; }
29
+ .prose li::marker { color: var(--faint); }
30
+ .prose li.task { list-style: none; margin-left: -18px; }
31
+ .prose li.task::before { content: '☐ '; color: var(--faint); }
32
+ .prose li.task.done::before { content: '☑ '; color: var(--good); }
33
+ .prose strong { color: var(--ink); font-weight: 600; }
34
+ .prose a { color: var(--accent-ink); text-decoration: underline; text-underline-offset: 3px; text-decoration-color: color-mix(in srgb, var(--accent) 40%, transparent); }
35
+ .prose code, .b-hero code, .note code, .b-steps code, .q-text code, .b-check code, .b-compare code, .b-commits code {
36
+ font-size: 0.86em; padding: 1px 5px; border-radius: 5px; background: var(--bg-2); border: 1px solid var(--line); color: var(--ink);
37
+ }
38
+ .prose blockquote { border-left: 2px solid var(--line-2); padding-left: 14px; color: var(--muted); }
39
+ .prose hr { border: 0; border-top: 1px solid var(--line); margin: 18px 0; }
40
+ .table-wrap { overflow-x: auto; border: 1px solid var(--line); border-radius: 10px; }
41
+ .prose table { border-collapse: collapse; width: 100%; font-size: 13.5px; }
42
+ .prose th, .prose td { padding: 7px 12px; text-align: left; border-bottom: 1px solid var(--line); }
43
+ .prose th { font-weight: 600; color: var(--ink); background: var(--surface-2); }
44
+ .prose tr:last-child td { border-bottom: 0; }
45
+ pre.code { margin: 0 0 12px; padding: 12px 14px; border-radius: 10px; background: var(--surface-2); border: 1px solid var(--line); overflow-x: auto; font-size: 12.5px; line-height: 1.6; }
46
+ .b-md { padding: 0 2px; }
47
+
48
+ /* steps */
49
+ .b-steps { padding: 18px 20px 8px; }
50
+ .b-steps ol { list-style: none; margin: 0; padding: 0; position: relative; }
51
+ .b-steps ol::before {
52
+ content: ''; position: absolute; left: 10px; top: 12px; bottom: 22px; width: 1.5px; background: var(--line-2);
53
+ transform-origin: top; animation: draw-y 1.1s var(--ease) calc(var(--d, 0ms) + 200ms) both;
54
+ }
55
+ .blk-steps { --dd: var(--d); }
56
+ .b-steps li { display: grid; grid-template-columns: 22px 1fr; gap: 12px; padding-bottom: 14px; position: relative; animation: rise 0.55s var(--ease) calc(240ms + var(--k) * 110ms) both; }
57
+ .b-steps .dot {
58
+ width: 22px; height: 22px; border-radius: 50%; display: grid; place-items: center; background: var(--surface);
59
+ border: 1.5px solid var(--good); color: var(--good); position: relative; z-index: 1;
60
+ }
61
+ .b-steps .dot .i { width: 12px; height: 12px; }
62
+ .b-steps .st-failed .dot { border-color: var(--bad); color: var(--bad); }
63
+ .b-steps .st-skipped .dot { border-color: var(--line-2); color: var(--faint); }
64
+ .b-steps b { font-weight: 600; display: block; line-height: 22px; }
65
+ .b-steps li p { margin: 2px 0 0; color: var(--muted); font-size: 13.5px; }
66
+ @keyframes draw-y { from { transform: scaleY(0); } }
67
+
68
+ /* stats */
69
+ .b-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 10px; }
70
+ .stat { position: relative; padding: 14px 16px 12px; border-radius: var(--radius); background: var(--surface); border: 1px solid var(--line); overflow: hidden; animation: rise 0.4s var(--ease) calc(var(--k) * 50ms) both; }
71
+ .stat .num { font: 600 26px/1.1 var(--display); letter-spacing: -0.03em; font-variant-numeric: tabular-nums; }
72
+ .stat .u { font-size: 15px; font-weight: 500; color: var(--muted); margin-left: 2px; letter-spacing: 0; }
73
+ .stat .lbl { margin-top: 4px; font-size: 12.5px; color: var(--muted); }
74
+ .stat .delta { position: absolute; top: 12px; right: 12px; font: 500 11.5px var(--mono); padding: 1px 6px; border-radius: 5px; background: var(--bg-2); color: var(--ink-2); }
75
+ .stat.tone-good .delta { background: var(--add-bg); color: var(--good); }
76
+ .stat.tone-bad .delta { background: var(--del-bg); color: var(--bad); }
77
+ @keyframes draw-x { from { transform: scaleX(0); } }
78
+
79
+ /* files */
80
+ .b-files { padding: 16px 8px 8px; }
81
+ .b-files .b-title { padding: 0 12px; }
82
+ .b-files ul { list-style: none; margin: 0; padding: 0; }
83
+ .b-files li { border-radius: 10px; animation: rise 0.5s var(--ease) calc(200ms + var(--k) * 60ms) both; }
84
+ .b-files li.has-diff { cursor: pointer; }
85
+ .b-files li:hover { background: var(--surface-2); }
86
+ .b-files li.open { background: var(--surface-2); }
87
+ .b-files .row { display: flex; align-items: center; gap: 10px; padding: 7px 12px; min-width: 0; }
88
+ .b-files .note { margin: -4px 0 0; padding: 0 12px 8px 42px; font-size: 13px; color: var(--muted); }
89
+ .b-files .actions { margin-left: auto; display: flex; opacity: 0; transition: opacity 0.15s; }
90
+ .b-files li:hover .actions, .b-files li.open .actions { opacity: 1; }
91
+ .b-files .toggle .i { transition: transform 0.2s; }
92
+ .b-files li.open .toggle .i { transform: rotate(90deg); }
93
+ .b-files .b-diff.bare { margin: 0 8px 10px; border: 1px solid var(--line); border-radius: 10px; background: var(--surface); }
94
+ .badge { display: grid; place-items: center; width: 20px; height: 20px; border-radius: 6px; font: 600 11px var(--mono); flex: none; }
95
+ .badge.add { background: var(--add-bg); color: var(--add); }
96
+ .badge.mod { background: color-mix(in srgb, var(--warn) 12%, transparent); color: var(--warn); }
97
+ .badge.del { background: var(--del-bg); color: var(--del); }
98
+ .badge.ren { background: var(--accent-soft); color: var(--accent-ink); }
99
+ .path { font: 12.5px var(--mono); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
100
+ .path .dir { color: var(--faint); }
101
+ .path .base { color: var(--ink); font-weight: 500; }
102
+ .nums { font: 500 11.5px var(--mono); display: inline-flex; gap: 6px; flex: none; }
103
+ .plus { color: var(--add); }
104
+ .minus { color: var(--del); }
105
+
106
+ /* tree */
107
+ .b-tree { padding: 16px 18px 12px; }
108
+ .b-tree ul { list-style: none; margin: 0; padding: 0; font: 12.5px/1.5 var(--mono); }
109
+ .b-tree li { padding-left: calc(var(--depth) * 18px); animation: rise 0.45s var(--ease) calc(150ms + var(--k) * 40ms) both; }
110
+ .b-tree .row { display: flex; align-items: center; gap: 7px; padding: 3px 6px; border-radius: 7px; }
111
+ .b-tree li.file .row { cursor: pointer; }
112
+ .b-tree li.file .row:hover { background: var(--surface-2); }
113
+ .b-tree .i { width: 14px; height: 14px; color: var(--faint); }
114
+ .b-tree .dir .name { color: var(--muted); }
115
+ .b-tree .badge { width: 17px; height: 17px; font-size: 10px; }
116
+ .b-tree .note { font-family: var(--sans); color: var(--muted); font-size: 12.5px; margin-left: 4px; }
117
+
118
+ /* diff & code */
119
+ .b-diff, .b-code { overflow: hidden; }
120
+ .diff-head, .code-head {
121
+ display: flex; align-items: center; gap: 10px; padding: 9px 10px 9px 14px; border-bottom: 1px solid var(--line); background: var(--surface-2);
122
+ }
123
+ .diff-head .i { color: var(--faint); }
124
+ .diff-head .nums { margin-left: auto; }
125
+ .code-head { justify-content: space-between; }
126
+ .code-head .lang { font: 500 11.5px var(--mono); color: var(--muted); }
127
+ .code-head .file { display: inline-flex; min-width: 0; }
128
+ .lineno { font: 12.5px var(--mono); color: var(--faint); }
129
+ .diff-scroll, .code-scroll { overflow-x: auto; max-height: 560px; overflow-y: auto; }
130
+ .b-diff table, .b-code table { border-collapse: collapse; width: 100%; font: 12.5px/1.65 var(--mono); }
131
+ .b-diff td, .b-code td { padding: 0; vertical-align: top; }
132
+ .b-diff .no, .b-code .no { width: 1%; min-width: 36px; padding: 0 10px 0 12px; text-align: right; color: var(--faint); user-select: none; font-size: 11.5px; }
133
+ .b-diff .sign { width: 1%; padding: 0 6px 0 4px; color: var(--faint); user-select: none; }
134
+ .b-diff .src, .b-code .src { white-space: pre; padding-right: 18px; color: var(--ink-2); }
135
+ .b-diff tr.add { background: var(--add-bg); }
136
+ .b-diff tr.add .sign, .b-diff tr.add .no { color: var(--add); }
137
+ .b-diff tr.del { background: var(--del-bg); }
138
+ .b-diff tr.del .sign, .b-diff tr.del .no { color: var(--del); }
139
+ .b-diff tr.del .src { opacity: 0.8; }
140
+ .b-diff tr.gap td { padding: 3px 12px; font: 11.5px var(--sans); color: var(--faint); background: var(--surface-2); }
141
+ .b-diff tr.gap .i { width: 12px; height: 12px; vertical-align: -2px; }
142
+ .b-diff tr.sep td { height: 10px; background: var(--surface-2); border-top: 1px dashed var(--line); border-bottom: 1px dashed var(--line); }
143
+ .b-diff tbody tr:first-child td { padding-top: 6px; }
144
+ .b-diff tbody tr:last-child td { padding-bottom: 6px; }
145
+ .b-diff tr.ln { animation: line-in 0.4s var(--ease) both; }
146
+ .b-diff.missing { padding: 0 0 4px; }
147
+ .b-diff.missing p { padding: 10px 14px; margin: 0; font-size: 13px; }
148
+ .b-code tr.hl { background: color-mix(in srgb, var(--accent) 10%, transparent); }
149
+ .b-code tr.hl .no { color: var(--accent); box-shadow: inset 2px 0 var(--accent); }
150
+ .b-code .code-scroll { padding: 6px 0; }
151
+ .copy.copied { color: var(--good); }
152
+ @keyframes line-in { from { opacity: 0; } }
153
+
154
+ .tk-k { color: var(--tk-k); }
155
+ .tk-s { color: var(--tk-s); }
156
+ .tk-c { color: var(--tk-c); font-style: italic; }
157
+ .tk-n { color: var(--tk-n); }
158
+ .tk-t { color: var(--tk-t); }
159
+
160
+ /* compare */
161
+ .b-compare { display: grid; grid-template-columns: 1fr 34px 1fr; align-items: stretch; }
162
+ .b-compare .side { padding: 16px 18px; border-radius: var(--radius); border: 1px solid var(--line); background: var(--surface); }
163
+ .b-compare .before { background: var(--surface-2); }
164
+ .b-compare .after { border-color: var(--line-2); }
165
+ .side-label { font-size: 13px; font-weight: 600; color: var(--muted); margin-bottom: 8px; }
166
+ .after .side-label { color: var(--good); }
167
+ .b-compare ul { list-style: none; margin: 0; padding: 0; }
168
+ .b-compare li { display: flex; gap: 9px; padding: 4px 0; font-size: 13.5px; animation: rise 0.5s var(--ease) calc(250ms + var(--k) * 90ms) both; }
169
+ .b-compare li .i { margin-top: 3px; width: 14px; height: 14px; }
170
+ .before li { color: var(--muted); }
171
+ .before li .i { color: var(--del); }
172
+ .after li .i { color: var(--good); }
173
+ .b-compare .arrow { display: grid; place-items: center; color: var(--faint); }
174
+ .b-compare pre.code { margin: 0; }
175
+
176
+ /* flow */
177
+ .b-flow { padding: 16px 18px 20px; }
178
+ .flow-stage { position: relative; padding: 4px 2px; }
179
+ .wires { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; overflow: visible; }
180
+ .wire { fill: none; stroke: var(--line-2); stroke-width: 1.5; stroke-dasharray: 1; stroke-dashoffset: 1; animation: draw 0.9s var(--ease) calc(500ms + var(--k) * 180ms) forwards; }
181
+ .wire.back { stroke-dasharray: 0.012 0.012; stroke-dashoffset: 0; animation: fade-in 0.6s calc(900ms + var(--k) * 180ms) both; stroke: var(--faint); }
182
+ .spark { fill: var(--accent); }
183
+ .spark.back { fill: var(--muted); }
184
+ .wire-label { font: 500 11px var(--sans); fill: var(--muted); paint-order: stroke; stroke: var(--surface); stroke-width: 4px; }
185
+ .cols { position: relative; display: flex; align-items: center; justify-content: space-between; gap: 46px; }
186
+ .col { flex: 1; display: flex; flex-direction: column; gap: 12px; min-width: 0; max-width: 220px; }
187
+ .cols.snake { display: grid; grid-template-columns: repeat(var(--per-row), minmax(0, 1fr)); column-gap: 46px; row-gap: 40px; align-items: center; }
188
+ .cols.snake .col { width: 100%; max-width: 220px; justify-self: center; }
189
+ .node {
190
+ position: relative; padding: 9px 12px; border-radius: 8px; background: var(--surface); border: 1px solid var(--line-2);
191
+ text-align: center; animation: pop 0.4s var(--ease) calc(200ms + var(--k) * 120ms) both;
192
+ }
193
+ .node b { display: block; font-weight: 600; font-size: 13.5px; line-height: 1.3; }
194
+ .node span { display: block; margin-top: 2px; font-size: 12px; color: var(--muted); line-height: 1.35; }
195
+ @keyframes draw { to { stroke-dashoffset: 0; } }
196
+ @keyframes dash { to { stroke-dashoffset: -0.024; } }
197
+ @keyframes fade-in { from { opacity: 0; } }
198
+ @keyframes pop { from { opacity: 0; transform: scale(0.9) translateY(6px); } }
199
+
200
+ /* chart */
201
+ .b-chart { padding: 16px 18px 14px; }
202
+ .bars { display: flex; flex-direction: column; gap: 10px; }
203
+ .bar-row { display: grid; grid-template-columns: minmax(80px, 28%) 1fr auto; align-items: center; gap: 12px; animation: rise 0.5s var(--ease) calc(150ms + var(--k) * 90ms) both; }
204
+ .bar-label { font-size: 13px; color: var(--ink-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
205
+ .bar-track { height: 8px; border-radius: 3px; background: var(--bg-2); overflow: hidden; }
206
+ .bar { display: block; height: 100%; width: var(--w); border-radius: 3px; background: var(--accent); transform-origin: left; animation: grow-x 0.8s var(--ease) calc(200ms + var(--k) * 100ms) both; }
207
+ .bar-row:nth-child(2n) .bar { background: color-mix(in srgb, var(--accent) 55%, var(--surface)); }
208
+ .bar-val { font: 500 13px var(--mono); font-variant-numeric: tabular-nums; min-width: 48px; text-align: right; }
209
+ .bar-val .u { color: var(--muted); margin-left: 2px; font-size: 11.5px; }
210
+ @keyframes grow-x { from { transform: scaleX(0); } }
211
+
212
+ /* terminal */
213
+ .b-term { border-radius: var(--radius); background: var(--term-bg); color: var(--term-ink); overflow: hidden; border: 1px solid var(--line); }
214
+ .term-head { display: flex; align-items: center; gap: 10px; padding: 8px 14px; border-bottom: 1px solid rgba(255, 255, 255, 0.07); font-size: 12px; color: #8a8a8a; }
215
+ .lights { display: none; }
216
+ .term-head .title { flex: 1; font-family: var(--mono); font-size: 11.5px; }
217
+ .exit { font: 500 11px var(--mono); padding: 1px 7px; border-radius: 5px; }
218
+ .exit.ok { background: rgba(76, 195, 138, 0.14); color: #4cc38a; }
219
+ .exit.bad { background: rgba(255, 99, 105, 0.14); color: #ff6369; }
220
+ .b-term pre { margin: 0; padding: 12px 14px 14px; font: 12.5px/1.6 var(--mono); white-space: pre-wrap; word-break: break-word; max-height: 440px; overflow-y: auto; }
221
+ .b-term .ps { color: #8a8a8a; }
222
+ .b-term .cmd { color: #fff; }
223
+ .b-term .caret { display: inline-block; width: 7px; height: 14px; margin-left: 1px; vertical-align: -2px; background: #e8e8e6; animation: blink 1s steps(1) infinite; }
224
+ .b-term.ran .caret { display: none; }
225
+ .b-term .out { color: #b4b4b0; opacity: 0; transition: opacity 0.4s; }
226
+ .b-term.ran .out { opacity: 1; }
227
+ @keyframes blink { 50% { opacity: 0; } }
228
+
229
+ /* tests */
230
+ .b-tests { padding: 18px 20px; }
231
+ .tests-main { display: flex; align-items: center; gap: 18px; position: relative; }
232
+ .ring { width: 76px; height: 76px; transform: rotate(-90deg); flex: none; }
233
+ .ring circle { fill: none; stroke-width: 7; }
234
+ .ring .track { stroke: var(--bg-2); }
235
+ .ring .seg { stroke-linecap: butt; animation: ring-in 1.3s var(--ease) 0.35s both; }
236
+ .ring .pass { stroke: var(--good); }
237
+ .ring .fail { stroke: var(--bad); }
238
+ .ring .skip { stroke: var(--line-2); }
239
+ .ring-label { position: absolute; left: 0; width: 76px; display: grid; place-items: center; }
240
+ .ring-label .i { width: 24px; height: 24px; }
241
+ .b-tests.ok .ring-label { color: var(--good); }
242
+ .b-tests.bad .ring-label { color: var(--bad); }
243
+ .verdict { font: 600 18px/1.25 var(--display); letter-spacing: -0.015em; }
244
+ .counts { display: flex; flex-wrap: wrap; gap: 14px; margin-top: 4px; font-size: 13px; color: var(--muted); }
245
+ .counts b { font-weight: 600; font-variant-numeric: tabular-nums; }
246
+ .counts .pass b { color: var(--good); }
247
+ .counts .fail b { color: var(--bad); }
248
+ .cmdline { display: inline-block; margin-top: 8px; font-size: 12px; color: var(--muted); }
249
+ .failures { list-style: none; margin: 16px 0 0; padding: 12px 0 0; border-top: 1px solid var(--line); }
250
+ .failures li { display: flex; gap: 10px; padding: 6px 0; }
251
+ .failures li > .i { color: var(--bad); margin-top: 3px; }
252
+ .failures b { font-weight: 600; font-size: 13.5px; }
253
+ .failures pre { margin: 4px 0; padding: 8px 10px; border-radius: 8px; background: var(--del-bg); font-size: 12px; white-space: pre-wrap; color: var(--ink-2); }
254
+ .failures .file { font: 12px var(--mono); }
255
+ @keyframes ring-in { from { stroke-dasharray: 0 400; } }
256
+
257
+ /* commits */
258
+ .b-commits { padding: 16px 20px 10px; }
259
+ .b-commits .b-title .i { width: 14px; height: 14px; }
260
+ .b-commits ol { list-style: none; margin: 0; padding: 0; position: relative; }
261
+ .b-commits ol::before { content: ''; position: absolute; left: 6px; top: 8px; bottom: 16px; width: 2px; background: var(--line-2); transform-origin: top; animation: draw-y 0.9s var(--ease) 0.3s both; }
262
+ .b-commits li { display: grid; grid-template-columns: 14px 1fr; gap: 14px; padding-bottom: 12px; animation: rise 0.5s var(--ease) calc(300ms + var(--k) * 110ms) both; }
263
+ .b-commits .node { all: unset; width: 10px; height: 10px; margin-top: 5px; border-radius: 50%; background: var(--surface); border: 2px solid var(--ink-2); position: relative; z-index: 1; }
264
+ .b-commits .msg { font-weight: 500; }
265
+ .b-commits .sub { display: flex; gap: 10px; margin-top: 2px; font: 12px var(--mono); color: var(--muted); }
266
+ .b-commits .sub code { padding: 0 5px; }
267
+
268
+ /* graph: a PR's branches, the merge target and its conflicts */
269
+ .b-graph { --g-base: var(--faint); --g-1: #3b82f6; --g-2: #14b8a6; --g-3: #8b5cf6; --g-4: #e5487f; --g-merged: #8250df; padding: 14px 16px 12px; container-type: inline-size; }
270
+ .g-head { display: flex; align-items: baseline; gap: 12px; margin-bottom: 8px; }
271
+ .g-head h3 { flex: 1; min-width: 0; margin: 0; font-size: 14px; font-weight: 600; color: var(--ink); }
272
+ .g-ref { font-weight: 500; color: var(--muted); }
273
+ .g-pr { display: inline-flex; align-items: center; gap: 6px; font-size: 12.5px; font-weight: 500; --tone: var(--good); color: var(--tone); }
274
+ .g-pr i { width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
275
+ .g-pr.st-merged { --tone: var(--g-merged); }
276
+ .g-pr.st-closed { --tone: var(--bad); }
277
+ .g-pr.st-draft { --tone: var(--muted); }
278
+ .g-body { position: relative; display: grid; grid-template-columns: var(--g-w) 1fr; column-gap: 14px; }
279
+ .g-svg { overflow: visible; }
280
+ .g-wire { fill: none; stroke-width: 1.5; stroke-linecap: round; stroke-dasharray: 1; stroke-dashoffset: 1; opacity: 0.75; animation: draw 0.7s var(--ease) calc(250ms + var(--k) * 60ms) forwards; }
281
+ .g-wire.pending { stroke-dasharray: 3 3; stroke-dashoffset: 0; animation: fade-in 0.5s 0.5s both; stroke: var(--faint); }
282
+ .g-wire.pending.st-conflict { stroke: var(--warn); }
283
+ .g-wire.pending.st-ready { stroke: var(--good); }
284
+ .g-wire.st-merged { stroke: var(--g-merged); }
285
+ .g-tail { fill: none; stroke-width: 1.5; stroke-dasharray: 2 3; opacity: 0.5; animation: fade-in 0.5s 0.4s both; }
286
+ .g-dot { fill: var(--lc); stroke: var(--surface); stroke-width: 2; transform-box: fill-box; transform-origin: center; animation: pop 0.35s var(--ease) calc(200ms + var(--k) * 60ms) both; }
287
+ .g-dot.conflict { fill: var(--warn); }
288
+ .g-dot.merge { fill: var(--surface); stroke: var(--lc); stroke-width: 1.6; }
289
+ .g-target circle { fill: var(--surface); stroke: var(--faint); stroke-width: 1.5; stroke-dasharray: 2 2; }
290
+ .g-target path { fill: none; stroke: #fff; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
291
+ .g-target.st-conflict circle { fill: var(--warn); stroke: color-mix(in srgb, var(--warn) 25%, transparent); stroke-width: 4; stroke-dasharray: none; paint-order: stroke; }
292
+ .g-target.st-ready circle { fill: var(--good); stroke: color-mix(in srgb, var(--good) 22%, transparent); stroke-width: 4; stroke-dasharray: none; paint-order: stroke; }
293
+ .g-target.st-merged circle { fill: var(--g-merged); stroke: none; }
294
+ .g-target.st-blocked circle { fill: var(--bad); stroke: none; }
295
+ .g-rows { list-style: none; margin: 0; padding: 0; min-width: 0; }
296
+ .g-row { display: flex; align-items: center; gap: 8px; height: 30px; min-width: 0; margin: 0 -6px; padding: 0 6px; border-radius: 6px; font-size: 13.5px; animation: rise 0.4s var(--ease) calc(200ms + var(--k) * 60ms) both; transition: background 0.15s; }
297
+ .g-msg { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--ink); }
298
+ .g-row.other .g-msg, .g-row.target .g-msg { color: var(--muted); }
299
+ .g-row.conflict .g-msg { color: var(--warn); }
300
+ .g-row.lit { background: color-mix(in srgb, var(--warn) 9%, transparent); }
301
+ .g-tag { flex: none; padding: 1px 6px; border-radius: 5px; font: 11.5px var(--mono); color: var(--lc); background: color-mix(in srgb, var(--lc) 11%, transparent); }
302
+ .g-num { flex: none; display: inline-grid; place-items: center; min-width: 17px; height: 17px; padding: 0 4px; border-radius: 9px; font-size: 11px; font-weight: 600; color: var(--warn); background: color-mix(in srgb, var(--warn) 12%, transparent); }
303
+ .g-meta { flex: none; margin-left: auto; padding-left: 10px; font-size: 12.5px; color: var(--muted); white-space: nowrap; }
304
+ .g-meta code { font: 12px var(--mono); color: var(--faint); background: none; padding: 0; margin-right: 4px; }
305
+ .g-state { margin-left: auto; font-size: 12.5px; font-weight: 500; color: var(--muted); }
306
+ .g-row.st-conflict .g-state { color: var(--warn); }
307
+ .g-row.st-ready .g-state { color: var(--good); }
308
+ .g-row.st-merged .g-state { color: var(--g-merged); }
309
+ .g-row.st-blocked .g-state { color: var(--bad); }
310
+ .g-checks { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
311
+ .g-check { display: inline-flex; align-items: center; gap: 6px; height: 26px; padding: 0 10px; border: 1px solid var(--line); border-radius: 13px; font-size: 12.5px; animation: rise 0.4s var(--ease) calc(500ms + var(--k) * 60ms) both; }
312
+ .g-check .i { width: 12px; height: 12px; color: var(--good); }
313
+ .g-check b { font-weight: 500; }
314
+ .g-check span { color: var(--muted); }
315
+ .g-check.st-fail .i { color: var(--bad); }
316
+ .g-check.st-pending .i, .g-check.st-skip .i { color: var(--muted); }
317
+ .g-conflicts { list-style: none; margin: 10px 0 0; padding: 8px 0 0; border-top: 1px solid var(--line); }
318
+ .g-conflicts li { padding: 7px 6px; margin: 0 -6px; border-radius: 8px; animation: rise 0.4s var(--ease) calc(500ms + var(--k) * 70ms) both; transition: background 0.15s; }
319
+ .g-conflicts li.lit { background: color-mix(in srgb, var(--warn) 7%, transparent); }
320
+ .g-c-head { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; font-size: 13px; }
321
+ .g-c-head .g-num { align-self: center; }
322
+ .g-file { font: 12.5px var(--mono); }
323
+ .g-c-detail { color: var(--ink-2); }
324
+ .g-sides { display: grid; grid-template-columns: max-content 1fr; gap: 4px 10px; align-items: baseline; margin: 5px 0 0 25px; font-size: 12px; }
325
+ .g-side { display: contents; }
326
+ .g-num.plain { color: var(--muted); background: var(--bg-2); }
327
+ .g-who { font: 11.5px var(--mono); color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 180px; }
328
+ .g-side code { font: 12px var(--mono); white-space: pre-wrap; word-break: break-word; padding: 2px 6px; border-radius: 5px; background: var(--add-bg); color: var(--ink-2); }
329
+ .g-side.theirs code { background: color-mix(in srgb, var(--warn) 8%, transparent); }
330
+ .g-res { display: flex; gap: 6px; margin: 5px 0 0 25px; font-size: 12.5px; color: var(--ink-2); }
331
+ .g-res .i { width: 13px; height: 13px; margin-top: 2px; color: var(--good); flex: none; }
332
+ .g-foot { display: flex; align-items: center; gap: 8px; min-height: 32px; margin-top: 8px; font-size: 13.5px; color: var(--ink); }
333
+ .g-foot > .i { width: 14px; height: 14px; color: var(--muted); flex: none; }
334
+ .g-foot.st-conflict > .i, .g-count { color: var(--warn); }
335
+ .g-foot.st-ready > .i { color: var(--good); }
336
+ .g-foot.st-merged > .i { color: var(--g-merged); }
337
+ .g-foot.st-blocked > .i { color: var(--bad); }
338
+ .g-foot-text { flex: 1; min-width: 0; }
339
+ .g-count { font: inherit; text-decoration: underline dotted; text-underline-offset: 3px; cursor: pointer; }
340
+ .g-action { flex: none; height: 30px; padding: 0 12px; border-radius: 8px; font-size: 13px; font-weight: 500; color: var(--accent-ink); background: var(--accent-soft); transition: background 0.15s; }
341
+ .g-action:hover:not(:disabled) { background: color-mix(in srgb, var(--accent) 16%, transparent); }
342
+ .g-action:disabled { opacity: 0.5; cursor: default; }
343
+ @container (max-width: 520px) {
344
+ .g-meta { display: none; }
345
+ }
346
+ @media (prefers-color-scheme: dark) {
347
+ :root:not([data-theme='light']) .b-graph { --g-1: #6d8dff; --g-2: #2fd0b4; --g-3: #a78bfa; --g-4: #f472b6; --g-merged: #b48cff; }
348
+ }
349
+
350
+ /* checklist */
351
+ .b-check { padding: 16px 20px 12px; }
352
+ .b-check ul { list-style: none; margin: 0; padding: 0; }
353
+ .b-check li { display: flex; gap: 10px; padding: 5px 0; animation: rise 0.45s var(--ease) calc(200ms + var(--k) * 90ms) both; }
354
+ .b-check .box { display: grid; place-items: center; width: 18px; height: 18px; margin-top: 2px; border-radius: 6px; border: 1.5px solid var(--line-2); color: transparent; flex: none; }
355
+ .b-check .box .i { width: 12px; height: 12px; }
356
+ .b-check li.done .box { background: var(--good); border-color: var(--good); color: #fff; animation: check-in 0.4s var(--ease) calc(400ms + var(--k) * 90ms) both; }
357
+ .b-check li.done > span:last-child { color: var(--ink-2); }
358
+ .b-check li:not(.done) > span:last-child { color: var(--muted); }
359
+ @keyframes check-in { from { transform: scale(0.4); background: transparent; border-color: var(--line-2); } }
360
+
361
+ /* callout */
362
+ .b-callout { --t: var(--info); display: flex; gap: 12px; padding: 12px 14px; border-radius: var(--radius); background: color-mix(in srgb, var(--t) 5%, var(--surface)); border: 1px solid color-mix(in srgb, var(--t) 20%, var(--line)); }
363
+ .b-callout.tone-success { --t: var(--good); }
364
+ .b-callout.tone-warn { --t: var(--warn); }
365
+ .b-callout.tone-danger { --t: var(--bad); }
366
+ .b-callout .ic { color: var(--t); padding-top: 1px; }
367
+ .b-callout b { display: block; font-weight: 600; margin-bottom: 2px; color: var(--ink); }
368
+ .b-callout .prose { font-size: 14px; }
369
+
370
+ /* image */
371
+ .b-image { margin: 0; overflow: hidden; }
372
+ .b-image img { display: block; width: 100%; max-height: 520px; object-fit: contain; background: var(--surface-2); cursor: zoom-in; }
373
+ .b-image figcaption { padding: 10px 16px; font-size: 13px; color: var(--muted); border-top: 1px solid var(--line); }
374
+ .b-image.broken img { min-height: 80px; }
375
+ .lightbox { max-width: 92vw; max-height: 90vh; border-radius: 12px; box-shadow: var(--shadow-2); }
376
+
377
+ /* next */
378
+ .b-next { padding-top: 6px; }
379
+ .next-label { display: flex; align-items: center; gap: 7px; font-size: 13px; font-weight: 600; color: var(--ink); margin-bottom: 8px; }
380
+ .next-label .i { color: var(--muted); width: 14px; height: 14px; }
381
+ .chips { display: flex; flex-wrap: wrap; gap: 6px; }
382
+ .chip {
383
+ padding: 6px 12px; border-radius: 8px; background: var(--surface); border: 1px solid var(--line-2); font-size: 13px; color: var(--ink-2);
384
+ transition: border-color 0.15s, background 0.15s, color 0.15s; animation: rise 0.4s var(--ease) calc(200ms + var(--k) * 50ms) both; text-align: left;
385
+ }
386
+ .chip:hover { border-color: var(--faint); color: var(--ink); background: var(--surface-2); }
387
+
388
+ /* actions block */
389
+ .b-actions { padding: 16px 18px 12px; }
390
+ .act-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
391
+ .act-row { border-radius: 10px; border: 1px solid var(--line); background: var(--surface-2); overflow: hidden; animation: rise 0.45s var(--ease) calc(150ms + var(--k) * 70ms) both; transition: border-color 0.15s; }
392
+ .act-row.ran-ok { border-color: color-mix(in srgb, var(--good) 35%, var(--line)); }
393
+ .act-row.ran-bad { border-color: color-mix(in srgb, var(--bad) 45%, var(--line)); }
394
+ .act-bar { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 9px 12px; }
395
+ .act-info { min-width: 0; display: flex; flex-direction: column; gap: 2px; }
396
+ .act-info b { font-weight: 600; font-size: 13.5px; color: var(--ink); }
397
+ .act-cmd { font: 11.5px var(--mono); color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
398
+ .act-detail { font-size: 12.5px; color: var(--muted); }
399
+ .act-side { display: inline-flex; align-items: center; gap: 8px; flex: none; }
400
+ .act-side .exit { background: var(--bg-2); color: var(--muted); }
401
+ .act-side .exit.ok { background: var(--add-bg); color: var(--good); }
402
+ .act-side .exit.bad { background: var(--del-bg); color: var(--bad); }
403
+ .act-res { border-top: 1px solid var(--line); background: var(--term-bg); color: var(--term-ink); padding: 10px 12px; }
404
+ .act-out { margin: 0; font: 12px/1.55 var(--mono); white-space: pre-wrap; word-break: break-word; max-height: 280px; overflow-y: auto; color: #b4b4b0; }
405
+ .act-fix { margin-top: 8px; }
406
+
407
+ /* interactive terminal, tests, revert & checkpoints */
408
+ .term-run { color: #b4b4b0; border-color: rgba(255, 255, 255, 0.14); background: rgba(255, 255, 255, 0.05); }
409
+ .term-run:hover:not(:disabled) { color: #fff; background: rgba(255, 255, 255, 0.12); border-color: rgba(255, 255, 255, 0.25); }
410
+ .tests-cmd { display: flex; align-items: center; gap: 8px; margin-top: 8px; flex-wrap: wrap; }
411
+ .tests-cmd .cmdline { margin-top: 0; }
412
+ .tests-rerun-out { margin-top: 12px; padding: 10px 12px; border-radius: 10px; background: var(--term-bg); color: var(--term-ink); }
413
+ .tests-rerun-out pre { margin: 0; font: 12px/1.55 var(--mono); white-space: pre-wrap; word-break: break-word; max-height: 260px; overflow-y: auto; color: #b4b4b0; }
414
+ .rev-tag { display: inline-flex; align-items: center; padding: 1px 6px; border-radius: 5px; font: 500 11px var(--sans); background: var(--bg-2); color: var(--muted); border: 1px solid var(--line); }
415
+ .cp-sha { font: 500 11px var(--mono); color: var(--faint); padding: 1px 5px; border-radius: 5px; background: var(--surface); border: 1px solid var(--line); }
416
+ .b-diff.is-reverted .diff-scroll { opacity: 0.55; }
417
+ .b-diff.is-reverted .path .base, .b-files li.is-reverted .path .base { text-decoration: line-through; color: var(--muted); }
418
+ .cp-rollback { display: inline-flex; align-items: center; gap: 5px; }
419
+ .cp-rollback .i { width: 12px; height: 12px; }
420
+ .cp-rollback.rolled-back { color: var(--accent-ink); }
421
+
422
+ /* trail */
423
+ .trail { margin-top: 18px; }
424
+ .trail-bar { display: flex; align-items: center; flex-wrap: wrap; gap: 4px 14px; padding: 8px 2px; border-top: 1px dashed var(--line); font-size: 12px; color: var(--faint); }
425
+ .tb { display: inline-flex; align-items: center; gap: 5px; font-variant-numeric: tabular-nums; }
426
+ .tb .i { width: 13px; height: 13px; }
427
+ .trail-bar .link { font-size: 12px; }
428
+ /* Activity counts double as the Activity toggle, so the bar carries no separate "Activity" link. */
429
+ .tb-acts { display: inline-flex; align-items: center; gap: 10px; margin: -3px -6px; padding: 3px 6px; border-radius: 6px; color: inherit; transition: color 0.15s, background 0.15s; }
430
+ .tb-acts:hover, .tb-acts.on { color: var(--ink); background: var(--bg-2); }
431
+ /* Secondary turn actions: icon-only, faint until the turn is hovered (same rule as the thumbs). */
432
+ .tb-tools { display: inline-flex; align-items: center; gap: 1px; margin-left: -8px; }
433
+ .tb-btn { display: inline-grid; place-items: center; width: 24px; height: 22px; border-radius: 6px; color: var(--faint); opacity: 0.5; transition: color 0.15s, background 0.15s, opacity 0.15s; }
434
+ .tb-btn .i { width: 13px; height: 13px; }
435
+ .tb-btn:hover, .tb-btn.on { color: var(--ink); background: var(--bg-2); }
436
+ .turn:hover .tb-btn, .tb-btn:focus-visible, .tb-btn.on { opacity: 1; }
437
+ .trail-body { padding: 8px 0 0; animation: rise 0.4s var(--ease); }
438
+ .trail-body .presentation { gap: 10px; }
439
+ /* Thumbs: faint until the trail is hovered or the turn is rated, so a finished turn reads the same. */
440
+ .rate { display: inline-flex; gap: 1px; opacity: 0.5; transition: opacity 0.15s; }
441
+ .turn:hover .rate, .rate.rated, .rate:focus-within { opacity: 1; }
442
+ .rate-btn { display: inline-grid; place-items: center; width: 24px; height: 22px; border-radius: 6px; color: var(--faint); transition: color 0.15s, background 0.15s; }
443
+ .rate-btn .i { width: 13px; height: 13px; }
444
+ .rate-btn:hover { color: var(--ink); background: var(--bg-2); }
445
+ .rate-btn[data-rate="up"].on { color: var(--good); }
446
+ .rate-btn[data-rate="down"].on { color: var(--bad); }
447
+ .rate-btn.on .i { fill: color-mix(in srgb, currentColor 18%, transparent); }
448
+ .rate.thanked [data-rate="up"].on .i { animation: thumb-pop 0.45s var(--ease); }
449
+ @keyframes thumb-pop { 40% { transform: scale(1.35) rotate(-12deg); } }
450
+ .why { display: grid; gap: 6px; }
451
+ .why .textarea { min-height: 0; resize: none; }
452
+ .why-foot { display: flex; align-items: center; gap: 10px; }
453
+ .why-foot .muted { margin-right: auto; }
454
+ .why-foot .primary { height: 24px; padding: 0 10px; font-size: 12px; border-radius: 7px; }
455
+ .fb-modal { width: min(520px, 100%); }
456
+ .fb-rate { display: flex; align-items: center; gap: 4px; margin-bottom: 10px; font-size: 13px; color: var(--muted); }
457
+ .fb-rate span { margin-right: 6px; }
458
+ .fb-rate .rate-btn { width: 30px; height: 28px; }
459
+ .fb-rate .rate-btn .i { width: 16px; height: 16px; }
460
+ .fb-modal .ship-foot { margin-top: 12px; }
461
+
@@ -0,0 +1,62 @@
1
+ /* ---------- per-item composer ---------- */
2
+ .composer {
3
+ padding: 6px 8px 8px 12px; border-radius: 10px; background: var(--surface-2); border: 1px solid var(--line);
4
+ transition: box-shadow 0.15s, border-color 0.15s;
5
+ }
6
+ .composer:focus-within { background: var(--surface); border-color: color-mix(in srgb, var(--accent) 55%, var(--line-2)); box-shadow: 0 0 0 3px var(--accent-soft); }
7
+ .composer textarea { min-height: 26px; font-size: 14px; padding: 6px 2px; }
8
+ .composer textarea:disabled { cursor: not-allowed; }
9
+ .c-bar { display: flex; align-items: center; gap: 8px; }
10
+ .c-queued { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 4px; }
11
+ .c-queued:not(:empty) { padding: 4px 0 6px; }
12
+ .cq { position: relative; display: flex; align-items: baseline; gap: 8px; padding: 6px 30px 6px 10px; border-radius: 8px; border: 1px dashed var(--line-2); font-size: 12.5px; animation: pop 0.35s var(--ease); }
13
+ .cq-tag { flex: none; font-size: 11px; font-weight: 600; color: var(--accent-ink); }
14
+ .cq .att-x:hover { color: var(--bad); }
15
+ .cq-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--muted); }
16
+ .c-hint { flex: 1; font-size: 11.5px; color: var(--faint); }
17
+ .c-bar .mode-btn { height: 30px; min-width: 30px; padding: 0 8px; }
18
+ .c-bar .mode-btn.changed { background: var(--bg-2); }
19
+ .t-mode { display: inline-flex; align-items: center; gap: 4px; padding: 1px 6px; border-radius: 5px; font: 500 11px var(--sans); color: var(--muted); border: 1px solid var(--line); }
20
+ .t-mode .i { width: 12px; height: 12px; }
21
+ .t-mode.m-plan { color: var(--accent-ink); }
22
+ .t-mode.m-auto { color: var(--warn); }
23
+ .send { display: grid; place-items: center; width: 30px; height: 30px; border-radius: 8px; background: var(--ink); color: var(--bg); transition: opacity 0.15s; }
24
+ .send:hover { opacity: 0.86; }
25
+ .send:disabled { opacity: 0.5; }
26
+ .send.busy { opacity: 1; position: relative; color: transparent; }
27
+ .send.busy::after { content: ''; position: absolute; inset: 8px; border-radius: 50%; border: 2px solid var(--bg); border-right-color: transparent; animation: spin 0.7s linear infinite; }
28
+ @keyframes spin { to { transform: rotate(360deg); } }
29
+ .c-done { color: var(--muted); }
30
+ .c-ship { color: var(--accent-ink); }
31
+ .c-queue { color: var(--faint); font-size: 12px; }
32
+ .c-queue.on { color: var(--ink); background: var(--bg-2); }
33
+ .c-done:hover { color: var(--good); }
34
+
35
+ /* attachments tray */
36
+ .tray { display: flex; flex-wrap: wrap; gap: 8px; padding: 4px 0 8px; }
37
+ .att {
38
+ position: relative; display: flex; align-items: center; gap: 8px; height: 44px; padding: 0 30px 0 4px; border-radius: 10px;
39
+ background: var(--surface-2); border: 1px solid var(--line); max-width: 240px; animation: pop 0.35s var(--ease);
40
+ }
41
+ .att img { width: 36px; height: 36px; border-radius: 7px; object-fit: cover; }
42
+ .att-ic { display: grid; place-items: center; width: 36px; height: 36px; border-radius: 7px; background: var(--bg-2); color: var(--muted); }
43
+ .att-name { font-size: 12.5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
44
+ .att-size { font-size: 11px; color: var(--faint); white-space: nowrap; }
45
+ .att-x { position: absolute; right: 6px; top: 50%; translate: 0 -50%; display: grid; place-items: center; width: 20px; height: 20px; border-radius: 6px; color: var(--muted); }
46
+ .att-x:hover { background: var(--bg-2); color: var(--ink); }
47
+ .att-x .i { width: 12px; height: 12px; }
48
+ .att.uploading::after { content: ''; position: absolute; left: 6px; right: 6px; bottom: 3px; height: 2px; border-radius: 2px; background: linear-gradient(90deg, transparent, var(--accent), transparent); background-size: 200% 100%; animation: shimmer 1.1s linear infinite; }
49
+ .att.failed { border-color: var(--bad); }
50
+
51
+
52
+ /* harness · model for the next follow-up: a quiet logo, spelled out once it's switched */
53
+ .c-runner {
54
+ display: inline-flex; align-items: center; height: 30px; min-width: 30px; padding: 0 4px; border-radius: 8px; gap: 0;
55
+ font-size: 12px; color: var(--muted); transition: background 0.15s, color 0.15s;
56
+ }
57
+ .c-runner .rb-logo { margin-right: 0; background: transparent; }
58
+ .c-runner:hover, .c-runner.open, .c-runner.changed { background: var(--bg-2); color: var(--ink); }
59
+ .c-runner.changed { padding-right: 8px; }
60
+ .c-runner.changed .rb-logo { margin-right: 4px; }
61
+ .c-runner:focus-visible { outline: 0; box-shadow: 0 0 0 2px var(--accent-soft), 0 0 0 1px var(--accent); }
62
+ .cr-label { max-width: 180px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 500; }