@oxy-hq/sdk 2.1.0 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/shell.css ADDED
@@ -0,0 +1,1187 @@
1
+ /* ============================================================================
2
+ @oxy-hq/sdk/shell — workspace chrome styles (icon rail + universal top bar)
3
+
4
+ Namespaced (`oxy-shell-*`) and self-contained: no Tailwind required in the
5
+ consuming app. Every color resolves through a two-level token scheme:
6
+
7
+ --oxy-shell-<name>: var(--<host token>, <pinned fallback>);
8
+
9
+ Inside the Oxygen web-app the host tokens (--sidebar-background, --border,
10
+ …) exist, so the shell tracks the product theme exactly. In an external
11
+ customer app the pinned fallbacks apply — their values are copied verbatim
12
+ from web-app/src/styles/shadcn/{light,dark}.css and must be kept in sync
13
+ with that file, not restyled here.
14
+
15
+ Dark mode: a `.dark` class on the scope element or any ancestor — the same
16
+ contract as the web-app (`data-theme` is decorative there; no CSS keys on
17
+ it). `color-scheme` is intentionally not set: the host app owns it.
18
+ ============================================================================ */
19
+
20
+ .oxy-shell-scope {
21
+ --oxy-shell-sidebar-bg: var(--sidebar-background, #fafafa);
22
+ --oxy-shell-sidebar-accent: var(--sidebar-accent, rgba(228, 228, 231, 0.5));
23
+ --oxy-shell-sidebar-accent-fg: var(--sidebar-accent-foreground, #18181b);
24
+ --oxy-shell-sidebar-border: var(--sidebar-border, #e5e7eb);
25
+ --oxy-shell-background: var(--background, #ffffff);
26
+ --oxy-shell-foreground: var(--foreground, #0a0a0a);
27
+ --oxy-shell-muted: var(--muted, #e4e4e7);
28
+ --oxy-shell-muted-fg: var(--muted-foreground, #52525b);
29
+ --oxy-shell-primary: var(--primary, #18181b);
30
+ --oxy-shell-primary-fg: var(--primary-foreground, #fafafa);
31
+ --oxy-shell-accent: var(--accent, #f5f5f5);
32
+ --oxy-shell-border: var(--border, #d4d4d8);
33
+ --oxy-shell-ring: var(--ring, #a1a1a1);
34
+ --oxy-shell-success: var(--success, #22c55e);
35
+ --oxy-shell-destructive: var(--destructive, #e7000b);
36
+ --oxy-shell-tooltip-bg: var(--zinc-200, #e4e4e7);
37
+ --oxy-shell-link: var(--info, #2563eb);
38
+ --oxy-shell-radius: var(--radius, 0.625rem);
39
+ --oxy-shell-font: var(--font-inter, "Inter", ui-sans-serif, system-ui, -apple-system, sans-serif);
40
+ --oxy-shell-font-mono: ui-monospace, "SF Mono", Menlo, monospace;
41
+
42
+ font-family: var(--oxy-shell-font);
43
+ }
44
+
45
+ .dark .oxy-shell-scope,
46
+ .oxy-shell-scope.dark {
47
+ --oxy-shell-sidebar-bg: var(--sidebar-background, #000000);
48
+ --oxy-shell-sidebar-accent: var(--sidebar-accent, rgba(255, 255, 255, 0.145));
49
+ --oxy-shell-sidebar-accent-fg: var(--sidebar-accent-foreground, #ededed);
50
+ --oxy-shell-sidebar-border: var(--sidebar-border, #27272a);
51
+ --oxy-shell-background: var(--background, #0a0a0a);
52
+ --oxy-shell-foreground: var(--foreground, #ededed);
53
+ --oxy-shell-muted: var(--muted, #27272a);
54
+ --oxy-shell-muted-fg: var(--muted-foreground, #a1a1aa);
55
+ --oxy-shell-primary: var(--primary, #ededed);
56
+ --oxy-shell-primary-fg: var(--primary-foreground, #0a0a0a);
57
+ --oxy-shell-accent: var(--accent, #262626);
58
+ --oxy-shell-border: var(--border, rgba(255, 255, 255, 0.145));
59
+ --oxy-shell-ring: var(--ring, #525252);
60
+ --oxy-shell-success: var(--success, #22c55e);
61
+ --oxy-shell-destructive: var(--destructive, #ff6467);
62
+ --oxy-shell-tooltip-bg: var(--muted, #27272a);
63
+ --oxy-shell-link: var(--info, #60a5fa);
64
+ }
65
+
66
+ /* ─── Frame (OxyShell / ShellLayout) ────────────────────────────────────── */
67
+
68
+ .oxy-shell {
69
+ position: relative; /* portal anchor for tooltips */
70
+ display: flex;
71
+ height: 100%;
72
+ width: 100%;
73
+ background: var(--oxy-shell-background);
74
+ color: var(--oxy-shell-foreground);
75
+ }
76
+
77
+ /* Degraded (bootstrap unavailable): the wrappers stay mounted so the app
78
+ tree never reparents, but they impose nothing — no chrome, no colors,
79
+ no font, no scroll trap. */
80
+ .oxy-shell--degraded,
81
+ .oxy-shell--degraded .oxy-shell__main {
82
+ background: transparent;
83
+ color: inherit;
84
+ font-family: inherit;
85
+ }
86
+
87
+ .oxy-shell--degraded .oxy-shell__main {
88
+ overflow: visible;
89
+ }
90
+
91
+ .oxy-shell__content-col {
92
+ display: flex;
93
+ height: 100%;
94
+ min-width: 0;
95
+ flex: 1;
96
+ flex-direction: column;
97
+ }
98
+
99
+ .oxy-shell__main {
100
+ position: relative;
101
+ display: flex;
102
+ height: 100%;
103
+ min-height: 0;
104
+ min-width: 0;
105
+ flex: 1;
106
+ flex-direction: column;
107
+ background: var(--oxy-shell-background);
108
+ /* `auto`, not `hidden`: bundle content flows naturally and scrolls
109
+ inside the frame; apps that manage their own scroll regions are
110
+ unaffected. */
111
+ overflow: auto;
112
+ }
113
+
114
+ /* ─── Icon rail ─────────────────────────────────────────────────────────── */
115
+
116
+ .oxy-rail {
117
+ display: flex;
118
+ height: 100%;
119
+ width: 3rem; /* 48px — matches the web-app rail */
120
+ flex-shrink: 0;
121
+ flex-direction: column;
122
+ /* border color: the web-app frame borders resolve to --border (the global
123
+ base rule), NOT --sidebar-border — only the group divider uses that. */
124
+ border-right: 1px solid var(--oxy-shell-border);
125
+ background: var(--oxy-shell-sidebar-bg);
126
+ }
127
+
128
+ /* Fixed 3rem so the logo cell matches the top bar height exactly — the two
129
+ bottom borders line up into one continuous divider. */
130
+ .oxy-rail__top {
131
+ display: flex;
132
+ height: 3rem;
133
+ flex-shrink: 0;
134
+ flex-direction: column;
135
+ align-items: center;
136
+ justify-content: center;
137
+ border-bottom: 1px solid var(--oxy-shell-border);
138
+ padding: 0 0.25rem;
139
+ }
140
+
141
+ .oxy-rail__nav {
142
+ display: flex;
143
+ min-height: 0;
144
+ flex: 1;
145
+ flex-direction: column;
146
+ align-items: center;
147
+ gap: 0.25rem;
148
+ overflow-y: auto;
149
+ padding: 0.5rem 0.25rem;
150
+ }
151
+
152
+ .oxy-rail__divider {
153
+ margin: 0.25rem 0;
154
+ height: 1px;
155
+ width: 1.25rem;
156
+ flex-shrink: 0;
157
+ background: var(--oxy-shell-sidebar-border);
158
+ }
159
+
160
+ .oxy-rail__footer {
161
+ margin-top: auto;
162
+ display: flex;
163
+ flex-direction: column;
164
+ align-items: center;
165
+ gap: 0.25rem;
166
+ padding-top: 0.5rem;
167
+ }
168
+
169
+ .oxy-rail__bottom {
170
+ display: flex;
171
+ flex-shrink: 0;
172
+ flex-direction: column;
173
+ align-items: center;
174
+ gap: 0.25rem;
175
+ border-top: 1px solid var(--oxy-shell-border);
176
+ padding: 0.5rem 0.25rem;
177
+ }
178
+
179
+ /* Rail entry — replicates the web-app ghost icon Button + itemClasses. */
180
+ .oxy-rail__item {
181
+ display: inline-flex;
182
+ height: 2rem;
183
+ width: 2rem;
184
+ flex-shrink: 0;
185
+ align-items: center;
186
+ justify-content: center;
187
+ border: none;
188
+ border-radius: calc(var(--oxy-shell-radius) - 2px);
189
+ background: transparent;
190
+ color: var(--oxy-shell-foreground);
191
+ padding: 0;
192
+ margin: 0;
193
+ cursor: pointer;
194
+ text-decoration: none;
195
+ opacity: 0.6;
196
+ outline: none;
197
+ transition:
198
+ color 0.15s,
199
+ opacity 0.15s,
200
+ box-shadow 0.15s;
201
+ }
202
+
203
+ .oxy-rail__item:hover {
204
+ opacity: 1;
205
+ background: var(--oxy-shell-accent);
206
+ }
207
+
208
+ .oxy-rail__item:focus-visible {
209
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--oxy-shell-ring) 50%, transparent);
210
+ }
211
+
212
+ .oxy-rail__item--active {
213
+ opacity: 1;
214
+ background: var(--oxy-shell-sidebar-accent);
215
+ color: var(--oxy-shell-sidebar-accent-fg);
216
+ }
217
+
218
+ .oxy-rail__item--active:hover {
219
+ /* Matches the original ghost Button: hover:bg-accent applies even on the
220
+ active item. */
221
+ background: var(--oxy-shell-accent);
222
+ }
223
+
224
+ .oxy-rail__item svg {
225
+ pointer-events: none;
226
+ flex-shrink: 0;
227
+ }
228
+
229
+ /* Replicates the shadcn Button rule [&_svg:not([class*='size-'])]:size-4 —
230
+ unsized icons clamp to 16px. */
231
+ .oxy-rail__item svg:not([class*="size-"]) {
232
+ height: 1rem;
233
+ width: 1rem;
234
+ }
235
+
236
+ .oxy-rail__item-img {
237
+ height: 1.25rem;
238
+ width: 1.25rem;
239
+ border-radius: calc(var(--oxy-shell-radius) - 4px);
240
+ object-fit: contain;
241
+ }
242
+
243
+ .oxy-rail__item-letter {
244
+ font-size: 12px;
245
+ line-height: 1;
246
+ font-weight: 600;
247
+ color: var(--oxy-shell-primary);
248
+ }
249
+
250
+ /* ─── Workspace tile ────────────────────────────────────────────────────── */
251
+
252
+ .oxy-workspace-tile {
253
+ display: flex;
254
+ height: 2rem;
255
+ width: 2rem;
256
+ align-items: center;
257
+ justify-content: center;
258
+ overflow: hidden;
259
+ border-radius: calc(var(--oxy-shell-radius) - 2px);
260
+ background: color-mix(in srgb, var(--oxy-shell-primary) 10%, transparent);
261
+ }
262
+
263
+ .oxy-workspace-tile__img {
264
+ height: 100%;
265
+ width: 100%;
266
+ object-fit: contain;
267
+ }
268
+
269
+ .oxy-workspace-tile__letter {
270
+ font-size: 12px;
271
+ line-height: 1;
272
+ font-weight: 700;
273
+ color: var(--oxy-shell-primary);
274
+ }
275
+
276
+ /* ─── Top bar ───────────────────────────────────────────────────────────── */
277
+
278
+ .oxy-topbar {
279
+ display: flex;
280
+ height: 3rem;
281
+ flex-shrink: 0;
282
+ align-items: center;
283
+ gap: 0.75rem;
284
+ border-bottom: 1px solid var(--oxy-shell-border);
285
+ background: var(--oxy-shell-sidebar-bg);
286
+ padding: 0 0.75rem;
287
+ }
288
+
289
+ .oxy-topbar__right {
290
+ margin-left: auto;
291
+ display: flex;
292
+ align-items: center;
293
+ gap: 0.75rem;
294
+ }
295
+
296
+ /* ─── Breadcrumb ────────────────────────────────────────────────────────── */
297
+
298
+ .oxy-breadcrumb {
299
+ display: flex;
300
+ min-width: 0;
301
+ align-items: center;
302
+ gap: 0.5rem;
303
+ font-size: 14px;
304
+ line-height: 1.4;
305
+ }
306
+
307
+ .oxy-breadcrumb__workspace {
308
+ flex-shrink: 0;
309
+ font-weight: 500;
310
+ color: var(--oxy-shell-foreground);
311
+ text-decoration: none;
312
+ transition: opacity 0.15s;
313
+ }
314
+
315
+ .oxy-breadcrumb__workspace:hover {
316
+ opacity: 0.7;
317
+ }
318
+
319
+ .oxy-breadcrumb__sep {
320
+ color: color-mix(in srgb, var(--oxy-shell-muted-fg) 40%, transparent);
321
+ }
322
+
323
+ .oxy-breadcrumb__page {
324
+ overflow: hidden;
325
+ text-overflow: ellipsis;
326
+ white-space: nowrap;
327
+ color: var(--oxy-shell-muted-fg);
328
+ }
329
+
330
+ /* ─── System indicator ──────────────────────────────────────────────────── */
331
+
332
+ .oxy-sysind {
333
+ display: none;
334
+ align-items: center;
335
+ gap: 0.375rem;
336
+ font-family: var(--oxy-shell-font-mono);
337
+ font-size: 12px;
338
+ color: var(--oxy-shell-muted-fg);
339
+ }
340
+
341
+ .oxy-sysind__state {
342
+ display: inline-flex;
343
+ align-items: center;
344
+ gap: 0.25rem;
345
+ }
346
+
347
+ .oxy-sysind__state--online {
348
+ color: var(--oxy-shell-success);
349
+ }
350
+
351
+ .oxy-sysind__state--offline {
352
+ color: var(--oxy-shell-destructive);
353
+ }
354
+
355
+ .oxy-sysind__dot-wrap {
356
+ position: relative;
357
+ display: inline-flex;
358
+ height: 0.375rem;
359
+ width: 0.375rem;
360
+ }
361
+
362
+ .oxy-sysind__dot {
363
+ position: relative;
364
+ display: inline-flex;
365
+ height: 0.375rem;
366
+ width: 0.375rem;
367
+ border-radius: 9999px;
368
+ }
369
+
370
+ .oxy-sysind__dot--online {
371
+ background: var(--oxy-shell-success);
372
+ }
373
+
374
+ .oxy-sysind__dot--offline {
375
+ background: var(--oxy-shell-destructive);
376
+ }
377
+
378
+ .oxy-sysind__ping {
379
+ position: absolute;
380
+ display: inline-flex;
381
+ height: 0.375rem;
382
+ width: 0.375rem;
383
+ border-radius: 9999px;
384
+ background: var(--oxy-shell-success);
385
+ opacity: 0.75;
386
+ animation: oxy-shell-ping 1s cubic-bezier(0, 0, 0.2, 1) infinite;
387
+ }
388
+
389
+ @keyframes oxy-shell-ping {
390
+ 75%,
391
+ 100% {
392
+ transform: scale(2);
393
+ opacity: 0;
394
+ }
395
+ }
396
+
397
+ /* ─── Clock ─────────────────────────────────────────────────────────────── */
398
+
399
+ .oxy-clock {
400
+ display: none;
401
+ font-family: var(--oxy-shell-font-mono);
402
+ font-size: 12px;
403
+ font-variant-numeric: tabular-nums;
404
+ color: var(--oxy-shell-muted-fg);
405
+ }
406
+
407
+ @media (min-width: 640px) {
408
+ .oxy-sysind {
409
+ display: inline-flex;
410
+ }
411
+
412
+ .oxy-clock {
413
+ display: inline;
414
+ }
415
+ }
416
+
417
+ /* ─── Tooltip (Radix content, portaled into the shell scope) ────────────── */
418
+
419
+ .oxy-shell-tooltip {
420
+ z-index: 50;
421
+ width: fit-content;
422
+ border-radius: calc(var(--oxy-shell-radius) - 2px);
423
+ background: var(--oxy-shell-tooltip-bg);
424
+ color: var(--oxy-shell-foreground);
425
+ padding: 0.375rem 0.75rem;
426
+ font-family: var(--oxy-shell-font);
427
+ font-size: 12px;
428
+ font-weight: 400;
429
+ line-height: 1.5;
430
+ text-wrap: balance;
431
+ box-shadow:
432
+ 0 4px 6px -1px rgb(0 0 0 / 0.1),
433
+ 0 2px 4px -2px rgb(0 0 0 / 0.1);
434
+ animation: oxy-shell-tooltip-in 0.15s ease-out;
435
+ }
436
+
437
+ /* Side-aware entry slide (0.5rem, mirroring the web-app's
438
+ data-[side=*]:slide-in-from-*-2) and an exit animation — Radix keeps the
439
+ content mounted until the closed-state animation finishes. */
440
+ .oxy-shell-tooltip[data-side="right"] {
441
+ --oxy-shell-tip-slide: translateX(-0.5rem);
442
+ }
443
+
444
+ .oxy-shell-tooltip[data-side="left"] {
445
+ --oxy-shell-tip-slide: translateX(0.5rem);
446
+ }
447
+
448
+ .oxy-shell-tooltip[data-side="top"] {
449
+ --oxy-shell-tip-slide: translateY(0.5rem);
450
+ }
451
+
452
+ .oxy-shell-tooltip[data-side="bottom"] {
453
+ --oxy-shell-tip-slide: translateY(-0.5rem);
454
+ }
455
+
456
+ .oxy-shell-tooltip[data-state="closed"] {
457
+ animation: oxy-shell-tooltip-out 0.15s ease-in forwards;
458
+ }
459
+
460
+ @keyframes oxy-shell-tooltip-out {
461
+ from {
462
+ opacity: 1;
463
+ transform: none;
464
+ }
465
+
466
+ to {
467
+ opacity: 0;
468
+ transform: scale(0.95);
469
+ }
470
+ }
471
+
472
+ .oxy-shell-tooltip__arrow {
473
+ z-index: 50;
474
+ height: 0.625rem;
475
+ width: 0.625rem;
476
+ translate: 0 calc(-50% - 2px);
477
+ rotate: 45deg;
478
+ border-radius: 2px;
479
+ background: var(--oxy-shell-tooltip-bg);
480
+ fill: var(--oxy-shell-tooltip-bg);
481
+ }
482
+
483
+ @keyframes oxy-shell-tooltip-in {
484
+ from {
485
+ opacity: 0;
486
+ transform: var(--oxy-shell-tip-slide, none) scale(0.95);
487
+ }
488
+
489
+ to {
490
+ opacity: 1;
491
+ transform: none;
492
+ }
493
+ }
494
+
495
+ /* ─── Ask Oxygen button (top bar) ───────────────────────────────────────── */
496
+
497
+ .oxy-askbtn {
498
+ display: flex;
499
+ align-items: center;
500
+ gap: 0.375rem;
501
+ border: 1px solid var(--oxy-shell-border);
502
+ border-radius: calc(var(--oxy-shell-radius) - 2px);
503
+ background: transparent;
504
+ padding: 0.25rem 0.5rem;
505
+ font-family: var(--oxy-shell-font);
506
+ font-size: 12px;
507
+ color: var(--oxy-shell-muted-fg);
508
+ cursor: pointer;
509
+ transition:
510
+ color 0.15s,
511
+ border-color 0.15s,
512
+ background 0.15s;
513
+ }
514
+
515
+ .oxy-askbtn:hover {
516
+ border-color: color-mix(in srgb, var(--oxy-shell-primary) 40%, transparent);
517
+ color: var(--oxy-shell-foreground);
518
+ }
519
+
520
+ .oxy-askbtn--open {
521
+ border-color: color-mix(in srgb, var(--oxy-shell-primary) 40%, transparent);
522
+ background: color-mix(in srgb, var(--oxy-shell-primary) 10%, transparent);
523
+ color: var(--oxy-shell-foreground);
524
+ }
525
+
526
+ .oxy-askbtn:focus-visible {
527
+ outline: none;
528
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--oxy-shell-ring) 50%, transparent);
529
+ }
530
+
531
+ .oxy-askbtn__mark {
532
+ width: 0.875rem;
533
+ height: 0.875rem;
534
+ color: var(--oxy-shell-primary);
535
+ }
536
+
537
+ .oxy-askbtn__label,
538
+ .oxy-askbtn__kbd {
539
+ display: none;
540
+ }
541
+
542
+ .oxy-askbtn__kbd {
543
+ border-radius: 4px;
544
+ background: var(--oxy-shell-muted);
545
+ padding: 0.125rem 0.375rem;
546
+ font-family: var(--oxy-shell-font-mono);
547
+ font-size: 10px;
548
+ line-height: 1.2;
549
+ }
550
+
551
+ @media (min-width: 640px) {
552
+ .oxy-askbtn__label {
553
+ display: inline;
554
+ }
555
+
556
+ .oxy-askbtn__kbd {
557
+ display: inline-block;
558
+ }
559
+ }
560
+
561
+ /* ─── Ask Oxygen dock ───────────────────────────────────────────────────── */
562
+
563
+ .oxy-askdock {
564
+ display: flex;
565
+ height: 100%;
566
+ width: min(23rem, 85vw);
567
+ flex-shrink: 0;
568
+ flex-direction: column;
569
+ min-width: 0;
570
+ border-left: 1px solid var(--oxy-shell-border);
571
+ background: var(--oxy-shell-background);
572
+ color: var(--oxy-shell-foreground);
573
+ overflow: hidden;
574
+ transition: width 0.2s ease;
575
+ }
576
+
577
+ .oxy-askdock--closed {
578
+ width: 0;
579
+ border-left-width: 0;
580
+ visibility: hidden;
581
+ }
582
+
583
+ .oxy-askdock__head {
584
+ display: flex;
585
+ height: 3rem;
586
+ flex-shrink: 0;
587
+ align-items: center;
588
+ gap: 0.5rem;
589
+ border-bottom: 1px solid var(--oxy-shell-border);
590
+ padding: 0 0.75rem;
591
+ }
592
+
593
+ .oxy-askdock__mark {
594
+ width: 1rem;
595
+ height: 1rem;
596
+ flex-shrink: 0;
597
+ color: var(--oxy-shell-primary);
598
+ }
599
+
600
+ .oxy-askdock__title {
601
+ font-size: 14px;
602
+ font-weight: 600;
603
+ white-space: nowrap;
604
+ }
605
+
606
+ .oxy-askdock__actions {
607
+ margin-left: auto;
608
+ display: flex;
609
+ align-items: center;
610
+ gap: 0.25rem;
611
+ }
612
+
613
+ .oxy-askdock__iconbtn {
614
+ display: inline-flex;
615
+ height: 1.75rem;
616
+ width: 1.75rem;
617
+ align-items: center;
618
+ justify-content: center;
619
+ border: none;
620
+ border-radius: calc(var(--oxy-shell-radius) - 2px);
621
+ background: transparent;
622
+ color: var(--oxy-shell-muted-fg);
623
+ cursor: pointer;
624
+ transition:
625
+ color 0.15s,
626
+ background 0.15s;
627
+ }
628
+
629
+ .oxy-askdock__iconbtn:hover {
630
+ background: var(--oxy-shell-accent);
631
+ color: var(--oxy-shell-foreground);
632
+ }
633
+
634
+ .oxy-askdock__iconbtn:focus-visible {
635
+ outline: none;
636
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--oxy-shell-ring) 50%, transparent);
637
+ }
638
+
639
+ .oxy-askdock__iconbtn:disabled {
640
+ cursor: default;
641
+ opacity: 0.35;
642
+ }
643
+
644
+ .oxy-askdock__iconbtn:disabled:hover {
645
+ background: transparent;
646
+ color: var(--oxy-shell-muted-fg);
647
+ }
648
+
649
+ .oxy-askdock__iconbtn--active {
650
+ background: var(--oxy-shell-accent);
651
+ color: var(--oxy-shell-foreground);
652
+ }
653
+
654
+ /* ─── Chat history (session-scoped) ─────────────────────────────────────── */
655
+
656
+ .oxy-askdock__history {
657
+ display: flex;
658
+ min-height: 0;
659
+ flex: 1;
660
+ flex-direction: column;
661
+ overflow-y: auto;
662
+ padding: 0.5rem;
663
+ gap: 0.25rem;
664
+ }
665
+
666
+ .oxy-askdock__history-empty {
667
+ margin: 0.75rem 0.5rem;
668
+ font-size: 12.5px;
669
+ color: var(--oxy-shell-muted-fg);
670
+ }
671
+
672
+ .oxy-askdock__history-item {
673
+ display: flex;
674
+ flex-direction: column;
675
+ gap: 0.125rem;
676
+ width: 100%;
677
+ border: none;
678
+ border-radius: calc(var(--oxy-shell-radius) - 2px);
679
+ background: transparent;
680
+ padding: 0.5rem 0.625rem;
681
+ font-family: var(--oxy-shell-font);
682
+ text-align: left;
683
+ cursor: pointer;
684
+ transition: background 0.15s;
685
+ }
686
+
687
+ .oxy-askdock__history-item:hover {
688
+ background: var(--oxy-shell-accent);
689
+ }
690
+
691
+ .oxy-askdock__history-item:focus-visible {
692
+ outline: none;
693
+ box-shadow: 0 0 0 2px color-mix(in srgb, var(--oxy-shell-ring) 50%, transparent);
694
+ }
695
+
696
+ .oxy-askdock__history-title {
697
+ overflow: hidden;
698
+ text-overflow: ellipsis;
699
+ white-space: nowrap;
700
+ font-size: 13px;
701
+ color: var(--oxy-shell-foreground);
702
+ }
703
+
704
+ .oxy-askdock__history-meta {
705
+ font-size: 11px;
706
+ color: var(--oxy-shell-muted-fg);
707
+ }
708
+
709
+ .oxy-askdock__scroll {
710
+ display: flex;
711
+ min-height: 0;
712
+ flex: 1;
713
+ flex-direction: column;
714
+ overflow-y: auto;
715
+ padding: 0.75rem;
716
+ }
717
+
718
+ .oxy-askdock__chips {
719
+ display: flex;
720
+ flex-direction: column;
721
+ align-items: flex-start;
722
+ gap: 0.5rem;
723
+ }
724
+
725
+ .oxy-askdock__chip {
726
+ border: 1px solid var(--oxy-shell-border);
727
+ border-radius: 999px;
728
+ background: transparent;
729
+ padding: 0.375rem 0.75rem;
730
+ font-family: var(--oxy-shell-font);
731
+ font-size: 12.5px;
732
+ text-align: left;
733
+ color: var(--oxy-shell-foreground);
734
+ cursor: pointer;
735
+ transition: background 0.15s;
736
+ }
737
+
738
+ .oxy-askdock__chip:hover {
739
+ background: var(--oxy-shell-accent);
740
+ }
741
+
742
+ .oxy-askdock__chip:focus-visible {
743
+ outline: none;
744
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--oxy-shell-ring) 50%, transparent);
745
+ }
746
+
747
+ .oxy-askdock__turn {
748
+ display: flex;
749
+ flex-direction: column;
750
+ font-size: 13.5px;
751
+ }
752
+
753
+ .oxy-askdock__q {
754
+ align-self: flex-end;
755
+ max-width: 85%;
756
+ border-radius: calc(var(--oxy-shell-radius) - 2px);
757
+ background: var(--oxy-shell-muted);
758
+ padding: 0.375rem 0.625rem;
759
+ margin: 0.5rem 0 0.375rem;
760
+ white-space: pre-wrap;
761
+ overflow-wrap: anywhere;
762
+ }
763
+
764
+ .oxy-askdock__composer {
765
+ margin: 0.75rem;
766
+ flex-shrink: 0;
767
+ border: 1px solid var(--oxy-shell-border);
768
+ border-radius: var(--oxy-shell-radius);
769
+ padding: 0.625rem;
770
+ transition: border-color 0.15s;
771
+ }
772
+
773
+ .oxy-askdock__composer:focus-within {
774
+ border-color: var(--oxy-shell-ring);
775
+ }
776
+
777
+ .oxy-askdock__input {
778
+ display: block;
779
+ width: 100%;
780
+ border: none;
781
+ outline: none;
782
+ resize: none;
783
+ background: transparent;
784
+ color: var(--oxy-shell-foreground);
785
+ font-family: var(--oxy-shell-font);
786
+ font-size: 13.5px;
787
+ line-height: 1.5;
788
+ }
789
+
790
+ .oxy-askdock__input::placeholder {
791
+ color: var(--oxy-shell-muted-fg);
792
+ }
793
+
794
+ .oxy-askdock__composer-row {
795
+ display: flex;
796
+ justify-content: flex-end;
797
+ }
798
+
799
+ .oxy-askdock__send {
800
+ display: inline-flex;
801
+ height: 1.75rem;
802
+ width: 1.75rem;
803
+ align-items: center;
804
+ justify-content: center;
805
+ border: none;
806
+ border-radius: calc(var(--oxy-shell-radius) - 2px);
807
+ background: var(--oxy-shell-primary);
808
+ color: var(--oxy-shell-primary-fg);
809
+ cursor: pointer;
810
+ transition: opacity 0.15s;
811
+ }
812
+
813
+ .oxy-askdock__send:disabled {
814
+ cursor: default;
815
+ opacity: 0.35;
816
+ }
817
+
818
+ .oxy-askdock__send:focus-visible {
819
+ outline: none;
820
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--oxy-shell-ring) 50%, transparent);
821
+ }
822
+
823
+ /* ─── Reasoning trace (Ask dock) ────────────────────────────────────────── */
824
+
825
+ .oxy-trace {
826
+ margin: 0.375rem 0;
827
+ border: 1px solid var(--oxy-shell-border);
828
+ border-radius: calc(var(--oxy-shell-radius) - 2px);
829
+ font-size: 12px;
830
+ color: var(--oxy-shell-muted-fg);
831
+ overflow: hidden;
832
+ }
833
+
834
+ .oxy-trace__head {
835
+ display: flex;
836
+ width: 100%;
837
+ align-items: center;
838
+ gap: 0.375rem;
839
+ border: none;
840
+ background: transparent;
841
+ padding: 0.375rem 0.625rem;
842
+ font-family: var(--oxy-shell-font);
843
+ font-size: 12px;
844
+ color: var(--oxy-shell-muted-fg);
845
+ cursor: pointer;
846
+ text-align: left;
847
+ }
848
+
849
+ .oxy-trace__head:hover {
850
+ color: var(--oxy-shell-foreground);
851
+ }
852
+
853
+ .oxy-trace__head:focus-visible {
854
+ outline: none;
855
+ box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--oxy-shell-ring) 50%, transparent);
856
+ }
857
+
858
+ .oxy-trace__title {
859
+ font-weight: 600;
860
+ color: var(--oxy-shell-foreground);
861
+ }
862
+
863
+ .oxy-trace__meta {
864
+ color: var(--oxy-shell-muted-fg);
865
+ }
866
+
867
+ .oxy-trace__body {
868
+ display: flex;
869
+ flex-direction: column;
870
+ gap: 0.375rem;
871
+ border-top: 1px solid var(--oxy-shell-border);
872
+ padding: 0.5rem 0.625rem;
873
+ }
874
+
875
+ .oxy-trace__step {
876
+ display: flex;
877
+ flex-direction: column;
878
+ gap: 0.25rem;
879
+ }
880
+
881
+ .oxy-trace__step-row {
882
+ display: flex;
883
+ align-items: baseline;
884
+ gap: 0.375rem;
885
+ min-width: 0;
886
+ }
887
+
888
+ .oxy-trace__label {
889
+ flex-shrink: 0;
890
+ font-weight: 500;
891
+ color: var(--oxy-shell-foreground);
892
+ }
893
+
894
+ .oxy-trace__summary {
895
+ min-width: 0;
896
+ overflow: hidden;
897
+ text-overflow: ellipsis;
898
+ white-space: nowrap;
899
+ color: var(--oxy-shell-muted-fg);
900
+ }
901
+
902
+ .oxy-trace__icon {
903
+ flex-shrink: 0;
904
+ width: 0.875rem;
905
+ text-align: center;
906
+ font-size: 10px;
907
+ }
908
+
909
+ .oxy-trace__icon--ok {
910
+ color: var(--oxy-shell-success);
911
+ }
912
+
913
+ .oxy-trace__icon--fail {
914
+ color: var(--oxy-shell-destructive);
915
+ }
916
+
917
+ .oxy-trace__icon--wait {
918
+ color: var(--oxy-shell-muted-fg);
919
+ }
920
+
921
+ .oxy-trace__items {
922
+ display: flex;
923
+ flex-direction: column;
924
+ gap: 0.25rem;
925
+ margin-left: 0.375rem;
926
+ border-left: 2px solid var(--oxy-shell-border);
927
+ padding-left: 0.75rem;
928
+ }
929
+
930
+ .oxy-trace__row {
931
+ display: flex;
932
+ align-items: baseline;
933
+ gap: 0.375rem;
934
+ min-width: 0;
935
+ font-size: 11.5px;
936
+ }
937
+
938
+ .oxy-trace__row--error .oxy-trace__row-label,
939
+ .oxy-trace__row--error .oxy-trace__row-detail {
940
+ color: var(--oxy-shell-destructive);
941
+ }
942
+
943
+ .oxy-trace__row-label {
944
+ flex-shrink: 0;
945
+ font-weight: 500;
946
+ color: var(--oxy-shell-foreground);
947
+ }
948
+
949
+ .oxy-trace__row-preview {
950
+ min-width: 0;
951
+ flex: 1;
952
+ overflow: hidden;
953
+ text-overflow: ellipsis;
954
+ white-space: nowrap;
955
+ color: var(--oxy-shell-muted-fg);
956
+ }
957
+
958
+ .oxy-trace__row-detail {
959
+ margin-left: auto;
960
+ flex-shrink: 0;
961
+ font-family: var(--oxy-shell-font-mono);
962
+ font-size: 10.5px;
963
+ color: var(--oxy-shell-muted-fg);
964
+ }
965
+
966
+ .oxy-trace__think {
967
+ margin: 0.125rem 0;
968
+ font-size: 11.5px;
969
+ line-height: 1.5;
970
+ color: var(--oxy-shell-muted-fg);
971
+ white-space: pre-wrap;
972
+ overflow-wrap: anywhere;
973
+ }
974
+
975
+ .oxy-trace__spin {
976
+ display: inline-block;
977
+ width: 0.625rem;
978
+ height: 0.625rem;
979
+ flex-shrink: 0;
980
+ border-radius: 50%;
981
+ border: 2px solid var(--oxy-shell-border);
982
+ border-top-color: var(--oxy-shell-muted-fg);
983
+ animation: oxy-shell-spin 0.8s linear infinite;
984
+ }
985
+
986
+ .oxy-trace__spin--sm {
987
+ width: 0.5rem;
988
+ height: 0.5rem;
989
+ border-width: 1.5px;
990
+ }
991
+
992
+ @keyframes oxy-shell-spin {
993
+ to {
994
+ transform: rotate(360deg);
995
+ }
996
+ }
997
+
998
+ @media (prefers-reduced-motion: reduce) {
999
+ .oxy-trace__spin {
1000
+ animation: none;
1001
+ }
1002
+ }
1003
+
1004
+ /* ─── Answer charts (chart_rendered blocks) ─────────────────────────────── */
1005
+
1006
+ .oxy-chart {
1007
+ margin: 0.5rem 0;
1008
+ border: 1px solid var(--oxy-shell-border);
1009
+ border-radius: calc(var(--oxy-shell-radius) - 2px);
1010
+ padding: 0.625rem 0.625rem 0.375rem;
1011
+ }
1012
+
1013
+ .oxy-chart__title {
1014
+ margin-bottom: 0.375rem;
1015
+ font-size: 12.5px;
1016
+ font-weight: 600;
1017
+ color: var(--oxy-shell-foreground);
1018
+ }
1019
+
1020
+ .oxy-chart__svg {
1021
+ display: block;
1022
+ width: 100%;
1023
+ height: auto;
1024
+ }
1025
+
1026
+ .oxy-chart__grid line {
1027
+ stroke: var(--oxy-shell-border);
1028
+ stroke-width: 0.5;
1029
+ }
1030
+
1031
+ /* Zero baseline for signed (negative-valued) bar/line charts — a touch
1032
+ stronger than the grid so it reads as the axis origin. */
1033
+ .oxy-chart__grid-zero {
1034
+ stroke: var(--oxy-shell-muted-fg);
1035
+ stroke-width: 1;
1036
+ }
1037
+
1038
+ .oxy-chart__tick {
1039
+ fill: var(--oxy-shell-muted-fg);
1040
+ font-family: var(--oxy-shell-font);
1041
+ font-size: 8px;
1042
+ }
1043
+
1044
+ .oxy-chart__legend {
1045
+ display: flex;
1046
+ flex-wrap: wrap;
1047
+ gap: 0.375rem 0.75rem;
1048
+ padding: 0.25rem 0 0.125rem;
1049
+ }
1050
+
1051
+ .oxy-chart__legend-item {
1052
+ display: inline-flex;
1053
+ align-items: center;
1054
+ gap: 0.25rem;
1055
+ font-size: 10.5px;
1056
+ color: var(--oxy-shell-muted-fg);
1057
+ }
1058
+
1059
+ .oxy-chart__legend-dot {
1060
+ width: 0.5rem;
1061
+ height: 0.5rem;
1062
+ border-radius: 2px;
1063
+ }
1064
+
1065
+ .oxy-chart__table-wrap {
1066
+ overflow-x: auto;
1067
+ }
1068
+
1069
+ .oxy-chart__table {
1070
+ width: 100%;
1071
+ border-collapse: collapse;
1072
+ font-size: 11.5px;
1073
+ }
1074
+
1075
+ .oxy-chart__table th {
1076
+ text-align: left;
1077
+ padding: 0.25rem 0.5rem;
1078
+ border-bottom: 1px solid var(--oxy-shell-border);
1079
+ font-weight: 600;
1080
+ color: var(--oxy-shell-foreground);
1081
+ }
1082
+
1083
+ .oxy-chart__table td {
1084
+ padding: 0.25rem 0.5rem;
1085
+ border-bottom: 1px solid var(--oxy-shell-border);
1086
+ color: var(--oxy-shell-muted-fg);
1087
+ }
1088
+
1089
+ .oxy-chart__note {
1090
+ padding: 0.25rem 0.5rem;
1091
+ font-size: 10.5px;
1092
+ color: var(--oxy-shell-muted-fg);
1093
+ }
1094
+
1095
+ /* Per-step detail toggle: running steps show their rows, finished steps
1096
+ collapse to the header line; the whole row is the toggle. */
1097
+ .oxy-trace__step-row--btn {
1098
+ width: 100%;
1099
+ border: none;
1100
+ background: transparent;
1101
+ padding: 0;
1102
+ font-family: var(--oxy-shell-font);
1103
+ font-size: 12px;
1104
+ cursor: pointer;
1105
+ text-align: left;
1106
+ }
1107
+
1108
+ .oxy-trace__step-row--btn:hover .oxy-trace__label {
1109
+ color: var(--oxy-shell-foreground);
1110
+ }
1111
+
1112
+ .oxy-trace__step-row--btn:focus-visible {
1113
+ outline: none;
1114
+ box-shadow: 0 0 0 2px color-mix(in srgb, var(--oxy-shell-ring) 50%, transparent);
1115
+ border-radius: 4px;
1116
+ }
1117
+
1118
+ .oxy-trace__count {
1119
+ flex-shrink: 0;
1120
+ margin-left: auto;
1121
+ font-size: 10.5px;
1122
+ color: var(--oxy-shell-muted-fg);
1123
+ }
1124
+
1125
+ .oxy-trace__step-chevron {
1126
+ flex-shrink: 0;
1127
+ display: inline-flex;
1128
+ align-self: center;
1129
+ color: var(--oxy-shell-muted-fg);
1130
+ }
1131
+
1132
+ .oxy-trace__step-row--btn .oxy-trace__step-chevron:only-of-type,
1133
+ .oxy-trace__step-row--btn .oxy-trace__step-chevron {
1134
+ margin-left: 0.25rem;
1135
+ }
1136
+
1137
+ .oxy-trace__step-row--btn:not(:hover) .oxy-trace__step-chevron {
1138
+ opacity: 0.6;
1139
+ }
1140
+
1141
+ /* Expandable action detail: full tool input/output under the row. */
1142
+ .oxy-trace__item {
1143
+ display: flex;
1144
+ flex-direction: column;
1145
+ gap: 0.25rem;
1146
+ }
1147
+
1148
+ .oxy-trace__row--btn {
1149
+ width: 100%;
1150
+ border: none;
1151
+ background: transparent;
1152
+ padding: 0;
1153
+ font-family: var(--oxy-shell-font);
1154
+ cursor: pointer;
1155
+ text-align: left;
1156
+ }
1157
+
1158
+ .oxy-trace__row--btn:focus-visible {
1159
+ outline: none;
1160
+ box-shadow: 0 0 0 2px color-mix(in srgb, var(--oxy-shell-ring) 50%, transparent);
1161
+ border-radius: 4px;
1162
+ }
1163
+
1164
+ .oxy-trace__row--btn:not(:hover) .oxy-trace__step-chevron {
1165
+ opacity: 0.6;
1166
+ }
1167
+
1168
+ .oxy-trace__payloads {
1169
+ display: flex;
1170
+ flex-direction: column;
1171
+ gap: 0.25rem;
1172
+ }
1173
+
1174
+ /* Plain colored text, no card — matches the inline preview style. */
1175
+ .oxy-trace__payload {
1176
+ margin: 0 0 0 0.25rem;
1177
+ font-family: var(--oxy-shell-font-mono);
1178
+ font-size: 10.5px;
1179
+ line-height: 1.5;
1180
+ color: var(--oxy-shell-muted-fg);
1181
+ white-space: pre-wrap;
1182
+ overflow-wrap: anywhere;
1183
+ }
1184
+
1185
+ .oxy-trace__payload--out {
1186
+ color: var(--oxy-shell-success);
1187
+ }