File size: 145,276 Bytes
a1b6014
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
3142
3143
3144
3145
3146
3147
3148
3149
3150
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
3328
3329
3330
3331
3332
3333
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351
3352
3353
3354
3355
3356
3357
3358
3359
3360
3361
3362
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
3389
3390
3391
3392
3393
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430
3431
3432
3433
3434
3435
3436
3437
3438
3439
3440
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
3473
3474
3475
3476
3477
3478
3479
3480
3481
3482
3483
3484
3485
3486
3487
3488
3489
3490
3491
3492
3493
3494
3495
3496
3497
3498
3499
3500
3501
3502
3503
3504
3505
3506
3507
3508
3509
3510
3511
3512
3513
3514
3515
3516
3517
3518
3519
3520
3521
3522
3523
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
3557
3558
3559
3560
3561
3562
3563
3564
3565
3566
3567
3568
3569
3570
3571
3572
3573
3574
3575
3576
3577
3578
3579
3580
3581
3582
3583
@import 'tailwindcss';
@plugin '@tailwindcss/typography';
@import 'tw-shimmer';
@import 'katex/dist/katex.min.css';
@import '@vscode/codicons/dist/codicon.css';

/* Titlebar clusters: 24Γ—24 hit targets, 13.9px glyphs. codicon.css is
   unlayered (`font: 16px/1`); Tailwind utilities in @layer lose that fight. */
.titlebar-icon-button .codicon[class*='codicon-'] {
  font-size: var(--titlebar-icon-size);
}

/* v4 gates hover: on @media (hover: hover). Some Windows hosts with a
   digitizer answer false even with a mouse, so hover-reveal controls stay
   opacity-0 (clickable, invisible). Trust :hover itself. */
@custom-variant hover (&:hover);
@custom-variant dark (&:is(.dark *));

/* Blanket reduced-motion override: kill ALL CSS animations and transitions
   when the user (or the E2E test harness via prefers-reduced-motion) requests
   it. Per-component @media rules below handle specific cases; this catches
   everything else so overlays and loading bars resolve instantly instead of
   being caught mid-fade by a screenshot. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* Pause continuous animations only when the window is hidden/minimized, not
   merely unfocused. main.tsx owns this attribute for the primary window;
   wake/pet overlays retain their purpose-built visibility behavior. */
:root[data-renderer-animations-paused]
  :is(
    .shimmer,
    .quest-glow,
    .pet-egg,
    .pet-egg__glow,
    .pet-egg-shadow,
    .pet-wobble,
    .progress-slide,
    .kanban-arc,
    .glyph-spinner__strip
  ),
:root[data-renderer-animations-paused] .arc-border::before,
:root[data-renderer-animations-paused]
  [data-slot='aui_assistant-message-content']
  .aui-md
  [data-slot='code-card'][data-streaming='true'] {
  animation-play-state: paused !important;
}

/* Sidebar sections: tall viewports give each its own scroller; compact ones
   (this variant) flatten everything into one shared scroll. See ChatSidebar. */
@custom-variant compact (@media (max-height: 768px));

@font-face {
  font-family: 'Collapse';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('../../../node_modules/@nous-research/ui/dist/fonts/Collapse-Bold.woff2') format('woff2');
}

/* JetBrains Mono β€” bundled terminal font (Apache-2.0) so bold/italic share the
   regular face's metrics instead of squeezing against a system fallback. */
@font-face {
  font-family: 'JetBrains Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('./fonts/JetBrainsMono-Regular.woff2') format('woff2');
}
@font-face {
  font-family: 'JetBrains Mono';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('./fonts/JetBrainsMono-Bold.woff2') format('woff2');
}
@font-face {
  font-family: 'JetBrains Mono';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url('./fonts/JetBrainsMono-Italic.woff2') format('woff2');
}

