@danieltmn/tamnora 0.1.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 (123) hide show
  1. package/CHANGELOG.md +48 -0
  2. package/LICENSE +21 -0
  3. package/README.md +130 -0
  4. package/SECURITY.md +31 -0
  5. package/harness/packages/cli/bin/tamnora.mjs +11 -0
  6. package/harness/packages/cli/package.json +10 -0
  7. package/harness/packages/cli/src/cli.js +90 -0
  8. package/harness/packages/cli/src/commands/autostart.js +121 -0
  9. package/harness/packages/cli/src/commands/bridge.js +274 -0
  10. package/harness/packages/cli/src/commands/doctor.js +73 -0
  11. package/harness/packages/cli/src/commands/eval.js +183 -0
  12. package/harness/packages/cli/src/commands/init.js +31 -0
  13. package/harness/packages/cli/src/commands/mcp.js +101 -0
  14. package/harness/packages/cli/src/commands/repl.js +172 -0
  15. package/harness/packages/cli/src/commands/run.js +165 -0
  16. package/harness/packages/cli/src/commands/serve.js +1 -0
  17. package/harness/packages/cli/src/commands/server.js +345 -0
  18. package/harness/packages/cli/src/commands/tui.js +110 -0
  19. package/harness/packages/cli/src/commands/update.js +76 -0
  20. package/harness/packages/cli/src/commands/user.js +135 -0
  21. package/harness/packages/cli/src/lib/core.js +2 -0
  22. package/harness/packages/cli/src/lib/daemon.js +153 -0
  23. package/harness/packages/cli/src/lib/qr.js +203 -0
  24. package/harness/packages/cli/src/lib/runtime.js +110 -0
  25. package/harness/packages/cli/src/lib/tunnel.js +113 -0
  26. package/harness/packages/cli/src/lib/util.js +24 -0
  27. package/harness/packages/cli/src/tui/app.js +302 -0
  28. package/harness/packages/cli/src/tui/keys.js +78 -0
  29. package/harness/packages/cli/src/tui/layout.js +130 -0
  30. package/harness/packages/cli/src/tui/screen.js +13 -0
  31. package/harness/packages/cli/src/ui/color.js +15 -0
  32. package/harness/packages/cli/test/release.test.js +34 -0
  33. package/harness/packages/cli/test/tui.test.js +99 -0
  34. package/harness/packages/cli/test/tunnel.test.js +20 -0
  35. package/harness/packages/core/package.json +14 -0
  36. package/harness/packages/core/src/agent/context.js +66 -0
  37. package/harness/packages/core/src/agent/modes.js +26 -0
  38. package/harness/packages/core/src/agent/runAgent.js +257 -0
  39. package/harness/packages/core/src/config/app.js +49 -0
  40. package/harness/packages/core/src/config/home.js +98 -0
  41. package/harness/packages/core/src/config/identity.js +41 -0
  42. package/harness/packages/core/src/config/index.js +69 -0
  43. package/harness/packages/core/src/config/providers.js +24 -0
  44. package/harness/packages/core/src/env.js +19 -0
  45. package/harness/packages/core/src/eval/dataset.js +47 -0
  46. package/harness/packages/core/src/eval/judge.js +39 -0
  47. package/harness/packages/core/src/eval/report.js +48 -0
  48. package/harness/packages/core/src/eval/runTask.js +71 -0
  49. package/harness/packages/core/src/eval/runner.js +150 -0
  50. package/harness/packages/core/src/eval/scorers.js +217 -0
  51. package/harness/packages/core/src/eval/task.js +59 -0
  52. package/harness/packages/core/src/index.js +72 -0
  53. package/harness/packages/core/src/mcp/common.js +82 -0
  54. package/harness/packages/core/src/mcp/http.js +149 -0
  55. package/harness/packages/core/src/mcp/index.js +167 -0
  56. package/harness/packages/core/src/mcp/stdio.js +218 -0
  57. package/harness/packages/core/src/providers/index.js +119 -0
  58. package/harness/packages/core/src/providers/ollama.js +76 -0
  59. package/harness/packages/core/src/providers/openaiCompatible.js +57 -0
  60. package/harness/packages/core/src/providers/openrouter.js +57 -0
  61. package/harness/packages/core/src/providers/presets.js +19 -0
  62. package/harness/packages/core/src/providers/resilience.js +74 -0
  63. package/harness/packages/core/src/providers/stream.js +200 -0
  64. package/harness/packages/core/src/providers/utils.js +66 -0
  65. package/harness/packages/core/src/storage/sqlite.js +453 -0
  66. package/harness/packages/core/src/tools/diff.js +90 -0
  67. package/harness/packages/core/src/tools/executors.js +277 -0
  68. package/harness/packages/core/src/tools/glob.js +67 -0
  69. package/harness/packages/core/src/tools/index.js +28 -0
  70. package/harness/packages/core/src/tools/paths.js +29 -0
  71. package/harness/packages/core/src/tools/permissions.js +69 -0
  72. package/harness/packages/core/src/tools/registry.js +44 -0
  73. package/harness/packages/core/src/tools/schema.js +177 -0
  74. package/harness/packages/core/test/agent.test.js +237 -0
  75. package/harness/packages/core/test/config.test.js +33 -0
  76. package/harness/packages/core/test/context.test.js +44 -0
  77. package/harness/packages/core/test/diff.test.js +20 -0
  78. package/harness/packages/core/test/eval.test.js +144 -0
  79. package/harness/packages/core/test/git-tools.test.js +44 -0
  80. package/harness/packages/core/test/home.test.js +62 -0
  81. package/harness/packages/core/test/mcp.test.js +158 -0
  82. package/harness/packages/core/test/providers.test.js +80 -0
  83. package/harness/packages/core/test/resilience.test.js +61 -0
  84. package/harness/packages/core/test/storage.test.js +55 -0
  85. package/harness/packages/core/test/stream.test.js +91 -0
  86. package/harness/packages/core/test/tools.test.js +96 -0
  87. package/harness/packages/server/bin/tamnora-server.mjs +11 -0
  88. package/harness/packages/server/package.json +10 -0
  89. package/harness/packages/server/public/app.js +2188 -0
  90. package/harness/packages/server/public/img/fondo-agentes.webp +0 -0
  91. package/harness/packages/server/public/index.html +368 -0
  92. package/harness/packages/server/public/landing/index.html +523 -0
  93. package/harness/packages/server/public/landing/landing.js +89 -0
  94. package/harness/packages/server/public/markdown.js +174 -0
  95. package/harness/packages/server/public/styles.css +923 -0
  96. package/harness/packages/server/src/auth.js +146 -0
  97. package/harness/packages/server/src/cli.js +61 -0
  98. package/harness/packages/server/src/index.js +1 -0
  99. package/harness/packages/server/src/lib/approvals.js +51 -0
  100. package/harness/packages/server/src/lib/core.js +2 -0
  101. package/harness/packages/server/src/lib/http.js +74 -0
  102. package/harness/packages/server/src/lib/modelCache.js +32 -0
  103. package/harness/packages/server/src/lib/prompt.js +48 -0
  104. package/harness/packages/server/src/lib/workspace.js +74 -0
  105. package/harness/packages/server/src/routes/auth.js +56 -0
  106. package/harness/packages/server/src/routes/chat.js +222 -0
  107. package/harness/packages/server/src/routes/eval.js +100 -0
  108. package/harness/packages/server/src/routes/files.js +117 -0
  109. package/harness/packages/server/src/routes/folders.js +80 -0
  110. package/harness/packages/server/src/routes/mcp.js +50 -0
  111. package/harness/packages/server/src/routes/models.js +26 -0
  112. package/harness/packages/server/src/routes/providers.js +135 -0
  113. package/harness/packages/server/src/routes/sessions.js +157 -0
  114. package/harness/packages/server/src/server.js +249 -0
  115. package/harness/packages/server/src/static.js +67 -0
  116. package/harness/packages/server/test/markdown.test.js +36 -0
  117. package/harness/packages/server/test/modelCache.test.js +72 -0
  118. package/harness/packages/server/test/server.test.js +809 -0
  119. package/harness/scripts/example-dataset.jsonl +4 -0
  120. package/harness/scripts/mcp-echo-server.mjs +108 -0
  121. package/harness/scripts/mock-provider.mjs +134 -0
  122. package/harness/tamnora.example.json +18 -0
  123. package/package.json +70 -0
