aimeat 3.3.1 → 3.3.2

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 (98) hide show
  1. package/dist/.env.example +10 -1
  2. package/dist/build-stamp.json +4 -4
  3. package/dist/locales/en.json +9263 -9225
  4. package/dist/locales/es.json +9255 -9217
  5. package/dist/locales/fi.json +9263 -9225
  6. package/dist/public/css/views/admin.css +935 -860
  7. package/dist/public/css/views/chat.css +393 -388
  8. package/dist/public/js/services/admin.js +12 -0
  9. package/dist/public/robots.node.txt +4 -0
  10. package/dist/public/views/admin/config-tab.js +333 -185
  11. package/dist/public/views/admin/usage-tab.js +373 -307
  12. package/dist/public/views/chat/parts.js +25 -6
  13. package/dist/public/views/profile/landing-page.cards.js +732 -700
  14. package/dist/public/views/profile/landing-page.js +6 -2
  15. package/dist/scripts/audit-mcp-schemas.js +12 -5
  16. package/dist/scripts/audit-mcp-schemas.js.map +1 -1
  17. package/dist/scripts/check-config-coverage.d.ts +2 -0
  18. package/dist/scripts/check-config-coverage.d.ts.map +1 -0
  19. package/dist/scripts/check-config-coverage.js +129 -0
  20. package/dist/scripts/check-config-coverage.js.map +1 -0
  21. package/dist/src/cli/connect/mcp/tools/apps.d.ts.map +1 -1
  22. package/dist/src/cli/connect/mcp/tools/apps.js +102 -20
  23. package/dist/src/cli/connect/mcp/tools/apps.js.map +1 -1
  24. package/dist/src/cli/connect/tool-call-defs-apps.d.ts.map +1 -1
  25. package/dist/src/cli/connect/tool-call-defs-apps.js +103 -96
  26. package/dist/src/cli/connect/tool-call-defs-apps.js.map +1 -1
  27. package/dist/src/cli/connect/tool-call-defs-packages.d.ts +23 -0
  28. package/dist/src/cli/connect/tool-call-defs-packages.d.ts.map +1 -0
  29. package/dist/src/cli/connect/tool-call-defs-packages.js +45 -0
  30. package/dist/src/cli/connect/tool-call-defs-packages.js.map +1 -0
  31. package/dist/src/cli/connect/tool-call-defs-workflows.d.ts +14 -0
  32. package/dist/src/cli/connect/tool-call-defs-workflows.d.ts.map +1 -0
  33. package/dist/src/cli/connect/tool-call-defs-workflows.js +75 -0
  34. package/dist/src/cli/connect/tool-call-defs-workflows.js.map +1 -0
  35. package/dist/src/cli/connect/tool-call.d.ts.map +1 -1
  36. package/dist/src/cli/connect/tool-call.js +4 -0
  37. package/dist/src/cli/connect/tool-call.js.map +1 -1
  38. package/dist/src/config-types-ai.d.ts +13 -0
  39. package/dist/src/config-types-ai.d.ts.map +1 -1
  40. package/dist/src/config.d.ts.map +1 -1
  41. package/dist/src/config.js +2 -0
  42. package/dist/src/config.js.map +1 -1
  43. package/dist/src/generated/api-types.d.ts +40 -0
  44. package/dist/src/generated/api-types.d.ts.map +1 -1
  45. package/dist/src/mcp/annotations.d.ts.map +1 -1
  46. package/dist/src/mcp/annotations.js +8 -0
  47. package/dist/src/mcp/annotations.js.map +1 -1
  48. package/dist/src/mcp/catalog/definitions/organisms-workspaces-apps.d.ts.map +1 -1
  49. package/dist/src/mcp/catalog/definitions/organisms-workspaces-apps.js +25 -8
  50. package/dist/src/mcp/catalog/definitions/organisms-workspaces-apps.js.map +1 -1
  51. package/dist/src/mcp/catalog/definitions/packages.d.ts +17 -0
  52. package/dist/src/mcp/catalog/definitions/packages.d.ts.map +1 -0
  53. package/dist/src/mcp/catalog/definitions/packages.js +46 -0
  54. package/dist/src/mcp/catalog/definitions/packages.js.map +1 -0
  55. package/dist/src/mcp/catalog/definitions.d.ts.map +1 -1
  56. package/dist/src/mcp/catalog/definitions.js +2 -0
  57. package/dist/src/mcp/catalog/definitions.js.map +1 -1
  58. package/dist/src/mcp/catalog/scopes.d.ts.map +1 -1
  59. package/dist/src/mcp/catalog/scopes.js +2 -0
  60. package/dist/src/mcp/catalog/scopes.js.map +1 -1
  61. package/dist/src/mcp/catalog/surfaces.d.ts.map +1 -1
  62. package/dist/src/mcp/catalog/surfaces.js +2 -0
  63. package/dist/src/mcp/catalog/surfaces.js.map +1 -1
  64. package/dist/src/routes/admin-usage.d.ts.map +1 -1
  65. package/dist/src/routes/admin-usage.js +57 -0
  66. package/dist/src/routes/admin-usage.js.map +1 -1
  67. package/dist/src/routes/bootstrap.d.ts +2 -1
  68. package/dist/src/routes/bootstrap.d.ts.map +1 -1
  69. package/dist/src/routes/bootstrap.js +7 -18
  70. package/dist/src/routes/bootstrap.js.map +1 -1
  71. package/dist/src/routes/chat.d.ts +3 -0
  72. package/dist/src/routes/chat.d.ts.map +1 -1
  73. package/dist/src/routes/chat.js +20 -0
  74. package/dist/src/routes/chat.js.map +1 -1
  75. package/dist/src/routes/sitemaps.d.ts +22 -0
  76. package/dist/src/routes/sitemaps.d.ts.map +1 -0
  77. package/dist/src/routes/sitemaps.js +67 -0
  78. package/dist/src/routes/sitemaps.js.map +1 -0
  79. package/dist/src/services/chat-session.d.ts +3 -0
  80. package/dist/src/services/chat-session.d.ts.map +1 -1
  81. package/dist/src/services/chat-session.js +4 -0
  82. package/dist/src/services/chat-session.js.map +1 -1
  83. package/dist/src/services/config-schema.d.ts +4 -0
  84. package/dist/src/services/config-schema.d.ts.map +1 -1
  85. package/dist/src/services/config-schema.js +33 -0
  86. package/dist/src/services/config-schema.js.map +1 -1
  87. package/dist/src/services/goose-acp.d.ts.map +1 -1
  88. package/dist/src/services/goose-acp.js +11 -0
  89. package/dist/src/services/goose-acp.js.map +1 -1
  90. package/dist/src/services/handbooks/appdev.d.ts +1 -1
  91. package/dist/src/services/handbooks/appdev.d.ts.map +1 -1
  92. package/dist/src/services/handbooks/appdev.js +7 -1
  93. package/dist/src/services/handbooks/appdev.js.map +1 -1
  94. package/dist/src/services/usage-summary.d.ts +15 -0
  95. package/dist/src/services/usage-summary.d.ts.map +1 -1
  96. package/dist/src/services/usage-summary.js +15 -0
  97. package/dist/src/services/usage-summary.js.map +1 -1
  98. package/package.json +4 -1