@theme inline {
  --color-background: var(--dt-background);
  --color-foreground: var(--dt-foreground);
  --color-card: var(--dt-card);
  --color-card-foreground: var(--dt-card-foreground);
  --color-muted: var(--dt-muted);
  --color-muted-foreground: var(--dt-muted-foreground);
  --color-popover: var(--dt-popover);
  --color-popover-foreground: var(--dt-popover-foreground);
  --color-primary: var(--dt-primary);
  --color-primary-foreground: var(--dt-primary-foreground);
  --color-secondary: var(--dt-secondary);
  --color-secondary-foreground: var(--dt-secondary-foreground);
  --color-accent: var(--dt-accent);
  --color-accent-foreground: var(--dt-accent-foreground);
  --color-border: var(--dt-border);
  --color-input: var(--dt-input);
  --color-ring: var(--dt-ring);
  --color-destructive: var(--dt-destructive);
  --color-destructive-foreground: var(--dt-destructive-foreground);

  --color-midground: var(--dt-midground);
  --color-midground-foreground: var(--dt-midground-foreground);

  --font-sans: var(--dt-font-sans);
  --font-mono: var(--dt-font-mono);

  --spacing-mul: var(--dt-spacing-mul, 1);

  --radius-xs: calc(var(--radius-scalar) * 0.125rem);
  --radius-sm: calc(var(--radius-scalar) * 0.5rem);
  --radius-md: calc(var(--radius-scalar) * 0.625rem);
  --radius-lg: calc(var(--radius-scalar) * 0.75rem);
  --radius-xl: calc(var(--radius-scalar) * 1rem);
  --radius-2xl: calc(var(--radius-scalar) * 1.5rem);
  --radius-3xl: calc(var(--radius-scalar) * 2rem);
  --radius-4xl: calc(var(--radius-scalar) * 2.5rem);

  --color-sidebar-ring: var(--sidebar-ring);
  --color-sidebar-border: var(--sidebar-border);
  --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
  --color-sidebar-accent: var(--sidebar-accent);
  --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
  --color-sidebar-primary: var(--sidebar-primary);
  --color-sidebar-foreground: var(--sidebar-foreground);
  --color-sidebar: var(--sidebar);

  --shadow-xs: 0 0.0625rem 0.125rem color-mix(in srgb, #000 5%, transparent);
  --shadow-sm:
    0 0 0 0.0625rem color-mix(in srgb, var(--dt-foreground) 6%, transparent),
    0 0.125rem 0.5rem color-mix(in srgb, #000 4%, transparent);
  --shadow-md:
    0 0 0 0.0625rem color-mix(in srgb, var(--dt-foreground) 8%, transparent),
    0 0.25rem 1rem color-mix(in srgb, #000 8%, transparent),
    0 1rem 2rem -1.5rem color-mix(in srgb, #000 18%, transparent);
  /* Soft floating shadow for borderless modals/overlays. Single top light
     source: every layer is centered (x=0) and cast downward, with negative
     spread that grows with the blur so each layer is pulled horizontally inward
     β€” the shadow pools below the panel instead of bleeding out every side.
     Layered (contact β†’ ambient) for a smooth, natural falloff. */
  --shadow-nous:
    0 0.125rem 0.25rem -0.125rem color-mix(in srgb, #000 7%, transparent),
    0 0.5rem 0.75rem -0.375rem color-mix(in srgb, #000 6%, transparent),
    0 1.25rem 1.75rem -0.875rem color-mix(in srgb, #000 6%, transparent),
    0 2.25rem 3rem -1.75rem color-mix(in srgb, #000 0%, transparent);
  /* Hairline border paired with --shadow-nous on borderless overlays.
     currentColor resolves per-element, so it adapts to text color/theme. */
  --stroke-nous: color-mix(in srgb, currentColor 3%, transparent);
  --shadow-lg:
    inset 0 0.0625rem 0 color-mix(in srgb, #fff 28%, transparent),
    0 0 0 0.0625rem color-mix(in srgb, var(--dt-foreground) 8%, transparent),
    0 0.75rem 2rem color-mix(in srgb, #000 12%, transparent);
  --shadow-composer: 0 0.0625rem 0.125rem color-mix(in srgb, #000 5%, transparent);
}

@layer base {
  :root {
    color-scheme: light;

    --theme-foreground: #17171a;
    --theme-primary: #0053fd;
    --theme-secondary: color-mix(in srgb, #0053fd 7%, #ffffff);
    --theme-accent-soft: color-mix(in srgb, #0053fd 10%, #ffffff);
    --theme-midground: #0053fd;
    --theme-warm: #cf806d;
    --theme-background-seed: #f8faff;
    --theme-sidebar-seed: #f3f7ff;
    --theme-card-seed: #ffffff;
    --theme-elevated-seed: #ffffff;
    --theme-bubble-seed: color-mix(in srgb, #0053fd 6%, #ffffff);
    --theme-neutral-chrome: #f3f3f3;
    --theme-neutral-sidebar: #f3f3f3;
    --theme-neutral-card: #fcfcfc;
    --theme-mix-chrome: 92%;
    --theme-mix-sidebar: 100%;
    --theme-mix-card: 22%;
    --theme-mix-elevated: 28%;
    --theme-mix-bubble: 0%;
    --theme-fill-primary-accent-mix: 16%;
    --theme-fill-secondary-accent-mix: 11%;
    --theme-fill-tertiary-accent-mix: 8%;
    --theme-fill-quaternary-accent-mix: 5%;
    --theme-fill-quinary-accent-mix: 3%;
    --theme-stroke-primary-accent-mix: 24%;
    --theme-stroke-secondary-accent-mix: 16%;
    --theme-stroke-tertiary-accent-mix: 10%;
    --theme-stroke-quaternary-accent-mix: 6%;
    --theme-row-hover-accent-mix: 4%;
    --theme-row-active-accent-mix: 8%;
    --theme-control-hover-accent-mix: 6%;
    --theme-control-active-accent-mix: 8%;

    --ui-base: var(--theme-foreground);
    --ui-accent: var(--theme-midground);
    --ui-accent-secondary: var(--theme-primary);
    --ui-warm: var(--theme-warm);
    --ui-red: #cf2d56;
    --ui-orange: #db704b;
    --ui-yellow: #c08532;
    --ui-green: #1f8a65;
    --ui-cyan: #4c7f8c;
    --ui-blue: #0053fd;
    --ui-purple: #9e94d5;
    --context-usage-system: color-mix(in srgb, var(--ui-base) 55%, transparent);
    --context-usage-tools: var(--ui-purple);
    --context-usage-rules: var(--ui-green);
    --context-usage-skills: var(--ui-yellow);
    --context-usage-mcp: color-mix(in srgb, var(--ui-red) 72%, var(--ui-purple));
    --context-usage-subagents: color-mix(in srgb, var(--ui-blue) 70%, var(--ui-cyan));
    --context-usage-memory: color-mix(in srgb, var(--ui-orange) 80%, var(--ui-yellow));
    --context-usage-conversation: var(--ui-cyan);
    /* Landed memory-write tool row β€” gold β†’ purple, never amber warning. */
    --tool-memory-legendary-from: color-mix(in srgb, var(--ui-yellow) 72%, #f5d08a);
    --tool-memory-legendary-mid: color-mix(in srgb, var(--ui-orange) 55%, var(--ui-purple));
    --tool-memory-legendary-to: color-mix(in srgb, var(--ui-purple) 82%, #c4b5fd);
    --tool-memory-legendary-icon: color-mix(in srgb, var(--ui-yellow) 55%, var(--ui-purple));
    --tool-memory-legendary-meta: color-mix(in srgb, var(--ui-purple) 58%, var(--ui-text-tertiary));
    --tool-memory-legendary-glow: color-mix(in srgb, var(--ui-purple) 38%, transparent);
    /* Diff add/remove, derived from the semantic palette so every diff surface
       (tool cards, preview, review pane) tracks the theme's green/red. Only the
       foregrounds need a dark override β€” they mix toward the page instead of
       away from it. */
    --ui-diff-add-border: var(--ui-green);
    --ui-diff-add-background: color-mix(in srgb, var(--ui-green) 12%, transparent);
    --ui-diff-add-foreground: color-mix(in srgb, var(--ui-green) 70%, #000);
    --ui-diff-remove-border: var(--ui-red);
    --ui-diff-remove-background: color-mix(in srgb, var(--ui-red) 12%, transparent);
    --ui-diff-remove-foreground: color-mix(in srgb, var(--ui-red) 70%, #000);

    /* Overlay ladder. DESIGN.md: app-wide surfaces must not compete through
       ad-hoc z-index literals β€” pick the rung that describes the surface.
       Values are deliberately sparse so a one-off can slot between two rungs
       without a renumber. Local stacking inside a component (a sticky header
       over its own scroll area) stays on plain `z-10`/`z-20`; these rungs are
       only for surfaces that float over the app. */
    --z-modal-backdrop: 120;
    --z-modal: 130;
    /* A select/dropdown/popover opened from inside a modal, portaled to body. */
    --z-modal-popover: 140;
    /* Must clear any open modal: toasts, tooltips, command-surface backdrops. */
    --z-over-modal: 200;
    --z-over-modal-content: 210;
    --z-switcher-backdrop: 219;
    --z-switcher: 220;
    /* Boot and blocking states, in the order they can stack. */
    --z-connecting: 1200;
    --z-onboarding: 1300;
    --z-onboarding-popover: 1310;
    --z-setup: 1400;
    --z-crash: 1500;
    --ui-bg-chrome: color-mix(
      in srgb,
      var(--theme-background-seed) var(--theme-mix-chrome),
      var(--theme-neutral-chrome)
    );
    --ui-bg-sidebar: color-mix(
      in srgb,
      var(--theme-sidebar-seed) var(--theme-mix-sidebar),
      var(--theme-neutral-sidebar)
    );
    --ui-bg-editor: color-mix(in srgb, var(--theme-card-seed) var(--theme-mix-card), var(--theme-neutral-card));
    --ui-bg-elevated: color-mix(
      in srgb,
      var(--theme-elevated-seed) var(--theme-mix-elevated),
      var(--theme-neutral-card)
    );
    --ui-bg-card: color-mix(in srgb, var(--ui-accent) 4%, color-mix(in srgb, var(--ui-base) 4%, transparent));
    --ui-bg-input: #fcfcfc;
    --ui-bg-primary: color-mix(
      in srgb,
      var(--ui-accent) var(--theme-fill-primary-accent-mix),
      color-mix(in srgb, var(--ui-base) 10%, transparent)
    );
    --ui-bg-secondary: color-mix(
      in srgb,
      var(--ui-accent) var(--theme-fill-secondary-accent-mix),
      color-mix(in srgb, var(--ui-base) 7%, transparent)
    );
    --ui-bg-tertiary: color-mix(
      in srgb,
      var(--ui-accent) var(--theme-fill-tertiary-accent-mix),
      color-mix(in srgb, var(--ui-base) 5%, transparent)
    );
    --ui-bg-quaternary: color-mix(
      in srgb,
      var(--ui-accent) var(--theme-fill-quaternary-accent-mix),
      color-mix(in srgb, var(--ui-base) 4%, transparent)
    );
    --ui-bg-quinary: color-mix(
      in srgb,
      var(--ui-accent) var(--theme-fill-quinary-accent-mix),
      color-mix(in srgb, var(--ui-base) 3%, transparent)
    );
    --ui-row-hover-background: color-mix(
      in srgb,
      var(--ui-accent) var(--theme-row-hover-accent-mix),
      color-mix(in srgb, var(--ui-base) 3%, transparent)
    );
    --ui-row-active-background: color-mix(
      in srgb,
      var(--ui-accent) var(--theme-row-active-accent-mix),
      color-mix(in srgb, var(--ui-base) 5%, transparent)
    );
    /* Open in a pane, but not the FOCUSED one: the active band at reduced
       strength, so every session on screen is marked and the one you're in
       still wins. Mixed from the active token so a theme tunes both at once. */
    --ui-row-open-background: color-mix(in srgb, var(--ui-row-active-background) 28%, transparent);
    --ui-control-hover-background: color-mix(
      in srgb,
      var(--ui-accent) var(--theme-control-hover-accent-mix),
      color-mix(in srgb, var(--ui-base) 4%, transparent)
    );
    --ui-control-active-background: color-mix(
      in srgb,
      var(--ui-accent) var(--theme-control-active-accent-mix),
      color-mix(in srgb, var(--ui-base) 5%, transparent)
    );
    --ui-text-primary: color-mix(in srgb, var(--ui-base) 94%, transparent);
    --ui-text-secondary: color-mix(in srgb, var(--ui-base) 74%, transparent);
    --ui-text-tertiary: color-mix(in srgb, var(--ui-base) 54%, transparent);
    --ui-text-quaternary: color-mix(in srgb, var(--ui-base) 36%, transparent);
    /* Transcript scaffolding β€” thinking headers, settled tool runs, the live
       activity ticker. One colour for all of them (see `ScaffoldRow`), pitched
       between the secondary and tertiary greys those lines used to pick
       individually, and dimmed once more by the fade rule below so the prose
       reading column stays primary. */
    --conversation-scaffold-text: color-mix(in srgb, var(--ui-base) 64%, transparent);
    --conversation-scaffold-meta: color-mix(in srgb, var(--ui-base) 44%, transparent);
    --ui-stroke-primary: color-mix(
      in srgb,
      var(--ui-accent) var(--theme-stroke-primary-accent-mix),
      color-mix(in srgb, var(--ui-base) 10%, transparent)
    );
    --ui-stroke-secondary: color-mix(
      in srgb,
      var(--ui-accent) var(--theme-stroke-secondary-accent-mix),
      color-mix(in srgb, var(--ui-base) 7%, transparent)
    );
    --ui-stroke-tertiary: color-mix(
      in srgb,
      var(--ui-accent) var(--theme-stroke-tertiary-accent-mix),
      color-mix(in srgb, var(--ui-base) 5%, transparent)
    );
    --ui-stroke-quaternary: color-mix(
      in srgb,
      var(--ui-accent) var(--theme-stroke-quaternary-accent-mix),
      color-mix(in srgb, var(--ui-base) 3%, transparent)
    );
    --ui-sash-hover-border: color-mix(in srgb, var(--ui-accent) 18%, var(--ui-stroke-tertiary));
    --ui-sash-hover-background: color-mix(in srgb, var(--ui-accent) 6%, transparent);
    --ui-surface-background: var(--ui-bg-editor);
    --ui-sidebar-surface-background: var(--ui-bg-sidebar);
    --ui-chat-surface-background: var(--ui-bg-chrome);
    --ui-editor-surface-background: var(--ui-bg-chrome);
    /* The integrated terminal wears the transcript's background, not the
       editor's β€” it reads as part of the conversation surface. Its own token so
       the two can diverge without dragging the terminal along, and so a skin
       gets one knob for it. xterm's canvas can't use a var, so the probe in
       terminal/selection.ts resolves this same name to a concrete rgb. */
    --ui-terminal-surface-background: var(--ui-chat-surface-background);
    /* Inline chat widgets (clarify, artifact card) β€” the card fill in light
       mode, nudged down in dark so a widget settles into the transcript
       instead of glowing above it (see the `.dark` override). */
    --ui-widget-surface-background: var(--ui-bg-editor);
    --ui-chat-bubble-background: color-mix(
      in srgb,
      var(--theme-bubble-seed) var(--theme-mix-bubble),
      var(--theme-neutral-card)
    );
    --ui-chat-bubble-opaque-background: var(--ui-bg-editor);
    --ui-inline-code-background: color-mix(in srgb, #141414 5%, transparent);
    --ui-inline-code-foreground: color-mix(in srgb, #141414 88%, transparent);
    --ui-selection-background: color-mix(in srgb, #ffd24a 55%, transparent);

    --dt-background: var(--ui-bg-chrome);
    --dt-foreground: var(--ui-text-primary);
    --dt-card: var(--ui-bg-editor);
    --dt-card-foreground: var(--ui-text-primary);
    --dt-muted: var(--ui-bg-tertiary);
    --dt-muted-foreground: var(--ui-text-tertiary);
    --dt-popover: color-mix(in srgb, var(--ui-bg-elevated) 96%, transparent);
    --dt-popover-foreground: var(--ui-text-primary);
    --dt-primary: var(--theme-primary);
    --dt-primary-foreground: #fcfcfc;
    /* Boot-paint fallbacks. themes/context.tsx replaces --dt-primary-solid with
       the hue deepened until #fcfcfc clears AA on it; until it runs, the raw
       primary is the closest honest guess. */
    --dt-primary-solid: var(--theme-primary);
    --dt-primary-solid-foreground: #fcfcfc;
    --dt-secondary: var(--theme-secondary);
    --dt-secondary-foreground: var(--ui-text-secondary);
    --dt-accent: var(--theme-accent-soft);
    --dt-accent-foreground: var(--ui-text-primary);
    --dt-border: var(--ui-stroke-secondary);
    --dt-input: var(--ui-stroke-primary);
    /* THE single knob for input-field borders: the resting alpha (% of the ring
       color). Hover doubles it; focus/open go full. 0% = invisible at rest. */
    --dt-input-border: 7%;
    /* Knob for input-field background fill: alpha (% of --dt-card) across all
       states. 100% = fully opaque, lower = translucent over the blurred chrome. */
    --dt-input-bg: 0%;
    /* Classic recessed "inset" β€” a crisp 1px inner shadow at the TOP edge.
       :root.dark bumps the alpha since a dark card swallows shadow. Removed on
       focus (the focus border carries the state). */
    --dt-input-inset: inset 0 1px 1px color-mix(in srgb, #000 10%, transparent);
    /* Hovered inactive tab: deepen it AWAY from the lighter active surface, so
       hover can never be mistaken for selected. Dark mode needs more β€” black
       over a dark gutter shows less. */
    --ui-tab-hover-darken: 2.5%;
    --dt-ring: var(--ui-stroke-primary);
    --dt-midground: var(--theme-midground);
    /* Scrollbars carry no theme colour: the accent-tinted thumb read as a
       coloured element in the corner of every list. Same lightness as the
       midground so each theme still gets a thumb that sits right against its
       own surfaces β€” chroma 0 is the only thing removed. */
    --dt-scrollbar-thumb: oklch(from var(--dt-midground) l 0 h);
    --dt-composer-ring: var(--ui-base);
    --dt-destructive: #cf2d56;
    --dt-destructive-foreground: #ffffff;
    --dt-sidebar-bg: var(--ui-bg-sidebar);
    --dt-sidebar-border: var(--ui-stroke-secondary);
    /* `--user-bubble-keep` is the Settings β†’ Appearance β†’ Message Bubble lever
       (store/user-bubble-transparency.ts): the share of the theme's bubble
       fill to keep. Unset at the default, so the mix is a no-op and the bubble
       is the theme's fill exactly as before. The border stays put either way β€”
       at full transparency the outline is what still marks your turn. */
    --dt-user-bubble: color-mix(in srgb, var(--ui-chat-bubble-background) var(--user-bubble-keep, 100%), transparent);
    --dt-user-bubble-border: var(--ui-stroke-tertiary);

    --dt-font-sans:
      'Segoe WPC', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'SF Pro Text', system-ui, sans-serif,
      'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji', emoji;
    /* Key caps always use the native UI face β€” never theme typography overrides. */
    --dt-font-kbd: -apple-system, BlinkMacSystemFont, 'SF Pro Text', 'Segoe UI', system-ui, sans-serif;
    /* Menlo/Monaco first β€” Apple's native monospace faces β€” so code/diff read
       in the system mono on macOS, with SF Mono and bundled Courier Prime as
       fallbacks. */
    --dt-font-mono:
      Menlo, Monaco, 'SF Mono', 'Courier Prime', monospace, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol',
      'Noto Color Emoji', emoji;
    --dt-base-size: 1rem;
    --dt-line-height: 1.5;
    --dt-letter-spacing: 0;
    --dt-spacing-mul: 1;

    --radius: 0.75rem;
    /* Effective value everywhere: the chat backdrop used to force 0.2 onto the
       root element at runtime (an ungated leva slider default), so this 0.6
       only ever applied to the windows that don't mount the backdrop. Pinned
       to the value the app actually renders at. */
    --radius-scalar: 0.2;

    /* Space under last message vs overlay composer β€” driven by the measured composer DOCK height (see
       composer/index.tsx), which covers the micro-action strip, the status stack, the composer, and the
       underside strip in one number.
       This is the default; each chat surface re-declares the calc against its own measurement (see below). */
    --thread-last-message-clearance: calc(var(--composer-measured-height) + 2rem);

    --composer-shell-pad-block-end: 0.625rem;
    --message-text-indent: 0.75rem;
    --conversation-text-font-size: 0.8125rem;
    --conversation-tool-font-size: 0.6875rem;
    --conversation-caption-font-size: 0.75rem;
    --conversation-line-height: 1.125rem;
    --conversation-caption-line-height: 1rem;
    --conversation-turn-gap: 0.375rem;
    /* Gap between top-level turn blocks (prose ↔ tools ↔ thinking) β€” enough air
       that scaffolding reads as separate from the reply, not crammed into it. */
    --turn-block-gap: 0.75rem;
    /* Between adjacent scaffolding, though: a back-to-back run of thinking
       headers and tool rows is one sequence, not blocks to hold apart. Derived
       so retuning the block gap carries it along. */
    --scaffold-block-gap: calc(var(--turn-block-gap) / 3);
    /* Tight gap between tool rows inside a single action group, so a back-to-back
       run still reads as one cohesive sequence. */
    --tool-row-gap: 0.375rem;
    /* Resting opacity of a disclosure caret β€” invisible until hover, except
       where a surface opts into a faint hint of the affordance. */
    --disclosure-caret-rest: 0;
    /* Paragraph spacing β€” vertical gap between prose paragraphs, both inside a
       markdown block and between consecutive prose parts. Single knob; tweak
       freely. */
    --paragraph-gap: 0.7rem;
    --sticky-human-top: 0.23rem;
    --file-tree-row-height: 1.375rem;

    --composer-width: 100%;
    --composer-control-size: 1.5rem;
    --composer-control-primary-size: 1.625rem;
    --composer-control-gap: 0.25rem;
    --composer-row-gap: 0.25rem;
    --composer-ring-strength: 1;
    --composer-surface-pad-x: 0.5rem;
    --composer-surface-pad-y: 0.3125rem;
    --composer-input-min-height: 1.625rem;
    --composer-input-max-height: 9.375rem;
    --composer-input-inline-min-width: 8rem;
    --composer-fallback-height: 2.75rem;
    --composer-measured-height: calc(0.5rem + var(--composer-shell-pad-block-end) + var(--composer-fallback-height));
    --composer-surface-measured-height: var(--composer-fallback-height);
    --thread-viewport-height: max(
      0rem,
      calc(100% - var(--composer-measured-height) + var(--composer-surface-measured-height))
    );
    --vsq: min(0.5vh, 0.5vw);
    --image-preview-max-width: 34rem;
    --image-preview-height: clamp(16.25rem, calc(var(--vsq) * 100), 26.25rem);

    --sidebar-width: 14.8125rem;
    --chat-min-width: 28rem;
    --titlebar-control-size: 24px;
    --titlebar-control-height: 24px;
    --titlebar-icon-size: 13.9px;
    --sidebar-content-inline-padding: 1rem;

    --sidebar: var(--dt-sidebar-bg);
    --sidebar-foreground: var(--dt-foreground);
    --sidebar-primary: var(--dt-primary);
    --sidebar-primary-foreground: var(--dt-primary-foreground);
    --sidebar-accent: var(--ui-control-active-background);
    --sidebar-accent-foreground: var(--dt-accent-foreground);
    --sidebar-border: var(--dt-sidebar-border);
    --sidebar-ring: var(--dt-ring);
    --sidebar-edge-border: color-mix(in srgb, var(--ui-base) 7.5%, transparent);
    --chrome-action-hover: var(--ui-control-hover-background);

    --midground: var(--dt-midground);
    --background: var(--dt-background);
    --foreground: var(--dt-foreground);

    --warm-glow: color-mix(in srgb, var(--ui-warm) 32%, color-mix(in srgb, var(--ui-accent) 6%, transparent));
    /* `--noise-opacity-mul` is set per-mode by `applyTheme()`. */
    --noise-opacity-mul: 1;
    --backdrop-invert-mul: 1;
  }

  :root.dark {
    /* Per-mode mix knobs β€” overridden inline by `applyTheme()` per skin. */
    --theme-mix-chrome: 74%;
    --theme-mix-card: 38%;
    --theme-mix-elevated: 46%;
    --theme-mix-bubble: 46%;
    --theme-neutral-chrome: #0d0d0e;
    --theme-neutral-sidebar: #0a0a0b;
    --theme-neutral-card: #161618;

    /* Dark-only accent palette overrides. */
    --ui-red: #e75e78;
    --ui-green: #55a583;
    --ui-cyan: #6f9ba6;
    --ui-diff-add-foreground: color-mix(in srgb, var(--ui-green) 62%, #fff);
    --ui-diff-remove-foreground: color-mix(in srgb, var(--ui-red) 62%, #fff);

    --sidebar-edge-border: color-mix(in srgb, var(--ui-base) 12%, transparent);
    --composer-ring-strength: 1.3;
    --backdrop-invert-mul: 0;
    /* Dark mode: a dark card needs a stronger black inset to show the recess. */
    --dt-input-inset: inset 0 1px 1px color-mix(in srgb, #000 38%, transparent);
    --ui-tab-hover-darken: 6%;
    /* Dark needs a lighter resting border than light mode. */
    --dt-input-border: 4%;

    --ui-inline-code-background: color-mix(in srgb, #ffffff 7%, transparent);
    --ui-inline-code-foreground: color-mix(in srgb, #ffffff 88%, transparent);
    --ui-selection-background: color-mix(in srgb, #ffd24a 38%, transparent);
    /* A dark card sits ABOVE the chrome (#161618 over #0d0d0e), so an inline
       widget wearing the raw card fill reads as a lit panel. Take it down a
       touch β€” still clearly a surface, no longer the brightest thing in the
       transcript. Derived from the card so every skin follows its own seed. */
    --ui-widget-surface-background: color-mix(in srgb, var(--ui-bg-editor) 88%, #000);
  }

  /* ── Window glass (Settings β†’ Appearance β†’ Window Translucency: Glass) ──
     Set on <html> by store/translucency.ts; chat windows on a glass-capable
     OS (macOS vibrancy, Windows 11 DWM acrylic/mica). The native material
     composites BELOW the web contents; the page normally buries it under
     fully opaque surfaces.

     ONE PAINTER: <body> paints the glass tint exactly once, at
     `--translucency-glass-keep` (set inline from the Tint slider, linear to
     zero β€” the top of the lever is bare material), and the field tokens
     (chat / sidebar / editor surface) go fully transparent. The field
     surfaces NEST β€” body > pane container > chat section > transcript
     wrapper all wear these tokens β€” so thinning the tokens themselves stacks
     the tint once per layer and a session pane ends up near-opaque (~0.93 at
     60%) while the landing page, with fewer layers, reads far clearer. With a
     single painter the field alpha is the same number on every route. Raised
     content (cards, popovers, bubbles, the composer) keeps its own opaque
     fills over full-contrast text; regions still read distinct through their
     borders and the material itself. Unlike Clear, nothing on the page fades
     β€” the separate Fade lever does that natively, at the window level, and
     defaults to off.

     The boot script in index.html pins an opaque inline background on <html>
     before first paint; it has to go transparent here or it sits behind the
     translucent <body> and blocks the material. The terminal surface is
     pinned back to the opaque chrome mix: xterm resolves its surface var to a
     concrete color for its canvas (see right-sidebar/terminal/selection.ts),
     which does not composite page alpha. */
  :root[data-hermes-glass] {
    background-color: transparent !important;
    --ui-chat-surface-background: transparent;
    --ui-sidebar-surface-background: transparent;
    --ui-editor-surface-background: transparent;
    --ui-terminal-surface-background: var(--ui-bg-chrome);
  }

  :root[data-hermes-glass] body {
    background: color-mix(in srgb, var(--ui-bg-chrome) var(--translucency-glass-keep, 100%), transparent);
  }

  /* Sidebar scope (the Finder shape): glass rail, opaque content column.
     <body> stays the one painter but splits at the rail's visual edge β€” the
     store publishes it as --glass-rail-edge (live-tracked through collapse
     animation and pane resizes). Left of the seam: the normal glass mix.
     Right of it: the full opaque chrome. A hard gradient stop, so there is
     no smear across the seam; RTL mirrors via html[dir='rtl']. The content
     column's own surfaces stay transparent (they'd double-paint the tint
     otherwise) β€” the body backdrop alone restores the opaque look. */
  :root[data-hermes-glass][data-hermes-glass-scope='sidebar'] body {
    background: linear-gradient(
      to right,
      color-mix(in srgb, var(--ui-bg-chrome) var(--translucency-glass-keep, 100%), transparent)
        var(--glass-rail-edge, 0px),
      var(--ui-bg-chrome) var(--glass-rail-edge, 0px)
    );
  }

  :root[data-hermes-glass][data-hermes-glass-scope='sidebar'][dir='rtl'] body {
    background: linear-gradient(
      to left,
      color-mix(in srgb, var(--ui-bg-chrome) var(--translucency-glass-keep, 100%), transparent)
        var(--glass-rail-edge, 0px),
      var(--ui-bg-chrome) var(--glass-rail-edge, 0px)
    );
  }

  /* The app shell's two full-window opaque painters (the contrib controller
     root and the SidebarProvider wrapper) sit between <body> and every
     surface. Their fills are Tailwind utilities (bg-(--ui-bg-chrome) /
     bg-background), which cascade-layer above these base rules β€” hence the
     !important. Clearing them makes <body> the window's only field paint. */
  :root[data-hermes-glass] [data-contrib-shell],
  :root[data-hermes-glass] [data-slot='sidebar-wrapper'] {
    background-color: transparent !important;
  }

  /* Surfaces that MASK sibling content must stay filled under glass β€” a
     see-through mask reads as text bleeding through text, not as glass.
     Anything that paints over its own siblings declares `data-glass-opaque`
     at its call site (the diff gutter, a dragged sidebar row), rather than
     styles.css reaching in by class name. */
  :root[data-hermes-glass] [data-glass-opaque] {
    --ui-chat-surface-background: var(--ui-bg-chrome);
    --ui-editor-surface-background: var(--ui-bg-chrome);
    --ui-sidebar-surface-background: var(--ui-bg-sidebar);
  }

  /* Content RAISED above the field (overlay cards, the inline edit box) runs
     counter to it: near-opaque over a glass field, never thinner than the
     field itself β€” max() covers low slider values where the field still keeps
     more than 94%. The card wears the chat token and its internal nav asides
     wear the sidebar token, so both come back as almost-solid fills and the
     two-tone layout survives. */
  :root[data-hermes-glass] [data-glass-raised] {
    --ui-chat-surface-background: color-mix(
      in srgb,
      var(--ui-bg-chrome) max(94%, var(--translucency-glass-keep, 100%)),
      transparent
    );
    --ui-sidebar-surface-background: color-mix(
      in srgb,
      var(--ui-bg-sidebar) max(94%, var(--translucency-glass-keep, 100%)),
      transparent
    );
    --ui-editor-surface-background: var(--ui-bg-chrome);
  }

  /* The status bar spans the rail AND the content column. Transparent, it
     showed the body's hard stop through itself, and the seam cut whichever
     item sat on it (the free-tier chip, in the guided window). Finder's
     shape: the bar belongs to the opaque content column across the full
     width, and the rail's glass ends at its top edge. Window scope has no
     seam, so the bar stays transparent there. */
  :root[data-hermes-glass][data-hermes-glass-scope='sidebar'] [data-slot='statusbar'] {
    --ui-sidebar-surface-background: var(--ui-bg-chrome);
  }

  /* Clear mode (native window opacity) fades EVERYTHING in the window
     uniformly, so when an overlay opens over a session two layers of text
     fade by the same amount and fight through the overlay's light default
     scrim (bg-black/22 + 2px blur). While clear is active, the scrim works
     for a living: darken it and widen the blur so the covered transcript
     drops away and the overlay's own text is the only line of type in front
     of the desktop. Set on <html> by store/translucency.ts whenever
     mode='clear' and intensity > 0; !important because the utility classes
     live in a later cascade layer. */
  :root[data-hermes-clear] [data-overlay-surface] {
    background-color: rgb(0 0 0 / 0.55) !important;
    backdrop-filter: blur(0.5rem) !important;
  }

  /* Translucency peek: while the user holds the intensity slider (or for a
     short pulse after a frost/area/mode click) the entire overlay layer β€”
     scrim, blur and near-opaque card as ONE group β€” ghosts down so the live
     window behind it becomes the preview. The layer keeps pointer events:
     a held drag keeps delivering to the slider it started on. Opacity is
     the one property that fades the scrim, its backdrop-blur and the card
     together without relayout. Asymmetric easing: quick reveal while the
     hand is on the control, unhurried return.

     Both the peek and its return are scoped to a settings overlay that has
     ARMED the interaction ([data-translucency-peek-scope], set by the
     appearance row). An unscoped `[data-overlay-surface] { transition:
     opacity … }` would tax every overlay in the app β€” command center, cron,
     agents, model picker β€” with a 420ms opacity transition for the life of
     the process, to serve one slider. */
  :root [data-overlay-surface]:has([data-translucency-peek-scope]) {
    transition: opacity 420ms cubic-bezier(0.22, 1, 0.36, 1);
  }

  :root[data-hermes-translucency-peek] [data-overlay-surface]:has([data-translucency-peek-scope]) {
    opacity: 0.08;
    transition: opacity 160ms cubic-bezier(0.32, 0.72, 0, 1);
  }

  * {
    box-sizing: border-box;
    border-color: var(--dt-border);
  }

  html,
  body,
  #root {
    height: 100%;
    /* App shell, not a document: the window itself never scrolls on either axis
       (panes own their own scroll). Belt to the auto-scroll axis-lock in the
       sidebar reorder DnD β€” nothing can drag the whole shell sideways. */
    overflow: hidden;
  }

  html {
    font-size: var(--dt-base-size, 0.875rem);
  }

  body {
    margin: 0;
    background: var(--ui-chat-surface-background);
    color: var(--dt-foreground);
    font-family: var(--dt-font-sans);
    font-size: 0.8125rem;
    line-height: var(--dt-line-height, 1.55);
    letter-spacing: var(--dt-letter-spacing, 0);
    -webkit-user-select: none;
    user-select: none;
    -webkit-font-smoothing: antialiased;
  }

  button,
  textarea {
    font: inherit;
  }

  :where(
    a,
    .underline,
    [class~='hover:underline'],
    [class~='focus:underline'],
    [class~='focus-visible:underline'],
    [class~='group-hover:underline'],
    [class~='peer-hover:underline']
  ) {
    text-decoration-color: color-mix(in srgb, currentColor 20%, transparent);
    text-underline-offset: 0.25rem;
  }

  *::selection {
    background: var(--ui-selection-background);
    color: inherit;
  }
}

.dither {
  background: repeating-conic-gradient(currentColor 0% 25%, transparent 0% 50%) 0 0 / 0.125rem 0.125rem;
}

/* ─────────────────────────────────────────────────────────────────────────
   INLINE REFERENCES β€” the one system for anything that points at something
   from inside a run of text.

   A pasted link, an `@file:` the user picked, a `/skill`, a `@session:` the
   agent wrote: all the same species. They render the same way in the composer
   and in a sent message, because they're the same thing before and after send.

   A reference is TEXT, not a badge β€” colour and an optional icon, no fill, no
   padding, no border. A pill turns every mention into a widget the eye has to
   step over, and mid-sentence that's most of the sentence.

   Usage: `class="ref"` plus `data-ref="<kind>"` for the accent. Kinds live in
   `components/assistant-ui/reference-kinds.ts` (icon + label); their colour
   lives here, so a theme restyles every reference at once and TS never ships a
   hex. No `data-ref` = an ordinary link, which keeps the primary link colour.
   ───────────────────────────────────────────────────────────────────────── */
/* Kind β†’ accent. Keyed on the attribute ALONE so anything can adopt a
   reference's colour without also taking its inline-text layout (a completion
   row's icon column wants the hue, not the margin). Grouped by what a
   reference DOES, so the palette reads as meaning rather than decoration:
     Β· things you point at (paths)          β†’ neutral, they're the common case
     Β· things you fetch (links, media)      β†’ secondary
     Β· things that act (commands, tools)    β†’ accent
     Β· things that change code (skills, git)β†’ warm */
[data-ref] {
  --ref-color: var(--dt-primary);
}

[data-ref='file'],
[data-ref='folder'],
[data-ref='line'],
[data-ref='terminal'] {
  --ref-color: var(--ui-text-secondary);
}

[data-ref='url'],
[data-ref='image'],
[data-ref='session'],
[data-ref='theme'] {
  --ref-color: color-mix(in srgb, var(--ui-accent-secondary) 82%, var(--foreground));
}

[data-ref='command'],
[data-ref='tool'] {
  --ref-color: color-mix(in srgb, var(--ui-accent) 82%, var(--foreground));
}

[data-ref='skill'],
[data-ref='git'],
[data-ref='diff'],
[data-ref='staged'] {
  --ref-color: color-mix(in srgb, var(--ui-warm) 82%, var(--foreground));
}

.ref {
  --ref-color: var(--dt-primary);

  /* Prose links inherit the surrounding text's weight. `@tailwindcss/typography`
     sets `prose a { font-weight: 500 }`, which outranks a utility class on the
     anchor β€” so the override belongs here, on the shared class. */
  font-weight: inherit;
  color: var(--ref-color);
  /* Explicit: the base layer underlines every `a` (see the :where(a, …) reset). */
  text-decoration: none;
  /* A wrapped reference breaks per line fragment, not as one ragged box. */
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}

/* Affordance without chrome: only the ones you can actually activate respond,
   and they do it with an underline rather than a background. */
:where(a, button).ref:hover {
  text-decoration: underline;
  text-underline-offset: 0.15em;
}

/* The leading glyph. Sized in `em` so it tracks the text at any scale, and
   spaced with `margin` β€” not flex `gap` β€” so `.ref` stays an inline box whose
   label can wrap mid-word (a long URL has to break across lines like the prose
   around it, which a flex container would prevent).

   The margin is unconditional. A `:not(:only-child)` guard looks right and is
   silently wrong: CSS counts ELEMENT siblings, so an icon followed by a bare
   text-node label still matches `:only-child` β€” which is exactly how every
   chip lost its spacer. Icon-only users take the hue via `[data-ref]` instead
   of this class. */
.ref > :where(svg, i.codicon) {
  margin-inline-end: 0.25em;
  opacity: 0.8;
}

.ref > svg {
  display: inline-block;
  width: 0.875em;
  height: 0.875em;
  vertical-align: -0.1em;
}

.ref > i.codicon {
  font-size: 0.875em;
}

/* Hover-reveal suppression β€” the shared, declarative escape hatch.
   A collapsed pane slides in when the pointer dwells on its thin edge trigger.
   Controls that sit over that edge gutter would drag the panel in by accident.
   Mark any such region and, while it's hovered, the matching edge trigger(s) go
   pointer-transparent. Auto-resets on mouse-out, no JS.

   - data-suppress-pane-reveal       β†’ kills BOTH edges (use for small regions
                                         like the thread timeline).
   - data-suppress-pane-reveal-side  β†’ kills only the hovered region's OWN side
                                         (side read from its [data-pane-side]
                                         pane ancestor), so the opposite sidebar
                                         stays summonable while you work a pane. */
[data-pane-shell]:has([data-suppress-pane-reveal]:hover) [data-pane-reveal-trigger] {
  pointer-events: none;
}

[data-pane-shell]:has([data-pane-side='left'] [data-suppress-pane-reveal-side]:hover)
  [data-pane-side='left']
  [data-pane-reveal-trigger],
[data-pane-shell]:has([data-pane-side='right'] [data-suppress-pane-reveal-side]:hover)
  [data-pane-side='right']
  [data-pane-reveal-trigger] {
  pointer-events: none;
}

/* A pane's self-naming label ("REVIEW" atop the review pane) is redundant
   when its zone header is showing a tab with the same name β€” hide it there.
   Headerless zones (and the pane used outside the tree) keep the label. */
[data-tree-group][data-zone-header] [data-pane-self-label] {
  display: none;
}

:root:not([style*='--theme-asset-bg:']) .theme-default-filler {
  display: block;
}

:root[style*='--theme-asset-bg:'] .theme-default-filler {
  display: none;
}

/* ─────────────────────────────────────────────────────────────────────────
   Composer placeholder.

   The prompt is a PAINTED HINT, never content. Rendering `::before` inline β€”
   the obvious way β€” puts a box in the contenteditable's text flow, and the
   caret sits after it: click an empty composer and the insertion point lands
   at the right edge of the hint rather than the left edge of the field, and a
   hint that wraps makes the empty composer two lines tall. Taking it out of
   flow is what makes it a hint: the caret keeps the field's real origin, the
   box keeps its real height, and no pointer or selection can reach the text.

   `data-empty` carries emptiness because `:empty` can't: a cleared editor
   keeps a scaffolding <br>. See markEditorEmptiness in rich-editor.ts.
   ───────────────────────────────────────────────────────────────────────── */
[data-slot='composer-rich-input'] {
  position: relative;
}

[data-slot='composer-rich-input']:is(:empty, [data-empty])::before {
  content: attr(data-placeholder);
  position: absolute;
  inset: 0;
  padding: inherit;
  overflow: hidden;
  color: color-mix(in srgb, var(--muted-foreground) 60%, transparent);
  /* One line, clipped β€” the hint states the field's purpose; it never reflows
     the box it sits in. A narrow composer or a long locale string would
     otherwise wrap and double the empty composer's height. */
  white-space: nowrap;
  text-overflow: ellipsis;
  pointer-events: none;
  user-select: none;
}

/* Primitive-level pointer cursor for every interactive control (buttons,
   selects, menu items, switches, tabs, summaries). Keeps individual
   components from having to hardcode `cursor-pointer`; explicit cursor
   utilities (cursor-grab, cursor-default, disabled:cursor-*) still win since
   they live in the utilities layer. */
@layer base {
  button:not(:disabled):not([aria-disabled='true']),
  summary,
  [role='button']:not([aria-disabled='true']),
  [role='menuitem']:not([aria-disabled='true']),
  [role='menuitemradio']:not([aria-disabled='true']),
  [role='menuitemcheckbox']:not([aria-disabled='true']),
  [role='option']:not([aria-disabled='true']),
  [role='switch']:not([aria-disabled='true']),
  [role='tab']:not([aria-disabled='true']) {
    cursor: pointer;
  }
}

@layer utilities {
  [class*='rounded-full'],
  [class*=':rounded-full'] {
    border-radius: calc(var(--radius-scalar) * 9999rem);
  }
}

/* Interactive list-row hover β€” the sessions-list interaction, shared by every
   row list (sessions, capabilities, messaging, file trees, timeline): the
   highlight lands instantly on hover-in and fades out over 100ms on leave. */
@utility row-hover {
  cursor: pointer;
  transition:
    color 100ms ease-out,
    background-color 100ms ease-out;

  &:hover {
    background-color: var(--ui-row-hover-background);
    transition: none;
  }
}

/* The guided-onboarding thread is marked with [data-thread-type='onboarding']
   β€” the hook for onboarding-only transcript styling. */

/* Guided chat is a conversation, not a work surface: hide per-message action
   chrome (branch/copy/read-aloud/regenerate bar, reaction slot) and the turn-
   duration stamp β€” regenerate/branch would derail the scripted flow. */
[data-thread-type='onboarding'] [data-slot='aui_msg-actions'],
[data-thread-type='onboarding'] [data-slot='aui_msg-reactions'],
[data-thread-type='onboarding'] [data-slot='aui_turn-duration'] {
  display: none;
}

/* Hermes speaks first here: no user bubble sits above the opening assistant
   turn, so the first painted row would press against the pane chrome. The
   utility class on the row pulls the top pad 0.5rem ABOVE the titlebar; give
   the air back, and only in this thread. */
[data-slot='aui_thread-content'][data-thread-type='onboarding'] {
  padding-top: calc(var(--titlebar-height) + 1rem);
}

@keyframes arc-border {
  /* Compositor-only travel. The ::before layer is 300% Γ— 300% of the host
     (mirroring the old `background-size: 300%`), so translating it from
     -10% β†’ -50% of its own size reproduces the old
     `background-position: 15% β†’ 75%` exactly (offset = -2Β·WΒ·p), while
     `transform` animates on the compositor with zero per-frame style
     recalc/paint. The old background-position version cost ~3,600
     main-thread style recalcs per minute per arc, pinning idle renderers
     (#53902, #73082). */
  0% {
    transform: translate(-10%, -10%);
  }
  100% {
    transform: translate(-50%, -50%);
  }
}

.arc-border {
  --arc-c0: color-mix(in srgb, var(--dt-foreground) 0%, transparent);
  --arc-c1: var(--dt-midground);
  --arc-c2: var(--dt-background);
  --arc-angle: 160deg;
  --arc-width: 0.078125rem;
  /* How far the ring stands off its host, per side. */
  --arc-standoff: 0.125rem;
  /* An outset ring is only concentric when its radius grows by the standoff
     (r = r_host + gap); `border-radius: inherit` leaves the corner pinched.
     Defaults to the shared `rounded-md`; a host on another radius sets it. */
  --arc-radius: var(--radius-md);
  --arc-duration: 2.23s;

  pointer-events: none;
  position: absolute;
  overflow: hidden;
  border-radius: calc(var(--arc-radius) + var(--arc-standoff));
  inset: calc(var(--arc-standoff) * -1);
  padding: var(--arc-width);
  mask:
    linear-gradient(#000 0 0) content-box,
    linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask-composite: exclude;
}

:root.dark .arc-border {
  --arc-c1: var(--dt-foreground);
}

/* Landed `memory` tool row β€” gold β†’ purple on the brain glyph + title.
   Pair with `text-transparent` so the scaffold label color can't win. */
.tool-memory-legendary-title {
  background-image: linear-gradient(
    105deg,
    var(--tool-memory-legendary-from) 0%,
    var(--tool-memory-legendary-mid) 48%,
    var(--tool-memory-legendary-to) 100%
  );
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent !important;
  font-weight: 600;
}

.tool-memory-legendary-glyph {
  filter: drop-shadow(0 0 0.28rem var(--tool-memory-legendary-glow));
}

.tool-memory-legendary-meta {
  color: var(--tool-memory-legendary-meta);
}

/* Command-palette deep-link: briefly flash the targeted settings row. */
@keyframes setting-field-flash {
  0% {
    background-color: color-mix(in srgb, var(--dt-primary, #f59e0b) 22%, transparent);
  }
  100% {
    background-color: transparent;
  }
}

.setting-field-highlight {
  animation: setting-field-flash 1.6s ease-out;
}

@media (prefers-reduced-motion: reduce) {
  .setting-field-highlight {
    animation: none;
  }
}

.arc-border::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  /* The gradient layer IS 300% of the ring (the old version kept a host-sized
     ::before and slid a 300%-sized background through it). Sizing the layer
     itself lets the travel be a `transform` β€” composited, no main-thread
     style/paint work β€” while the host's mask + overflow clip it to the ring. */
  width: 300%;
  height: 300%;
  background: linear-gradient(
    var(--arc-angle),
    transparent 0%,
    var(--arc-c0) 15%,
    var(--arc-c1) 20%,
    var(--arc-c2) 25%,
    transparent 35%,
    transparent 40%,
    var(--arc-c0) 55%,
    var(--arc-c1) 60%,
    var(--arc-c2) 65%,
    transparent 75%,
    transparent 80%,
    var(--arc-c0) 95%,
    var(--arc-c1) 100%
  );
  will-change: transform;
  animation: arc-border var(--arc-duration) linear infinite;
}

/* Flip the arc's travel direction (e.g. the Nous Portal hero row). */
.arc-border.arc-reverse::before {
  animation-direction: reverse;
}

/* Nous Portal hero: slower, blue β†’ orange arc. */
.arc-border.arc-nous,
:root.dark .arc-border.arc-nous {
  --arc-c1: #4f8cff;
  --arc-c2: #ff8c42;
  --arc-duration: 3.27s;
}

/* Sidebar session row β€” a thin, clipped, single-line host, so it differs twice
   from the default ring:

   1. Flush, not outset. The sidebar scroller is `overflow-x-hidden` and rows sit
      `gap-px` apart, so an outset ring loses its left/right runs to the clip.

   2. A visible tail. `--arc-c2` defaults to `--dt-background` β€” invisible
      against the sidebar. With c0 a transparent sentinel and c2 invisible, only
      the bright c1 stop survives each pass, and the gradient has three of them:
      three moving dots instead of an arc. Tying c2 to c1 gives each spike a
      falloff. (`arc-nous` already overrides c2, so the hero is unaffected.) */
.arc-border.arc-row,
:root.dark .arc-border.arc-row {
  --arc-standoff: 0rem;
  --arc-c2: color-mix(in srgb, var(--arc-c1) 45%, transparent);
}

/* HUD composer β€” same travelling arc as a working sidebar row, 2px and pill-
   rounded to match the bar. */
.arc-border.arc-composer,
:root.dark .arc-border.arc-composer {
  --arc-width: 2px;
  --arc-standoff: 0rem;
  --arc-radius: 0.75rem;
  --arc-c2: color-mix(in srgb, var(--arc-c1) 45%, transparent);
  z-index: 6;
}

@media (prefers-reduced-motion: reduce) {
  .arc-border::before {
    animation: none;
  }
}

/* No focus rings, anywhere. Kills the native outline plus Tailwind's
   `focus-visible:ring-*` (a box-shadow driven by --tw-ring-*). Unlayered so it
   beats the utilities layer without !important on the outline. The composer /
   .desktop-input-chrome focus glow is untouched β€” those set `box-shadow`
   directly rather than through the ring vars. */
*:focus,
*:focus-visible {
  outline: none;
}

*:focus-visible {
  --tw-ring-shadow: 0 0 #0000 !important;
  --tw-ring-offset-shadow: 0 0 #0000 !important;
}

button {
  -webkit-app-region: no-drag;
}

/* Button variant styling lives entirely in the cva in components/ui/button.tsx
   (the single source of truth). Don't re-add [data-slot='button'] rules here β€”
   attribute selectors out-specify the Tailwind utilities and silently override
   the variants. */

[data-slot='dropdown-menu-content'],
[data-slot='select-content'],
[data-slot='dialog-content'],
[data-slot='thread-timeline-popover'] {
  border-color: var(--ui-stroke-secondary);
  background: color-mix(in srgb, var(--ui-bg-elevated) 96%, transparent);
  box-shadow: var(--shadow-md);
  backdrop-filter: blur(0.75rem) saturate(1.08);
  -webkit-backdrop-filter: blur(0.75rem) saturate(1.08);
}

[data-slot='dropdown-menu-item']:focus,
[data-slot='dropdown-menu-checkbox-item']:focus,
[data-slot='dropdown-menu-radio-item']:focus {
  background: var(--ui-bg-tertiary);
  color: var(--ui-text-primary);
}

input,
textarea,
[contenteditable]:not([contenteditable='false']),
[data-slot='aui_user-message-root'],
[data-slot='aui_assistant-message-content'],
[data-slot='aui_system-message-root'],
[data-selectable-text='true'],
[data-selectable-text='true'] * {
  -webkit-user-select: text;
  user-select: text;
}

button,
[role='button'] {
  -webkit-user-select: none;
  user-select: none;
}

/* User bubbles are <button>s (click β†’ edit), so the rule above would kill
   drag-to-select and leave ⌘C with nothing to grab. Message text stays
   selectable; chrome controls outside the bubble keep user-select: none. */
[data-slot='aui_user-message-root'] button,
[data-slot='aui_user-message-root'] [role='button'] {
  -webkit-user-select: text;
  user-select: text;
}

img,
picture,
video,
canvas,
svg {
  -webkit-user-select: none;
  user-select: none;
}

img,
video,
canvas {
  -webkit-user-drag: none;
}

/* Tabs render 2-wide on every HTML code surface β€” the source preview, inline
   diffs, markdown code blocks, tool output β€” so indentation matches the editor
   and the terminal instead of the browser default (8). */
pre,
code {
  tab-size: 2;
  -moz-tab-size: 2;
}

/* Arc-style multicolor action surface (static, not animated). Reusable on any
   Button via className. Unlayered so it beats Tailwind's bg- and text- variant
   utilities. */
.btn-arc {
  background-image: linear-gradient(110deg, #5b6cff 0%, #8b5cf6 28%, #d946ef 58%, #fb7185 82%, #fb923c 100%);
  color: #fff;
  border-color: transparent;
}

.btn-arc:hover:not(:disabled) {
  filter: brightness(1.08) saturate(1.06);
}

/* Shared input chrome β€” mirrors composer hover/focus FX. Unlayered to beat Tailwind utilities. */
/* Border strength is driven by the single --dt-input-border alpha knob (Γ— the
   theme's tuned ring color); hover doubles it and focus triples it. Only the
   border-color animates β€” animating the translucent background over the window's
   backdrop-blur flickers (badly on textareas), so the bg fill snaps instead.
   (:focus is declared after :hover so a focused+hovered field shows focus.) */
.desktop-input-chrome {
  background: color-mix(in srgb, var(--dt-card) var(--dt-input-bg), transparent);
  border-color: color-mix(in srgb, var(--dt-composer-ring) var(--dt-input-border), transparent);
  box-shadow: var(--dt-input-inset);
  transition: border-color 200ms ease-out;
}

.desktop-input-chrome:hover {
  border-color: color-mix(in srgb, var(--dt-composer-ring) calc(var(--dt-input-border) * 2), transparent);
}

/* `[data-state='open']` keeps the trigger looking focused while its dropdown is
   open β€” Radix moves focus into the list, so the trigger itself loses :focus. */
.desktop-input-chrome:focus,
.desktop-input-chrome:focus-within,
.desktop-input-chrome[data-state='open'] {
  border-color: var(--dt-composer-ring);
  box-shadow: none;
  outline: none;
}

.desktop-input-chrome[aria-invalid='true'] {
  border-color: var(--dt-destructive);
}

/* Drag in progress (sash resize, console resize, tab drag): webview/iframe
   guests hit-test in their own process and swallow the gesture the moment the
   pointer crosses them β€” see lib/guest-pointer-guard.ts. */
body.guest-pointer-lock :is(webview, iframe) {
  pointer-events: none;
}

@layer components {
  /* Chromium 121+ (Electron) prefers standard scrollbar-* over
     ::-webkit-scrollbar and ignores the latter when both are set β€” platform
     thin on mac still looks chunky. Use webkit for real thin thumbs; gate the
     standard props so only non-webkit engines (Firefox) take that path.
     https://developer.chrome.com/docs/css-ui/scrollbar-styling
     https://syntackle.com/blog/changes-to-scrollbar-styling-in-chrome-121/

     Any author rule on ::-webkit-scrollbar switches that scroller from
     platform overlay (fade in on scroll, zero gutter) to classic always-on
     gutters. `.scrollbar-overlay` opts a surface out of the themed rules so
     Electron keeps native overlay β€” used by conversation code blocks where a
     permanent 4px track eats the card and always draws a bar. */

  .scrollbar-dt::-webkit-scrollbar,
  .scrollbar-dt *:not(.scrollbar-overlay)::-webkit-scrollbar {
    width: 0.25rem;
    height: 0.25rem;
  }

  .scrollbar-dt::-webkit-scrollbar-track,
  .scrollbar-dt::-webkit-scrollbar-corner,
  .scrollbar-dt *:not(.scrollbar-overlay)::-webkit-scrollbar-track,
  .scrollbar-dt *:not(.scrollbar-overlay)::-webkit-scrollbar-corner {
    background: transparent;
  }

  .scrollbar-dt::-webkit-scrollbar-thumb,
  .scrollbar-dt *:not(.scrollbar-overlay)::-webkit-scrollbar-thumb {
    background: color-mix(in srgb, var(--dt-scrollbar-thumb) 18%, transparent);
    border-radius: 9999rem;
    background-clip: padding-box;
  }

  .scrollbar-dt::-webkit-scrollbar-thumb:hover,
  .scrollbar-dt *:not(.scrollbar-overlay)::-webkit-scrollbar-thumb:hover {
    background: color-mix(in srgb, var(--dt-scrollbar-thumb) 40%, transparent);
    background-clip: padding-box;
  }

  .scrollbar-dt::-webkit-scrollbar-button,
  .scrollbar-dt *:not(.scrollbar-overlay)::-webkit-scrollbar-button {
    display: none;
  }

  /* Hover-only bars. A thumb sitting on a list you aren't touching is chrome,
     not information β€” the gutter is reserved either way, so fading it in and
     out costs no reflow. Opt-in per surface: the sidebar wants it, a document
     you're reading down wants its bar where you can see it. */
  .scrollbar-fade::-webkit-scrollbar-thumb,
  .scrollbar-dt .scrollbar-fade::-webkit-scrollbar-thumb {
    background-color: transparent;
    transition: background-color 150ms ease-out;
  }

  .scrollbar-fade:hover::-webkit-scrollbar-thumb,
  .scrollbar-dt .scrollbar-fade:hover::-webkit-scrollbar-thumb {
    background-color: color-mix(in srgb, var(--dt-scrollbar-thumb) 18%, transparent);
  }

  .scrollbar-fade:hover::-webkit-scrollbar-thumb:hover,
  .scrollbar-dt .scrollbar-fade:hover::-webkit-scrollbar-thumb:hover {
    background-color: color-mix(in srgb, var(--dt-scrollbar-thumb) 40%, transparent);
  }

  /* Hover marquee: a truncated line that scrolls its overflow into view while
     hovered. Opt-in via .hover-marquee + an inner .hover-marquee-inner; the
     JS side measures the overflow on pointerenter and sets --marquee-d (and
     data-marquee) only when the text actually overflows, so short titles
     keep their plain ellipsis and never wiggle. Alternate direction reads
     back to the start; the 300ms delay keeps casual pointer passes still. */
  .hover-marquee[data-marquee='true'] {
    text-overflow: clip;
  }

  .hover-marquee[data-marquee='true'] > .hover-marquee-inner {
    display: inline-block;
    animation: hover-marquee var(--marquee-t, 3s) linear infinite;
  }

  /* One direction, Spotify-style: scroll the tail in, hold, snap back, hold.
     The percentages pin the two holds; the travel occupies the middle. */
  @keyframes hover-marquee {
    0%,
    10% {
      transform: translateX(0);
    }

    75%,
    100% {
      transform: translateX(calc(-1 * var(--marquee-d, 0px)));
    }
  }

  /* Variant for portaled overlays (Radix DropdownMenu, Popover, etc.) that
     render under document.body, outside the `.scrollbar-dt` scope on
     #root. Same visual treatment, applied directly to the overlay
     container so its (and only its) internal scrollbar is themed. */
  .dt-portal-scrollbar::-webkit-scrollbar {
    width: 0.25rem;
    height: 0.25rem;
  }

  .dt-portal-scrollbar::-webkit-scrollbar-track,
  .dt-portal-scrollbar::-webkit-scrollbar-corner {
    background: transparent;
  }

  .dt-portal-scrollbar::-webkit-scrollbar-thumb {
    background: color-mix(in srgb, var(--dt-scrollbar-thumb) 28%, transparent);
    border-radius: 9999rem;
    background-clip: padding-box;
  }

  .dt-portal-scrollbar::-webkit-scrollbar-thumb:hover {
    background: color-mix(in srgb, var(--dt-scrollbar-thumb) 50%, transparent);
    background-clip: padding-box;
  }

  .dt-portal-scrollbar::-webkit-scrollbar-button {
    display: none;
  }

  @supports not selector(::-webkit-scrollbar) {
    .scrollbar-dt,
    .scrollbar-dt *:not(.scrollbar-overlay) {
      scrollbar-width: thin;
      scrollbar-color: color-mix(in srgb, var(--dt-scrollbar-thumb) 18%, transparent) transparent;
    }

    .dt-portal-scrollbar {
      scrollbar-width: thin;
      scrollbar-color: color-mix(in srgb, var(--dt-scrollbar-thumb) 28%, transparent) transparent;
    }

    /* Firefox has no real overlay mode; thin + transparent track is the closest
       match to the Chromium overlay opt-out above. */
    .scrollbar-overlay {
      scrollbar-width: thin;
      scrollbar-color: color-mix(in srgb, var(--dt-scrollbar-thumb) 28%, transparent) transparent;
    }

    /* No transition β€” Firefox doesn't animate scrollbar-color. */
    .scrollbar-fade {
      scrollbar-color: transparent transparent;
    }

    .scrollbar-fade:hover {
      scrollbar-color: color-mix(in srgb, var(--dt-scrollbar-thumb) 18%, transparent) transparent;
    }
  }
}

/* Bottom clearance lives on [data-slot='aui_composer-clearance'] β€”
   virtualized items unmount, so :nth-last-child can't fire reliably. */

[data-slot='aui_assistant-message-content'] {
  padding-left: var(--message-text-indent);
  font-size: var(--conversation-text-font-size);
  line-height: 1.5;
}

[data-slot='aui_assistant-message-root'] {
  width: 100%;
}

/* Remove label pixels under the hover close button; translucent paint would
   stack the glass tint and still let the label bleed through. */
[data-slot='pane-tab'][data-closeable] {
  --pane-tab-close-width: 1.5rem;
}

[data-slot='pane-tab'][data-closeable]:hover > .pane-tab-content {
  mask-image: linear-gradient(
    to right,
    #000 calc(100% - var(--pane-tab-close-width) - 1rem),
    transparent calc(100% - var(--pane-tab-close-width))
  );
}

[data-slot='aui_assistant-message-content'] .aui-md,
[data-slot='aui_assistant-message-content'] .aui-md :where(p, li, blockquote, table, pre) {
  font-size: inherit;
}

/* Ask / onboarding pills sit flush with the prose left edge. `.aui-md` is
   `overflow-hidden` so wide code/tables don't blow the column; that same clip
   shears the first pill's left cap. Cards opt the surface out; tables/code keep
   their own overflow. */
[data-slot='aui_assistant-message-content'] .aui-md:has([data-onboarding-card]) {
  overflow: visible;
}

/* Tailwind Typography sets `.prose :where(p) { margin: 1.25em }` (~16px). That
   selector ties our `my-*` utility on specificity and wins on source order, so
   paragraph spacing must be reclaimed here at higher specificity. One tight
   top-margin (bottom zeroed to avoid doubling), first child reset to flush. */
[data-slot='aui_assistant-message-content'] .aui-md :where(p) {
  margin-block: var(--paragraph-gap) 0;
}

/* Headings are section breaks, so they own a larger top gap than prose β€” a
   leading `# title` (common in re-entered/delegated turns) no longer butts
   against the block above. Top-owned + bottom snug; the first-child reset
   below still flushes a leading heading. */
[data-slot='aui_assistant-message-content'] .aui-md :where(h1, h2, h3, h4) {
  margin-block: 1rem 0.25rem;
}

/* First rendered element of a prose block is flush β€” the block-level gap above
   (tool / paragraph) already provides the separation. Reach one level deep too:
   Streamdown wraps blocks in a `div.space-y-*`, so the real first line is the
   first child's first child. */
[data-slot='aui_assistant-message-content'] .aui-md > :first-child,
[data-slot='aui_assistant-message-content'] .aui-md > :first-child > :first-child {
  margin-top: 0;
}

/* Prose, tools, todos, and thinking all share one left edge (the message
   content's --message-text-indent). No extra prose indent β€” a single gutter
   reads cleaner than a ragged tool-vs-reply column. */

/* RTL/bidi chat text (#44150): each block resolves its own base direction from
   its first strong char (UAX#9 plaintext). text-align:start makes that resolved
   direction drive alignment too β€” load-bearing, since the user bubble pins
   text-left. direction is never set, so chrome/layout/list-indent stay LTR (the
   issue asks not to flip the whole UI). Covers assistant prose, user lines, and
   both composers (main + edit share composer-rich-input). */
[data-slot='aui_assistant-message-content'] .aui-md :where(p, h1, h2, h3, h4, h5, h6, li, blockquote),
[data-slot='aui_user-inline-text'],
[data-slot='composer-rich-input'] {
  unicode-bidi: plaintext;
  text-align: start;
}

/* Inline code/KaTeX don't vote on direction and keep their own order: isolate
   makes bidi treat each as one neutral, so a block that *starts* with `./run.sh`
   then Arabic still resolves RTL, and the command's neutrals (dots/slashes)
   aren't reordered by the surrounding RTL run. */
[data-slot='aui_assistant-message-content'] .aui-md :where(:not(pre) > code),
[data-slot='aui_user-inline-code'],
[data-slot='aui_assistant-message-content'] .aui-md .katex {
  direction: ltr;
  unicode-bidi: isolate;
}

/* Fenced code stays LTR even inside an RTL list item/blockquote β€” never mirrors. */
[data-slot='aui_assistant-message-content'] .aui-md [data-slot='code-card'],
[data-slot='aui_user-fence'] {
  direction: ltr;
  text-align: left;
}

[data-slot='aui_user-message-root'] {
  --sticky-human-offset: calc(var(--sticky-human-top) + 1px);
  top: var(--sticky-human-offset);
}

/* The sticky prompt owns no field paint. Clip only the scrolling siblings
   behind it, including the top gap, so bubble transparency still works. */
[data-sticky-prompt-clip] {
  clip-path: inset(var(--sticky-prompt-clip) 0 0);
}

[data-slot='aui_user-message-root'],
[data-slot='aui_edit-composer-root'] {
  --human-msg-line-height: 1.3;
  font-size: var(--conversation-text-font-size);
}

[data-slot='aui_user-inline-text'] {
  line-height: var(--human-msg-line-height);
}

[data-slot='aui_edit-composer-root'] [data-slot='composer-rich-input'] {
  line-height: var(--human-msg-line-height);
}

/* Sticky human bubbles clamp to ~2 lines with a soft bottom fade so a long
   prompt doesn't dominate the viewport. The clamp lifts only in the edit
   composer; expanding on read-only :focus-within ran on mousedown (before the
   swap) and fought stick-to-bottom when parked at the bottom. */
.sticky-human-clamp {
  cursor: pointer;
  max-height: calc(4 * var(--human-msg-line-height) * var(--conversation-text-font-size) + 0.15rem);
  overflow: hidden;
}

.sticky-human-clamp[data-clamped='true'] {
  -webkit-mask-image: linear-gradient(to bottom, #000 55%, transparent);
  mask-image: linear-gradient(to bottom, #000 55%, transparent);
}

/* Stick-to-bottom owns scrollTop while following. Once escaped, native anchoring
   is safe and keeps sticky human edits from shoving the viewport; data-editing
   enables that path before React swaps in the inline editor. */
[data-slot='aui_thread-viewport'] {
  overflow-anchor: none;
}

[data-slot='aui_thread-viewport'][data-following='false'],
[data-slot='aui_thread-viewport'][data-editing='true'] {
  overflow-anchor: auto;
}

[data-slot='aui_thread-content'] {
  max-width: var(--composer-width);
  padding-inline: 1.5rem;
}

[data-slot='aui_intro'] {
  align-items: center;
  justify-content: center;
  padding-bottom: var(--composer-measured-height);
  text-align: center;
}

[data-slot='aui_intro'] > div {
  max-width: var(--composer-width);
}

[data-slot='aui_intro'] p:last-child {
  max-width: 34rem;
  margin-inline: auto;
  color: var(--ui-text-tertiary);
  font-size: 0.875rem;
  line-height: 1.45;
}

.fit-text {
  --fit-captured-length: initial;
  --fit-support-sentinel: var(--fit-captured-length, 9999px);

  display: flex;
  container-type: inline-size;
}

/* The display lettering an empty chat is titled with. Kept here beside
   `.fit-text` rather than as utilities on the element: the two always travel
   together, and the face is the whole point of the treatment β€” it must not be
   something a class-merge or a missed scan can quietly drop, leaving the
   wordmark rendered in body text. */
.wordmark {
  font-family: 'Collapse', var(--font-sans);
  font-weight: 700;
  line-height: 0.9;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.fit-text > [aria-hidden] {
  visibility: hidden;
}

.fit-text > :not([aria-hidden]) {
  flex-grow: 1;
  container-type: inline-size;

  --fit-captured-length: 100cqi;
  --fit-available-space: var(--fit-captured-length);
}

.fit-text > :not([aria-hidden]) > * {
  --fit-support-sentinel: inherit;
  --fit-captured-length: 100cqi;
  --fit-ratio: tan(atan2(var(--fit-available-space), var(--fit-available-space) - var(--fit-captured-length)));

  display: block;
  inline-size: var(--fit-available-space);
  font-size: clamp(
    var(--fit-min, 1em),
    1em * var(--fit-ratio),
    var(--fit-max, infinity * 1px) - var(--fit-support-sentinel)
  );
}

@container (inline-size > 0) {
  .fit-text > :not([aria-hidden]) > * {
    white-space: nowrap;
  }
}

@property --fit-captured-length {
  syntax: '<length>';
  initial-value: 0px;
  inherits: true;
}

/* The dock column owns the composer's width; the composer keeps the 5px
   transparent grab margin that the peel-out drag needs. +10px width compensates
   that padding so the visible surface keeps its exact width/position. */
[data-slot='composer-dock'] {
  width: calc(min(var(--composer-width), calc(100% - 2rem)) + 10px);
  padding-bottom: var(--composer-shell-pad-block-end);
}

[data-slot='composer-root'] {
  width: 100%;
  padding-inline: 5px;
}

/* Popped-out (floating) composer: compact width + an even 5px transparent grab
   platform. The higher-specificity selector resets the base rule's padding-bottom
   so the inset is equal on all four sides (not 5px sides / shell-pad bottom). */
[data-slot='composer-dock'][data-popped-out] {
  width: var(--composer-popout-width, 24rem);
  max-width: calc(100vw - 1.5rem);
  padding-bottom: 0;
}

[data-slot='composer-root'][data-popped-out] {
  padding: 5px;
}

/* Dock glow intensity scale β€” dimmer in light mode (the primary glow reads
   much stronger over a light backdrop), full strength in dark mode. */
:root {
  --dock-glow-scale: 0.55;
  /* Unfocused chat surface (multi-pane): a pane the user isn't in recedes so
     the focused conversation reads as the one being worked in. Light needs a
     deeper cut β€” a dim over a bright surface loses contrast far more slowly
     than the same dim over a dark one. Pairs with a grayscale pass on the same
     element β€” one treatment for the whole pane, not per-part tuning. */
  --chat-unfocused-opacity: 0.62;
}

.dark {
  --dock-glow-scale: 1;
  --chat-unfocused-opacity: 0.72;
}

/* The whole surface recedes as ONE layer β€” thread, timeline rail, composer,
   header β€” fading and desaturating together rather than each part taking its
   own treatment. Both properties on the surface root also composite the
   already-painted layer instead of repainting descendants. */
[data-chat-surface][data-chat-unfocused] {
  opacity: var(--chat-unfocused-opacity);
  filter: grayscale(1);
}

[data-chat-surface] {
  transition:
    opacity 75ms ease-out,
    filter 75ms ease-out;
}

/* Drag-region hatch β€” a diagonal ///// pattern (Photoshop-style) that fades into
   the transparent grab margin on hover (and stays while dragging) to signal the
   composer is draggable. Inherits the root radius so it clips to the corners. */
[data-slot='composer-drag-region'] {
  /* Hatch frame radius (tuned by hand). */
  border-radius: 0.4rem;
  opacity: 0;
  transition: opacity 150ms ease;
  background-image: repeating-linear-gradient(
    -45deg,
    color-mix(in srgb, var(--ui-text-tertiary) 38%, transparent) 0,
    color-mix(in srgb, var(--ui-text-tertiary) 38%, transparent) 1px,
    transparent 1px,
    transparent 3.5px
  );
}

[data-slot='composer-drag-region']:hover,
[data-slot='composer-drag-region'][data-dragging] {
  opacity: 0.33;
}

[data-slot='composer-root'] > .pointer-events-none {
  background: linear-gradient(
    to bottom,
    transparent,
    color-mix(in srgb, var(--ui-chat-surface-background) 88%, transparent)
  ) !important;
}

[data-slot='composer-surface'] {
  border-color: var(--ui-stroke-secondary) !important;
}

[data-slot='composer-fade'] {
  min-height: 2.375rem;
}

[data-slot='composer-rich-input'] {
  color: var(--ui-text-primary);
  font-size: 0.8125rem;
}

[data-slot='composer-rich-input']:is(:empty, [data-empty])::before {
  color: var(--ui-text-tertiary) !important;
}

/* ── Composer fill β€” ONE var painted by the surface AND anything docked to it
   (slashΒ·@ popover, `?` help). State ladder sets the var; consumers just paint
   `background: var(--composer-fill)`, so every state matches by construction.
   The :has() rule is last on purpose: while a completion drawer is open it
   beats focus/scroll and forces an OPAQUE fill (both mix endpoints solid) β€”
   translucent glass can never match across the two layers because they sample
   different backdrops. */
:root {
  /* Fallback for drawers outside the main composer (e.g. edit-message). */
  --composer-fill: color-mix(in srgb, var(--dt-card) 90%, var(--dt-background));
}

[data-slot='composer-root'] {
  --composer-fill: color-mix(in srgb, var(--dt-card) 72%, transparent);
}

[data-slot='composer-root'][data-thread-scrolled-up] {
  --composer-fill: color-mix(in srgb, var(--dt-card) 48%, transparent);
}

/* Tool/thinking blocks now live at message-text alignment (no leading
   chevron column to escape into), so their headers and bodies share a
   common left edge with the model's text. */
[data-slot='aui_assistant-message-content'] > [data-slot='tool-block'],
[data-slot='aui_assistant-message-content'] > [data-slot='aui_thinking-disclosure'] {
  width: 100%;
  max-width: 100%;
}

/* A delegation is a list of short rows β€” goal, model, timer β€” not prose, so it
   reads better narrow than stretched across the full reading column. Scoped
   here rather than as a utility on the element: the rule above sets width on
   every tool block and would win over it. */
[data-slot='aui_assistant-message-content'] [data-slot='tool-block'][data-delegate-card] {
  max-width: 75%;
}

[data-slot='aui_assistant-message-content'] .aui-md [data-streamdown='code-block'] code {
  max-width: none;
  font-family: inherit;
  font-size: inherit;
  padding: 0;
  border-radius: 0;
  background: transparent;
  color: inherit;
  overflow-x: visible;
  overflow-wrap: inherit;
  vertical-align: baseline;
  word-break: inherit;
  white-space: inherit;
}

/* Streamdown's adapter wraps code fences in a `data-streamdown="code-block"`
   container with its own card chrome. We render our own <CodeCard>, so this
   strips the upstream chrome down to a layout-only passthrough. */
[data-slot='aui_assistant-message-content'] .aui-md [data-streamdown='code-block'] {
  contain: none;
  overflow: visible;
  margin-block: var(--paragraph-gap) 0 !important;
  padding: 0 !important;
  gap: 0 !important;
  border: 0 !important;
  border-radius: 0 !important;
  background: transparent !important;
  color: inherit;
}

[data-slot='aui_assistant-message-content'] .aui-md [data-streamdown='code-block']:has(.aui-prose-fence) {
  margin-block: 0 !important;
}

[data-slot='aui_assistant-message-content'] .aui-md [data-slot='code-card'] {
  /* Streamdown nests blocks, so the container's child-combinator rhythm can't
     reach the card. Carry the paragraph gap on the card itself (top-owned);
     collapses cleanly with the wrapper's margin when one is present, and the
     first-child reset still flushes a leading code block. */
  margin-block: var(--paragraph-gap) 0;
  position: relative;
  transition:
    box-shadow 180ms ease-out,
    background-color 180ms ease-out;
}

[data-slot='aui_assistant-message-content'] .aui-md [data-slot='code-card'][data-streaming='true'] {
  animation:
    code-card-stream-enter 180ms cubic-bezier(0.16, 1, 0.3, 1) both,
    code-card-stream-glow 1.8s ease-in-out 180ms infinite alternate;
  box-shadow:
    0 0 0 0.0625rem color-mix(in srgb, var(--dt-ring) 10%, transparent),
    0 0.625rem 1.75rem color-mix(in srgb, var(--dt-ring) 8%, transparent);
}

[data-slot='aui_assistant-message-content']
  .aui-md
  [data-slot='code-card'][data-streaming='true']
  [data-slot='code-card-body'] {
  -webkit-mask-image: linear-gradient(to bottom, black 0%, black calc(100% - 1.5rem), rgb(0 0 0 / 64%) 100%);
  mask-image: linear-gradient(to bottom, black 0%, black calc(100% - 1.5rem), rgb(0 0 0 / 64%) 100%);
}

[data-slot='aui_assistant-message-content'] .aui-md :not(pre) > code {
  background: var(--ui-inline-code-background);
  color: var(--ui-inline-code-foreground);
}

[data-slot='aui_assistant-message-content'] .aui-md :where(.aui-shiki, .aui-shiki > pre) {
  margin: 0 !important;
}

/* react-shiki nests its own `pre.shiki` inside our `.aui-shiki` Pre, so the
   code card's `[&_pre]` padding lands on both and doubles the inset. The outer
   Pre already carries the card's padding β€” zero the inner one. */
[data-slot='aui_assistant-message-content'] .aui-md .aui-shiki .shiki {
  padding: 0 !important;
}

[data-slot='aui_assistant-message-content'] .aui-md .aui-md-table {
  border-spacing: 0;
}

[data-slot='aui_assistant-message-content'] .aui-md .aui-md-table > table,
[data-slot='aui_assistant-message-content'] .aui-md .aui-md-table thead,
[data-slot='aui_assistant-message-content'] .aui-md .aui-md-table tbody,
[data-slot='aui_assistant-message-content'] .aui-md .aui-md-table tr,
[data-slot='aui_assistant-message-content'] .aui-md .aui-md-table th,
[data-slot='aui_assistant-message-content'] .aui-md .aui-md-table td {
  margin: 0 !important;
  margin-block-start: 0 !important;
  margin-block-end: 0 !important;
}

[data-slot='aui_assistant-message-content'] .aui-md .aui-md-table thead {
  border-bottom-color: var(--ui-stroke-tertiary) !important;
}

/* Tool / thinking blocks are scaffolding around the model's reply, so we
   keep them transparent and fade them slightly. The reading column (prose)
   stays at full strength; scaffolding lifts back to full opacity on
   hover/focus so it stays legible when the user actually wants to read it. */
[data-slot='tool-block'],
[data-slot='aui_thinking-disclosure'] {
  background: transparent !important;
}

/* Fade scaffolding so the prose reading column stays primary. Each surface
   opts in with `data-conversation-scaffold` β€” thinking header, tool row, run
   summary, live status line β€” instead of being named by its own selector here.
   Spelling them out individually is how the status line came to sit a shade
   brighter than the rows either side of it.

   Marked per surface and never on a container: opacity opens a stacking
   context, so nothing inside a faded parent can be more opaque than it, and
   one row (an open diff) could not stay lit while its siblings dimmed. Hence
   the tool group wrapper carries no mark and each row inside it carries its
   own β€” no two marked elements nest, so the fade never compounds. */
[data-slot='aui_assistant-message-content'] [data-conversation-scaffold] {
  opacity: 0.67;
  transition: opacity 120ms ease-out;
}

/* Lift on hover or *keyboard* focus only. `:focus-within` also matches the
   focus a mouse click leaves on the disclosure toggle, which kept a row lit
   after you clicked to collapse it; `:has(:focus-visible)` excludes that. */
[data-slot='aui_assistant-message-content'] [data-conversation-scaffold]:is(:hover, :has(:focus-visible)) {
  opacity: 1;
}

/* Shiki surfaces in the inline file diff + source preview: strip the theme's
   own background/margins, and lay each `.line` on its own grid row so the
   inter-line `\n` text nodes can't double-space full-width rows. Empty lines
   carry a non-breaking space so blank rows keep their height. */
[data-slot='file-diff-panel'] .shiki,
[data-slot='file-diff-panel'] .shiki code,
.preview-source-code .shiki,
.preview-source-code .shiki code {
  margin: 0;
  background: transparent !important;
}

[data-slot='file-diff-panel'] .shiki code,
.preview-source-code .shiki code {
  display: grid;
}

[data-slot='file-diff-panel'] .shiki code .line:empty::before,
.preview-source-code .shiki code .line:empty::before {
  content: '\00a0';
}

/* Inline diff rows keep their utility-class padding; just floor the height. */
[data-slot='file-diff-panel'] .shiki code .line {
  min-height: 1.25rem;
  white-space: pre;
}

/* Source rows are a fixed editor-height box so source⇄diff toggling never
   shifts and the gutter stays aligned. */
.preview-source-code .shiki code {
  min-width: max-content;
}

.preview-source-code .shiki code .line {
  display: block;
  height: 1.25rem;
  padding: 0 0.625rem;
  line-height: 1.25rem;
  white-space: pre;
}

/* The github-dark token palette reads candy-bright at our small code size.
   `github-dark-dimmed` only dims the *background* (which we strip), so soften
   the token *foregrounds* directly β€” a small saturation + brightness pullback,
   hues preserved β€” for both code blocks and inline diffs. Dark mode only. */
.dark .shiki {
  filter: saturate(0.82) brightness(0.92);
}

/* File edits (write_file / edit_file / patch) are the deliverable, not
   scaffolding β€” the diff is what the user reviews, like a PR. An *expanded*
   edit stays at full strength; collapsed it fades like any other row. The
   `data-file-edit` marker sits on the same row element and is only present
   while the row is open. */
[data-slot='aui_assistant-message-content'] [data-slot='tool-block'][data-tool-row][data-file-edit] {
  opacity: 1;
}

/* Conversation block rhythm. assistant-ui renders each range as a direct child
   of the message content with no per-part wrapper, so adjacency rules cover
   every pairing β€” first block needs no reset, nested tool rows are untouched.

   One gap between top-level blocks, whatever they are. Spelling out which
   *pairs* qualified meant the live status line (not tool, thinking or prose)
   fell through every branch and carried its own half-size margin instead. */
[data-slot='aui_assistant-message-content']
  > :is([data-slot='tool-block'], [data-slot='aui_thinking-disclosure'], [data-slot='aui_turn-activity'], .aui-md)
  + :is([data-slot='tool-block'], [data-slot='aui_thinking-disclosure'], [data-slot='aui_turn-activity'], .aui-md) {
  margin-top: var(--turn-block-gap);
}

/* Except prose ↔ prose: one reading column that happens to arrive as several
   parts, so it keeps the in-block paragraph rhythm. Same specificity as the
   rule above and deliberately after it. */
[data-slot='aui_assistant-message-content'] > .aui-md + .aui-md {
  margin-top: var(--paragraph-gap);
}

/* And except scaffolding ↔ scaffolding: the full gap is the space between the
   reply and the work around it, so a back-to-back run of thinking headers,
   tool rows and status lines spent it between every line and read as stacked
   cards. Same list as the rule above minus prose β€” `data-conversation-scaffold`
   is the wrong hook here: it's absent on a multi-call tool GROUP, which is most
   of a real run, and present on rows nested inside one. */
[data-slot='aui_assistant-message-content']
  > :is([data-slot='tool-block'], [data-slot='aui_thinking-disclosure'], [data-slot='aui_turn-activity'])
  + :is([data-slot='tool-block'], [data-slot='aui_thinking-disclosure'], [data-slot='aui_turn-activity']) {
  margin-top: var(--scaffold-block-gap);
}

/* Except a file edit, which is the deliverable rather than another line in the
   run β€” a diff you read like a PR, so it keeps the full block gap on both
   sides while the scaffolding around it stays tight. `data-file-edit` is only
   on the row while it's open, so a collapsed edit rejoins the run. Margins on
   the block itself, not adjacency pairs: it needs the clearance whatever sits
   next to it, and adjacent margins collapse rather than stacking. */
[data-slot='aui_assistant-message-content'] > [data-tool-row][data-file-edit] {
  margin-block: var(--turn-block-gap);
}

/* Thinking headers carry a faint resting caret. A run of them is the one place
   the affordance isn't otherwise discoverable β€” every other disclosure sits in
   a row you're already reaching for. The scaffold fade multiplies this, so the
   painted value lands well under the number here. */
[data-slot='aui_thinking-disclosure'] {
  --disclosure-caret-rest: 0.4;
}

/* A streaming turn is sealed into several assistant bubbles as it goes
   (`message.interim`) and rehydrates into fewer, so the same two blocks are
   sometimes siblings inside one bubble and sometimes split across two. The
   flex gap between bubbles is the turn gap β€” half the block gap β€” which made
   the rhythm visibly tighten and then relax as a turn settled. Top it up so
   the column ticks at one interval either way. */
[data-slot='aui_turn-pair'] > [data-slot='aui_assistant-message-root'] + [data-slot='aui_assistant-message-root'] {
  margin-top: calc(var(--turn-block-gap) - var(--conversation-turn-gap));
}

/* Unless the blocks either side of that seal are both scaffolding, in which
   case the scaffold gap is the target and the flex gap already overshoots it.
   Topping up to the full block gap here is what made a live run relax between
   rows and then tighten once it rehydrated into one bubble. A bubble carrying
   an open diff is excluded β€” it keeps the full gap, same as in-flow. */
[data-slot='aui_turn-pair']
  > [data-slot='aui_assistant-message-root']:has(
    > [data-slot='aui_assistant-message-content']
      > :is([data-slot='tool-block'], [data-slot='aui_thinking-disclosure'], [data-slot='aui_turn-activity']):last-child
  ):not(:has([data-file-edit]))
  + [data-slot='aui_assistant-message-root']:has(
    > [data-slot='aui_assistant-message-content']
      > :is(
        [data-slot='tool-block'],
        [data-slot='aui_thinking-disclosure'],
        [data-slot='aui_turn-activity']
      ):first-child
  ):not(:has([data-file-edit])) {
  margin-top: calc(var(--scaffold-block-gap) - var(--conversation-turn-gap));
}

/* Message action bars β€” flat icon hits with default dim; only the hovered/focused control is full-strength.
   The reaction slot lives OUTSIDE the bar (a landed emoji must not ride the
   bar's hover fade) but is still one of these controls visually. */
[data-slot='aui_msg-actions'] button,
button[data-slot='aui_msg-reactions'] {
  border: 0;
  border-radius: 0;
  background: transparent;
  box-shadow: none;
  padding: 0;
  gap: 0;
  height: auto;
  width: auto;
  min-height: 0;
  min-width: 0;
  flex-shrink: 0;
  cursor: pointer;
  color: var(--color-muted-foreground);
  opacity: 0.5;
}

/* A landed reaction is content, not a dimmed affordance β€” emoji render at
   full strength everywhere, always (color dim would gray them anyway; they're
   glyphs, not icons). */
button[data-slot='aui_msg-reactions'][data-reacted] {
  opacity: 1;
  color: inherit;
}

/* The EMPTY slot is an affordance and follows its action-bar neighbors
   exactly: hidden until the message is hovered, then the same 0.5 dim, full
   strength under the pointer. Stylesheet-owned because the base rule above
   outweighs Tailwind's opacity utilities (0,1,1 vs 0,1,0). */
button[data-slot='aui_msg-reactions']:not([data-reacted]) {
  opacity: 0;
  pointer-events: none;
}

.group:hover button[data-slot='aui_msg-reactions']:not([data-reacted]),
button[data-slot='aui_msg-reactions']:not([data-reacted]):focus-visible,
button[data-slot='aui_msg-reactions']:not([data-reacted])[data-state='open'] {
  opacity: 0.5;
  pointer-events: auto;
}

/* Failed-turn error card actions (Retry Β· Switch provider Β· Open logs Β·
   Copy diagnostics) β€” compact pill buttons tinted to the card's destructive
   palette. Stylesheet-owned so the CopyButton inline appearance picks the
   same look via the shared class. */
.aui-error-action {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  border: 1px solid color-mix(in srgb, var(--dt-destructive) 30%, transparent);
  border-radius: 9999px;
  background: transparent;
  padding: 0.1rem 0.55rem;
  font-size: 0.72rem;
  line-height: 1.1rem;
  color: color-mix(in srgb, var(--dt-destructive) 80%, var(--ui-text-secondary));
  cursor: pointer;
}

.aui-error-action:hover {
  background: color-mix(in srgb, var(--dt-destructive) 10%, transparent);
}

.group:hover button[data-slot='aui_msg-reactions']:not([data-reacted]):hover,
button[data-slot='aui_msg-reactions']:not([data-reacted])[data-state='open'] {
  opacity: 1;
}

/* Emoji in ANY reaction surface (badge under a user bubble, footer slot,
   picker rows) never inherit a translucent treatment from their container. */
[data-slot='aui_msg-reactions'] .reaction-pop,
span[data-slot='aui_msg-reactions'] {
  opacity: 1;
}

[data-slot='aui_msg-actions'] button:disabled {
  cursor: default;
}

[data-slot='aui_msg-actions'] button:hover,
button[data-slot='aui_msg-reactions']:hover {
  background: transparent;
  color: var(--color-foreground);
  opacity: 1;
}

[data-slot='aui_msg-actions'] button:active,
button[data-slot='aui_msg-reactions']:active {
  background: transparent;
}

[data-slot='aui_msg-actions'] button:focus-visible,
button[data-slot='aui_msg-reactions']:focus-visible {
  opacity: 1;
}

[data-slot='aui_msg-actions'] button svg,
button[data-slot='aui_msg-reactions'] svg {
  width: 0.875rem;
  height: 0.875rem;
}

/* Re-declare the clearance calc on every chat surface. `:root` computes it
   once against the ROOT measurement, so scoping only the input would leave
   every thread reading the same substituted value. Redeclaring here makes each
   surface resolve the calc against its own dock height, falling back to the
   root default until this surface publishes its first measurement. See
   surface-vars.ts. */
[data-chat-surface] {
  --thread-last-message-clearance: calc(var(--composer-measured-height) + 2rem);
}

/* A live tool run, shown as one line. `ToolRunTicker` stacks the run's rows
   into a reel and offsets it by the newest row's index, so each new action
   slides the one before it up and out of a single-line window β€” the run reads
   as one line ticking over in place rather than a list growing down the page.
   Rows are clipped to a uniform line box so the offset stays exact whatever a
   row contains. */
.tool-ticker {
  height: var(--conversation-line-height);
  overflow: hidden;
}

.tool-ticker__reel {
  transform: translateY(calc(var(--tool-ticker-index, 0) * var(--conversation-line-height) * -1));
  transition: transform 240ms cubic-bezier(0.22, 1, 0.36, 1);
}

.tool-ticker__row {
  display: flex;
  height: var(--conversation-line-height);
  align-items: center;
  overflow: hidden;
}

@media (prefers-reduced-motion: reduce) {
  .tool-ticker__reel {
    transition: none;
  }
}

@keyframes code-card-stream-enter {
  from {
    opacity: 0.74;
    transform: translateY(0.375rem);
  }

  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* Floating "jump to bottom" control (see scroll-to-bottom-button.tsx).
   Directional scale: it contracts toward 1 as it arrives (from 1.1) and keeps
   contracting to 0.9 as it leaves β€” always shrinking in the direction of
   travel, so the motion reads as a soft settle / recede rather than a pop. The
   X half-offset stays baked into every transform so `left-1/2` centering holds
   through the animation. */
.thread-jump-button {
  opacity: 0;
  transform: translateX(-50%) translateY(0.3rem) scale(0.9);
}

.thread-jump-button[data-state='in'] {
  animation: thread-jump-in 200ms cubic-bezier(0.22, 1, 0.36, 1) forwards;
}

.thread-jump-button[data-state='out'] {
  animation: thread-jump-out 180ms ease-in forwards;
}

@keyframes thread-jump-in {
  from {
    opacity: 0;
    transform: translateX(-50%) translateY(0.3rem) scale(1.1);
  }

  to {
    opacity: 1;
    transform: translateX(-50%) translateY(0) scale(1);
  }
}

@keyframes thread-jump-out {
  from {
    opacity: 1;
    transform: translateX(-50%) translateY(0) scale(1);
  }

  to {
    opacity: 0;
    transform: translateX(-50%) translateY(0.3rem) scale(0.9);
  }
}

@media (prefers-reduced-motion: reduce) {
  .thread-jump-button[data-state='in'],
  .thread-jump-button[data-state='out'] {
    animation: none;
    transition: opacity 120ms linear;
  }

  .thread-jump-button[data-state='in'] {
    opacity: 1;
    transform: translateX(-50%) translateY(0) scale(1);
  }
}

@keyframes code-card-stream-glow {
  from {
    box-shadow:
      0 0 0 0.0625rem color-mix(in srgb, var(--dt-ring) 6%, transparent),
      0 0.5rem 1.5rem color-mix(in srgb, var(--dt-ring) 5%, transparent);
  }

  to {
    box-shadow:
      0 0 0 0.0625rem color-mix(in srgb, var(--dt-ring) 12%, transparent),
      0 0.75rem 2rem color-mix(in srgb, var(--dt-ring) 10%, transparent);
  }
}

@media (prefers-reduced-motion: reduce) {
  [data-slot='aui_assistant-message-content'] .aui-md [data-slot='code-card'][data-streaming='true'] {
    animation: none;
  }
}

/* -------------------------------------------------------------------------- */
/* Pet egg hatch (Cmd-K β†’ Pets β†’ Generate)                                    */
/* The incubation wobble + reveal flash/pop give the draft→pet step a         */
/* PokΓ©mon-style "egg is hatching" beat instead of a bare spinner.            */
/* -------------------------------------------------------------------------- */

.pet-egg {
  position: relative;
  width: 5.5rem;
  height: 7rem;
  border-radius: 50% 50% 50% 50% / 62% 62% 38% 38%;
  background: radial-gradient(
    120% 90% at 32% 26%,
    color-mix(in srgb, var(--ui-accent) 14%, #fff) 0%,
    #f4ecd8 46%,
    #e4d3ad 100%
  );
  box-shadow:
    inset -0.45rem -0.6rem 1.1rem color-mix(in srgb, #000 16%, transparent),
    inset 0.35rem 0.4rem 0.7rem color-mix(in srgb, #fff 70%, transparent),
    0 0.4rem 0.9rem color-mix(in srgb, #000 22%, transparent);
  transform-origin: 50% 88%;
  animation: pet-egg-wobble 2.4s ease-in-out infinite;
}

/* Compact egg (empty-state hero). Children are %-based so they track the size;
   only the rem box-shadow needs scaling down to stay crisp. */
.pet-egg--sm {
  width: 3.25rem;
  height: 4.1rem;
  box-shadow:
    inset -0.28rem -0.38rem 0.7rem color-mix(in srgb, #000 16%, transparent),
    inset 0.22rem 0.26rem 0.45rem color-mix(in srgb, #fff 70%, transparent),
    0 0.25rem 0.55rem color-mix(in srgb, #000 22%, transparent);
}

.pet-egg__shine {
  position: absolute;
  top: 14%;
  left: 22%;
  width: 28%;
  height: 22%;
  border-radius: 50%;
  background: color-mix(in srgb, #fff 85%, transparent);
  filter: blur(2px);
  opacity: 0.85;
}

.pet-egg__spot {
  position: absolute;
  border-radius: 50%;
  background: color-mix(in srgb, var(--ui-accent) 70%, #b89b63);
  opacity: 0.55;
}

.pet-egg__glow {
  position: absolute;
  inset: -35%;
  border-radius: 50%;
  background: radial-gradient(circle, color-mix(in srgb, var(--ui-accent) 55%, transparent) 0%, transparent 62%);
  animation: pet-egg-glow 2.4s ease-in-out infinite;
  pointer-events: none;
}

.pet-egg-shadow {
  width: 4.5rem;
  height: 0.8rem;
  border-radius: 50%;
  /* Lighter on light backgrounds (~20% less ink); dark mode keeps it grounded. */
  background: radial-gradient(
    circle,
    color-mix(in srgb, #000 var(--pet-egg-shadow-ink, 26%), transparent) 0%,
    transparent 72%
  );
  animation: pet-egg-shadow 2.4s ease-in-out infinite;
}

.dark .pet-egg-shadow {
  --pet-egg-shadow-ink: 32%;
}

/* Contact shadow sized for the compact incubator egg (roughly its footprint). */
.pet-egg-shadow--sm {
  width: 3rem;
  height: 0.6rem;
}

/* Contact shadow under the revealed pet β€” mirrors the floating mascot's in-app
   shadow: an ellipse at the feet, ~55% of the sprite width, sitting behind it. */
.pet-contact-shadow {
  position: absolute;
  bottom: -0.15rem;
  left: 50%;
  width: 55%;
  aspect-ratio: 100 / 28;
  transform: translateX(-50%);
  background: radial-gradient(ellipse at center, color-mix(in srgb, #000 42%, transparent) 0%, transparent 70%);
  pointer-events: none;
  z-index: 0;
}

/* Hatch wiggle for the pixel egg (rocks around its base). */
.pet-wobble {
  transform-origin: 50% 85%;
  animation: pet-egg-wobble 2.4s ease-in-out infinite;
}

@media (prefers-reduced-motion: reduce) {
  .pet-wobble {
    animation: none;
  }
}

@keyframes pet-egg-wobble {
  0%,
  62%,
  100% {
    transform: rotate(0deg);
  }
  8% {
    transform: rotate(-7deg);
  }
  16% {
    transform: rotate(6deg);
  }
  24% {
    transform: rotate(-5deg);
  }
  32% {
    transform: rotate(4deg);
  }
  40% {
    transform: rotate(0deg);
  }
  /* the "almost out" burst */
  70% {
    transform: rotate(-12deg);
  }
  76% {
    transform: rotate(12deg);
  }
  82% {
    transform: rotate(-9deg);
  }
  88% {
    transform: rotate(7deg);
  }
  94% {
    transform: rotate(-3deg);
  }
}

@keyframes pet-egg-glow {
  0%,
  100% {
    opacity: 0.35;
    transform: scale(0.92);
  }
  70% {
    opacity: 0.4;
  }
  84% {
    opacity: 0.85;
    transform: scale(1.08);
  }
}

@keyframes pet-egg-shadow {
  0%,
  62%,
  100% {
    transform: scaleX(1);
    opacity: 0.6;
  }
  76% {
    transform: scaleX(0.8);
    opacity: 0.45;
  }
}

.pet-reveal {
  animation: pet-reveal-pop 620ms cubic-bezier(0.22, 1.4, 0.4, 1) both;
}

@keyframes pet-reveal-pop {
  0% {
    opacity: 0;
    transform: scale(0.35) translateY(0.4rem);
  }
  60% {
    opacity: 1;
    transform: scale(1.12) translateY(0);
  }
  100% {
    transform: scale(1) translateY(0);
  }
}

@keyframes reaction-pop {
  0% {
    opacity: 0;
    transform: scale(0.4);
  }
  60% {
    opacity: 1;
    transform: scale(1.18);
  }
  100% {
    transform: scale(1);
  }
}

/* Landing a reaction should feel like something β€” same pop shape as
   pet-reveal-pop, scaled down for an inline glyph. */
.reaction-pop {
  animation: reaction-pop 260ms cubic-bezier(0.34, 1.56, 0.64, 1) both;
}

@media (prefers-reduced-motion: reduce) {
  .pet-egg,
  .pet-egg__glow,
  .pet-egg-shadow,
  .pet-reveal {
    animation: none;
  }
  .reaction-pop {
    animation: none;
  }
  .pet-reveal {
    opacity: 1;
    transform: none;
  }
}

/* Pet generation progress bar β€” determinate (hatch rows: done/total) or         */
/* indeterminate (drafts, which return together so a % would just snap).         */
/* Sliding indeterminate block for the `accent` Progress variant (pet hatch
   flow). Color/positioning come from the primitive; this owns the animation. */
.progress-slide {
  width: 40%;
  /* left is pinned; travel is compositor-only (see arc-border note). */
  left: 0;
  will-change: transform;
  animation: progress-slide 1.15s ease-in-out infinite;
}

@keyframes progress-slide {
  /* Old version animated `left: -42% β†’ 100%`, forcing main-thread layout
     every frame for the whole hatch flow. The block is 40% of its track, so
     the same travel in units of its own width is -105% β†’ 250%. */
  0% {
    transform: translateX(-105%);
  }
  100% {
    transform: translateX(250%);
  }
}

@media (prefers-reduced-motion: reduce) {
  .progress-slide {
    animation: none;
    left: 0;
    width: 100%;
    opacity: 0.4;
  }
}

/* ── HUD mode ────────────────────────────────────────────────────────────────
   The chrome-free floating chat (`?win=hud`). Same renderer, same components,
   same transcript as any other window β€” this block only removes the frame and
   makes the window see-through. It deliberately does NOT restyle how messages
   render: the transcript is the app's transcript, and a HUD that reinvents
   bubbles is a second design to keep in sync. Layout and surface only. */

/* The HOST LAYERS are made transparent at mount, not here: index.html's
   pre-paint script sets an opaque themed background on <html> as an INLINE
   style (the anti-white-flash trick), and an inline style beats a stylesheet
   rule. Against that opaque wall every translucent panel below is just glass
   over white β€” which is exactly how this shipped: a plain opaque slab. The
   pet overlay and quick entry inject a style tag at mount for the same
   reason; HudShell does it too. See `hud-shell.tsx`. */

[data-hud-shell] {
  background: transparent;
  /* Arrive decisively and settle; leave gently and get out of the way. Linear
     both directions is what made this feel mechanical. */
  --hud-ease-enter: cubic-bezier(0.16, 1, 0.3, 1);
  --hud-ease-exit: cubic-bezier(0.4, 0, 0.7, 0.2);
  /* The band is narrower than the bar, centred under it, so the bar's corner
     controls sit clear of the sheet's edge instead of on top of it. */
  --hud-band-inset: 0.5rem;
}

/* Chat surface carries nothing in HUD mode β€” the visual is the BAND below. */
[data-hud-shell] [data-chat-surface] {
  background: transparent !important;
  overflow: hidden !important;
}

/* The scrollback β€” the chat BAND, straight from the nous-viz2d chat (which is
   the reference for this whole surface): a fixed-height smoked strip hugging
   the input, tinted from the theme, with the text simply sitting in it.

     - viz2d: `bg-black/20` at rest β†’ `bg-black/60` on hover / focus-within /
       pending. Same mechanism here, theme-aware: the tint is the theme's own
       background colour, so it reads correctly on dark and light themes alike
       and text keeps its normal contrast against it.
     - VISIBILITY keeps the WoW fade: shown while a turn is recent/streaming
       (`data-hud-recent`) or the composer is focused, melted away otherwise.
       viz2d's band never hides β€” ours does, because idle HUD mode is just the
       Spotlight bar.
     - Focus steps the tint to fully solid: typing means reading conditions.

   Reveal is fast, fade-out is slow β€” the reveal is an answer to the user, the
   fade is furniture leaving the room. */
[data-hud-shell] [data-slot='composer-bounds'] {
  position: absolute !important;
  /* THE BAND IS THIS BOX. It sits against the bar and is exactly as tall as the
     transcript is allowed to be β€” same geometry as the sheet behind it, same
     clock β€” so the text is clipped away as the panel rolls rather than fading
     in place, and the box that scrolls is the box you can see.

     It ran the full window for a long time, clipped down to the band for paint
     and hit-testing. That works right up until the band is CAPPED: the scroll
     container was still window-tall, so content shorter than the window never
     overflowed it and never scrolled, while the clip hid everything past the
     cap. A capped band has to be a real box or half the transcript is
     unreachable.

     No fill of its own β€” the sheet is its own layer ([data-hud-glass]) so it
     can animate independently of the text. */
  inset: auto var(--hud-band-inset) var(--hud-bar-height, var(--composer-fallback-height)) var(--hud-band-inset) !important;
  height: var(--hud-band-height, 0px) !important;
  width: auto !important;
  max-width: none !important;
  flex: none !important;
  border: 0 !important;
  /* Rounded away from the bar, square where it meets it. */
  border-radius: 0.75rem 0.75rem 0 0;
  background: transparent !important;
  /* Three opacity states: gone at rest, half strength when a turn is recent or
     you've just let go of the composer (there to glance at, not to demand
     attention), full while you're actually reading it. */
  opacity: 0;
  translate: 0 var(--hud-exit-shift, 2.5rem);
  transition:
    opacity var(--hud-fade) var(--hud-ease-exit),
    translate var(--hud-collapse) var(--hud-ease-exit),
    scale var(--hud-dim) var(--hud-ease-enter),
    filter var(--hud-dim) var(--hud-ease-enter);
  transform-origin: bottom center;
}

/* Shown: recent turn / streaming, or a focused composer.

   POINTER EVENTS ARE THE GATE: unfocused, the band is a ghost you can't touch
   β€” clicks in that region fall through to the shell's drag region (so the
   whole upper window is a drag handle at rest) and the band can't eat a
   scroll or a stray click while you're aiming at the app behind it. Focus the
   composer and it becomes a real scrollable surface. This also means hover
   alone can't reveal the band anymore β€” hover is not engagement. */
/* The band's sheet, behind the transcript: a tint the whole surface ramps out
   with, so the band has no top edge at all.

   CSS backdrop-filter reaches nothing here β€” a transparent window's backdrop
   root is the document, and the desktop was never in it (verified on the real
   window, not assumed). The blur is a native platform material instead, and
   because it is composited below the web contents after this process has
   finished drawing, no mask, clip or stacking order can shape it: it is the
   whole window rectangle or nothing. That is why it is switched on only while
   the band covers the window (useHudGlass) and why the sheet must be a flat
   panel β€” under a fading GRADIENT the frost stayed a slab and the top of the
   band went pale exactly where it should have been disappearing. Shaping it
   would need NSVisualEffectView.maskImage behind a native addon.

   Under Glass the sheet wears the SAME paint the docked thread does:
   `--ui-bg-chrome` kept at `--translucency-glass-keep`, the one number
   store/translucency publishes from the Tint slider (see the
   `[data-hermes-glass]` block). One painter, one token, one lever β€” the band
   reads as the app's thread surface rather than as a HUD-only lookalike that
   drifts the first time either side is touched.

   With Glass off there is no material behind the window, so the sheet keeps
   its own card tint. Heavier than the text in front of it, deliberately: with
   no blur to separate the band from what it lies over, the sheet is the only
   thing keeping half-opacity text off someone else's UI. Fade the words, keep
   the paper. */
/* A DARK scrim, not the theme's card. The band's ink is white unconditionally
   (see above), so the sheet it lands on has to be dark in every theme β€”
   `--dt-card` is near-white on a light theme and would put white text on a white
   panel. This is the overlay's own surface, the way a game's chat backdrop is
   its own thing rather than a piece of the desktop UI. */
[data-hud-shell] [data-hud-glass] {
  position: absolute;
  right: var(--hud-band-inset);
  bottom: var(--hud-bar-height, var(--composer-fallback-height));
  left: var(--hud-band-inset);
  z-index: 0;
  pointer-events: none;
  border-radius: 0.75rem 0.75rem 0 0;
  background: rgb(12 14 18 / 0.62);
  /* Slides down behind the bar as it fades. A TRANSFORM, not height: it is
     composited, so it stays smooth where animating height re-lays-out the panel
     every frame and looked coarse β€” and it leaves the box alone, which matters
     because the one time the transcript's own container was collapsed the
     messages spilled out of a zero-height box. Translate rather than scale: the
     panel keeps its proportions on the way out instead of being squashed.
 
     The height below still tracks the transcript; only the offset animates on
     exit, and it finishes ahead of the fade so the panel has left while the last
     of the text is still going. */
  height: var(--hud-band-height, 0px);
  translate: 0 var(--hud-exit-shift, 2.5rem);
  opacity: 0;
  transform-origin: bottom center;
  transition:
    opacity var(--hud-fade) var(--hud-ease-exit),
    translate var(--hud-collapse) var(--hud-ease-exit),
    scale var(--hud-dim) var(--hud-ease-enter),
    filter var(--hud-dim) var(--hud-ease-enter),
    height var(--hud-reveal) var(--hud-ease-enter),
    background-color var(--hud-dim) var(--hud-ease-enter);
}

/* The sheet is FOCUS-ONLY. A turn landing brings the text up (see
   `composer-bounds` below) but must not paint a panel behind it: over a game
   the tinted sheet is the thing that reads as a desktop window parked on the
   action, and it is most of the HUD's rectangle. Streaming shows words on the
   game; sitting down to read promotes the surface. */
[data-hud-shell]:has([data-slot='composer-rich-input']:focus) [data-hud-glass] {
  translate: none;
  opacity: 1;
  transition-duration: var(--hud-reveal);
}

/* ── Under Glass ─────────────────────────────────────────────────────────────
   The band becomes the app's thread surface: the docked window's field mix,
   over the platform material.

   Keyed to `data-hermes-glass-on` β€” "the user's Glass setting is live" β€” and
   NOT to `data-hermes-glass`, which additionally means "this window's field
   surfaces may be rewritten" and is false here by design: the HUD is a
   transparent window that owns its own backgrounds (isChatWindow). Two flags,
   because the HUD wants the setting without the rewrite. */
:root[data-hermes-glass-on] [data-hud-shell] [data-hud-glass] {
  /* Same dark scrim under Glass. The docked thread's `--ui-bg-chrome` follows
     the theme and goes near-white on a light one, which is the wrong paper for
     this band's white ink β€” the HUD is over a game, not inside the app. */
  background: rgb(12 14 18 / 0.55);
}

/* The band spans the window edge to edge under glass. The 8px side inset keeps
   the sheet clear of the bar's corner controls when it is an opaque panel β€”
   but the frost is the WINDOW, so an inset sheet leaves a hairline of bare
   untinted material down both sides. Nothing to hold off the material's edge:
   the window's own rounded corners are where the band ends. */
/* Inset under Glass too β€” 6px, so the sheet is narrower than the bar and
   centered under it. Full-bleed looked like a slab with two slivers beside the
   bar's rounded bottom corners: the sheet's square top corners poked out past
   the bar's silhouette, which is the gap down each side. Narrower than the bar
   means the bar's shape is the widest thing in the HUD and nothing peeks. */
:root[data-hermes-glass-on] [data-hud-shell] {
  --hud-band-inset: 0.375rem;
}

/* Radius follows the edge the band hangs from, and this rule has to carry the
   edge itself: `:root[data-hermes-glass-on] … [data-hud-glass]` outweighs the
   `[data-hud-edge='top']` flip below (four compound parts against three), so a
   radius set here unqualified wins everywhere and rounds the corners that meet
   the bar while squaring the free ones. */
:root[data-hermes-glass-on] [data-hud-shell] [data-hud-glass] {
  border-radius: 0.75rem 0.75rem 0 0;
}

:root[data-hermes-glass-on] [data-hud-shell][data-hud-edge='top'] [data-hud-glass] {
  border-radius: 0 0 0.75rem 0.75rem;
}

/* Engaged, the field steps up the same way the docked thread's does β€” but
   never below the resting tint, so a high lever cannot make focusing the
   composer paint MORE transparent than glancing at it. */
:root[data-hermes-glass-on] [data-hud-shell]:has([data-slot='composer-rich-input']:focus) [data-hud-glass] {
  background: rgb(12 14 18 / 0.72);
}

/* Engaged means the caret is in the composer, not merely that the window holds
   focus somewhere. Activating a window restores focus to whatever had it last,
   so `:focus-within` counted grabbing the bar to DRAG the HUD as sitting down
   to use it, and the transcript flew open every time it was moved. Hit-testing
   below stays on :focus-within β€” being permissive about what can be clicked is
   harmless, being permissive about what lights up is not. */
[data-hud-shell]:has([data-slot='composer-rich-input']:focus) [data-hud-glass] {
  background: rgb(12 14 18 / 0.82);
}

/* Flipped, the sheet hangs from the bar instead of standing on it. */
[data-hud-shell][data-hud-edge='top'] [data-hud-glass] {
  top: var(--hud-bar-height, var(--composer-fallback-height));
  bottom: auto;
  --hud-exit-shift: -2.5rem;
  border-radius: 0 0 0.75rem 0.75rem;
}

/* WHAT ANSWERS THE CURSOR β€” and, because `useHudClickThrough` hands the window
   to the desktop wherever the document reports nothing under the mouse, what
   the HUD occupies as far as the rest of the screen is concerned.

   Default to none and let surfaces opt in. The HUD is mostly scaffolding β€” the
   shell, the chat surface, the routes wrapper β€” all full-window, all invisible,
   and all hit-testable, so the window came back "something is here" for every
   point in its rectangle and ate clicks meant for the app behind it. Written
   this way round because that scaffolding is not a list anyone maintains: one
   more wrapper between the shell and the bar would quietly restore the dead
   rectangle, whereas a control that forgets to opt in is visibly dead. */
[data-hud-shell] {
  pointer-events: none;
}

/* WHAT ANSWERS THE CURSOR is FOCUS, not visibility. A streaming reply is
   something you read over the game, not something you aim at: while the band is
   merely visible every click inside its rectangle is a click the game does not
   get (the window is only mouse-transparent where the document reports nothing,
   so an interactive band IS a dead zone over the action). Sitting down in the
   composer is the deliberate act that makes the transcript a surface you can
   scroll and click links in. */
[data-hud-shell]:has([data-slot='composer-rich-input']:focus) [data-slot='composer-bounds'] {
  pointer-events: auto;
}

/* A held band is the interface β€” clarify / approval / a live turn. It must
   take clicks even if the composer never received focus. On click-through
   hosts that is a deliberate dead zone over the game; on a prompt it is a
   surface you cannot use. */
[data-hud-shell][data-hud-held] [data-slot='composer-bounds'] {
  pointer-events: auto;
}

/* Linux X11 is a solid window: ignore-mouse cannot restore, so a visible
   band that still has pointer-events:none swallows the click and does
   nothing. Once the band is up it is the surface. */
[data-hud-shell][data-hud-input='solid'][data-hud-recent] [data-slot='composer-bounds'] {
  pointer-events: auto;
}

/* Widgets and links opt in even when the band is a ghost, so a click-through
   HUD can still answer a clarify option or open an OAuth URL without sitting
   in the composer first. Children inherit auto from these roots. */
[data-hud-shell]
  :is(
    [data-slot='clarify-inline'],
    [data-clarify-choices],
    [data-clarify-batch],
    [data-slot='tool-approval-inline'],
    [data-slot='tool-approval-fallback'],
    [data-slot='tool-approval-actions'],
    a[href]
  ) {
  pointer-events: auto;
}

/* Three states, not two. A turn landing brings the transcript up, but only part
   way β€” it is there to be glanced at over whatever you are actually doing, and
   full-strength text over another app reads as the HUD demanding attention it
   hasn't earned. Focus is what promotes it to properly readable; the hold and
   fade then take it away from wherever it was. */
[data-hud-shell][data-hud-recent] [data-slot='composer-bounds'] {
  opacity: 1;
  translate: none;
  /* Same duration AND curve as the sheet's tint step, or the two visibly ease
     apart on the way down. */
  transition-duration: var(--hud-dim);
  transition-timing-function: var(--hud-ease-enter);
}

/* THE BAND IS ALWAYS LIGHT-ON-DARK. Unconditional, and that is the point: the
   transcript here is either bare text over another app or text on a translucent
   scrim, and in both cases the theme's near-black body ink is the wrong ink.
   Every earlier cut gated this on something β€” focus, then `data-hud-game` β€” and
   every gate produced a state where the words went black on a dark game. A
   HUD's legibility cannot depend on a condition being evaluated correctly; it
   is a property of the surface. The scrim below is darkened to match, so white
   is right whether the sheet is up or not. */
[data-hud-shell] [data-slot='composer-bounds'] {
  --hud-overlay-ink: #fff;
  /* WoW-epic gold: reads as "yours" against white agent text and survives being
     over a dark cave or a bright loading screen. */
  --hud-overlay-ink-user: #ffcf6b;
  color: var(--hud-overlay-ink);
  text-shadow:
    0 1px 2px rgb(0 0 0 / 0.9),
    0 0 6px rgb(0 0 0 / 0.55);
  /* Ramp the scrollback out at the top instead of guillotining it against the
     bar. With no sheet to end on, a hard edge reads as text sliced off; the
     fade says "there is more above" the way a game's chat log does. */
  --hud-top-fade: 3.5rem;
}

/* The mask has to ride the SCROLLER, not the band. `composer-bounds` is a
   static box: the rows scroll inside the thread viewport nested in it, so a
   mask there ramps over the band's own first 3.5rem while the overflowing text
   is already ABOVE that box (measured: rows at -117px, -81px, -55px relative
   to the band, and `scrollHeight === clientHeight` β€” nothing overflows the
   band itself). The viewport clips it hard before the band's mask is ever
   consulted, which is why raising the value changed nothing on screen. Masking
   the viewport puts the ramp where the clipping actually happens. */
[data-hud-shell] [data-slot='aui_thread-viewport'] {
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 var(--hud-top-fade, 3.5rem));
  mask-image: linear-gradient(to bottom, transparent 0, #000 var(--hud-top-fade, 3.5rem));
}

/* Every descendant that sets its own colour β€” assistant prose, user text,
   markdown, timestamps β€” inherits it too, or the ink change reaches the
   wrapper and nothing you can actually read. Widgets carve themselves out by
   resetting the variable (see below), so this stays one rule. */
[data-hud-shell] [data-slot='composer-bounds'] * {
  color: var(--hud-overlay-ink) !important;
}

/* Anything that paints its OWN light surface inside the band keeps the theme's
   ink β€” a clarify question, an approval prompt, an artifact card, a code block,
   a form control. The overlay's white ink exists for text sitting on the game;
   a widget brings its own paper, and forcing white there made the panel
   unreadable (a clarify prompt with white options on a near-white card).
   Done by moving the VARIABLE rather than adding a competing `color` rule: the
   one !important above reads `--hud-overlay-ink` from whatever ancestor is
   nearest, so a widget re-pointing it at the theme's ink re-inks its whole
   subtree with no specificity fight and no second copy of the selector list.
   The list is deliberately by SURFACE, not by feature: every entry paints a
   fill. That distinction matters for approvals β€” `tool-approval-fallback` wraps
   a real card (`--ui-chat-surface-background`) and its `<pre>` command block
   brings its own, but `tool-approval-inline` / `-actions` are bare rows sitting
   directly on the band, so they must stay WHITE like ordinary prose. Matching
   them by slot made their labels dark-on-game, which is the exact bug this rule
   exists to prevent, one level down. Match the fill, never the feature.
   Widgets on the shared shell (components/chat/widget-shell.ts β†’
   `--ui-widget-surface-background`) and any chat-surface card are matched on
   their class, so new ones inherit this without touching the list. */
[data-hud-shell]
  [data-slot='composer-bounds']
  :is(
    [data-slot='clarify-inline'],
    [data-slot='tool-block'],
    [data-slot='file-diff-panel'],
    [data-slot='code-card'],
    [data-slot='aui_system-message-root'],
    [class*='ui-widget-surface-background'],
    [class*='ui-chat-surface-background'],
    pre,
    input,
    textarea,
    select
  ) {
  --hud-overlay-ink: var(--ui-text-primary);
  --hud-overlay-ink-user: var(--ui-text-primary);
  text-shadow: none;
}

/* …except your OWN lines. With the bubble gone at rest, white-on-white is the
   only thing telling you apart from the agent, and it doesn't: the log reads as
   one voice. Tint them instead β€” the same job the bubble was doing, done with
   ink so it costs no surface. Warm gold rather than the theme's accent: it has
   to hold up over whatever is behind the window, and a blue or purple lands on
   top of exactly the palette most games use for their own UI. */
[data-hud-shell] :is([data-slot='aui_user-message-root'], .composer-human-message),
[data-hud-shell] :is([data-slot='aui_user-message-root'], .composer-human-message) * {
  color: var(--hud-overlay-ink-user) !important;
}

[data-hud-shell]:has([data-slot='composer-rich-input']:focus) [data-slot='composer-bounds'] {
  opacity: 1;
  translate: none;
  transition-duration: var(--hud-reveal);
  transition-delay: 0s;
}

/* A completion list is the whole interface for as long as it is open, and it
   hangs over the band. Two half-lit surfaces stacked on a third thing β€” the
   app underneath β€” is unreadable however the numbers are tuned, so the list
   goes fully opaque and the band falls back behind it: dimmer, fractionally
   smaller, slightly out of focus. Scaled from the bar's edge, so it reads as
   depth rather than as the panel shrinking. */
[data-hud-shell]:has([data-slot='composer-completion-drawer']) :is([data-slot='composer-bounds'], [data-hud-glass]) {
  opacity: 0.25 !important;
  scale: 0.97;
  filter: blur(1.5px);
}

[data-hud-shell] [data-slot='composer-completion-drawer'] {
  background: var(--dt-card) !important;
}

/* User messages ride the band like every other line. In the app each sticky
   user row paints an OPAQUE chat-surface slab behind it (so a stuck bubble can
   slide over scrolled text) and the bubble is solid --dt-user-bubble β€” inside
   the smoked band both read as fully opaque cards that ignore every fade. The
   slab goes unconditionally; the bubble is gone entirely at rest and returns
   when engaged. ONE variable carries the fill so there is no specificity fight
   between rest/engaged rules β€” the states just move the var. */
[data-hud-shell] {
  /* At rest there is no bubble: unfocused, the band is bare text over someone
     else's window, and a card around your own lines is the one thing in it
     that still reads as an app. The words stay (they are the log); the
     container stops being drawn. */
  --hud-bubble-fill: transparent;
  --hud-bubble-stroke: transparent;
}

/* ONE opacity law for the whole band: solid on focus, material otherwise.
   Bubbles going solid on `recent` too made them opaque cards floating on the
   62% band mid-stream β€” the band only steps solid on focus, so nothing inside
   it may step earlier. */
/* No bubble in the HUD, ever. The band's ink already distinguishes the two
   voices (white agent / gold yours), and a light card behind gold text is the
   one thing in here that fights the overlay's own contrast. */
[data-hud-shell]:has([data-slot='composer-rich-input']:focus) {
  --hud-bubble-fill: transparent;
  --hud-bubble-stroke: transparent;
}

[data-hud-shell] [data-slot='aui_user-message-root'] {
  background: transparent !important;
  /* Not sticky in HUD mode: the band is a short log, and a pinned bubble
     spends a third of it on a line you already read. Static rows scroll away
     like everything else (the app keeps its sticky behavior β€” this is the
     HUD's call, not a global one). */
  position: static !important;
}

/* User bubbles: the ONE thing in the band that paints its own opaque fill
   (bg-(--dt-user-bubble) on USER_BUBBLE_BASE_CLASS), so it survives every
   fade the band applies to its own background and reads as a solid card
   floating on glass. Two things are needed, and only doing one of them is
   why this kept coming back:
     - the FILL follows the band's state (--hud-bubble-fill), and
     - the BORDER does too; an opaque hairline outlines the card even when
       the fill is right.
   Fill and border both ride the same variable, so they cannot desync. */
[data-hud-shell] .composer-human-message {
  background: var(--hud-bubble-fill) !important;
  border-color: var(--hud-bubble-stroke) !important;
  backdrop-filter: none !important;
  -webkit-backdrop-filter: none !important;
  transition:
    background-color var(--hud-reveal) var(--hud-ease-enter),
    border-color 350ms ease;
}

/* The bubble's own container also paints the chat surface behind it. */
[data-hud-shell] .composer-human-message-container {
  background: transparent !important;
}

/* ONE glass element in HUD mode: [data-hud-glass]. Everything else drops its
   backdrop-filter β€” the composer tree ships several Tailwind backdrop-blur
   utilities (surface glass, fallback surface, attachment spinners, voice
   pills) that are invisible inside the opaque app but paint as smeared halos
   around the pill's rounded corners on a transparent window.

   Keep this exemption in step with whatever carries the glass: pointing it at
   the wrong element silently deletes the blur, which looks exactly like
   backdrop-filter not working at all. */
[data-hud-shell] *:not([data-hud-glass], [data-hud-glass] *) {
  backdrop-filter: none !important;
  -webkit-backdrop-filter: none !important;
}

/* No session header, no jump-to-bottom pill, no timeline rail. */
[data-hud-shell] header,
[data-hud-shell] [data-slot='thread-timeline'],
[data-hud-shell] .thread-jump-button {
  display: none !important;
}

/* The band is three lines of conversation over someone else's window, not a
   transcript. Tool rows, file diffs, and background notices ("Self-improvement
   review: patched …") are the docked app's job β€” here they push the actual
   answer out of view and read as junk pinned over the app below. */
[data-hud-shell] [data-slot='tool-block'],
[data-hud-shell] [data-slot='file-diff-panel'],
[data-hud-shell] [data-slot='aui_system-message-root'] {
  display: none !important;
}

/* ── Edge flip ───────────────────────────────────────────────────────────────
   Parked in the top half of the screen (data-hud-edge='top', broadcast by
   main on move/resize), the whole HUD mirrors vertically: composer hugs the
   window's top edge, the band hangs BELOW it, and text melts at the bottom.
   Same surfaces, same variables β€” only the anchors swap. */
[data-hud-shell][data-hud-edge='top'] [data-slot='composer-dock'] {
  top: 0 !important;
  bottom: auto !important;
}

/* Flipped, the band hangs from the bar instead of standing on it. */
[data-hud-shell][data-hud-edge='top'] [data-slot='composer-bounds'] {
  top: var(--hud-bar-height, var(--composer-fallback-height)) !important;
  bottom: auto !important;
  border-radius: 0 0 0.75rem 0.75rem;
}

/* …so the edge it falls back from is the bar's, which is now above it. */
[data-hud-shell][data-hud-edge='top'] :is([data-slot='composer-bounds'], [data-hud-glass]) {
  transform-origin: top center;
}

/* The completion list β€” `/`, `@`, `:`, and the help hint β€” hangs off the bar's
   outer edge, the same side the band is on. It grows UP by default, which is
   right everywhere the composer has a window above it; parked at the top edge
   there is nothing up there, so the list rendered off screen and `/` looked
   dead. Capped to the room below the bar, since the app's own cap assumes a
   full window. */
[data-hud-shell][data-hud-edge='top'] [data-slot='composer-completion-drawer'] {
  top: 100%;
  bottom: auto;
  margin-top: 0.25rem;
  margin-bottom: 0;
  max-height: calc(100dvh - var(--hud-bar-height, var(--composer-fallback-height)) - 0.75rem);
}

/* Tighten the thread on every side. The docked chat's gutters (px-6 py-8 plus
   a 1.5rem inline pad) are sized for a full window column; in a bar a few
   lines tall they're most of the surface. Bottom pad drops to a hairline β€”
   the band already ends at the bar, so any block-end padding here reads as a
   gap between the last message and the composer. */
/* Nudged inward, not edge to edge. The thread is a log floating over someone
   else's window, and text running into the band's rounded corners reads as a
   panel that has outgrown its box. The composer keeps the full width β€” it is
   the object; the log is what hangs off it. */
[data-hud-shell] [data-slot='aui_thread-content'] {
  width: 92% !important;
  margin-inline: auto !important;
  padding-inline: 0.6rem !important;
  padding-block: 0.35rem 0.25rem !important;
  /* A chat frame fills from the bottom. The docked thread hangs from the top
     because it is always taller than its content is short; the band is a few
     lines tall, so a two-message conversation left a dead gap between the last
     reply and the composer. Filling the viewport and packing to the end puts
     that slack ABOVE the text, where it's just more transparent window. */
  min-height: 100%;
  justify-content: flex-end;
}

/* Parked at the top the band hangs below the bar, so it fills downward. */
[data-hud-shell][data-hud-edge='top'] [data-slot='aui_thread-content'] {
  justify-content: flex-start;
}

/* The band's box already ends at the bar, so the app's dock clearance β€” sized
   to hold text out from under a composer it overlaps β€” would only open a hole
   the height of the bar between the last message and the composer. */
[data-hud-shell] [data-chat-surface] {
  --thread-last-message-clearance: 0.25rem;
}

/* Same for the dock's own bottom pad β€” this var also feeds
   --composer-measured-height, so the thread and the composer stay in
   agreement from one value. */
[data-hud-shell] {
  /* Conversation rhythm, tightened for a bar a few lines tall. The docked
     thread's spacing is sized for a full-height column; in the HUD that air is
     most of the band, and the ramp eats the older turns before you can read
     them. Same knobs the app uses, just smaller here. */
  --conversation-turn-gap: 0.1875rem;
  --turn-block-gap: 0.375rem;
  --paragraph-gap: 0.4rem;
  --composer-shell-pad-block-end: 0px;
  /* The viewport fills the band, period. The app's calc shortens the viewport
     to leave the dock's strips visible below it; the HUD hides those strips, so
     applying it here just strands a dead zone at the end of the thread that
     grows as you type. Room for the bar comes from the clearance instead. */
  --thread-viewport-height: 100%;
}

/* `-webkit-app-region: drag` in HUD mode is NATIVE WAYLAND ONLY. The window
   manager takes a draggable region's mouse input whole, so the page never sees the
   cursor arrive there β€” on macOS/Windows that starves `useHudClickThrough`,
   which decides solidity from exactly those moves, so the press falls through
   to the app behind (every app-region attempt there was therefore unusable,
   and left the HUD solid over dead space once you left it). Native Wayland's
   click-through decision is fed by MAIN's cursor poll (`startHudCursorFeed`),
   not page events, and apps cannot position their own top-level surfaces, so
   the compositor takes the press and moves the window with xdg_toplevel.move.
   X11 deliberately keeps the renderer drag path: a Chromium drag region
   intercepts the pointer stream needed by Ctrl+primary-button drag. The
   composer's interactive surface opts out with `-webkit-app-region: no-drag`
   (input element + global button rule); the rest of the bar is the handle.
   macOS/Windows/X11 use `useHudComposerDrag` β€” press and hold, then move. */

/* Grip affordance for the native Wayland drag band: the top padding (pt-4)
   is the only surface the region owns once the input/buttons are carved out,
   so make it look like a handle β€” a centered pill, like a mobile grip. */
.hud-native-drag::before {
  content: '';
  position: absolute;
  top: 6px;
  left: 50%;
  transform: translateX(-50%);
  width: 40px;
  height: 4px;
  border-radius: 9999px;
  background: color-mix(in srgb, var(--ui-text-tertiary) 55%, transparent);
  pointer-events: none;
}

[data-hud-shell] [data-slot='composer-dock'] {
  /* The one surface that is always there, so the one that always takes the
     mouse β€” everything else in the shell earns it by being on screen. */
  pointer-events: auto;
}

/* HUD mode is the input and the log β€” nothing else. The dock stacks
   [micro-action pills] Β· [status stack] Β· [composer] Β· [underside slot], and
   only the composer belongs here: the status stack (todos, subagents,
   background tasks, queue, the coding/cwd/git-branch row) and the strips
   around it are ambient chrome for a full window, and in a bar a few lines
   tall they'd shove the input off screen.

   Written as "keep the composer, hide its siblings" rather than a list of
   selectors, because those siblings carry no data-slot of their own β€” a list
   would silently miss whatever gets added to the dock next. */
[data-hud-shell] [data-slot='composer-dock'] > *:not([data-slot='composer-root']) {
  display: none !important;
}

/* The coding/cwd/git-branch strip is NOT a dock sibling β€” it renders inside
   `composer-surface` (it's meant to inherit the composer's width and top
   radius), so the rule above never reaches it. Same intent, own selector. */
[data-hud-shell] .coding-status-bar {
  display: none !important;
}

/* The composer is the Spotlight bar: centered, capped width, the ONE
   permanent object on screen. When the thread is faded out, this is all HUD
   mode is.

   The dock is `absolute bottom-0 left-1/2 -translate-x-1/2` against the chat
   surface. Two traps live in that, and both silently ate earlier attempts:
     - `margin-bottom` does NOTHING to an absolutely-positioned box anchored to
       an edge; the lift has to come from `bottom`.
     - Tailwind centers it with `left-1/2` + a translate, so BOTH `transform`
       and `translate` (the standalone property) must be cancelled β€” absolute
       centering here is left/right 0 + capped width + margin-inline auto.

   Do NOT restyle `position`: the controls row (model pill, mic, send) resolves
   against the nearest positioned ancestor, so making the dock static re-anchors
   that row and the composer tears in half β€” input in flow at the top, controls
   stranded at the bottom. */
[data-hud-shell] [data-slot='composer-dock'],
[data-hud-shell] [data-slot='composer-dock'][data-popped-out] {
  left: 0 !important;
  right: 0 !important;
  bottom: 0 !important;
  top: auto !important;
  width: 100% !important;
  max-width: none !important;
  transform: none !important;
  /* Keep this value indirect. Lightning CSS folds literal identity values into
     `transform: translate(0)`, which does not override Tailwind's standalone
     `translate: -50%`; the dock then starts half a HUD width off-screen. */
  --hud-composer-translate: 0;
  translate: var(--hud-composer-translate) !important;
  padding: 0 !important;
}

/* The bar is never "away". In the docked app the composer dims to 30% while
   you read back through the thread, and comes back on hover or focus β€” sensible
   when it's a panel at the bottom of a big window you're scrolling past. Here
   it IS the interface: the one permanent, fully-present object, whatever the
   transcript above it is doing. */
[data-hud-shell] [data-slot='composer-fade'] {
  opacity: 1 !important;
}

[data-hud-shell] [data-slot='composer-root'] {
  /* Opaque, so anything docked to the composer (status stack, queue panel)
     paints the same solid fill the bar does β€” they share this var. */
  --composer-fill: var(--dt-card);
  /* The base rule adds 5px of transparent grab margin for the peel-out drag,
     and the dock compensates with +10px of width. Neither applies here (the
     HUD composer doesn't peel out), and left in they inset the card unevenly
     inside its own float. */
  padding: 0 !important;
  width: 100% !important;
}

/* The composer surface paints TWO layers: the surface itself, plus an
   `absolute inset-0 -z-10` fill+glass div behind it (composerFill /
   composerSurfaceGlass). Two stacked fills read as a box inside a box, so the
   backing layer goes and the surface carries the single fill. */
[data-hud-shell] [data-slot='composer-surface'] > .pointer-events-none.absolute.inset-0 {
  display: none !important;
}

/* Opaque, pill-rounded β€” the Spotlight bar. Same surface tokens the composer
   already uses; only the radius steps up so a lone floating bar reads as an
   object rather than a snippet of app chrome.

   ALWAYS fully opaque. It's the input β€” the one thing that must never be
   compromised by whatever's behind the window, in any state. The idle/engaged
   breathing belongs to the thread and the chat surface; the bar just sits
   there, solid, like Spotlight does. */
[data-hud-shell] [data-slot='composer-surface'] {
  border: 1px solid var(--ui-stroke-secondary) !important;
  /* Same radius as the band's top and the window's own corners, so the HUD
     reads as one object however the band is behaving. Its top corners let a
     sliver of band through, which is the point β€” the glass wraps the bar's
     shoulders instead of stopping in a straight line above it. */
  border-radius: 0.75rem !important;
  background: var(--dt-card) !important;
  backdrop-filter: none !important;
  -webkit-backdrop-filter: none !important;
  /* Bottom edge only. Enough to lift the bar off whatever it is lying over β€”
     without it the HUD reads as pasted onto the other app β€” and tight enough
     that it never becomes a glow around a floating card. */
  box-shadow: 0 2px 2px -1px rgb(0 0 0 / 0.12) !important;
  transition: border-color var(--hud-reveal) var(--hud-ease-enter);
}

/* Focus: the border the bar already has, in the accent. Everything with its own
   geometry is out β€” the bar sits flush against the window, so a ring or a
   shadow is sawn off by the window before any CSS can shape it, and paying for
   the clearance moves the bar. Recolouring what is already drawn costs no
   space, cannot be clipped, and leaves the working arc as the only ring. */
[data-hud-shell]:has([data-slot='composer-rich-input']:focus) [data-slot='composer-surface'] {
  border-color: var(--dt-primary) !important;
}

/* GAME OVERLAY β€” a fullscreen app owns the screen (data-hud-game, pushed by
   main's window watch). The Discord treatment: the idle bar steps back to a
   low, glanceable opacity so it reads as part of the game's own HUD instead of
   a desktop window parked over the action. The bar's "always fully opaque"
   contract above is about never being COMPROMISED by what's behind it; over a
   game the whole bar fades as one object, which keeps it legible the moment it
   returns.

   Engagement wins, exactly like the band's own reveal: a recent turn, the
   caret in the composer, or the cursor over the bar (mousemove keeps flowing
   through the click-through window, so :hover is live even while ignoring)
   restores full strength β€” fast in, slow out, on the shell's shared clocks.

   The window keeps normal chrome-free behavior otherwise: no other state
   changes, so leaving the game hands back the standard HUD without a rebuild. */
[data-hud-shell][data-hud-game] [data-slot='composer-dock'] {
  opacity: 0.35;
  transition: opacity var(--hud-fade) var(--hud-ease-exit);
}

[data-hud-shell][data-hud-game][data-hud-recent] [data-slot='composer-dock'],
[data-hud-shell][data-hud-game]:focus-within [data-slot='composer-dock'],
[data-hud-shell][data-hud-game] [data-slot='composer-dock']:hover {
  opacity: 1;
  transition: opacity var(--hud-reveal) var(--hud-ease-enter);
}

/* Long-press drag armed β€” the whole bar is the handle until release. */
[data-hud-shell] [data-slot='composer-root'][data-hud-grabbing] [data-slot='composer-dock'] {
  cursor: grabbing;
}

/* The exit button. HUD mode has no titlebar, so this is the only visible way
   back β€” it rides the composer's controls row (see ExitHudButton in
   composer/controls.tsx) and therefore needs no placement, no reveal, and no
   substrate of its own here: it is one of the bar's buttons and wears what
   they wear.

   It used to float above the bar in a reserved 26px strip, hidden until you
   hovered. That strip was transparent window, which the glass band then
   rendered as a slab of bare untinted material across the top of the HUD, and
   the chip needed its own opaque card to be legible over an unknown desktop.
   Both problems were the placement, not the button: on the bar it is already
   on our surface. */

/* The resize frame β€” hot edges/corners, not buttons. The window is created
   non-resizable (the transparent-frameless Windows drag-growth bug), so this
   is the one sanctioned way to change the HUD's size; it drives
   `hermes:hud:set-bounds`, which flips resizable on for the call.

   CanvasTTY grammar: four edge strips + four larger corner targets, each with
   its native resize cursor and each preserving the opposite edge. Deliberately
   invisible chrome: no glyph or border over whatever app is below the HUD. */
[data-hud-shell] [data-hud-resize] {
  position: absolute;
  z-index: 20;
  pointer-events: auto;
  touch-action: none;
}

[data-hud-shell] [data-hud-resize='n'] {
  top: 0;
  right: 1.25rem;
  left: 1.25rem;
  height: 0.625rem;
  cursor: ns-resize;
}

[data-hud-shell] [data-hud-resize='e'] {
  top: 1.25rem;
  right: 0;
  bottom: 1.25rem;
  width: 0.625rem;
  cursor: ew-resize;
}

[data-hud-shell] [data-hud-resize='s'] {
  right: 1.25rem;
  bottom: 0;
  left: 1.25rem;
  height: 0.625rem;
  cursor: ns-resize;
}

[data-hud-shell] [data-hud-resize='w'] {
  top: 1.25rem;
  bottom: 1.25rem;
  left: 0;
  width: 0.625rem;
  cursor: ew-resize;
}

[data-hud-shell] [data-hud-resize='ne'],
[data-hud-shell] [data-hud-resize='se'],
[data-hud-shell] [data-hud-resize='sw'],
[data-hud-shell] [data-hud-resize='nw'] {
  width: 1.25rem;
  height: 1.25rem;
}

[data-hud-shell] [data-hud-resize='ne'] {
  top: 0;
  right: 0;
  cursor: nesw-resize;
}

[data-hud-shell] [data-hud-resize='se'] {
  right: 0;
  bottom: 0;
  cursor: nwse-resize;
}

[data-hud-shell] [data-hud-resize='sw'] {
  bottom: 0;
  left: 0;
  cursor: nesw-resize;
}

[data-hud-shell] [data-hud-resize='nw'] {
  top: 0;
  left: 0;
  cursor: nwse-resize;
}

/* The composer's drop target is a full-window dashed sheet sized for the app's
   chat column. In the HUD it is a white slab hanging under the bar on a fresh
   thread, and there is nowhere to drop anything into a bar anyway. */
[data-hud-shell] [data-slot='chat-drop-overlay'] {
  display: none !important;
}

/* The dock's fade-to-surface gradient assumes a chat column behind it; over a
   transparent HUD it's a grey smear. */
[data-hud-shell] [data-slot='composer-root'] > .pointer-events-none {
  display: none !important;
}

/* Popovers in a ~320px-tall window. Two separate problems:

   1. Radix clamps the popover to --radix-*-available-height, but fixed
      max-heights INSIDE the panels (the model catalog's max-h-[max(150px,
      30dvh)] list) don't shrink with it, so the list keeps its own floor and
      the menu overflows the window.
   2. The window IS the collision boundary, so even a correctly-clamped menu
      has only ~320px to live in.

   (1) is ours to fix in CSS; inner scrollers yield to the window instead of
   their own floor. (2) is why the menus are compact here rather than roomy β€”
   a HUD is a small window and a 400px menu cannot fit in it. */
html:has([data-hud-shell]) [data-slot='dropdown-menu-content'] [class*='max-h-'],
html:has([data-hud-shell]) [data-slot='popover-content'] [class*='max-h-'] {
  max-height: max(5rem, calc(100dvh - 9rem)) !important;
}

/* The menu panels themselves: never taller than the window minus the bar.
   Portalled out of the shell, they must still take the pointer β€” the HUD
   defaults to none and a right-click menu that cannot be clicked is dead. */
html:has([data-hud-shell]) [data-slot='dropdown-menu-content'],
html:has([data-hud-shell]) [data-slot='popover-content'] {
  max-height: calc(100dvh - 4.5rem) !important;
  overflow-y: auto;
  pointer-events: auto;
}

/* Hide the scrollbar β€” a HUD with a visible track stops reading as an overlay. */
[data-hud-shell] [data-slot='composer-bounds'] * {
  scrollbar-width: none;
}

[data-hud-shell] [data-slot='composer-bounds'] *::-webkit-scrollbar {
  display: none;
}