@@ -0,0 +1,923 @@
1
+ /* tamnora console — paper / aguada theme (opencode/codex-like) */
2
+ :root {
3
+ --bg: #161712;
4
+ --panel: rgba(28, 29, 23, 0.82);
5
+ --rail: rgba(24, 25, 19, 0.78);
6
+ --theirs: #24251d;
7
+ --mine: #d9704a;
8
+ --mine-soft: rgba(217, 112, 74, 0.12);
9
+ --text: #e9e4d6;
10
+ --muted: #9c9789;
11
+ --border: rgba(240, 234, 219, 0.14);
12
+ --danger: #e0705c;
13
+ --accent: #d9704a;
14
+ --accent-dark: #b8542f;
15
+ --accent-soft: rgba(217, 112, 74, 0.18);
16
+ --ok: #8fae7f;
17
+ --warn: #d9a441;
18
+ --solid: #1b1c16;
19
+ --primary-fg: #fff7ef;
20
+ --sans: Manrope, system-ui, "Segoe UI", Arial, sans-serif;
21
+ --serif: "Libre Baskerville", Georgia, "Times New Roman", serif;
22
+ --mono: "DM Mono", ui-monospace, "Cascadia Code", "JetBrains Mono", "SF Mono", Consolas, monospace;
23
+ --font: var(--sans);
24
+ --page-bg: linear-gradient(rgba(22, 23, 15, 0.94), rgba(22, 23, 15, 0.94)), url("/img/fondo-agentes.webp") center/cover fixed no-repeat;
25
+ color-scheme: dark;
26
+ }
27
+
28
+ html[data-theme='paper'] {
29
+ color-scheme: light;
30
+ --paper: #f5efe2;
31
+ --paper-2: #ebe4d4;
32
+ --glass: rgba(247, 242, 230, 0.73);
33
+ --bg: #f5efe2;
34
+ --panel: rgba(247, 242, 230, 0.73);
35
+ --rail: rgba(235, 228, 212, 0.72);
36
+ --theirs: #ebe4d4;
37
+ --mine: #bd542f;
38
+ --mine-soft: rgba(189, 84, 47, 0.09);
39
+ --text: #20211d;
40
+ --muted: #68685d;
41
+ --border: rgba(43, 43, 37, 0.16);
42
+ --danger: #934022;
43
+ --accent: #bd542f;
44
+ --accent-dark: #934022;
45
+ --accent-soft: rgba(189, 84, 47, 0.1);
46
+ --ok: #66865d;
47
+ --warn: #8a5a00;
48
+ --solid: #f7f2e6;
49
+ --primary-fg: #fbf6ec;
50
+ --page-bg: linear-gradient(90deg, rgba(248, 244, 234, 0.9), rgba(244, 238, 224, 0.86)), url("/img/fondo-agentes.webp") center/cover fixed no-repeat;
51
+ }
52
+ html[data-theme='paper'] .tok-comment { color: #7a7669; }
53
+ html[data-theme='paper'] .tok-string { color: #7a4a2c; }
54
+ html[data-theme='paper'] .tok-number { color: #8a5a00; }
55
+ html[data-theme='paper'] .tok-keyword { color: #a3341f; }
56
+ html[data-theme='paper'] .btn.primary { color: #fbf6ec; }
57
+
58
+ * { box-sizing: border-box; }
59
+ [hidden] { display: none !important; }
60
+
61
+ * { scrollbar-width: thin; scrollbar-color: var(--border) transparent; }
62
+ ::-webkit-scrollbar { width: 10px; height: 10px; }
63
+ ::-webkit-scrollbar-track { background: transparent; }
64
+ ::-webkit-scrollbar-thumb {
65
+ background: var(--border);
66
+ border-radius: 8px;
67
+ border: 2px solid transparent;
68
+ background-clip: content-box;
69
+ }
70
+ ::-webkit-scrollbar-thumb:hover { background: var(--muted); background-clip: content-box; }
71
+ ::-webkit-scrollbar-corner { background: transparent; }
72
+
73
+ html, body {
74
+ margin: 0;
75
+ height: 100%;
76
+ color: var(--text);
77
+ font: 13.5px/1.5 var(--font);
78
+ }
79
+
80
+ body { display: flex; flex-direction: column; background: var(--page-bg); }
81
+ pre, code, kbd, samp { font-family: var(--mono); }
82
+ .muted { color: var(--muted); }
83
+
84
+ /* topbar ------------------------------------------------------------------ */
85
+ .topbar {
86
+ display: flex;
87
+ align-items: center;
88
+ gap: 16px;
89
+ padding: 10px 16px;
90
+ border-bottom: 1px solid var(--border);
91
+ background: var(--panel);
92
+ backdrop-filter: blur(14px);
93
+ }
94
+ .brand {
95
+ font-family: var(--serif);
96
+ font-weight: 700;
97
+ font-size: 15px;
98
+ letter-spacing: -0.02em;
99
+ display: flex;
100
+ align-items: center;
101
+ gap: 9px;
102
+ }
103
+ .brand .logo {
104
+ width: 26px;
105
+ height: 26px;
106
+ border: 1px solid var(--border);
107
+ border-radius: 8px;
108
+ display: grid;
109
+ place-items: center;
110
+ color: var(--accent);
111
+ font: 700 14px var(--serif);
112
+ flex: 0 0 auto;
113
+ }
114
+ .brand .ver { color: var(--muted); font-family: var(--mono); font-weight: 400; font-size: 10px; letter-spacing: 0.04em; }
115
+ .tabs { display: flex; gap: 2px; }
116
+ .tab {
117
+ background: transparent;
118
+ color: var(--muted);
119
+ border: 1px solid transparent;
120
+ border-radius: 999px;
121
+ padding: 6px 14px;
122
+ cursor: pointer;
123
+ font: 600 12.5px var(--sans);
124
+ }
125
+ .tab:hover { color: var(--text); }
126
+ .tab.active { color: var(--text); background: var(--theirs); border-color: var(--border); }
127
+
128
+ .menu { position: relative; }
129
+ #more-tab { display: grid; place-items: center; padding: 6px 10px; }
130
+ #more-tab svg { width: 18px; height: 18px; display: block; }
131
+
132
+ #theme-toggle .ico-moon { display: none; }
133
+ html[data-theme='dark'] #theme-toggle .ico-sun { display: none; }
134
+ html[data-theme='dark'] #theme-toggle .ico-moon { display: block; }
135
+ .menu-pop {
136
+ position: absolute;
137
+ top: calc(100% + 4px);
138
+ left: 0;
139
+ z-index: 20;
140
+ min-width: 130px;
141
+ display: flex;
142
+ flex-direction: column;
143
+ gap: 2px;
144
+ padding: 4px;
145
+ background: var(--solid, var(--panel));
146
+ border: 1px solid var(--border);
147
+ border-radius: 10px;
148
+ box-shadow: 0 14px 34px rgba(20, 18, 12, 0.24);
149
+ backdrop-filter: blur(18px);
150
+ }
151
+ .menu-pop button {
152
+ background: transparent;
153
+ border: 0;
154
+ color: var(--text);
155
+ text-align: left;
156
+ padding: 7px 10px;
157
+ border-radius: 6px;
158
+ cursor: pointer;
159
+ font: inherit;
160
+ }
161
+ .menu-pop button:hover { background: var(--theirs); }
162
+ .settings { margin-left: auto; display: flex; align-items: center; gap: 8px; }
163
+ .settings select { max-width: 220px; }
164
+ .check { color: var(--muted); display: flex; align-items: center; gap: 5px; cursor: pointer; }
165
+
166
+ select, input, textarea {
167
+ background: var(--bg);
168
+ border: 1px solid var(--border);
169
+ border-radius: 10px;
170
+ color: var(--text);
171
+ padding: 7px 10px;
172
+ font: inherit;
173
+ outline: none;
174
+ }
175
+ select:focus, input:focus, textarea:focus { border-color: var(--accent); box-shadow: 0 0 0 4px var(--accent-soft); }
176
+
177
+ /* layout ------------------------------------------------------------------ */
178
+ main { flex: 1; min-height: 0; min-width: 0; display: flex; }
179
+ .view { display: none; flex: 1; min-height: 0; min-width: 0; }
180
+ .view.active { display: flex; min-width: 0; }
181
+
182
+ .btn {
183
+ background: var(--theirs);
184
+ color: var(--text);
185
+ border: 1px solid var(--border);
186
+ border-radius: 10px;
187
+ padding: 7px 13px;
188
+ cursor: pointer;
189
+ font: 600 12.5px var(--sans);
190
+ transition: 0.15s ease;
191
+ }
192
+ .btn:hover { border-color: var(--accent); color: var(--text); }
193
+ .btn.primary { background: var(--accent); border-color: var(--accent); color: var(--primary-fg); font-weight: 700; }
194
+ .btn.primary:hover { filter: brightness(1.08); }
195
+ .btn.block { width: 100%; }
196
+ .btn.danger:hover { border-color: var(--danger); color: var(--danger); }
197
+ .btn:disabled { opacity: 0.5; cursor: default; }
198
+
199
+ /* chat -------------------------------------------------------------------- */
200
+ .sidebar {
201
+ width: 260px;
202
+ border-right: 1px solid var(--border);
203
+ background: var(--rail);
204
+ backdrop-filter: blur(14px);
205
+ padding: 10px;
206
+ display: flex;
207
+ flex-direction: column;
208
+ gap: 8px;
209
+ overflow-y: auto;
210
+ }
211
+ .sessions { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 5px; flex: 1; overflow-y: auto; }
212
+ .session-group { list-style: none; }
213
+ .group-head {
214
+ display: flex;
215
+ align-items: center;
216
+ gap: 7px;
217
+ padding: 5px 7px;
218
+ border-radius: 7px;
219
+ cursor: pointer;
220
+ color: var(--muted);
221
+ }
222
+ .group-head:hover { background: var(--panel); color: var(--text); }
223
+ .group-head .tw { width: 14px; height: 14px; flex: 0 0 auto; display: grid; place-items: center; }
224
+ .group-head .fi { width: 15px; height: 15px; flex: 0 0 auto; color: var(--accent); }
225
+ .group-head .gname {
226
+ flex: 1;
227
+ min-width: 0;
228
+ overflow: hidden;
229
+ text-overflow: ellipsis;
230
+ white-space: nowrap;
231
+ font: 600 11px var(--sans);
232
+ letter-spacing: 0.02em;
233
+ }
234
+ .group-head .gcount { font: 500 10px var(--mono); opacity: 0.65; }
235
+ .group-sessions { list-style: none; margin: 0; padding: 3px 0 0 15px; display: flex; flex-direction: column; gap: 2px; }
236
+ .session-item {
237
+ padding: 6px 9px;
238
+ border-radius: 6px;
239
+ cursor: pointer;
240
+ color: var(--muted);
241
+ white-space: nowrap;
242
+ overflow: hidden;
243
+ text-overflow: ellipsis;
244
+ border: 1px solid transparent;
245
+ }
246
+ .session-item:hover { background: var(--panel); color: var(--text); }
247
+ .session-item.active { background: var(--theirs); color: var(--text); border-color: var(--border); }
248
+ .session-item .sub { color: var(--muted); font-size: 11px; overflow: hidden; text-overflow: ellipsis; }
249
+ .rail-footer { border-top: 1px solid var(--border); padding-top: 8px; color: var(--muted); font-size: 12px; }
250
+ .rail-footer b { color: var(--text); display: block; word-break: break-all; font-weight: 500; }
251
+ .rail-exit {
252
+ display: inline-block;
253
+ margin-top: 9px;
254
+ color: var(--muted);
255
+ font: 500 11px var(--mono);
256
+ letter-spacing: 0.06em;
257
+ text-decoration: none;
258
+ }
259
+ .rail-exit:hover { color: var(--accent); }
260
+
261
+ .conversation { flex: 1; display: flex; flex-direction: column; min-width: 0; }
262
+ .panes { flex: 1; min-height: 0; display: flex; min-width: 0; }
263
+ .panes > .messages { flex: 1; min-height: 0; min-width: 0; }
264
+ .messages { flex: 1; overflow-y: auto; overflow-x: hidden; min-width: 0; padding: 20px 24px 28px; display: flex; flex-direction: column; gap: 20px; }
265
+
266
+ /* resizable gutters -------------------------------------------------------- */
267
+ .resizer {
268
+ flex: 0 0 auto;
269
+ width: 7px;
270
+ cursor: col-resize;
271
+ background: transparent;
272
+ transition: background 0.12s ease;
273
+ }
274
+ .resizer:hover, .resizer.dragging { background: var(--accent-soft); }
275
+ body.resizing { cursor: col-resize; user-select: none; }
276
+ body.resizing * { cursor: col-resize !important; }
277
+
278
+ /* session tabs ------------------------------------------------------------- */
279
+ .tabbar {
280
+ display: flex;
281
+ align-items: center;
282
+ gap: 5px;
283
+ padding: 8px 12px 0;
284
+ overflow-x: auto;
285
+ flex: 0 0 auto;
286
+ }
287
+ .session-tab {
288
+ display: flex;
289
+ align-items: center;
290
+ gap: 7px;
291
+ max-width: 220px;
292
+ padding: 5px 8px 5px 11px;
293
+ border: 1px solid var(--border);
294
+ border-radius: 999px;
295
+ background: transparent;
296
+ color: var(--muted);
297
+ cursor: pointer;
298
+ font: 600 12px var(--sans);
299
+ flex: 0 0 auto;
300
+ }
301
+ .session-tab:hover { color: var(--text); border-color: var(--accent-soft); }
302
+ .session-tab.active { color: var(--text); background: var(--theirs); border-color: var(--accent); }
303
+ .session-tab .tab-title { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
304
+ .session-tab .tab-close { display: grid; place-items: center; width: 16px; height: 16px; border-radius: 50%; color: var(--muted); flex: 0 0 auto; }
305
+ .session-tab .tab-close:hover { background: var(--border); color: var(--text); }
306
+ .session-tab .tab-close svg { width: 12px; height: 12px; }
307
+ .tab-spinner {
308
+ width: 12px;
309
+ height: 12px;
310
+ flex: 0 0 auto;
311
+ border: 2px solid var(--accent);
312
+ border-right-color: transparent;
313
+ border-radius: 50%;
314
+ animation: spin 0.7s linear infinite;
315
+ }
316
+ @keyframes spin { to { transform: rotate(360deg); } }
317
+ .empty { color: var(--muted); margin: auto; text-align: center; line-height: 1.8; }
318
+ .empty-brand {
319
+ display: flex;
320
+ flex-direction: column;
321
+ align-items: center;
322
+ font: 700 clamp(34px, 5.2vw, 58px) / 1.02 var(--serif);
323
+ letter-spacing: -0.045em;
324
+ color: var(--text);
325
+ }
326
+ .empty-brand .accent { color: var(--accent); }
327
+ .empty-sub { margin: 20px 0 0; font-size: 14px; color: var(--muted); }
328
+ .empty-hints { margin-top: 24px; display: flex; flex-wrap: wrap; gap: 10px 18px; justify-content: center; max-width: 620px; }
329
+ .hint { display: inline-flex; align-items: center; gap: 7px; font-size: 12px; color: var(--muted); }
330
+ .hint kbd {
331
+ font: 600 11px var(--mono);
332
+ background: var(--theirs);
333
+ border: 1px solid var(--border);
334
+ border-radius: 6px;
335
+ padding: 3px 7px;
336
+ color: var(--text);
337
+ }
338
+
339
+ /* transcript style: role label, no bubbles */
340
+ .msg { min-width: 0; }
341
+ .msg::before {
342
+ display: block;
343
+ font: 500 10px var(--mono);
344
+ letter-spacing: 0.14em;
345
+ text-transform: uppercase;
346
+ color: var(--muted);
347
+ margin-bottom: 5px;
348
+ }
349
+ .msg.user::before { content: '❯ vos'; color: var(--mine); }
350
+ .msg.assistant::before { content: 'tamnora'; }
351
+ .bubble {
352
+ max-width: 900px;
353
+ min-width: 0;
354
+ padding-left: 12px;
355
+ border-left: 2px solid var(--border);
356
+ white-space: pre-wrap;
357
+ word-break: break-word;
358
+ overflow-wrap: anywhere;
359
+ }
360
+ .msg.user .bubble { border-left-color: var(--mine); color: var(--text); }
361
+ .msg-actions { display: flex; gap: 6px; margin-top: 7px; opacity: 0.45; transition: opacity 0.12s ease; }
362
+ .msg:hover .msg-actions,
363
+ .msg:focus-within .msg-actions { opacity: 1; }
364
+ .msg-actions button.msg-act {
365
+ background: transparent;
366
+ border: 1px solid var(--border);
367
+ border-radius: 7px;
368
+ color: var(--muted);
369
+ font: 500 11px var(--mono);
370
+ padding: 2px 8px;
371
+ cursor: pointer;
372
+ }
373
+ .msg-actions button.msg-act:hover { color: var(--text); border-color: var(--accent); }
374
+ .msg-actions button.msg-act.danger:hover { color: var(--danger); border-color: var(--danger); }
375
+ .bubble .tools { margin-top: 10px; display: flex; flex-direction: column; gap: 6px; }
376
+
377
+ .tool-card { font-size: 12.5px; border-left: 2px solid var(--border); padding-left: 10px; min-width: 0; }
378
+ .tool-card .tool-head { display: flex; gap: 8px; align-items: baseline; min-width: 0; }
379
+ .tool-card .tool-glyph { color: var(--muted); flex: 0 0 auto; }
380
+ .tool-card.running .tool-glyph { color: var(--accent); animation: pulse 1s steps(2, start) infinite; }
381
+ .tool-card.done .tool-glyph { color: var(--ok); }
382
+ .tool-card.failed .tool-glyph { color: var(--danger); }
383
+ .tool-card .tool-name { color: var(--accent); font-weight: 700; flex: 0 0 auto; white-space: nowrap; }
384
+ .tool-card .tool-args {
385
+ color: var(--muted);
386
+ flex: 1 1 auto;
387
+ min-width: 0;
388
+ overflow: hidden;
389
+ text-overflow: ellipsis;
390
+ white-space: nowrap;
391
+ }
392
+ .tool-card .tool-out {
393
+ color: var(--muted);
394
+ margin: 4px 0 2px 18px;
395
+ padding-left: 10px;
396
+ border-left: 1px solid var(--border);
397
+ white-space: pre-wrap;
398
+ word-break: break-word;
399
+ max-height: 260px;
400
+ overflow: auto;
401
+ }
402
+ .tool-card .tool-out:empty { display: none; }
403
+ .tool-out .diff-line { display: block; }
404
+ .tool-out .diff-add { color: var(--ok); }
405
+ .tool-out .diff-del { color: var(--danger); }
406
+ .tool-out .diff-eq { color: var(--muted); }
407
+ .tool-out .diff-sep { color: var(--muted); opacity: 0.55; }
408
+
409
+ .perm-card {
410
+ border: 1px solid var(--warn);
411
+ border-radius: 7px;
412
+ padding: 9px 11px;
413
+ background: rgba(210, 153, 34, 0.06);
414
+ }
415
+ .perm-card .perm-head { display: flex; gap: 7px; align-items: center; color: var(--warn); font-weight: 700; }
416
+ .perm-card .perm-args { color: var(--muted); margin: 5px 0 9px; white-space: pre-wrap; word-break: break-word; }
417
+ .perm-card .perm-actions { display: flex; align-items: center; gap: 8px; }
418
+ .perm-card .spacer { flex: 1; }
419
+ .perm-card.approved { border-color: var(--ok); background: rgba(63, 185, 80, 0.06); }
420
+ .perm-card.approved .perm-head { color: var(--ok); }
421
+ .perm-card.denied { border-color: var(--danger); background: rgba(248, 81, 73, 0.06); }
422
+ .perm-card.denied .perm-head { color: var(--danger); }
423
+ .perm-card.collapsed { padding: 5px 11px; background: transparent; }
424
+ .perm-card.collapsed .perm-args,
425
+ .perm-card.collapsed .perm-actions { display: none; }
426
+
427
+ /* activity indicators ------------------------------------------------------ */
428
+ .activity { display: flex; align-items: center; gap: 9px; margin-top: 10px; color: var(--muted); font-size: 12.5px; }
429
+ .activity .loader { color: var(--accent); }
430
+ .activity-label { color: var(--muted); }
431
+ #sb-rounds.running { color: var(--accent); }
432
+
433
+ .loader-thinking {
434
+ width: 32px;
435
+ height: 8px;
436
+ --c: currentColor 92%, transparent;
437
+ background:
438
+ radial-gradient(circle closest-side, var(--c)) calc(100% / -4) 0,
439
+ radial-gradient(circle closest-side, var(--c)) calc(100% / 4) 0;
440
+ background-size: calc(100% / 2) 100%;
441
+ animation: loader-thinking 1.5s infinite;
442
+ }
443
+ @keyframes loader-thinking {
444
+ 0% { background-position: calc(100% / -4) 0, calc(100% / 4) 0; }
445
+ 50% { background-position: calc(100% / -4) -8px, calc(100% / 4) 8px; }
446
+ 100% { background-position: calc(100% / 4) -8px, calc(300% / 4) 8px; }
447
+ }
448
+
449
+ .loader-working {
450
+ width: 18px;
451
+ height: 18px;
452
+ --g: conic-gradient(from -90deg at 3px 3px, currentColor 90deg, transparent 0);
453
+ background: var(--g), var(--g), var(--g);
454
+ background-size: 50% 50%;
455
+ animation: loader-working 1s infinite;
456
+ }
457
+ @keyframes loader-working {
458
+ 0% { background-position: 0 0, 3px 3px, 6px 6px; }
459
+ 50% { background-position: 0 6px, 3px 3px, 6px 0; }
460
+ 100% { background-position: 6px 6px, 3px 3px, 0 0; }
461
+ }
462
+
463
+ .chip {
464
+ font-size: 12.5px;
465
+ color: var(--muted);
466
+ border-left: 2px solid var(--warn);
467
+ padding: 2px 0 2px 10px;
468
+ white-space: pre-wrap;
469
+ word-break: break-word;
470
+ }
471
+ .chip.err { border-left-color: var(--danger); color: var(--danger); }
472
+ details.reasoning { margin-top: 6px; }
473
+ details.reasoning > summary { color: var(--muted); cursor: pointer; font-size: 12.5px; }
474
+ details.reasoning .body { color: var(--muted); white-space: pre-wrap; margin-top: 4px; border-left: 1px solid var(--border); padding-left: 10px; }
475
+
476
+ @keyframes pulse { 50% { opacity: 0.35; } }
477
+
478
+ .composer { display: flex; flex-direction: column; gap: 8px; padding: 12px 14px; border-top: 1px solid var(--border); background: var(--panel); backdrop-filter: blur(14px); }
479
+ .composer.dragging { outline: 1px dashed var(--accent); outline-offset: -4px; }
480
+ .composer-row { display: flex; align-items: flex-end; gap: 8px; }
481
+ .prompt-mark { color: var(--mine); font-weight: 700; padding-bottom: 8px; }
482
+ .composer textarea { flex: 1; resize: none; max-height: 180px; }
483
+ .btn.icon {
484
+ width: 34px;
485
+ height: 34px;
486
+ padding: 0;
487
+ display: grid;
488
+ place-items: center;
489
+ flex: 0 0 auto;
490
+ line-height: 1;
491
+ }
492
+ .btn.icon svg { width: 18px; height: 18px; display: block; }
493
+ .btn.icon:hover { color: var(--accent); }
494
+
495
+ .attach-preview { display: flex; gap: 8px; flex-wrap: wrap; padding-bottom: 2px; }
496
+ .attach-thumb { position: relative; }
497
+ .attach-thumb img { height: 64px; border-radius: 6px; border: 1px solid var(--border); display: block; }
498
+ .attach-remove {
499
+ position: absolute;
500
+ top: -6px;
501
+ right: -6px;
502
+ width: 20px;
503
+ height: 20px;
504
+ padding: 0;
505
+ line-height: 1;
506
+ border-radius: 50%;
507
+ background: var(--danger);
508
+ color: #fff;
509
+ border: 0;
510
+ cursor: pointer;
511
+ }
512
+ .msg-images { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 8px; }
513
+ .msg-image { max-height: 220px; max-width: 100%; border-radius: 8px; border: 1px solid var(--border); }
514
+
515
+ /* markdown ----------------------------------------------------------------- */
516
+ .text > *:first-child { margin-top: 0; }
517
+ .text > *:last-child { margin-bottom: 0; }
518
+ .text p { margin: 0 0 10px; }
519
+ .text h1, .text h2, .text h3, .text h4, .text h5, .text h6 { margin: 14px 0 8px; line-height: 1.3; }
520
+ .text h1 { font-size: 1.35em; border-bottom: 1px solid var(--border); padding-bottom: 4px; }
521
+ .text h2 { font-size: 1.2em; }
522
+ .text h3 { font-size: 1.08em; }
523
+ .text ul, .text ol { margin: 0 0 10px; padding-left: 22px; }
524
+ .text li { margin: 3px 0; }
525
+ .text blockquote { margin: 0 0 10px; padding-left: 12px; border-left: 2px solid var(--border); color: var(--muted); }
526
+ .text a { color: var(--accent); }
527
+ .text hr { border: 0; border-top: 1px solid var(--border); margin: 14px 0; }
528
+ .text code {
529
+ background: var(--theirs);
530
+ border: 1px solid var(--border);
531
+ border-radius: 4px;
532
+ padding: 1px 5px;
533
+ font-size: 0.92em;
534
+ }
535
+ .text.notice { color: var(--muted); }
536
+ .text.notice.err { color: var(--danger); }
537
+
538
+ .code-block { margin: 10px 0; border: 1px solid var(--border); border-radius: 12px; overflow: hidden; background: var(--solid, var(--panel)); }
539
+ .code-bar { display: flex; justify-content: space-between; align-items: center; padding: 5px 11px; border-bottom: 1px solid var(--border); background: var(--theirs); }
540
+ .code-lang { color: var(--muted); font-size: 11px; text-transform: uppercase; letter-spacing: 0.5px; }
541
+ .code-copy { background: transparent; border: 0; color: var(--muted); cursor: pointer; font: inherit; font-size: 11px; }
542
+ .code-copy:hover { color: var(--text); }
543
+ pre.code { margin: 0; padding: 10px 12px; overflow: auto; max-height: 420px; }
544
+ pre.code code { background: none; border: 0; padding: 0; font-size: 12.5px; }
545
+ .tok-comment { color: #8c8779; font-style: italic; }
546
+ .tok-string { color: #c2a878; }
547
+ .tok-number { color: #e0a05c; }
548
+ .tok-keyword { color: #e0794f; }
549
+
550
+ .statusbar {
551
+ display: flex;
552
+ gap: 8px;
553
+ align-items: center;
554
+ padding: 5px 14px;
555
+ border-top: 1px solid var(--border);
556
+ background: var(--rail);
557
+ backdrop-filter: blur(14px);
558
+ color: var(--muted);
559
+ font: 500 11px var(--mono);
560
+ letter-spacing: 0.02em;
561
+ }
562
+ .statusbar .dot { opacity: 0.5; }
563
+ .statusbar .spacer { flex: 1; }
564
+
565
+ /* providers / eval / runs ------------------------------------------------- */
566
+ .panel { flex: 1; overflow-y: auto; padding: 18px; display: flex; flex-direction: column; gap: 12px; }
567
+ .panel h2 { margin: 0; font: 700 20px var(--serif); letter-spacing: -0.02em; }
568
+ .field { display: flex; flex-direction: column; gap: 5px; color: var(--muted); }
569
+ .field.grow { flex: 1; }
570
+ .field > span { font-size: 12px; }
571
+ .panel textarea { width: 100%; }
572
+ .row { display: flex; gap: 8px; align-items: flex-end; flex-wrap: wrap; }
573
+ .row.between { justify-content: space-between; align-items: center; }
574
+ .row input[type="number"] { width: 78px; }
575
+
576
+ .card { border: 1px solid var(--border); background: var(--panel); backdrop-filter: blur(14px); border-radius: 14px; padding: 14px; display: flex; flex-direction: column; gap: 10px; }
577
+
578
+ .providers { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 4px; }
579
+ .providers li {
580
+ display: flex;
581
+ align-items: center;
582
+ gap: 10px;
583
+ padding: 9px 11px;
584
+ border: 1px solid var(--border);
585
+ border-radius: 11px;
586
+ background: var(--panel);
587
+ backdrop-filter: blur(10px);
588
+ cursor: pointer;
589
+ }
590
+ .providers li:hover { border-color: var(--accent); }
591
+ .providers li.active { border-color: var(--mine); }
592
+ .providers .pdot { width: 8px; height: 8px; border-radius: 50%; background: var(--border); flex: none; }
593
+ .providers .pdot.on { background: var(--ok); }
594
+ .providers .pid { font-weight: 700; }
595
+ .providers .pmeta { color: var(--muted); font-size: 12px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
596
+ .providers .grow { flex: 1; min-width: 0; }
597
+
598
+ .summary { color: var(--muted); }
599
+ .summary.ok { color: var(--ok); }
600
+ .summary.err { color: var(--danger); }
601
+
602
+ .ctx-ok { color: var(--ok); }
603
+ .ctx-mid { color: var(--text); }
604
+ .ctx-warn { color: var(--warn); }
605
+ .ctx-danger { color: var(--danger); }
606
+
607
+ /* folder picker ------------------------------------------------------------ */
608
+ .folder-modal { width: min(680px, calc(100vw - 40px)); }
609
+ .folder-toolbar { display: flex; align-items: center; gap: 6px; }
610
+ .crumbs {
611
+ display: flex;
612
+ align-items: center;
613
+ gap: 1px;
614
+ flex-wrap: wrap;
615
+ min-width: 0;
616
+ font-size: 12.5px;
617
+ color: var(--muted);
618
+ }
619
+ .crumb { padding: 3px 7px; border-radius: 5px; white-space: nowrap; cursor: pointer; }
620
+ .crumb:hover { background: var(--theirs); color: var(--text); }
621
+ .crumb.current { color: var(--text); font-weight: 600; cursor: default; }
622
+ .crumb.current:hover { background: transparent; }
623
+ .crumb-sep { color: var(--muted); opacity: 0.55; }
624
+
625
+ .folder-search { display: flex; gap: 8px; }
626
+ .folder-search input { flex: 1; min-width: 0; }
627
+ .folder-create { display: flex; gap: 8px; }
628
+ .folder-create input { flex: 1; min-width: 0; border-color: var(--accent); }
629
+
630
+ .folders {
631
+ list-style: none;
632
+ margin: 0;
633
+ padding: 2px;
634
+ display: flex;
635
+ flex-direction: column;
636
+ gap: 2px;
637
+ max-height: 42vh;
638
+ overflow-y: auto;
639
+ }
640
+ .folders li {
641
+ /* Sin flex-shrink:0 los items se aplastan en vez de scrollear. El overflow:hidden
642
+ de abajo anula el min-height:auto de flex, asi que sin esto cada fila queda
643
+ mas baja que su texto y se ve cortada. */
644
+ flex: 0 0 auto;
645
+ display: flex;
646
+ align-items: center;
647
+ gap: 9px;
648
+ min-width: 0;
649
+ padding: 8px 10px;
650
+ border-radius: 7px;
651
+ cursor: pointer;
652
+ color: var(--text);
653
+ white-space: nowrap;
654
+ overflow: hidden;
655
+ border: 1px solid transparent;
656
+ }
657
+ .folder-item:focus-visible { outline: 1px solid var(--accent); outline-offset: -1px; }
658
+ .folder-item:hover { background: var(--theirs); border-color: var(--border); }
659
+ .folder-ico { width: 16px; height: 16px; flex: 0 0 auto; color: var(--muted); }
660
+ .folder-item:hover .folder-ico, .folder-item:focus-visible .folder-ico { color: var(--accent); }
661
+ .folder-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
662
+ .folder-enter { color: var(--muted); font-size: 11px; opacity: 0; flex: 0 0 auto; }
663
+ .folder-item:hover .folder-enter, .folder-item:focus-visible .folder-enter { opacity: 1; }
664
+ .folders .folders-empty { color: var(--muted); cursor: default; padding: 10px; }
665
+
666
+ .folder-footer { display: flex; align-items: center; gap: 10px; border-top: 1px solid var(--border); padding-top: 12px; }
667
+ .folder-footer .summary { font-size: 12px; }
668
+
669
+ .results { width: 100%; border-collapse: collapse; font-size: 12.5px; }
670
+ .results th, .results td { text-align: left; padding: 5px 8px; border-bottom: 1px solid var(--border); vertical-align: top; }
671
+ .results th { color: var(--muted); font-weight: 600; }
672
+ .results .pass { color: var(--ok); font-weight: 700; }
673
+ .results .fail { color: var(--danger); font-weight: 700; }
674
+ .results td.detail { color: var(--muted); }
675
+
676
+ .runs { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 5px; }
677
+ .runs li {
678
+ padding: 8px 11px;
679
+ border: 1px solid var(--border);
680
+ border-radius: 11px;
681
+ background: var(--panel);
682
+ backdrop-filter: blur(10px);
683
+ cursor: pointer;
684
+ display: flex;
685
+ justify-content: space-between;
686
+ gap: 10px;
687
+ }
688
+ .runs li:hover, .runs li.active { border-color: var(--accent); }
689
+
690
+ /* explorer (right panel) --------------------------------------------------- */
691
+ .explorer {
692
+ width: 300px;
693
+ flex: 0 0 auto;
694
+ display: flex;
695
+ flex-direction: column;
696
+ min-height: 0;
697
+ border-left: 1px solid var(--border);
698
+ background: var(--rail);
699
+ backdrop-filter: blur(14px);
700
+ }
701
+ .explorer-head { display: flex; align-items: center; gap: 6px; padding: 9px 12px; border-bottom: 1px solid var(--border); }
702
+ .explorer-title { font: 700 14px var(--serif); letter-spacing: -0.02em; }
703
+ .explorer-head .spacer { flex: 1; }
704
+ .explorer-cwd { padding: 9px 12px 0; color: var(--muted); font: 500 11px var(--mono); word-break: break-all; }
705
+ .explorer-cwd:empty { display: none; }
706
+ .explorer-filter { padding: 9px 12px; }
707
+ .explorer-filter input { width: 100%; }
708
+
709
+ .tree { list-style: none; margin: 0; padding: 2px 8px 12px; overflow-y: auto; flex: 1; min-height: 0; }
710
+ .tree .tree { padding: 0 0 0 13px; overflow: visible; }
711
+ .tree-row { display: flex; align-items: center; gap: 6px; padding: 3px 6px; border-radius: 7px; cursor: pointer; white-space: nowrap; }
712
+ .tree-row:hover { background: var(--theirs); }
713
+ .tree-row .tw { width: 14px; height: 14px; flex: 0 0 auto; display: grid; place-items: center; color: var(--muted); }
714
+ .tree-row .fi { width: 15px; height: 15px; flex: 0 0 auto; color: var(--muted); }
715
+ .tree-row.dir .fi { color: var(--accent); }
716
+ .tree-name { overflow: hidden; text-overflow: ellipsis; min-width: 0; }
717
+ .explorer-status { padding: 6px 12px; border-top: 1px solid var(--border); color: var(--muted); font: 500 11px var(--mono); min-height: 27px; }
718
+ .explorer-status.err { color: var(--danger); }
719
+
720
+ .file-actions { display: flex; align-items: center; gap: 10px; }
721
+ .file-modal { width: min(880px, calc(100vw - 40px)); }
722
+ .file-preview {
723
+ margin: 0;
724
+ padding: 12px 14px;
725
+ max-height: 62vh;
726
+ overflow: auto;
727
+ background: var(--theirs);
728
+ border: 1px solid var(--border);
729
+ border-radius: 10px;
730
+ font: 12px/1.55 var(--mono);
731
+ white-space: pre;
732
+ }
733
+
734
+ .drawer-backdrop {
735
+ position: fixed;
736
+ inset: 0;
737
+ z-index: 44;
738
+ background: rgba(24, 22, 16, 0.45);
739
+ backdrop-filter: blur(2px);
740
+ }
741
+
742
+ @media (max-width: 900px) {
743
+ .explorer {
744
+ position: fixed;
745
+ top: 0;
746
+ right: 0;
747
+ bottom: 0;
748
+ z-index: 45;
749
+ width: min(340px, 86vw) !important;
750
+ box-shadow: -20px 0 50px rgba(40, 36, 26, 0.25);
751
+ }
752
+ }
753
+
754
+ /* mobile / angosto -------------------------------------------------------- */
755
+ @media (max-width: 820px) {
756
+ .topbar {
757
+ flex-wrap: wrap;
758
+ gap: 8px 10px;
759
+ padding: 8px 12px;
760
+ }
761
+ .brand .ver {
762
+ display: none;
763
+ }
764
+ .tabs {
765
+ overflow-x: auto;
766
+ max-width: 100%;
767
+ }
768
+ .settings {
769
+ margin-left: 0;
770
+ flex: 1 1 100%;
771
+ flex-wrap: wrap;
772
+ gap: 8px;
773
+ }
774
+ .settings .btn.icon {
775
+ flex: 0 0 auto;
776
+ }
777
+
778
+ /* sidebar como drawer deslizante */
779
+ .sidebar {
780
+ position: fixed;
781
+ top: 0;
782
+ left: 0;
783
+ bottom: 0;
784
+ z-index: 50;
785
+ width: min(300px, 84vw) !important;
786
+ transform: translateX(-100%);
787
+ transition: transform 0.22s ease;
788
+ box-shadow: 18px 0 44px rgba(40, 36, 26, 0.28);
789
+ will-change: transform;
790
+ }
791
+ .sidebar.open {
792
+ transform: translateX(0);
793
+ }
794
+ .sidebar[hidden] {
795
+ display: flex;
796
+ }
797
+ .resizer {
798
+ display: none;
799
+ }
800
+
801
+ .messages {
802
+ padding: 16px 14px 22px;
803
+ gap: 16px;
804
+ }
805
+ .composer {
806
+ padding: 10px 12px;
807
+ }
808
+ .composer textarea {
809
+ max-height: 40vh;
810
+ }
811
+ .statusbar {
812
+ flex-wrap: wrap;
813
+ gap: 4px 10px;
814
+ padding: 6px 12px;
815
+ }
816
+ .statusbar .spacer {
817
+ display: none;
818
+ }
819
+ .empty-brand {
820
+ font-size: clamp(30px, 12vw, 46px);
821
+ }
822
+ .empty-hints {
823
+ gap: 8px 12px;
824
+ }
825
+ .tabbar {
826
+ padding: 8px 10px 0;
827
+ }
828
+ .session-tab {
829
+ max-width: 160px;
830
+ }
831
+ }
832
+
833
+ @media (max-width: 480px) {
834
+ .settings select {
835
+ flex: 1 1 100%;
836
+ }
837
+ .messages {
838
+ padding: 12px 11px 18px;
839
+ }
840
+ }
841
+
842
+ /* settings modal ---------------------------------------------------------- */
843
+ .settings-modal { width: min(430px, calc(100vw - 32px)); }
844
+ .settings-modal .modal-card { gap: 7px; }
845
+ .settings-modal label {
846
+ color: var(--muted);
847
+ font: 600 11px var(--mono);
848
+ letter-spacing: 0.06em;
849
+ text-transform: uppercase;
850
+ }
851
+ .settings-modal select { width: 100%; }
852
+ .settings-modal .check {
853
+ display: flex;
854
+ align-items: center;
855
+ gap: 8px;
856
+ margin-top: 6px;
857
+ color: var(--text);
858
+ font: 500 12.5px var(--sans);
859
+ letter-spacing: 0;
860
+ text-transform: none;
861
+ }
862
+ .settings-actions { margin-top: 10px; }
863
+
864
+ /* command palette --------------------------------------------------------- */
865
+ .palette-modal { width: min(560px, calc(100vw - 24px)); }
866
+ .palette { display: flex; flex-direction: column; }
867
+ .palette-row {
868
+ display: flex;
869
+ align-items: center;
870
+ gap: 10px;
871
+ padding: 12px 14px;
872
+ border-bottom: 1px solid var(--border);
873
+ }
874
+ .palette-ico { width: 18px; height: 18px; color: var(--muted); flex: 0 0 auto; }
875
+ .palette-row input {
876
+ flex: 1;
877
+ min-width: 0;
878
+ border: 0;
879
+ background: transparent;
880
+ padding: 4px 0;
881
+ font-size: 15px;
882
+ box-shadow: none;
883
+ }
884
+ .palette-row input:focus { border: 0; box-shadow: none; }
885
+ .palette-hint {
886
+ color: var(--muted);
887
+ font: 500 10px var(--mono);
888
+ border: 1px solid var(--border);
889
+ border-radius: 5px;
890
+ padding: 2px 5px;
891
+ flex: 0 0 auto;
892
+ }
893
+ .palette-list {
894
+ list-style: none;
895
+ margin: 0;
896
+ padding: 6px;
897
+ max-height: min(52vh, 420px);
898
+ overflow-y: auto;
899
+ }
900
+ .palette-item { padding: 8px 10px; border-radius: 8px; cursor: pointer; }
901
+ .palette-item.active { background: var(--theirs); }
902
+ .palette-item-main { display: flex; align-items: baseline; gap: 10px; min-width: 0; }
903
+ .palette-item-label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
904
+ .palette-item-hint { color: var(--muted); font: 500 11px var(--mono); flex: 0 0 auto; }
905
+ .palette-empty { padding: 14px; color: var(--muted); text-align: center; }
906
+
907
+ /* provider modal ---------------------------------------------------------- */
908
+ dialog.modal {
909
+ width: min(760px, calc(100vw - 40px));
910
+ max-height: calc(100vh - 60px);
911
+ padding: 0;
912
+ border: 1px solid var(--border);
913
+ border-radius: 18px;
914
+ background: var(--solid, var(--panel));
915
+ color: var(--text);
916
+ font: inherit;
917
+ overflow: auto;
918
+ box-shadow: 0 28px 65px rgba(40, 36, 26, 0.28);
919
+ }
920
+ dialog.modal::backdrop { background: rgba(24, 22, 16, 0.55); backdrop-filter: blur(3px); }
921
+ .modal-card { display: flex; flex-direction: column; gap: 12px; padding: 20px; }
922
+ .modal-card h3 { margin: 0; font: 700 17px var(--serif); letter-spacing: -0.02em; }
923
+ .row .spacer { flex: 1; }