@@ -1,388 +1,393 @@
1
- /**
2
- * @file chat.css
3
- * @description Styles for the chat page: the conversation list, the turns, the work log under each
4
- * one, and the composer. Two panes on a desktop, one at a time on a phone.
5
- *
6
- * The work log is styled to be read, not hidden. It is the evidence that what the agent said it
7
- * did, it did, and folding it away by default would turn the page back into something a person has
8
- * to take on trust. All colours and spacing come from theme.css so it flips with the theme.
9
- *
10
- * NOTE: this file must be linked in spa.html (useViewCSS is a no-op).
11
- * @version-history
12
- * v1.1.0 — 2026-08-16 — The recorder beside the send button, and the read-aloud control on a turn.
13
- * v1.0.0 — 2026-08-16 — Initial.
14
- */
15
-
16
- /* ── Layout ── */
17
- .chat-view {
18
- display: grid;
19
- grid-template-columns: 260px 1fr;
20
- gap: 16px;
21
- max-width: 1100px;
22
- margin: 0 auto;
23
- padding: 16px;
24
- height: calc(100dvh - 120px);
25
- /* Low enough that a short window (a laptop with a docked terminal, 1280x460) still puts the
26
- composer on screen. A taller floor pushed it 70px below the fold, and the composer is the one
27
- control the page exists for. */
28
- min-height: 320px;
29
- }
30
-
31
- .chat-view--signin {
32
- display: block;
33
- height: auto;
34
- }
35
-
36
- /* ── The conversation list ── */
37
- .chat-threads {
38
- display: flex;
39
- flex-direction: column;
40
- gap: 10px;
41
- min-height: 0;
42
- overflow-y: auto;
43
- padding-right: 4px;
44
- }
45
-
46
- .chat-new { width: 100%; }
47
-
48
- /* The way back out of the list. Only a phone needs it: on a desktop the list and the conversation
49
- are both on screen, so there is nothing to go back from. */
50
- .chat-threads-close { display: none; }
51
-
52
- .chat-threads-empty {
53
- color: var(--text-muted);
54
- font-size: 0.85rem;
55
- line-height: 1.5;
56
- margin: 0;
57
- }
58
-
59
- .chat-thread-list {
60
- list-style: none;
61
- margin: 0;
62
- padding: 0;
63
- display: flex;
64
- flex-direction: column;
65
- gap: 4px;
66
- }
67
-
68
- .chat-thread {
69
- display: flex;
70
- align-items: center;
71
- gap: 4px;
72
- border-radius: var(--radius-sm);
73
- }
74
-
75
- .chat-thread--active { background: var(--bg-surface); }
76
-
77
- .chat-thread-open {
78
- flex: 1 1 auto;
79
- min-width: 0;
80
- text-align: left;
81
- background: none;
82
- border: none;
83
- cursor: pointer;
84
- padding: 8px 10px;
85
- display: flex;
86
- flex-direction: column;
87
- gap: 2px;
88
- color: inherit;
89
- font: inherit;
90
- }
91
-
92
- .chat-thread-title {
93
- font-size: 0.9rem;
94
- font-weight: 600;
95
- white-space: nowrap;
96
- overflow: hidden;
97
- text-overflow: ellipsis;
98
- }
99
-
100
- .chat-thread-sub {
101
- font-size: 0.75rem;
102
- color: var(--text-muted);
103
- }
104
-
105
- .chat-thread-del {
106
- flex: 0 0 auto;
107
- padding: 4px 8px;
108
- opacity: 0;
109
- transition: opacity 0.15s;
110
- }
111
-
112
- .chat-thread:hover .chat-thread-del,
113
- .chat-thread--active .chat-thread-del { opacity: 1; }
114
-
115
- /* ── The conversation ── */
116
- .chat-main {
117
- display: flex;
118
- flex-direction: column;
119
- min-height: 0;
120
- background: var(--bg-card);
121
- border: 1px solid var(--border);
122
- border-radius: var(--radius);
123
- overflow: hidden;
124
- }
125
-
126
- .chat-head {
127
- display: flex;
128
- align-items: center;
129
- gap: 10px;
130
- padding: 12px 16px;
131
- border-bottom: 1px solid var(--border-subtle);
132
- }
133
-
134
- .chat-title {
135
- margin: 0;
136
- font-size: 1rem;
137
- font-weight: 600;
138
- white-space: nowrap;
139
- overflow: hidden;
140
- text-overflow: ellipsis;
141
- }
142
-
143
- /* The list is always visible on a desktop, so its toggle would be a button that does nothing. */
144
- .chat-list-toggle { display: none; }
145
-
146
- .chat-status {
147
- display: flex;
148
- align-items: center;
149
- gap: 12px;
150
- flex-wrap: wrap;
151
- padding: 6px 16px;
152
- font-size: 0.75rem;
153
- color: var(--text-muted);
154
- border-bottom: 1px solid var(--border-subtle);
155
- background: var(--bg-surface);
156
- }
157
-
158
- .chat-status-agent { font-family: var(--font-mono); }
159
- .chat-status-reset { margin-left: auto; font-size: 0.75rem; padding: 2px 8px; }
160
-
161
- .chat-scroll {
162
- flex: 1 1 auto;
163
- min-height: 0;
164
- overflow-y: auto;
165
- padding: 16px;
166
- display: flex;
167
- flex-direction: column;
168
- gap: 14px;
169
- }
170
-
171
- .chat-welcome {
172
- color: var(--text-muted);
173
- max-width: 46ch;
174
- margin: auto;
175
- text-align: center;
176
- }
177
-
178
- .chat-welcome h2 {
179
- font-size: 1.1rem;
180
- margin: 0 0 6px;
181
- color: var(--text-primary);
182
- }
183
-
184
- .chat-welcome p { margin: 0; line-height: 1.6; font-size: 0.9rem; }
185
-
186
- /* ── One turn ── */
187
- .chat-turn {
188
- display: flex;
189
- flex-direction: column;
190
- gap: 3px;
191
- max-width: 85%;
192
- }
193
-
194
- .chat-turn--user { align-self: flex-end; align-items: flex-end; }
195
- .chat-turn--agent { align-self: flex-start; }
196
-
197
- .chat-bubble {
198
- padding: 10px 14px;
199
- border-radius: var(--radius);
200
- background: var(--bg-surface);
201
- line-height: 1.6;
202
- font-size: 0.92rem;
203
- overflow-wrap: anywhere;
204
- }
205
-
206
- .chat-turn--user .chat-bubble {
207
- background: var(--accent-subtle);
208
- border: 1px solid var(--accent-border);
209
- }
210
-
211
- .chat-said { margin: 0; white-space: pre-wrap; }
212
-
213
- .chat-thinking {
214
- margin: 0;
215
- color: var(--text-muted);
216
- font-style: italic;
217
- }
218
-
219
- .chat-meta {
220
- display: flex;
221
- gap: 8px;
222
- font-size: 0.7rem;
223
- color: var(--text-muted);
224
- padding: 0 4px;
225
- }
226
-
227
- .chat-model { font-family: var(--font-mono); }
228
-
229
- /* ── The work log ── */
230
- .chat-work {
231
- margin-top: 10px;
232
- border-top: 1px solid var(--border-subtle);
233
- padding-top: 8px;
234
- }
235
-
236
- .chat-work-head {
237
- font-size: 0.7rem;
238
- text-transform: uppercase;
239
- letter-spacing: 0.04em;
240
- color: var(--text-muted);
241
- margin-bottom: 4px;
242
- }
243
-
244
- .chat-work-list {
245
- list-style: none;
246
- margin: 0;
247
- padding: 0;
248
- display: flex;
249
- flex-direction: column;
250
- gap: 2px;
251
- }
252
-
253
- .chat-work-line {
254
- display: flex;
255
- gap: 8px;
256
- align-items: baseline;
257
- font-size: 0.78rem;
258
- font-family: var(--font-mono);
259
- }
260
-
261
- .chat-work-status {
262
- flex: 0 0 auto;
263
- min-width: 68px;
264
- color: var(--text-muted);
265
- }
266
-
267
- .chat-work-line--completed .chat-work-status { color: var(--success, var(--text-secondary)); }
268
- .chat-work-line--failed .chat-work-status { color: var(--accent); }
269
-
270
- .chat-work-title {
271
- min-width: 0;
272
- overflow-wrap: anywhere;
273
- }
274
-
275
- /* ── A turn that could not run ── */
276
- .chat-error {
277
- align-self: stretch;
278
- border: 1px solid var(--accent-border);
279
- background: var(--accent-subtle);
280
- border-radius: var(--radius-sm);
281
- padding: 10px 14px;
282
- display: flex;
283
- align-items: center;
284
- gap: 12px;
285
- flex-wrap: wrap;
286
- }
287
-
288
- .chat-error-msg {
289
- margin: 0;
290
- flex: 1 1 240px;
291
- font-size: 0.85rem;
292
- line-height: 1.5;
293
- }
294
-
295
- /* ── The composer ── */
296
- .chat-composer {
297
- border-top: 1px solid var(--border-subtle);
298
- padding: 10px 16px;
299
- background: var(--bg-card);
300
- }
301
-
302
- .chat-composer-note {
303
- margin: 0 0 6px;
304
- font-size: 0.78rem;
305
- color: var(--text-muted);
306
- line-height: 1.5;
307
- }
308
-
309
- .chat-composer-row {
310
- display: flex;
311
- gap: 8px;
312
- align-items: flex-end;
313
- }
314
-
315
- .chat-input {
316
- flex: 1 1 auto;
317
- min-width: 0;
318
- resize: none;
319
- max-height: 200px;
320
- padding: 10px 12px;
321
- border: 1px solid var(--border);
322
- border-radius: var(--radius-sm);
323
- background: var(--bg-input);
324
- color: inherit;
325
- font: inherit;
326
- font-size: 0.92rem;
327
- line-height: 1.5;
328
- }
329
-
330
- .chat-input:focus {
331
- outline: none;
332
- border-color: var(--border-focus);
333
- background: var(--bg-input-focus);
334
- }
335
-
336
- .chat-send { flex: 0 0 auto; }
337
- .chat-voice { flex: 0 0 auto; }
338
-
339
- /* The read-aloud control sits with the timestamp rather than on the bubble: it is about the turn,
340
- not part of what was said. */
341
- .chat-listen { font-size: 0.7rem; padding: 0 6px; }
342
-
343
- /* ── Phones ──
344
- One pane at a time. The page takes the whole viewport, the shell's sticky nav is hidden (it lives
345
- in a higher stacking context, so a z-index here cannot cover it), and the composer sits on the
346
- keyboard: --chat-avail is the measured visual-viewport height, with 100dvh as the fallback the
347
- viewport meta's interactive-widget=resizes-content already provides. Same pattern as the inbox,
348
- which is the surface this one is modelled on. */
349
- @media (max-width: 760px) {
350
- .chat-view {
351
- position: fixed;
352
- inset: 0;
353
- z-index: 1000;
354
- grid-template-columns: 1fr;
355
- gap: 0;
356
- padding: 0;
357
- max-width: none;
358
- height: var(--chat-avail, 100dvh);
359
- background: var(--bg);
360
- }
361
-
362
- body:has(.chat-view) { overflow: hidden; }
363
- body:has(.chat-view) .topnav { display: none; }
364
-
365
- /* The list is a place you go to, not a column that would leave neither pane readable. */
366
- .chat-threads { display: none; }
367
- .chat-view--list .chat-threads {
368
- display: flex;
369
- padding: 12px;
370
- background: var(--bg-card);
371
- }
372
- .chat-view--list .chat-main { display: none; }
373
-
374
- .chat-list-toggle { display: inline-flex; }
375
- .chat-threads-close { display: inline-flex; align-self: flex-start; }
376
-
377
- .chat-main {
378
- border: none;
379
- border-radius: 0;
380
- height: 100%;
381
- }
382
-
383
- .chat-turn { max-width: 92%; }
384
- .chat-scroll { padding: 12px 10px; }
385
- .chat-composer {
386
- padding: 8px 10px calc(8px + env(safe-area-inset-bottom, 0px));
387
- }
388
- }
1
+ /**
2
+ * @file chat.css
3
+ * @description Styles for the chat page: the conversation list, the turns, the work log under each
4
+ * one, and the composer. Two panes on a desktop, one at a time on a phone.
5
+ *
6
+ * The work log is styled to be read, not hidden. It is the evidence that what the agent said it
7
+ * did, it did, and folding it away by default would turn the page back into something a person has
8
+ * to take on trust. All colours and spacing come from theme.css so it flips with the theme.
9
+ *
10
+ * NOTE: this file must be linked in spa.html (useViewCSS is a no-op).
11
+ * @version-history
12
+ * v1.2.0 — 2026-08-16 — .chat-status-model: which model answered, beside the payer line.
13
+ * v1.1.0 — 2026-08-16 — The recorder beside the send button, and the read-aloud control on a turn.
14
+ * v1.0.0 — 2026-08-16 — Initial.
15
+ */
16
+
17
+ /* ── Layout ── */
18
+ .chat-view {
19
+ display: grid;
20
+ grid-template-columns: 260px 1fr;
21
+ gap: 16px;
22
+ max-width: 1100px;
23
+ margin: 0 auto;
24
+ padding: 16px;
25
+ height: calc(100dvh - 120px);
26
+ /* Low enough that a short window (a laptop with a docked terminal, 1280x460) still puts the
27
+ composer on screen. A taller floor pushed it 70px below the fold, and the composer is the one
28
+ control the page exists for. */
29
+ min-height: 320px;
30
+ }
31
+
32
+ .chat-view--signin {
33
+ display: block;
34
+ height: auto;
35
+ }
36
+
37
+ /* ── The conversation list ── */
38
+ .chat-threads {
39
+ display: flex;
40
+ flex-direction: column;
41
+ gap: 10px;
42
+ min-height: 0;
43
+ overflow-y: auto;
44
+ padding-right: 4px;
45
+ }
46
+
47
+ .chat-new { width: 100%; }
48
+
49
+ /* The way back out of the list. Only a phone needs it: on a desktop the list and the conversation
50
+ are both on screen, so there is nothing to go back from. */
51
+ .chat-threads-close { display: none; }
52
+
53
+ .chat-threads-empty {
54
+ color: var(--text-muted);
55
+ font-size: 0.85rem;
56
+ line-height: 1.5;
57
+ margin: 0;
58
+ }
59
+
60
+ .chat-thread-list {
61
+ list-style: none;
62
+ margin: 0;
63
+ padding: 0;
64
+ display: flex;
65
+ flex-direction: column;
66
+ gap: 4px;
67
+ }
68
+
69
+ .chat-thread {
70
+ display: flex;
71
+ align-items: center;
72
+ gap: 4px;
73
+ border-radius: var(--radius-sm);
74
+ }
75
+
76
+ .chat-thread--active { background: var(--bg-surface); }
77
+
78
+ .chat-thread-open {
79
+ flex: 1 1 auto;
80
+ min-width: 0;
81
+ text-align: left;
82
+ background: none;
83
+ border: none;
84
+ cursor: pointer;
85
+ padding: 8px 10px;
86
+ display: flex;
87
+ flex-direction: column;
88
+ gap: 2px;
89
+ color: inherit;
90
+ font: inherit;
91
+ }
92
+
93
+ .chat-thread-title {
94
+ font-size: 0.9rem;
95
+ font-weight: 600;
96
+ white-space: nowrap;
97
+ overflow: hidden;
98
+ text-overflow: ellipsis;
99
+ }
100
+
101
+ .chat-thread-sub {
102
+ font-size: 0.75rem;
103
+ color: var(--text-muted);
104
+ }
105
+
106
+ .chat-thread-del {
107
+ flex: 0 0 auto;
108
+ padding: 4px 8px;
109
+ opacity: 0;
110
+ transition: opacity 0.15s;
111
+ }
112
+
113
+ .chat-thread:hover .chat-thread-del,
114
+ .chat-thread--active .chat-thread-del { opacity: 1; }
115
+
116
+ /* ── The conversation ── */
117
+ .chat-main {
118
+ display: flex;
119
+ flex-direction: column;
120
+ min-height: 0;
121
+ background: var(--bg-card);
122
+ border: 1px solid var(--border);
123
+ border-radius: var(--radius);
124
+ overflow: hidden;
125
+ }
126
+
127
+ .chat-head {
128
+ display: flex;
129
+ align-items: center;
130
+ gap: 10px;
131
+ padding: 12px 16px;
132
+ border-bottom: 1px solid var(--border-subtle);
133
+ }
134
+
135
+ .chat-title {
136
+ margin: 0;
137
+ font-size: 1rem;
138
+ font-weight: 600;
139
+ white-space: nowrap;
140
+ overflow: hidden;
141
+ text-overflow: ellipsis;
142
+ }
143
+
144
+ /* The list is always visible on a desktop, so its toggle would be a button that does nothing. */
145
+ .chat-list-toggle { display: none; }
146
+
147
+ .chat-status {
148
+ display: flex;
149
+ align-items: center;
150
+ gap: 12px;
151
+ flex-wrap: wrap;
152
+ padding: 6px 16px;
153
+ font-size: 0.75rem;
154
+ color: var(--text-muted);
155
+ border-bottom: 1px solid var(--border-subtle);
156
+ background: var(--bg-surface);
157
+ }
158
+
159
+ .chat-status-agent { font-family: var(--font-mono); }
160
+ /* The model sits beside the payer line, not in place of it: which model answered and whose money
161
+ paid are two different questions and a person checking one still needs the other. */
162
+ .chat-status-model { color: var(--text-dim); }
163
+ .chat-status-elsewhere { color: var(--text-dim); }
164
+ .chat-status-reset { margin-left: auto; font-size: 0.75rem; padding: 2px 8px; }
165
+
166
+ .chat-scroll {
167
+ flex: 1 1 auto;
168
+ min-height: 0;
169
+ overflow-y: auto;
170
+ padding: 16px;
171
+ display: flex;
172
+ flex-direction: column;
173
+ gap: 14px;
174
+ }
175
+
176
+ .chat-welcome {
177
+ color: var(--text-muted);
178
+ max-width: 46ch;
179
+ margin: auto;
180
+ text-align: center;
181
+ }
182
+
183
+ .chat-welcome h2 {
184
+ font-size: 1.1rem;
185
+ margin: 0 0 6px;
186
+ color: var(--text-primary);
187
+ }
188
+
189
+ .chat-welcome p { margin: 0; line-height: 1.6; font-size: 0.9rem; }
190
+
191
+ /* ── One turn ── */
192
+ .chat-turn {
193
+ display: flex;
194
+ flex-direction: column;
195
+ gap: 3px;
196
+ max-width: 85%;
197
+ }
198
+
199
+ .chat-turn--user { align-self: flex-end; align-items: flex-end; }
200
+ .chat-turn--agent { align-self: flex-start; }
201
+
202
+ .chat-bubble {
203
+ padding: 10px 14px;
204
+ border-radius: var(--radius);
205
+ background: var(--bg-surface);
206
+ line-height: 1.6;
207
+ font-size: 0.92rem;
208
+ overflow-wrap: anywhere;
209
+ }
210
+
211
+ .chat-turn--user .chat-bubble {
212
+ background: var(--accent-subtle);
213
+ border: 1px solid var(--accent-border);
214
+ }
215
+
216
+ .chat-said { margin: 0; white-space: pre-wrap; }
217
+
218
+ .chat-thinking {
219
+ margin: 0;
220
+ color: var(--text-muted);
221
+ font-style: italic;
222
+ }
223
+
224
+ .chat-meta {
225
+ display: flex;
226
+ gap: 8px;
227
+ font-size: 0.7rem;
228
+ color: var(--text-muted);
229
+ padding: 0 4px;
230
+ }
231
+
232
+ .chat-model { font-family: var(--font-mono); }
233
+
234
+ /* ── The work log ── */
235
+ .chat-work {
236
+ margin-top: 10px;
237
+ border-top: 1px solid var(--border-subtle);
238
+ padding-top: 8px;
239
+ }
240
+
241
+ .chat-work-head {
242
+ font-size: 0.7rem;
243
+ text-transform: uppercase;
244
+ letter-spacing: 0.04em;
245
+ color: var(--text-muted);
246
+ margin-bottom: 4px;
247
+ }
248
+
249
+ .chat-work-list {
250
+ list-style: none;
251
+ margin: 0;
252
+ padding: 0;
253
+ display: flex;
254
+ flex-direction: column;
255
+ gap: 2px;
256
+ }
257
+
258
+ .chat-work-line {
259
+ display: flex;
260
+ gap: 8px;
261
+ align-items: baseline;
262
+ font-size: 0.78rem;
263
+ font-family: var(--font-mono);
264
+ }
265
+
266
+ .chat-work-status {
267
+ flex: 0 0 auto;
268
+ min-width: 68px;
269
+ color: var(--text-muted);
270
+ }
271
+
272
+ .chat-work-line--completed .chat-work-status { color: var(--success, var(--text-secondary)); }
273
+ .chat-work-line--failed .chat-work-status { color: var(--accent); }
274
+
275
+ .chat-work-title {
276
+ min-width: 0;
277
+ overflow-wrap: anywhere;
278
+ }
279
+
280
+ /* ── A turn that could not run ── */
281
+ .chat-error {
282
+ align-self: stretch;
283
+ border: 1px solid var(--accent-border);
284
+ background: var(--accent-subtle);
285
+ border-radius: var(--radius-sm);
286
+ padding: 10px 14px;
287
+ display: flex;
288
+ align-items: center;
289
+ gap: 12px;
290
+ flex-wrap: wrap;
291
+ }
292
+
293
+ .chat-error-msg {
294
+ margin: 0;
295
+ flex: 1 1 240px;
296
+ font-size: 0.85rem;
297
+ line-height: 1.5;
298
+ }
299
+
300
+ /* ── The composer ── */
301
+ .chat-composer {
302
+ border-top: 1px solid var(--border-subtle);
303
+ padding: 10px 16px;
304
+ background: var(--bg-card);
305
+ }
306
+
307
+ .chat-composer-note {
308
+ margin: 0 0 6px;
309
+ font-size: 0.78rem;
310
+ color: var(--text-muted);
311
+ line-height: 1.5;
312
+ }
313
+
314
+ .chat-composer-row {
315
+ display: flex;
316
+ gap: 8px;
317
+ align-items: flex-end;
318
+ }
319
+
320
+ .chat-input {
321
+ flex: 1 1 auto;
322
+ min-width: 0;
323
+ resize: none;
324
+ max-height: 200px;
325
+ padding: 10px 12px;
326
+ border: 1px solid var(--border);
327
+ border-radius: var(--radius-sm);
328
+ background: var(--bg-input);
329
+ color: inherit;
330
+ font: inherit;
331
+ font-size: 0.92rem;
332
+ line-height: 1.5;
333
+ }
334
+
335
+ .chat-input:focus {
336
+ outline: none;
337
+ border-color: var(--border-focus);
338
+ background: var(--bg-input-focus);
339
+ }
340
+
341
+ .chat-send { flex: 0 0 auto; }
342
+ .chat-voice { flex: 0 0 auto; }
343
+
344
+ /* The read-aloud control sits with the timestamp rather than on the bubble: it is about the turn,
345
+ not part of what was said. */
346
+ .chat-listen { font-size: 0.7rem; padding: 0 6px; }
347
+
348
+ /* ── Phones ──
349
+ One pane at a time. The page takes the whole viewport, the shell's sticky nav is hidden (it lives
350
+ in a higher stacking context, so a z-index here cannot cover it), and the composer sits on the
351
+ keyboard: --chat-avail is the measured visual-viewport height, with 100dvh as the fallback the
352
+ viewport meta's interactive-widget=resizes-content already provides. Same pattern as the inbox,
353
+ which is the surface this one is modelled on. */
354
+ @media (max-width: 760px) {
355
+ .chat-view {
356
+ position: fixed;
357
+ inset: 0;
358
+ z-index: 1000;
359
+ grid-template-columns: 1fr;
360
+ gap: 0;
361
+ padding: 0;
362
+ max-width: none;
363
+ height: var(--chat-avail, 100dvh);
364
+ background: var(--bg);
365
+ }
366
+
367
+ body:has(.chat-view) { overflow: hidden; }
368
+ body:has(.chat-view) .topnav { display: none; }
369
+
370
+ /* The list is a place you go to, not a column that would leave neither pane readable. */
371
+ .chat-threads { display: none; }
372
+ .chat-view--list .chat-threads {
373
+ display: flex;
374
+ padding: 12px;
375
+ background: var(--bg-card);
376
+ }
377
+ .chat-view--list .chat-main { display: none; }
378
+
379
+ .chat-list-toggle { display: inline-flex; }
380
+ .chat-threads-close { display: inline-flex; align-self: flex-start; }
381
+
382
+ .chat-main {
383
+ border: none;
384
+ border-radius: 0;
385
+ height: 100%;
386
+ }
387
+
388
+ .chat-turn { max-width: 92%; }
389
+ .chat-scroll { padding: 12px 10px; }
390
+ .chat-composer {
391
+ padding: 8px 10px calc(8px + env(safe-area-inset-bottom, 0px));
392
+ }
393
+ }