@haikit/client 0.7.0 → 0.9.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.
package/src/hai.css CHANGED
@@ -6,226 +6,595 @@
6
6
  *
7
7
  * It deliberately does not style the inside of your surfaces. Your components
8
8
  * emit their own class names and your own stylesheet owns them — otherwise the
9
- * framework starts dictating what your UI looks like.
9
+ * framework starts dictating what your UI looks like. They can use the tokens,
10
+ * though: --hai-hover and --hai-selected are there for rows and pickers.
10
11
  *
11
- * Everything is driven by custom properties. Override them in your own sheet:
12
+ * Light and dark, following the system. Every colour is a custom property set
13
+ * here at zero specificity, so a plain `:root` rule in your own sheet wins.
14
+ * Give one value per scheme with light-dark(), behind a plain dark value for
15
+ * the browsers that fall back to dark below:
12
16
  *
13
- * :root { --hai-accent: #b07cff; --hai-bg: #101014; }
17
+ * :root { --hai-accent: #b07cff; }
18
+ * @supports (color: light-dark(#000, #fff)) {
19
+ * :root { --hai-accent: light-dark(#6d28d9, #b07cff); }
20
+ * }
21
+ *
22
+ * <html data-hai-theme="dark"> pins the page to one scheme, as does
23
+ * `mountChat({ theme: "dark" })`. The pin is on the root because the tokens
24
+ * are: a minifier that lowers light-dark() resolves them there.
14
25
  */
15
26
 
16
- :root {
17
- --hai-bg: #0d1013;
18
- --hai-panel: #14181d;
19
- --hai-panel-2: #11161c;
20
- --hai-line: #242c34;
21
- --hai-fg: #dde3ea;
22
- --hai-dim: #7c8894;
23
- --hai-accent: #6ea8fe;
24
- --hai-good: #63c49a;
25
- --hai-warn: #e0b055;
26
- --hai-bad: #e07070;
27
- --hai-radius: 10px;
28
- --hai-mono: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
29
- --hai-sans: ui-sans-serif, system-ui, -apple-system, sans-serif;
27
+ :where(:root) {
28
+ color-scheme: light dark;
29
+
30
+ --hai-bg: light-dark(#f6f7f9, #0c0f13);
31
+ --hai-panel: light-dark(#ffffff, #141920);
32
+ --hai-panel-2: light-dark(#f9fafb, #10141a);
33
+ --hai-line: light-dark(#e1e5ea, #252c35);
34
+ --hai-fg: light-dark(#161b22, #e3e8ee);
35
+ --hai-dim: light-dark(#5b6675, #8a95a3);
36
+ --hai-accent: light-dark(#2160e0, #7aa7ff);
37
+ --hai-on-accent: light-dark(#ffffff, #0b1220);
38
+ --hai-good: light-dark(#127a4c, #5ec597);
39
+ --hai-warn: light-dark(#9a5b00, #e7b65c);
40
+ --hai-bad: light-dark(#c23338, #f07b7b);
41
+ --hai-user-bg: light-dark(#e7eefb, #1e2835);
42
+ --hai-code-bg: light-dark(#f3f5f8, #0a0d11);
43
+ --hai-shadow: 0 1px 2px light-dark(rgb(15 23 42 / .06), rgb(0 0 0 / .35));
44
+
45
+ /* tints, derived — override the colour and these follow */
46
+ --hai-line-soft: color-mix(in srgb, var(--hai-line) 60%, transparent);
47
+ --hai-hover: color-mix(in srgb, var(--hai-fg) 6%, transparent);
48
+ --hai-selected: color-mix(in srgb, var(--hai-good) 15%, transparent);
49
+ --hai-accent-soft: color-mix(in srgb, var(--hai-accent) 14%, transparent);
50
+ --hai-good-soft: color-mix(in srgb, var(--hai-good) 13%, transparent);
51
+ --hai-warn-soft: color-mix(in srgb, var(--hai-warn) 12%, transparent);
52
+ --hai-bad-soft: color-mix(in srgb, var(--hai-bad) 12%, transparent);
53
+
54
+ --hai-radius: 12px;
55
+ --hai-mono: ui-monospace, "SF Mono", "Cascadia Code", Menlo, Consolas, monospace;
56
+ --hai-sans: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
57
+ --hai-column: 780px;
30
58
  --hai-inspector-width: 400px;
31
59
  }
32
60
 
61
+ :where(:root[data-hai-theme="light"]) { color-scheme: light; }
62
+ :where(:root[data-hai-theme="dark"]) { color-scheme: dark; }
63
+
64
+ /* A browser without light-dark() gets the dark scheme, not no colours at all. */
65
+ @supports not (color: light-dark(#000, #fff)) {
66
+ :where(:root) {
67
+ color-scheme: dark;
68
+ --hai-bg: #0c0f13;
69
+ --hai-panel: #141920;
70
+ --hai-panel-2: #10141a;
71
+ --hai-line: #252c35;
72
+ --hai-fg: #e3e8ee;
73
+ --hai-dim: #8a95a3;
74
+ --hai-accent: #7aa7ff;
75
+ --hai-on-accent: #0b1220;
76
+ --hai-good: #5ec597;
77
+ --hai-warn: #e7b65c;
78
+ --hai-bad: #f07b7b;
79
+ --hai-user-bg: #1e2835;
80
+ --hai-code-bg: #0a0d11;
81
+ --hai-shadow: 0 1px 2px rgb(0 0 0 / .35);
82
+ }
83
+ }
84
+
85
+ /* the shell is the page */
86
+ :where(body:has(.hai-shell)) { margin: 0; }
87
+
33
88
  /* ── shell ──────────────────────────────────────────────────────────── */
34
89
  .hai-shell {
35
90
  height: 100vh;
91
+ height: 100dvh;
36
92
  display: flex;
37
93
  flex-direction: column;
38
94
  background: var(--hai-bg);
39
95
  color: var(--hai-fg);
40
- font: 14px/1.55 var(--hai-sans);
96
+ font: 14px/1.5 var(--hai-sans);
97
+ -webkit-font-smoothing: antialiased;
41
98
  }
99
+
100
+ .hai-icon { width: 16px; height: 16px; flex: none; }
101
+
42
102
  .hai-top {
103
+ flex: none;
43
104
  display: flex;
44
- align-items: baseline;
105
+ align-items: center;
45
106
  gap: 12px;
46
- padding: 10px 16px;
107
+ height: 52px;
108
+ padding: 0 10px 0 16px;
47
109
  border-bottom: 1px solid var(--hai-line);
48
110
  background: var(--hai-panel);
49
111
  }
50
- .hai-title { font-weight: 700; letter-spacing: .04em; }
51
- .hai-subtitle { color: var(--hai-dim); font-size: 12px; }
52
- .hai-model { margin-left: auto; font: 11px var(--hai-mono); color: var(--hai-warn); }
112
+ .hai-brand { display: flex; align-items: center; gap: 10px; min-width: 0; }
113
+ .hai-mark { width: 22px; height: 22px; color: var(--hai-accent); }
114
+ .hai-title { font-size: 15px; font-weight: 650; letter-spacing: -.01em; white-space: nowrap; }
115
+ .hai-subtitle {
116
+ color: var(--hai-dim);
117
+ font-size: 13px;
118
+ padding-left: 10px;
119
+ border-left: 1px solid var(--hai-line);
120
+ overflow: hidden;
121
+ text-overflow: ellipsis;
122
+ white-space: nowrap;
123
+ }
53
124
 
54
- .hai-main { flex: 1; display: grid; grid-template-columns: minmax(0, 1fr); min-height: 0; }
55
- .hai-main.has-inspector { grid-template-columns: minmax(0, 1fr) var(--hai-inspector-width); }
56
- .hai-chat { display: flex; flex-direction: column; min-height: 0; }
125
+ .hai-actions { margin-left: auto; display: flex; align-items: center; gap: 4px; flex: none; }
126
+ .hai-model {
127
+ display: inline-flex;
128
+ align-items: center;
129
+ gap: 6px;
130
+ margin-right: 6px;
131
+ padding: 3px 9px;
132
+ border: 1px solid var(--hai-line);
133
+ border-radius: 999px;
134
+ font: 11.5px var(--hai-mono);
135
+ color: var(--hai-dim);
136
+ }
137
+ .hai-model::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: var(--hai-good); }
138
+ .hai-model[hidden] { display: none; }
139
+
140
+ .hai-btn {
141
+ display: inline-flex;
142
+ align-items: center;
143
+ gap: 7px;
144
+ height: 32px;
145
+ padding: 0 10px;
146
+ border: none;
147
+ border-radius: 8px;
148
+ background: none;
149
+ color: var(--hai-dim);
150
+ font: inherit;
151
+ font-size: 13px;
152
+ font-weight: 500;
153
+ cursor: pointer;
154
+ }
155
+ .hai-btn:hover:not(:disabled) { background: var(--hai-hover); color: var(--hai-fg); }
156
+ .hai-btn:disabled { opacity: .4; cursor: default; }
157
+ .hai-btn[aria-expanded="true"] { color: var(--hai-fg); background: var(--hai-hover); }
158
+ .hai-ctx-count { font: 11.5px var(--hai-mono); color: var(--hai-dim); }
159
+ .hai-ctx-count:empty { display: none; }
57
160
 
58
- .hai-transcript { flex: 1; overflow-y: auto; padding: 18px 20px 8px; }
59
- .hai-empty { color: var(--hai-dim); max-width: 60ch; }
60
- .hai-suggestions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 14px; }
161
+ .hai-icon-btn {
162
+ display: grid;
163
+ place-items: center;
164
+ width: 30px;
165
+ height: 30px;
166
+ border: none;
167
+ border-radius: 8px;
168
+ background: none;
169
+ color: var(--hai-dim);
170
+ cursor: pointer;
171
+ }
172
+ .hai-icon-btn:hover { background: var(--hai-hover); color: var(--hai-fg); }
173
+
174
+ /* clips the drawer while it waits off the right edge */
175
+ .hai-main { flex: 1; display: grid; grid-template-columns: minmax(0, 1fr); min-height: 0; position: relative; overflow: hidden; }
176
+
177
+ /* the conversation is a centred column; the scrollbar stays at the edge */
178
+ .hai-chat {
179
+ --hai-gutter: max(16px, calc((100% - var(--hai-column)) / 2));
180
+ display: flex;
181
+ flex-direction: column;
182
+ min-width: 0;
183
+ min-height: 0;
184
+ transition: margin-right .25s cubic-bezier(.2, .8, .2, 1), opacity .25s;
185
+ }
186
+ /* behind the drawer on a narrow screen, out of reach until it closes */
187
+ .hai-chat[inert] { opacity: .4; }
188
+ /* on a wide screen the chat makes room for the open drawer */
189
+ @media (min-width: 900px) {
190
+ .hai-main.inspector-open > .hai-chat { margin-right: var(--hai-inspector-width); }
191
+ }
192
+ .hai-transcript {
193
+ flex: 1;
194
+ overflow-y: auto;
195
+ padding: 28px var(--hai-gutter) 8px;
196
+ scrollbar-width: thin;
197
+ scrollbar-color: var(--hai-line) transparent;
198
+ }
199
+
200
+ /* ── empty state ────────────────────────────────────────────────────── */
201
+ .hai-empty { color: var(--hai-dim); }
202
+ .hai-empty p { margin: 0; max-width: 54ch; font-size: 15px; line-height: 1.6; }
203
+ .hai-empty-mark {
204
+ width: 28px;
205
+ height: 28px;
206
+ padding: 12px;
207
+ margin-bottom: 18px;
208
+ border-radius: 16px;
209
+ background: var(--hai-accent-soft);
210
+ color: var(--hai-accent);
211
+ }
212
+ /* alone, it greets; after what init showed, it stays out of the way */
213
+ .hai-empty:first-child {
214
+ display: flex;
215
+ flex-direction: column;
216
+ align-items: center;
217
+ text-align: center;
218
+ padding-top: clamp(24px, 14vh, 140px);
219
+ }
220
+ .hai-empty:not(:first-child) .hai-empty-mark { display: none; }
221
+
222
+ .hai-suggestions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 20px; }
223
+ .hai-empty:first-child .hai-suggestions { justify-content: center; }
224
+ .hai-empty:not(:first-child) .hai-suggestions { margin-top: 12px; }
61
225
  .hai-suggestion {
62
- background: var(--hai-panel-2);
63
- color: var(--hai-fg);
226
+ padding: 7px 14px;
64
227
  border: 1px solid var(--hai-line);
65
228
  border-radius: 999px;
66
- padding: 5px 12px;
67
- cursor: pointer;
229
+ background: var(--hai-panel);
230
+ color: var(--hai-fg);
68
231
  font: inherit;
69
- font-size: 13px;
232
+ font-size: 13.5px;
233
+ cursor: pointer;
234
+ transition: border-color .15s, background-color .15s;
70
235
  }
71
- .hai-suggestion:hover { border-color: var(--hai-accent); }
236
+ .hai-suggestion:hover { border-color: var(--hai-accent); background: var(--hai-accent-soft); }
72
237
 
73
238
  /* ── transcript blocks ──────────────────────────────────────────────── */
74
- .hai-block { margin: 0 0 12px; max-width: 70ch; }
239
+ .hai-block { margin: 0 0 18px; }
240
+ .hai-user .hai-body,
241
+ .hai-assistant .hai-body {
242
+ white-space: pre-wrap;
243
+ overflow-wrap: anywhere;
244
+ /* each paragraph takes its own direction: a reply can mix scripts */
245
+ unicode-bidi: plaintext;
246
+ font-size: 15px;
247
+ }
248
+ .hai-assistant { max-width: 72ch; line-height: 1.65; }
249
+ .hai-user { display: flex; justify-content: flex-end; }
75
250
  .hai-user .hai-body {
76
- background: #1d2733;
77
- border: 1px solid #27333f;
78
- border-radius: var(--hai-radius);
79
- padding: 8px 12px;
80
- display: inline-block;
251
+ max-width: min(85%, 62ch);
252
+ padding: 9px 14px;
253
+ border-radius: 18px 18px 6px 18px;
254
+ background: var(--hai-user-bg);
81
255
  }
82
- .hai-assistant .hai-body { white-space: pre-wrap; }
83
- .hai-interaction {
256
+
257
+ /* an answer given in a surface — it went back to the model as the tool result */
258
+ .hai-interaction { display: flex; align-items: flex-start; gap: 10px; max-width: 72ch; font-size: 13.5px; color: var(--hai-dim); }
259
+ .hai-arrow {
260
+ flex: none;
261
+ display: grid;
262
+ place-items: center;
263
+ width: 22px;
264
+ height: 22px;
265
+ margin-top: -1px;
266
+ border-radius: 50%;
267
+ background: var(--hai-good-soft);
84
268
  color: var(--hai-good);
85
- font-size: 13px;
269
+ }
270
+ .hai-arrow .hai-icon { width: 13px; height: 13px; }
271
+
272
+ .hai-error,
273
+ .hai-expired {
86
274
  display: flex;
87
- gap: 8px;
88
- border-left: 2px solid var(--hai-good);
89
- padding-left: 10px;
275
+ align-items: flex-start;
276
+ gap: 10px;
277
+ padding: 11px 14px;
278
+ border: 1px solid;
279
+ border-radius: var(--hai-radius);
90
280
  }
91
- .hai-error { color: var(--hai-bad); font: 12px var(--hai-mono); }
281
+ .hai-error .hai-icon,
282
+ .hai-expired .hai-icon { margin-top: 2px; }
283
+ .hai-error {
284
+ border-color: color-mix(in srgb, var(--hai-bad) 35%, transparent);
285
+ background: var(--hai-bad-soft);
286
+ color: var(--hai-bad);
287
+ font: 12.5px/1.55 var(--hai-mono);
288
+ }
289
+ .hai-error .hai-body { overflow-wrap: anywhere; }
92
290
 
93
291
  /* tool provenance row — chrome for the surface directly beneath it */
94
292
  .hai-tool {
95
293
  border: 1px solid var(--hai-line);
96
- border-radius: var(--hai-radius) var(--hai-radius) 0 0;
97
- background: var(--hai-panel);
98
- max-width: none;
99
- margin-bottom: 0;
294
+ border-radius: var(--hai-radius);
295
+ background: var(--hai-panel-2);
296
+ overflow: hidden;
100
297
  }
298
+ .hai-tool:has(+ .hai-surface) { margin-bottom: 0; border-bottom-left-radius: 0; border-bottom-right-radius: 0; }
101
299
  .hai-tool summary {
102
300
  display: flex;
103
301
  align-items: center;
104
- gap: 8px;
302
+ gap: 9px;
303
+ min-height: 36px;
105
304
  padding: 7px 12px;
305
+ box-sizing: border-box;
106
306
  cursor: pointer;
107
- font: 12px var(--hai-mono);
108
307
  list-style: none;
308
+ font-size: 12.5px;
309
+ user-select: none;
109
310
  }
110
311
  .hai-tool summary::-webkit-details-marker { display: none; }
111
- .hai-gear { color: var(--hai-dim); }
112
- .hai-tname { color: var(--hai-accent); }
113
- .hai-targs { color: var(--hai-dim); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1; }
114
- .hai-tstatus { color: var(--hai-dim); }
115
- .hai-status-awaiting .hai-tstatus { color: var(--hai-warn); }
312
+ .hai-tool summary:hover { background: var(--hai-hover); }
313
+ .hai-ticon { flex: none; display: grid; place-items: center; width: 16px; height: 16px; color: var(--hai-dim); }
314
+ .hai-ticon .hai-icon { width: 14px; height: 14px; }
315
+ .hai-tname { font: 500 12.5px var(--hai-mono); }
316
+ .hai-targs {
317
+ flex: 1;
318
+ min-width: 0;
319
+ overflow: hidden;
320
+ text-overflow: ellipsis;
321
+ white-space: nowrap;
322
+ font: 12px var(--hai-mono);
323
+ color: var(--hai-dim);
324
+ }
325
+ .hai-tstatus { color: var(--hai-dim); white-space: nowrap; font-variant-numeric: tabular-nums; }
326
+ .hai-chevron { width: 14px; height: 14px; color: var(--hai-dim); transition: transform .15s; }
327
+ .hai-tool[open] .hai-chevron { transform: rotate(90deg); }
328
+
329
+ .hai-status-ok .hai-ticon { color: var(--hai-good); }
116
330
  .hai-status-running .hai-tstatus { color: var(--hai-accent); }
117
- .hai-tool-detail { padding: 0 12px 10px; border-top: 1px solid var(--hai-line); }
118
- .hai-label { font: 11px var(--hai-mono); color: var(--hai-dim); margin: 8px 0 4px; }
331
+ .hai-status-awaiting .hai-tstatus { color: var(--hai-warn); }
332
+ .hai-status-error .hai-ticon,
333
+ .hai-status-error .hai-tstatus { color: var(--hai-bad); }
334
+ /* the component is the question: the turn is parked on it */
335
+ .hai-tool.hai-status-awaiting { background: var(--hai-warn-soft); }
336
+ .hai-tool.hai-status-awaiting,
337
+ .hai-tool.hai-status-awaiting + .hai-surface { border-color: color-mix(in srgb, var(--hai-warn) 45%, var(--hai-line)); }
338
+
339
+ .hai-tool-detail { padding: 0 12px 12px; border-top: 1px solid var(--hai-line); }
340
+ .hai-label { margin: 10px 0 5px; font: 11px var(--hai-mono); color: var(--hai-dim); }
341
+ .hai-code,
119
342
  .hai-digest {
120
343
  margin: 0;
121
- padding: 8px 10px;
122
- background: #0b0e11;
344
+ padding: 9px 11px;
345
+ max-height: 200px;
346
+ overflow: auto;
123
347
  border: 1px solid var(--hai-line);
124
- border-radius: 6px;
125
- font: 11.5px/1.5 var(--hai-mono);
126
- color: var(--hai-good);
348
+ border-radius: 8px;
349
+ background: var(--hai-code-bg);
350
+ font: 12px/1.55 var(--hai-mono);
127
351
  white-space: pre-wrap;
128
- max-height: 180px;
129
- overflow: auto;
352
+ overflow-wrap: anywhere;
353
+ }
354
+ .hai-digest { color: var(--hai-good); }
355
+
356
+ .hai-spinner {
357
+ width: 12px;
358
+ height: 12px;
359
+ box-sizing: border-box;
360
+ border: 2px solid var(--hai-accent-soft);
361
+ border-top-color: var(--hai-accent);
362
+ border-radius: 50%;
363
+ animation: hai-spin .8s linear infinite;
364
+ }
365
+ .hai-pulse {
366
+ flex: none;
367
+ width: 8px;
368
+ height: 8px;
369
+ border-radius: 50%;
370
+ background: var(--hai-warn);
371
+ animation: hai-pulse 1.8s ease-out infinite;
130
372
  }
131
373
 
132
374
  /* surface container — your component mounts inside this */
133
375
  .hai-surface {
134
- border: 1px solid var(--hai-line);
135
- border-top: none;
136
- border-radius: 0 0 var(--hai-radius) var(--hai-radius);
137
- background: var(--hai-panel-2);
138
- margin-bottom: 14px;
376
+ margin-bottom: 18px;
139
377
  overflow: hidden;
378
+ border: 1px solid var(--hai-line);
379
+ border-radius: var(--hai-radius);
380
+ background: var(--hai-panel);
381
+ box-shadow: var(--hai-shadow);
382
+ }
383
+ .hai-tool + .hai-surface { border-top: none; border-top-left-radius: 0; border-top-right-radius: 0; }
384
+ .hai-skeleton { display: grid; gap: 9px; padding: 14px; }
385
+ .hai-skeleton-label { margin-bottom: 2px; font: 12px var(--hai-mono); color: var(--hai-dim); }
386
+ .hai-shimmer {
387
+ height: 10px;
388
+ border-radius: 5px;
389
+ background: linear-gradient(90deg, var(--hai-hover), var(--hai-line), var(--hai-hover)) 0 0 / 200% 100%;
390
+ animation: hai-shimmer 1.4s ease-in-out infinite;
391
+ }
392
+ .hai-shimmer:nth-child(3) { width: 82%; }
393
+ .hai-shimmer:nth-child(4) { width: 60%; }
394
+ .hai-surface-error {
395
+ margin-bottom: 18px;
396
+ padding: 11px 14px;
397
+ border: 1px solid color-mix(in srgb, var(--hai-bad) 35%, transparent);
398
+ border-radius: var(--hai-radius);
399
+ background: var(--hai-bad-soft);
400
+ color: var(--hai-bad);
401
+ font: 12.5px var(--hai-mono);
140
402
  }
141
- .hai-skeleton, .hai-surface-error { padding: 14px; font: 12px var(--hai-mono); color: var(--hai-dim); }
142
- .hai-surface-error { color: var(--hai-bad); }
143
403
 
144
404
  /* out of date — the runtime has made the surface inert; this only shows it */
145
405
  .hai-surface[data-expired] { opacity: .45; filter: grayscale(.7); }
146
406
  .hai-expired {
147
- display: flex;
148
407
  flex-wrap: wrap;
149
408
  align-items: center;
150
- gap: 10px 14px;
151
- padding: 10px 12px;
152
- border: 1px solid var(--hai-warn);
153
- border-radius: var(--hai-radius);
409
+ gap: 10px 12px;
410
+ border-color: color-mix(in srgb, var(--hai-warn) 45%, transparent);
411
+ background: var(--hai-warn-soft);
154
412
  color: var(--hai-warn);
155
413
  }
414
+ .hai-expired .hai-icon { margin-top: 0; }
156
415
  .hai-expired .hai-body { flex: 1 1 30ch; }
157
416
  .hai-new {
158
- background: var(--hai-warn);
159
- color: var(--hai-bg);
417
+ padding: 7px 14px;
160
418
  border: none;
161
419
  border-radius: 8px;
162
- padding: 6px 14px;
420
+ background: var(--hai-warn);
421
+ color: var(--hai-on-accent);
163
422
  font: inherit;
164
423
  font-weight: 600;
165
424
  cursor: pointer;
166
425
  }
167
426
 
168
427
  /* ── status + composer ──────────────────────────────────────────────── */
169
- .hai-status { padding: 0 20px 4px; font-size: 12px; min-height: 18px; color: var(--hai-dim); }
428
+ .hai-status {
429
+ display: flex;
430
+ align-items: center;
431
+ gap: 8px;
432
+ min-height: 22px;
433
+ padding: 0 var(--hai-gutter) 6px;
434
+ font-size: 12.5px;
435
+ color: var(--hai-dim);
436
+ }
170
437
  .hai-status[data-status="awaiting"] { color: var(--hai-warn); }
171
- .hai-composer { display: flex; gap: 8px; padding: 10px 20px 16px; border-top: 1px solid var(--hai-line); }
438
+ .hai-dots { display: inline-flex; gap: 3px; }
439
+ .hai-dots i { width: 5px; height: 5px; border-radius: 50%; background: currentColor; animation: hai-blink 1.2s infinite both; }
440
+ .hai-dots i:nth-child(2) { animation-delay: .2s; }
441
+ .hai-dots i:nth-child(3) { animation-delay: .4s; }
442
+
443
+ .hai-composer { flex: none; padding: 0 var(--hai-gutter) 18px; }
444
+ .hai-composer-box {
445
+ display: flex;
446
+ align-items: flex-end;
447
+ gap: 8px;
448
+ padding: 7px 7px 7px 14px;
449
+ border: 1px solid var(--hai-line);
450
+ border-radius: 16px;
451
+ background: var(--hai-panel);
452
+ box-shadow: var(--hai-shadow);
453
+ transition: border-color .15s, box-shadow .15s;
454
+ }
455
+ .hai-composer-box:focus-within { border-color: var(--hai-accent); box-shadow: 0 0 0 3px var(--hai-accent-soft); }
172
456
  .hai-input {
173
457
  flex: 1;
458
+ box-sizing: border-box;
459
+ min-height: 34px;
460
+ max-height: 200px;
461
+ padding: 6px 0;
462
+ overflow-y: auto;
174
463
  resize: none;
175
- background: var(--hai-panel);
464
+ border: none;
465
+ outline: none;
466
+ background: transparent;
176
467
  color: var(--hai-fg);
177
- border: 1px solid var(--hai-line);
178
- border-radius: 8px;
179
- padding: 9px 12px;
180
468
  font: inherit;
181
- min-height: 38px;
182
- max-height: 180px;
469
+ font-size: 15px;
470
+ line-height: 1.45;
183
471
  }
184
- .hai-input:focus { outline: none; border-color: var(--hai-accent); }
185
- .hai-input:disabled { opacity: .5; }
472
+ .hai-input::placeholder { color: var(--hai-dim); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
473
+ .hai-input:disabled { cursor: not-allowed; opacity: .6; }
186
474
  .hai-send {
187
- background: var(--hai-accent);
188
- color: var(--hai-bg);
475
+ flex: none;
476
+ display: grid;
477
+ place-items: center;
478
+ width: 34px;
479
+ height: 34px;
189
480
  border: none;
190
- border-radius: 8px;
191
- padding: 0 18px;
192
- font: inherit;
193
- font-weight: 600;
481
+ border-radius: 10px;
482
+ background: var(--hai-accent);
483
+ color: var(--hai-on-accent);
194
484
  cursor: pointer;
485
+ transition: opacity .15s;
195
486
  }
196
- .hai-send:disabled { opacity: .4; cursor: default; }
487
+ .hai-send .hai-icon { width: 18px; height: 18px; }
488
+ .hai-send:disabled { opacity: .35; cursor: default; }
197
489
 
198
- /* ── context inspector ──────────────────────────────────────────────── */
490
+ /* ── model context debug drawer ─────────────────────────────────────── */
491
+ /* Closed, it waits off the right edge, out of the tab order and the
492
+ accessibility tree; open, it slides in, over the chat on a narrow screen. */
199
493
  .hai-inspector {
200
- border-left: 1px solid var(--hai-line);
201
- background: var(--hai-panel-2);
494
+ position: absolute;
495
+ inset: 0 0 0 auto;
496
+ z-index: 10;
202
497
  display: flex;
203
498
  flex-direction: column;
499
+ width: min(100%, var(--hai-inspector-width));
204
500
  min-height: 0;
501
+ border-left: 1px solid var(--hai-line);
502
+ background: var(--hai-panel-2);
503
+ box-shadow: -16px 0 32px -12px rgb(0 0 0 / .25);
504
+ transform: translateX(100%);
505
+ visibility: hidden;
506
+ transition: transform .25s cubic-bezier(.2, .8, .2, 1), visibility 0s .25s;
205
507
  }
206
- .hai-inspector-title { padding: 10px 14px; border-bottom: 1px solid var(--hai-line); font-size: 12px; font-weight: 600; }
207
- .hai-inspector-title span { color: var(--hai-dim); font-weight: 400; }
208
- .hai-inspector-body { flex: 1; overflow-y: auto; padding: 12px 14px; }
209
- .hai-ctx-bar {
210
- display: flex;
211
- flex-direction: column;
212
- gap: 3px;
213
- margin-bottom: 14px;
214
- padding: 10px;
215
- border: 1px solid var(--hai-line);
216
- border-radius: 8px;
217
- background: var(--hai-bg);
218
- font: 11.5px var(--hai-mono);
508
+ .hai-main.inspector-open > .hai-inspector {
509
+ transform: none;
510
+ visibility: visible;
511
+ transition: transform .25s cubic-bezier(.2, .8, .2, 1), visibility 0s;
512
+ }
513
+ .hai-inspector-head { display: flex; align-items: center; gap: 8px; padding: 10px 10px 10px 16px; border-bottom: 1px solid var(--hai-line); }
514
+ .hai-inspector-title { flex: 1; display: flex; flex-direction: column; font-size: 13px; font-weight: 600; }
515
+ .hai-inspector-title span { color: var(--hai-dim); font-size: 12px; font-weight: 400; }
516
+ .hai-inspector-body {
517
+ flex: 1;
518
+ overflow-y: auto;
519
+ padding: 0 16px 16px;
520
+ scrollbar-width: thin;
521
+ scrollbar-color: var(--hai-line) transparent;
522
+ }
523
+ .hai-inspector-empty { margin: 16px 0; color: var(--hai-dim); font-size: 13px; }
524
+
525
+ /* the numbers stay in view as the context scrolls under them */
526
+ .hai-ctx {
527
+ position: sticky;
528
+ top: 0;
529
+ z-index: 1;
530
+ padding: 14px 0 12px;
531
+ border-bottom: 1px solid var(--hai-line);
532
+ background: var(--hai-panel-2);
533
+ }
534
+ .hai-ctx-headline { display: flex; align-items: baseline; gap: 8px; margin-bottom: 8px; font-size: 12.5px; color: var(--hai-dim); }
535
+ .hai-ctx-pct { font-size: 26px; font-weight: 650; letter-spacing: -.02em; color: var(--hai-good); font-variant-numeric: tabular-nums; }
536
+ .hai-meter { display: flex; height: 6px; margin-bottom: 10px; overflow: hidden; border-radius: 3px; background: var(--hai-good); }
537
+ .hai-meter-model { min-width: 2px; background: var(--hai-accent); }
538
+ .hai-ctx-stat { display: flex; justify-content: space-between; padding: 1px 0; font: 12px var(--hai-mono); }
539
+ .hai-ctx-label { display: inline-flex; align-items: center; gap: 7px; color: var(--hai-dim); }
540
+ .hai-ctx-tok { font-variant-numeric: tabular-nums; }
541
+ .hai-key { width: 8px; height: 8px; border-radius: 2px; }
542
+ .hai-key-model { background: var(--hai-accent); }
543
+ .hai-key-ui { background: var(--hai-good); }
544
+
545
+ .hai-msg { margin-top: 14px; padding-left: 11px; border-left: 2px solid var(--hai-line); }
546
+ .hai-role { margin-bottom: 4px; font: 600 10px var(--hai-mono); text-transform: uppercase; letter-spacing: .08em; color: var(--hai-dim); }
547
+ .hai-mbody { display: grid; gap: 6px; font: 12px/1.55 var(--hai-mono); white-space: pre-wrap; overflow-wrap: anywhere; }
548
+ .hai-tu,
549
+ .hai-tr { padding: 6px 8px; border-radius: 6px; }
550
+ .hai-tu { background: var(--hai-accent-soft); color: var(--hai-accent); }
551
+ .hai-tr { background: var(--hai-good-soft); color: var(--hai-good); }
552
+ .hai-kind { display: block; margin-bottom: 2px; font-size: 10.5px; opacity: .75; }
553
+
554
+ /* ── narrow screens ─────────────────────────────────────────────────── */
555
+ @media (max-width: 899.98px) {
556
+ .hai-subtitle { display: none; }
557
+ .hai-btn { padding: 0 8px; }
558
+ .hai-btn-label {
559
+ position: absolute;
560
+ width: 1px;
561
+ height: 1px;
562
+ overflow: hidden;
563
+ clip-path: inset(50%);
564
+ white-space: nowrap;
565
+ }
566
+ }
567
+ @media (max-width: 599.98px) {
568
+ .hai-model { display: none; }
569
+ .hai-transcript { padding-top: 18px; }
570
+ .hai-composer { padding-bottom: 12px; }
219
571
  }
220
- .hai-stat-dim { color: var(--hai-dim); }
221
- .hai-stat-good { color: var(--hai-good); }
222
- .hai-msg { margin-bottom: 10px; border-left: 2px solid var(--hai-line); padding-left: 9px; }
223
- .hai-role { font: 10px var(--hai-mono); text-transform: uppercase; color: var(--hai-dim); letter-spacing: .07em; }
224
- .hai-mbody { font: 11.5px/1.5 var(--hai-mono); white-space: pre-wrap; word-break: break-word; }
225
- .hai-tu { color: var(--hai-accent); }
226
- .hai-tr { color: var(--hai-good); }
227
-
228
- @media (max-width: 900px) {
229
- .hai-main.has-inspector { grid-template-columns: minmax(0, 1fr); }
230
- .hai-inspector { display: none; }
572
+
573
+ /* ── focus, motion ──────────────────────────────────────────────────── */
574
+ .hai-btn:focus-visible,
575
+ .hai-icon-btn:focus-visible,
576
+ .hai-send:focus-visible,
577
+ .hai-suggestion:focus-visible,
578
+ .hai-new:focus-visible { outline: 2px solid var(--hai-accent); outline-offset: 2px; }
579
+ .hai-tool summary:focus-visible { outline: 2px solid var(--hai-accent); outline-offset: -2px; }
580
+
581
+ @keyframes hai-spin { to { transform: rotate(360deg); } }
582
+ @keyframes hai-pulse {
583
+ 0% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--hai-warn) 55%, transparent); }
584
+ 100% { box-shadow: 0 0 0 7px transparent; }
585
+ }
586
+ @keyframes hai-blink { 0%, 80%, 100% { opacity: .25; } 40% { opacity: 1; } }
587
+ @keyframes hai-shimmer { from { background-position: 100% 0; } to { background-position: -100% 0; } }
588
+
589
+ @media (prefers-reduced-motion: reduce) {
590
+ .hai-spinner,
591
+ .hai-pulse,
592
+ .hai-dots i,
593
+ .hai-shimmer { animation: none; }
594
+ .hai-chevron,
595
+ .hai-suggestion,
596
+ .hai-composer-box,
597
+ .hai-chat,
598
+ .hai-inspector,
599
+ .hai-main.inspector-open > .hai-inspector { transition: none; }
231
600
  }