@fadenstack/ui-web 0.0.0-stage → 0.3.0-rc.1

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/styles.css ADDED
@@ -0,0 +1,1440 @@
1
+ /*
2
+ * The chat panel's look. By default it is Chrome's own (Material 3, Chrome 2023 refresh): its neutral surfaces,
3
+ * its blue, the system UI font, native scroll bars and controls -- and it follows the browser's light or dark
4
+ * setting as it changes (`data-theme="system"`). A host changes any token on `.fdn-chat`, e.g. the console's
5
+ * accent: `.fdn-chat { --fdn-accent: #4C6A92; }`.
6
+ *
7
+ * Shapes: one 12 px radius for rectangular surfaces (cards, bubbles, the composer, menus, buttons); pills for
8
+ * chips; circles for icon buttons. Nested surfaces stay concentric (inner = outer - inset).
9
+ *
10
+ * Every web skin (@fadenstack/ui-react, @fadenstack/ui-vue) draws the same markup with these classes. Directions
11
+ * are logical (start and end, not left and right), so the panel mirrors for a right-to-left language.
12
+ */
13
+
14
+ .fdn-chat {
15
+ --fdn-radius: 12px;
16
+ --fdn-font: system-ui, "Segoe UI Variable Text", "Segoe UI", -apple-system, BlinkMacSystemFont, Roboto, "Helvetica Neue", Arial, sans-serif;
17
+ --fdn-mono: ui-monospace, "Cascadia Mono", "Cascadia Code", Consolas, "SF Mono", Menlo, monospace;
18
+
19
+ --fdn-bg: #ffffff;
20
+ --fdn-surface: #f0f4f9;
21
+ --fdn-surface-high: #e9eef6;
22
+ --fdn-surface-hover: rgba(31, 31, 31, 0.06);
23
+ --fdn-text: #1f1f1f;
24
+ --fdn-text-muted: #474747;
25
+ /* Quiet text on the panel's background: 5.2:1 on white, 4.7:1 on the surface (a chip's subtitle). Text in a menu,
26
+ an approval card, a notice or a code block is muted, which keeps 4.5:1 on their hover and soft colours too. */
27
+ --fdn-text-faint: #6b6d6b;
28
+ --fdn-border: #c7c7c7;
29
+ --fdn-hairline: #e3e3e3;
30
+ --fdn-accent: #0b57d0;
31
+ --fdn-on-accent: #ffffff;
32
+ --fdn-accent-soft: #d3e3fd;
33
+ --fdn-on-accent-soft: #041e49;
34
+ --fdn-danger: #b3261e;
35
+ --fdn-danger-soft: #f9dedc;
36
+ --fdn-warning: #8c4a00;
37
+ --fdn-warning-soft: #ffeedc;
38
+ --fdn-success: #146c2e;
39
+ --fdn-code-bg: #f0f4f9;
40
+ --fdn-focus: #0b57d0;
41
+ --fdn-shadow: 0 2px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.3);
42
+
43
+ /* The agent avatar (the Fadenstack stack): navy plates, the rose thread plate. */
44
+ --fdn-agent-plate: #1c2436;
45
+ --fdn-agent-plate-side: #0a0e1a;
46
+ --fdn-agent-thread: #e2325a;
47
+ --fdn-agent-thread-side: #a8143e;
48
+ --fdn-agent-hollow: rgba(10, 14, 26, 0.38);
49
+ --fdn-agent-eye: #ffffff;
50
+ --fdn-agent-pupil: #0a0e1a;
51
+
52
+ color-scheme: light;
53
+ }
54
+
55
+ .fdn-chat[data-theme="dark"] {
56
+ --fdn-bg: #1f1f1f;
57
+ --fdn-surface: #282a2c;
58
+ --fdn-surface-high: #333537;
59
+ --fdn-surface-hover: rgba(227, 227, 227, 0.08);
60
+ --fdn-text: #e3e3e3;
61
+ --fdn-text-muted: #c4c7c5;
62
+ --fdn-text-faint: #8e918f;
63
+ --fdn-border: #5c5f5e;
64
+ --fdn-hairline: #444746;
65
+ --fdn-accent: #a8c7fa;
66
+ --fdn-on-accent: #062e6f;
67
+ --fdn-accent-soft: #0842a0;
68
+ --fdn-on-accent-soft: #d3e3fd;
69
+ --fdn-danger: #f2b8b5;
70
+ --fdn-danger-soft: #601410;
71
+ --fdn-warning: #ffb871;
72
+ --fdn-warning-soft: #4a2800;
73
+ --fdn-success: #6dd58c;
74
+ --fdn-code-bg: #282a2c;
75
+ --fdn-focus: #a8c7fa;
76
+ --fdn-shadow: 0 2px 6px rgba(0, 0, 0, 0.3), 0 1px 2px rgba(0, 0, 0, 0.5);
77
+ --fdn-agent-plate: #f3f4f6;
78
+ --fdn-agent-plate-side: #aeb7c6;
79
+ --fdn-agent-thread: #ff4d6d;
80
+ --fdn-agent-thread-side: #c21e48;
81
+ --fdn-agent-hollow: rgba(10, 14, 26, 0.55);
82
+
83
+ color-scheme: dark;
84
+ }
85
+
86
+ @media (prefers-color-scheme: dark) {
87
+ .fdn-chat[data-theme="system"] {
88
+ --fdn-bg: #1f1f1f;
89
+ --fdn-surface: #282a2c;
90
+ --fdn-surface-high: #333537;
91
+ --fdn-surface-hover: rgba(227, 227, 227, 0.08);
92
+ --fdn-text: #e3e3e3;
93
+ --fdn-text-muted: #c4c7c5;
94
+ --fdn-text-faint: #8e918f;
95
+ --fdn-border: #5c5f5e;
96
+ --fdn-hairline: #444746;
97
+ --fdn-accent: #a8c7fa;
98
+ --fdn-on-accent: #062e6f;
99
+ --fdn-accent-soft: #0842a0;
100
+ --fdn-on-accent-soft: #d3e3fd;
101
+ --fdn-danger: #f2b8b5;
102
+ --fdn-danger-soft: #601410;
103
+ --fdn-warning: #ffb871;
104
+ --fdn-warning-soft: #4a2800;
105
+ --fdn-success: #6dd58c;
106
+ --fdn-code-bg: #282a2c;
107
+ --fdn-focus: #a8c7fa;
108
+ --fdn-shadow: 0 2px 6px rgba(0, 0, 0, 0.3), 0 1px 2px rgba(0, 0, 0, 0.5);
109
+ --fdn-agent-plate: #f3f4f6;
110
+ --fdn-agent-plate-side: #aeb7c6;
111
+ --fdn-agent-thread: #ff4d6d;
112
+ --fdn-agent-thread-side: #c21e48;
113
+ --fdn-agent-hollow: rgba(10, 14, 26, 0.55);
114
+
115
+ color-scheme: dark;
116
+ }
117
+ }
118
+
119
+ /* High contrast (Windows contrast themes): the system's colours throughout. */
120
+ @media (forced-colors: active) {
121
+ .fdn-chat {
122
+ --fdn-bg: Canvas;
123
+ --fdn-surface: Canvas;
124
+ --fdn-surface-high: Canvas;
125
+ --fdn-text: CanvasText;
126
+ --fdn-text-muted: CanvasText;
127
+ --fdn-text-faint: GrayText;
128
+ --fdn-border: CanvasText;
129
+ --fdn-hairline: CanvasText;
130
+ --fdn-accent: Highlight;
131
+ --fdn-on-accent: HighlightText;
132
+ --fdn-focus: Highlight;
133
+ --fdn-agent-plate: CanvasText;
134
+ --fdn-agent-plate-side: CanvasText;
135
+ --fdn-agent-thread: Highlight;
136
+ --fdn-agent-thread-side: Highlight;
137
+ --fdn-agent-hollow: transparent;
138
+ --fdn-agent-eye: Canvas;
139
+ --fdn-agent-pupil: CanvasText;
140
+ }
141
+ }
142
+
143
+ /* -- the frame --------------------------------------------------------------------------------- */
144
+
145
+ .fdn-chat {
146
+ display: flex;
147
+ flex-direction: column;
148
+ height: 100%;
149
+ min-height: 0;
150
+ background: var(--fdn-bg);
151
+ color: var(--fdn-text);
152
+ font: 13px/1.5 var(--fdn-font);
153
+ -webkit-font-smoothing: antialiased;
154
+ }
155
+
156
+ .fdn-chat *,
157
+ .fdn-chat *::before,
158
+ .fdn-chat *::after {
159
+ box-sizing: border-box;
160
+ }
161
+
162
+ .fdn-chat button {
163
+ font: inherit;
164
+ color: inherit;
165
+ }
166
+
167
+ .fdn-chat :focus-visible {
168
+ outline: 2px solid var(--fdn-focus);
169
+ outline-offset: 2px;
170
+ }
171
+
172
+ .fdn-icon {
173
+ flex: none;
174
+ display: block;
175
+ }
176
+
177
+ .fdn-muted {
178
+ color: var(--fdn-text-faint);
179
+ }
180
+
181
+ /* -- the header -------------------------------------------------------------------------------- */
182
+
183
+ .fdn-header {
184
+ display: flex;
185
+ align-items: center;
186
+ gap: 2px;
187
+ min-height: 44px;
188
+ padding-block: 4px;
189
+ padding-inline: 14px 6px;
190
+ border-bottom: 1px solid var(--fdn-hairline);
191
+ }
192
+
193
+ .fdn-header-title {
194
+ flex: 1;
195
+ min-width: 0;
196
+ overflow: hidden;
197
+ text-overflow: ellipsis;
198
+ white-space: nowrap;
199
+ font-size: 14px;
200
+ font-weight: 500;
201
+ }
202
+
203
+ .fdn-icon-button {
204
+ display: inline-grid;
205
+ place-items: center;
206
+ width: 32px;
207
+ height: 32px;
208
+ padding: 0;
209
+ border: 0;
210
+ border-radius: 50%;
211
+ background: transparent;
212
+ color: var(--fdn-text-muted);
213
+ cursor: pointer;
214
+ }
215
+
216
+ .fdn-icon-button.fdn-small {
217
+ width: 26px;
218
+ height: 26px;
219
+ }
220
+
221
+ .fdn-icon-button:hover:not(:disabled) {
222
+ background: var(--fdn-surface-hover);
223
+ color: var(--fdn-text);
224
+ }
225
+
226
+ /* A button whose menu is open looks pressed; the gear also while About, which its menu opened, is open. */
227
+ .fdn-icon-button[aria-expanded="true"],
228
+ .fdn-icon-button.fdn-open {
229
+ background: var(--fdn-surface-hover);
230
+ color: var(--fdn-text);
231
+ }
232
+
233
+ .fdn-icon-button:disabled {
234
+ opacity: 0.38;
235
+ cursor: default;
236
+ }
237
+
238
+ .fdn-mode-button {
239
+ display: inline-flex;
240
+ align-items: center;
241
+ gap: 4px;
242
+ height: 28px;
243
+ padding-block: 0;
244
+ padding-inline: 10px 8px;
245
+ border: 1px solid var(--fdn-border);
246
+ border-radius: var(--fdn-radius);
247
+ background: transparent;
248
+ color: var(--fdn-text-muted);
249
+ font-size: 12px;
250
+ cursor: pointer;
251
+ }
252
+
253
+ .fdn-mode-button:hover:not(:disabled) {
254
+ background: var(--fdn-surface-hover);
255
+ color: var(--fdn-text);
256
+ }
257
+
258
+ .fdn-menu-anchor {
259
+ position: relative;
260
+ }
261
+
262
+ .fdn-menu {
263
+ position: absolute;
264
+ z-index: 10;
265
+ top: calc(100% + 4px);
266
+ inset-inline-end: 0;
267
+ min-width: 260px;
268
+ max-width: min(340px, calc(100vw - 16px));
269
+ padding: 6px;
270
+ border-radius: var(--fdn-radius);
271
+ background: var(--fdn-surface);
272
+ box-shadow: var(--fdn-shadow);
273
+ }
274
+
275
+ .fdn-menu-item {
276
+ display: flex;
277
+ gap: 8px;
278
+ width: 100%;
279
+ padding-block: 8px;
280
+ padding-inline: 6px 10px;
281
+ border: 0;
282
+ border-radius: 6px; /* concentric: 12 - 6 */
283
+ background: transparent;
284
+ text-align: start;
285
+ cursor: pointer;
286
+ }
287
+
288
+ .fdn-menu-item:hover:not(:disabled) {
289
+ background: var(--fdn-surface-hover);
290
+ }
291
+
292
+ .fdn-menu-item:disabled {
293
+ opacity: 0.45;
294
+ cursor: default;
295
+ }
296
+
297
+ .fdn-menu-check {
298
+ width: 16px;
299
+ padding-top: 2px;
300
+ color: var(--fdn-accent);
301
+ }
302
+
303
+ .fdn-menu-label {
304
+ display: block;
305
+ font-weight: 500;
306
+ }
307
+
308
+ .fdn-menu-description,
309
+ .fdn-menu-note {
310
+ display: block;
311
+ color: var(--fdn-text-muted);
312
+ font-size: 12px;
313
+ }
314
+
315
+ .fdn-menu-note {
316
+ padding: 6px 10px;
317
+ }
318
+
319
+ /* The settings: a heading over each group (the languages), the host's own items below a line. A heading on a menu
320
+ (and About's title) is muted, as all text on a surface. */
321
+ .fdn-menu-heading,
322
+ .fdn-about-title {
323
+ color: var(--fdn-text-muted);
324
+ font-size: 12px;
325
+ font-weight: 500;
326
+ }
327
+
328
+ .fdn-menu-heading {
329
+ display: block;
330
+ padding-block: 6px 2px;
331
+ padding-inline: 10px;
332
+ }
333
+
334
+ .fdn-menu-extra {
335
+ margin-block-start: 4px;
336
+ padding-block-start: 4px;
337
+ border-block-start: 1px solid var(--fdn-hairline);
338
+ }
339
+
340
+ .fdn-settings {
341
+ max-height: min(480px, 75vh);
342
+ overflow-y: auto;
343
+ }
344
+
345
+ /* The settings name languages in their own scripts; the fonts for Chinese have no weight 500 and fall back to 400, so
346
+ every item here is 400 (as the host's own items are), and the picked one 600, which those fonts show as bold. */
347
+ .fdn-settings .fdn-menu-label {
348
+ font-weight: 400;
349
+ }
350
+
351
+ .fdn-settings [aria-checked="true"] .fdn-menu-label {
352
+ font-weight: 600;
353
+ }
354
+
355
+ .fdn-history {
356
+ max-height: min(420px, 70vh);
357
+ overflow-y: auto;
358
+ }
359
+
360
+ .fdn-history-item {
361
+ display: flex;
362
+ align-items: center;
363
+ border-radius: 6px;
364
+ }
365
+
366
+ .fdn-history-item:hover,
367
+ .fdn-history-item.fdn-current {
368
+ background: var(--fdn-surface-hover);
369
+ }
370
+
371
+ .fdn-history-open {
372
+ flex: 1;
373
+ min-width: 0;
374
+ display: flex;
375
+ gap: 8px;
376
+ padding-block: 7px;
377
+ padding-inline: 10px 4px;
378
+ border: 0;
379
+ background: transparent;
380
+ text-align: start;
381
+ cursor: pointer;
382
+ }
383
+
384
+ .fdn-history-title {
385
+ flex: 1;
386
+ min-width: 0;
387
+ overflow: hidden;
388
+ text-overflow: ellipsis;
389
+ white-space: nowrap;
390
+ }
391
+
392
+ .fdn-history-when {
393
+ color: var(--fdn-text-muted);
394
+ font-size: 12px;
395
+ white-space: nowrap;
396
+ }
397
+
398
+ /* -- the conversation -------------------------------------------------------------------------- */
399
+
400
+ .fdn-body {
401
+ flex: 1;
402
+ min-height: 0;
403
+ overflow-y: auto;
404
+ scrollbar-width: thin;
405
+ scrollbar-gutter: stable;
406
+ }
407
+
408
+ .fdn-body-center {
409
+ display: grid;
410
+ place-items: center;
411
+ padding: 16px;
412
+ }
413
+
414
+ .fdn-turns {
415
+ display: flex;
416
+ flex-direction: column;
417
+ gap: 18px;
418
+ padding: 14px 14px 18px;
419
+ }
420
+
421
+ .fdn-turn {
422
+ display: flex;
423
+ flex-direction: column;
424
+ gap: 10px;
425
+ /* Long sessions: turns out of view are not laid out or painted. */
426
+ content-visibility: auto;
427
+ contain-intrinsic-size: auto 160px;
428
+ }
429
+
430
+ .fdn-earlier {
431
+ align-self: center;
432
+ padding: 4px 12px;
433
+ border: 0;
434
+ border-radius: var(--fdn-radius);
435
+ background: transparent;
436
+ color: var(--fdn-accent);
437
+ cursor: pointer;
438
+ }
439
+
440
+ .fdn-earlier:hover {
441
+ background: var(--fdn-surface-hover);
442
+ }
443
+
444
+ .fdn-user {
445
+ display: flex;
446
+ flex-direction: column;
447
+ align-items: flex-end;
448
+ gap: 4px;
449
+ }
450
+
451
+ .fdn-user-bubble {
452
+ max-width: 88%;
453
+ padding: 8px 12px;
454
+ border-radius: var(--fdn-radius);
455
+ background: var(--fdn-surface-high);
456
+ white-space: pre-wrap;
457
+ overflow-wrap: anywhere;
458
+ }
459
+
460
+ .fdn-user-blocked .fdn-user-bubble {
461
+ background: transparent;
462
+ border: 1px dashed var(--fdn-border);
463
+ color: var(--fdn-text-muted);
464
+ }
465
+
466
+ .fdn-user-note {
467
+ display: flex;
468
+ gap: 8px;
469
+ color: var(--fdn-text-faint);
470
+ font-size: 12px;
471
+ }
472
+
473
+ .fdn-link {
474
+ padding: 0;
475
+ border: 0;
476
+ background: none;
477
+ color: var(--fdn-accent);
478
+ cursor: pointer;
479
+ }
480
+
481
+ .fdn-answer {
482
+ display: flex;
483
+ flex-direction: column;
484
+ gap: 8px;
485
+ min-width: 0;
486
+ }
487
+
488
+ .fdn-status {
489
+ display: flex;
490
+ align-items: center;
491
+ gap: 8px;
492
+ color: var(--fdn-text-muted);
493
+ }
494
+
495
+ .fdn-error-text {
496
+ color: var(--fdn-danger);
497
+ }
498
+
499
+ .fdn-turn-actions {
500
+ display: flex;
501
+ align-items: center;
502
+ gap: 2px;
503
+ margin-inline-start: -4px;
504
+ color: var(--fdn-text-muted); /* quiet icons; not by opacity, which took the meta's text under 4.5:1 */
505
+ font-size: 12px;
506
+ }
507
+
508
+ .fdn-turn-actions .fdn-muted {
509
+ margin-inline-start: 6px;
510
+ }
511
+
512
+ .fdn-spinner {
513
+ display: inline-block;
514
+ flex: none;
515
+ border: 2px solid var(--fdn-hairline);
516
+ border-top-color: var(--fdn-accent);
517
+ border-radius: 50%;
518
+ animation: fdn-spin 0.8s linear infinite;
519
+ }
520
+
521
+ @keyframes fdn-spin {
522
+ to {
523
+ transform: rotate(360deg);
524
+ }
525
+ }
526
+
527
+ @media (prefers-reduced-motion: reduce) {
528
+ .fdn-spinner {
529
+ animation-duration: 2.4s;
530
+ }
531
+ }
532
+
533
+ /* -- markdown ---------------------------------------------------------------------------------- */
534
+
535
+ .fdn-md {
536
+ overflow-wrap: anywhere;
537
+ }
538
+
539
+ .fdn-md > :first-child {
540
+ margin-top: 0;
541
+ }
542
+
543
+ .fdn-md > :last-child {
544
+ margin-bottom: 0;
545
+ }
546
+
547
+ .fdn-md p,
548
+ .fdn-md ul,
549
+ .fdn-md ol,
550
+ .fdn-md blockquote,
551
+ .fdn-md .fdn-md-table,
552
+ .fdn-md .fdn-md-code {
553
+ margin: 0 0 8px;
554
+ }
555
+
556
+ .fdn-md h3,
557
+ .fdn-md h4,
558
+ .fdn-md h5,
559
+ .fdn-md h6 {
560
+ margin: 12px 0 4px;
561
+ line-height: 1.3;
562
+ }
563
+
564
+ .fdn-md .fdn-md-h1 {
565
+ font-size: 16px;
566
+ }
567
+
568
+ .fdn-md .fdn-md-h2 {
569
+ font-size: 15px;
570
+ }
571
+
572
+ .fdn-md .fdn-md-h3,
573
+ .fdn-md .fdn-md-h4,
574
+ .fdn-md .fdn-md-h5,
575
+ .fdn-md .fdn-md-h6 {
576
+ font-size: 13px;
577
+ }
578
+
579
+ .fdn-md ul,
580
+ .fdn-md ol {
581
+ padding-inline-start: 20px;
582
+ }
583
+
584
+ .fdn-md li + li {
585
+ margin-top: 2px;
586
+ }
587
+
588
+ .fdn-md .fdn-md-task {
589
+ list-style: none;
590
+ margin-inline-start: -18px;
591
+ }
592
+
593
+ .fdn-md .fdn-md-task input {
594
+ margin-block: 0;
595
+ margin-inline: 0 6px;
596
+ vertical-align: -1px;
597
+ }
598
+
599
+ .fdn-md li > .fdn-md-li {
600
+ display: block;
601
+ }
602
+
603
+ /* A task's text stays beside its box. */
604
+ .fdn-md .fdn-md-task > input + .fdn-md-li {
605
+ display: inline;
606
+ }
607
+
608
+ .fdn-md blockquote {
609
+ padding-block: 0;
610
+ padding-inline: 10px 0;
611
+ border-inline-start: 3px solid var(--fdn-border);
612
+ color: var(--fdn-text-muted);
613
+ }
614
+
615
+ .fdn-md a {
616
+ color: var(--fdn-accent);
617
+ text-decoration: underline;
618
+ text-underline-offset: 2px;
619
+ }
620
+
621
+ .fdn-md :not(pre) > code {
622
+ padding: 1px 4px;
623
+ border-radius: 4px;
624
+ background: var(--fdn-code-bg);
625
+ font: 12px var(--fdn-mono);
626
+ }
627
+
628
+ .fdn-md-image {
629
+ color: var(--fdn-text-muted);
630
+ }
631
+
632
+ .fdn-md hr {
633
+ margin: 12px 0;
634
+ border: 0;
635
+ border-top: 1px solid var(--fdn-hairline);
636
+ }
637
+
638
+ .fdn-md-code {
639
+ border-radius: var(--fdn-radius);
640
+ background: var(--fdn-code-bg);
641
+ overflow: hidden;
642
+ }
643
+
644
+ .fdn-md-code-bar {
645
+ display: flex;
646
+ align-items: center;
647
+ justify-content: space-between;
648
+ min-height: 30px;
649
+ padding-block: 2px 0;
650
+ padding-inline: 12px 4px;
651
+ color: var(--fdn-text-muted);
652
+ font-size: 12px;
653
+ }
654
+
655
+ .fdn-md-code pre {
656
+ margin: 0;
657
+ padding: 0 12px 10px;
658
+ overflow-x: auto;
659
+ scrollbar-width: thin;
660
+ font: 12px/1.55 var(--fdn-mono);
661
+ }
662
+
663
+ .fdn-md-table-scroll {
664
+ overflow-x: auto;
665
+ scrollbar-width: thin;
666
+ }
667
+
668
+ .fdn-md-table-bar {
669
+ display: flex;
670
+ justify-content: flex-end;
671
+ margin-top: 2px;
672
+ }
673
+
674
+ .fdn-chat table {
675
+ border-collapse: collapse;
676
+ font-size: 12.5px;
677
+ }
678
+
679
+ .fdn-chat th,
680
+ .fdn-chat td {
681
+ padding: 4px 10px;
682
+ border: 1px solid var(--fdn-hairline);
683
+ text-align: start;
684
+ vertical-align: top;
685
+ /* Not "anywhere" (as the answer around it): a column keeps its longest word; a wider table scrolls sideways. */
686
+ overflow-wrap: break-word;
687
+ }
688
+
689
+ .fdn-chat th {
690
+ background: var(--fdn-surface);
691
+ font-weight: 600;
692
+ }
693
+
694
+ /* Text still arriving: a caret after the last block. */
695
+ .fdn-md-streaming > :last-child::after {
696
+ content: "";
697
+ display: inline-block;
698
+ width: 7px;
699
+ height: 13px;
700
+ margin-inline-start: 2px;
701
+ vertical-align: -2px;
702
+ border-radius: 2px;
703
+ background: var(--fdn-text-faint);
704
+ animation: fdn-blink 1s steps(2) infinite;
705
+ }
706
+
707
+ .fdn-md-streaming > .fdn-md-code:last-child::after,
708
+ .fdn-md-streaming > .fdn-md-table:last-child::after,
709
+ .fdn-md-streaming > ul:last-child::after,
710
+ .fdn-md-streaming > ol:last-child::after {
711
+ display: none;
712
+ }
713
+
714
+ @keyframes fdn-blink {
715
+ to {
716
+ visibility: hidden;
717
+ }
718
+ }
719
+
720
+ /* -- tool calls, approvals, notices ------------------------------------------------------------ */
721
+
722
+ .fdn-tool {
723
+ border-radius: var(--fdn-radius);
724
+ }
725
+
726
+ .fdn-tool-line {
727
+ display: flex;
728
+ align-items: center;
729
+ gap: 8px;
730
+ width: 100%;
731
+ min-height: 30px;
732
+ padding: 4px 8px;
733
+ border: 1px solid var(--fdn-hairline);
734
+ border-radius: var(--fdn-radius);
735
+ background: transparent;
736
+ color: var(--fdn-text-muted);
737
+ text-align: start;
738
+ cursor: pointer;
739
+ }
740
+
741
+ .fdn-tool-line:hover:not(:disabled) {
742
+ background: var(--fdn-surface-hover);
743
+ }
744
+
745
+ .fdn-tool-line:disabled {
746
+ cursor: default;
747
+ }
748
+
749
+ .fdn-tool-status {
750
+ display: grid;
751
+ place-items: center;
752
+ width: 16px;
753
+ color: var(--fdn-success);
754
+ }
755
+
756
+ .fdn-tool-failed .fdn-tool-status {
757
+ color: var(--fdn-danger);
758
+ }
759
+
760
+ .fdn-tool-denied .fdn-tool-status {
761
+ color: var(--fdn-text-faint);
762
+ }
763
+
764
+ .fdn-tool-title {
765
+ flex: 1;
766
+ min-width: 0;
767
+ overflow: hidden;
768
+ text-overflow: ellipsis;
769
+ white-space: nowrap;
770
+ font-family: var(--fdn-mono);
771
+ font-size: 12px;
772
+ }
773
+
774
+ .fdn-tool-duration {
775
+ color: var(--fdn-text-faint);
776
+ font-size: 11.5px;
777
+ white-space: nowrap;
778
+ }
779
+
780
+ .fdn-chevron {
781
+ display: grid;
782
+ transition: transform 0.15s;
783
+ }
784
+
785
+ .fdn-chevron.fdn-open {
786
+ transform: rotate(180deg);
787
+ }
788
+
789
+ .fdn-tool-details {
790
+ margin-block: 4px 0;
791
+ margin-inline: 24px 0;
792
+ padding: 8px 10px;
793
+ border-radius: var(--fdn-radius);
794
+ background: var(--fdn-code-bg);
795
+ }
796
+
797
+ .fdn-tool-details pre,
798
+ .fdn-approval-args {
799
+ max-height: 260px;
800
+ margin: 2px 0 8px;
801
+ overflow: auto;
802
+ scrollbar-width: thin;
803
+ white-space: pre-wrap;
804
+ overflow-wrap: anywhere;
805
+ font: 12px/1.5 var(--fdn-mono);
806
+ }
807
+
808
+ .fdn-tool-details pre:last-child {
809
+ margin-bottom: 0;
810
+ }
811
+
812
+ .fdn-label {
813
+ color: var(--fdn-text-muted);
814
+ font-size: 11.5px;
815
+ font-weight: 500;
816
+ }
817
+
818
+ .fdn-badge {
819
+ flex: none;
820
+ padding: 1px 7px;
821
+ border-radius: 999px;
822
+ background: var(--fdn-surface-high);
823
+ color: var(--fdn-text-muted);
824
+ font-size: 11px;
825
+ line-height: 16px;
826
+ white-space: nowrap;
827
+ }
828
+
829
+ .fdn-badge.fdn-class-write {
830
+ background: var(--fdn-accent-soft);
831
+ color: var(--fdn-on-accent-soft);
832
+ }
833
+
834
+ .fdn-badge.fdn-class-destructive,
835
+ .fdn-badge.fdn-class-unknown {
836
+ background: var(--fdn-danger-soft);
837
+ color: var(--fdn-danger);
838
+ }
839
+
840
+ .fdn-approval {
841
+ padding: 10px 12px 12px;
842
+ border: 1px solid var(--fdn-border);
843
+ border-radius: var(--fdn-radius);
844
+ background: var(--fdn-surface);
845
+ }
846
+
847
+ .fdn-approval-danger {
848
+ border-color: var(--fdn-danger);
849
+ }
850
+
851
+ .fdn-approval-head {
852
+ display: flex;
853
+ align-items: center;
854
+ gap: 8px;
855
+ }
856
+
857
+ .fdn-approval-head strong {
858
+ flex: 1;
859
+ min-width: 0;
860
+ overflow-wrap: anywhere;
861
+ }
862
+
863
+ .fdn-approval-danger .fdn-approval-head .fdn-icon {
864
+ color: var(--fdn-danger);
865
+ }
866
+
867
+ .fdn-approval-reason {
868
+ margin: 6px 0 0;
869
+ color: var(--fdn-text-muted);
870
+ }
871
+
872
+ .fdn-approval-target {
873
+ margin: 8px 0 0;
874
+ font-weight: 600;
875
+ overflow-wrap: anywhere;
876
+ }
877
+
878
+ .fdn-approval-args {
879
+ margin-top: 8px;
880
+ padding: 8px 10px;
881
+ border-radius: 6px; /* concentric: 12 - 6 */
882
+ background: var(--fdn-bg);
883
+ }
884
+
885
+ /* The answers in two pairs (Allow, Allow for this chat | Allow always, Deny): one row where they fit, else a pair a
886
+ row, never three and one. Narrower padding than other buttons, so all four fit in a 420 px task pane. */
887
+ .fdn-approval-actions,
888
+ .fdn-approval-pair {
889
+ display: flex;
890
+ flex-wrap: wrap;
891
+ gap: 6px;
892
+ }
893
+
894
+ .fdn-approval-actions {
895
+ margin-top: 10px;
896
+ }
897
+
898
+ .fdn-chat .fdn-approval-actions .fdn-button {
899
+ padding-inline: 10px;
900
+ }
901
+
902
+ .fdn-approval-state {
903
+ margin-top: 8px;
904
+ color: var(--fdn-text-muted);
905
+ font-size: 12px;
906
+ }
907
+
908
+ .fdn-approval-approved,
909
+ .fdn-approval-approved_for_session {
910
+ color: var(--fdn-success);
911
+ }
912
+
913
+ /* Text buttons (approval cards, About). Under `.fdn-chat`, so their colour and weight outrank the reset that has
914
+ every button in the panel inherit its font and colour (`.fdn-chat button`). */
915
+ .fdn-chat .fdn-button {
916
+ height: 32px;
917
+ padding: 0 14px;
918
+ border: 1px solid var(--fdn-border);
919
+ border-radius: var(--fdn-radius);
920
+ background: transparent;
921
+ color: var(--fdn-accent);
922
+ font-weight: 500;
923
+ cursor: pointer;
924
+ }
925
+
926
+ .fdn-chat .fdn-button:hover:not(:disabled) {
927
+ background: var(--fdn-surface-hover);
928
+ }
929
+
930
+ .fdn-chat .fdn-button.fdn-primary {
931
+ border-color: var(--fdn-accent);
932
+ background: var(--fdn-accent);
933
+ color: var(--fdn-on-accent);
934
+ }
935
+
936
+ .fdn-chat .fdn-button.fdn-primary:hover:not(:disabled) {
937
+ background: var(--fdn-accent);
938
+ filter: brightness(1.08);
939
+ }
940
+
941
+ .fdn-chat .fdn-button.fdn-quiet {
942
+ border-color: transparent;
943
+ color: var(--fdn-text-muted);
944
+ }
945
+
946
+ .fdn-chat .fdn-button:disabled {
947
+ opacity: 0.45;
948
+ cursor: default;
949
+ }
950
+
951
+ .fdn-notice {
952
+ display: flex;
953
+ gap: 8px;
954
+ padding: 9px 12px;
955
+ border-radius: var(--fdn-radius);
956
+ background: var(--fdn-surface);
957
+ }
958
+
959
+ .fdn-notice .fdn-icon {
960
+ margin-top: 2px;
961
+ color: var(--fdn-text-muted);
962
+ }
963
+
964
+ .fdn-notice-warning {
965
+ background: var(--fdn-warning-soft);
966
+ }
967
+
968
+ .fdn-notice-warning .fdn-icon {
969
+ color: var(--fdn-warning);
970
+ }
971
+
972
+ .fdn-notice-blocked,
973
+ .fdn-notice-error {
974
+ background: var(--fdn-danger-soft);
975
+ }
976
+
977
+ .fdn-notice-blocked .fdn-icon,
978
+ .fdn-notice-error .fdn-icon {
979
+ color: var(--fdn-danger);
980
+ }
981
+
982
+ .fdn-notice-detail {
983
+ color: var(--fdn-text-muted);
984
+ font-size: 11.5px;
985
+ }
986
+
987
+ .fdn-collapsible-head {
988
+ display: inline-flex;
989
+ align-items: center;
990
+ gap: 6px;
991
+ padding-block: 3px;
992
+ padding-inline: 6px 8px;
993
+ border: 0;
994
+ border-radius: var(--fdn-radius);
995
+ background: transparent;
996
+ color: var(--fdn-text-muted);
997
+ cursor: pointer;
998
+ }
999
+
1000
+ .fdn-collapsible-head:hover {
1001
+ background: var(--fdn-surface-hover);
1002
+ }
1003
+
1004
+ .fdn-reasoning {
1005
+ margin-block: 4px 0;
1006
+ margin-inline: 8px 0;
1007
+ padding-inline-start: 12px;
1008
+ border-inline-start: 2px solid var(--fdn-hairline);
1009
+ color: var(--fdn-text-muted);
1010
+ white-space: pre-wrap;
1011
+ }
1012
+
1013
+ .fdn-citations {
1014
+ margin: 4px 0 0;
1015
+ padding-inline-start: 28px;
1016
+ color: var(--fdn-text-muted);
1017
+ }
1018
+
1019
+ .fdn-card {
1020
+ padding: 10px 12px;
1021
+ border: 1px solid var(--fdn-hairline);
1022
+ border-radius: var(--fdn-radius);
1023
+ }
1024
+
1025
+ .fdn-card dl {
1026
+ display: grid;
1027
+ gap: 2px;
1028
+ margin: 6px 0 0;
1029
+ }
1030
+
1031
+ .fdn-card dl > div {
1032
+ display: flex;
1033
+ gap: 8px;
1034
+ }
1035
+
1036
+ .fdn-card dt {
1037
+ min-width: 90px;
1038
+ color: var(--fdn-text-faint);
1039
+ }
1040
+
1041
+ .fdn-card dd {
1042
+ margin: 0;
1043
+ }
1044
+
1045
+ .fdn-progress {
1046
+ display: flex;
1047
+ align-items: center;
1048
+ gap: 8px;
1049
+ }
1050
+
1051
+ .fdn-progress progress {
1052
+ flex: 1;
1053
+ accent-color: var(--fdn-accent);
1054
+ }
1055
+
1056
+ .fdn-diff pre {
1057
+ margin: 4px 0 0;
1058
+ padding: 8px 10px;
1059
+ border-radius: var(--fdn-radius);
1060
+ background: var(--fdn-code-bg);
1061
+ overflow-x: auto;
1062
+ font: 12px/1.5 var(--fdn-mono);
1063
+ }
1064
+
1065
+ .fdn-diff-added {
1066
+ color: var(--fdn-success);
1067
+ }
1068
+
1069
+ .fdn-diff-removed {
1070
+ color: var(--fdn-danger);
1071
+ }
1072
+
1073
+ /* -- the empty chat ------------------------------------------------------------------------------ */
1074
+
1075
+ .fdn-empty {
1076
+ display: flex;
1077
+ flex-direction: column;
1078
+ align-items: center;
1079
+ gap: 12px;
1080
+ padding: 36px 8px 12px;
1081
+ text-align: center;
1082
+ }
1083
+
1084
+ /* The agent's face, on its own: the stack has its own silhouette, so no circle behind it. */
1085
+ .fdn-empty-mark {
1086
+ display: grid;
1087
+ place-items: center;
1088
+ }
1089
+
1090
+ .fdn-agent-avatar {
1091
+ display: block;
1092
+ flex: none;
1093
+ overflow: visible;
1094
+ }
1095
+
1096
+ .fdn-greeting {
1097
+ max-width: 320px;
1098
+ margin: 0;
1099
+ color: var(--fdn-text-muted);
1100
+ font-size: 14px;
1101
+ }
1102
+
1103
+ .fdn-suggestions {
1104
+ display: flex;
1105
+ flex-direction: column;
1106
+ gap: 6px;
1107
+ width: 100%;
1108
+ max-width: 340px;
1109
+ }
1110
+
1111
+ .fdn-suggestion {
1112
+ padding: 8px 12px;
1113
+ border: 1px solid var(--fdn-hairline);
1114
+ border-radius: var(--fdn-radius);
1115
+ background: transparent;
1116
+ text-align: start;
1117
+ cursor: pointer;
1118
+ }
1119
+
1120
+ .fdn-suggestion:hover:not(:disabled) {
1121
+ background: var(--fdn-surface-hover);
1122
+ }
1123
+
1124
+ /* -- the composer ---------------------------------------------------------------------------------- */
1125
+
1126
+ .fdn-banner {
1127
+ margin: 0 12px 8px;
1128
+ padding: 8px 12px;
1129
+ border-radius: var(--fdn-radius);
1130
+ background: var(--fdn-danger-soft);
1131
+ color: var(--fdn-danger);
1132
+ }
1133
+
1134
+ .fdn-composer {
1135
+ position: relative; /* the skill picker opens above it */
1136
+ margin: 0 10px 10px;
1137
+ padding-block: 8px 6px; /* the send button sits 6 in from the 12 corner */
1138
+ padding-inline: 12px 6px;
1139
+ border: 1px solid var(--fdn-border);
1140
+ border-radius: var(--fdn-radius);
1141
+ background: var(--fdn-bg);
1142
+ }
1143
+
1144
+ /* Under the composer: answers come from an AI and can be wrong. Quiet, but always there. Below it, on a line of
1145
+ its own and as quiet, the Fadenstack link (`branding: false` hides it). */
1146
+ .fdn-footer {
1147
+ margin: -4px 12px 8px;
1148
+ color: var(--fdn-text-faint);
1149
+ font-size: 11.5px;
1150
+ line-height: 1.4;
1151
+ text-align: center;
1152
+ }
1153
+
1154
+ .fdn-ai-notice,
1155
+ .fdn-footer-brand {
1156
+ margin: 0;
1157
+ }
1158
+
1159
+ /* A notice that wraps does so in even lines, never one word alone on the last; where balance is not supported,
1160
+ pretty keeps the last line from being one word, and older engines wrap as usual. */
1161
+ .fdn-ai-notice {
1162
+ text-wrap: pretty;
1163
+ text-wrap: balance;
1164
+ }
1165
+
1166
+ /* Just enough to tell the link's line from a notice that wraps. */
1167
+ .fdn-ai-notice + .fdn-footer-brand {
1168
+ margin-block-start: 2px;
1169
+ }
1170
+
1171
+ /* Muted like the notice, underlined so it is not told apart by colour alone; no arrow on so small a line. */
1172
+ .fdn-footer-link {
1173
+ color: inherit;
1174
+ text-decoration: underline;
1175
+ text-underline-offset: 2px;
1176
+ white-space: nowrap;
1177
+ }
1178
+
1179
+ .fdn-footer-link:hover {
1180
+ color: var(--fdn-text-muted);
1181
+ }
1182
+
1183
+ /* A link that opens in a new tab: a small arrow after its text, pointing the way the text runs. */
1184
+ .fdn-external .fdn-icon {
1185
+ display: inline-block;
1186
+ margin-inline-start: 2px;
1187
+ vertical-align: -1px;
1188
+ }
1189
+
1190
+ .fdn-external .fdn-icon:dir(rtl) {
1191
+ transform: scaleX(-1);
1192
+ }
1193
+
1194
+ /* About: an overlay below the settings' gear, like the menus. Its text starts where the menu items' labels start
1195
+ (6 the menu + 6 the item + 16 the check + 8 the gap), so it opens in place of the item that opened it. */
1196
+ .fdn-about {
1197
+ display: flex;
1198
+ flex-direction: column;
1199
+ gap: 10px;
1200
+ padding-block: 6px 12px;
1201
+ padding-inline: 36px 6px;
1202
+ }
1203
+
1204
+ .fdn-about-head {
1205
+ display: flex;
1206
+ align-items: center;
1207
+ justify-content: space-between;
1208
+ gap: 8px;
1209
+ }
1210
+
1211
+ .fdn-about-agent,
1212
+ .fdn-about-environment {
1213
+ display: flex;
1214
+ flex-direction: column;
1215
+ gap: 1px;
1216
+ padding-inline-end: 6px;
1217
+ overflow-wrap: anywhere;
1218
+ }
1219
+
1220
+ .fdn-about-name {
1221
+ font-size: 14px;
1222
+ font-weight: 500;
1223
+ }
1224
+
1225
+ .fdn-about-line {
1226
+ color: var(--fdn-text-muted);
1227
+ font-size: 12px;
1228
+ }
1229
+
1230
+ /* One link per line: nothing wraps unevenly, whatever the language makes of their names. */
1231
+ .fdn-about-links {
1232
+ display: flex;
1233
+ flex-direction: column;
1234
+ align-items: flex-start;
1235
+ gap: 4px;
1236
+ }
1237
+
1238
+ .fdn-about-link {
1239
+ color: var(--fdn-accent);
1240
+ text-decoration: none;
1241
+ }
1242
+
1243
+ .fdn-about-link:hover {
1244
+ text-decoration: underline;
1245
+ text-underline-offset: 2px;
1246
+ }
1247
+
1248
+ .fdn-about .fdn-button {
1249
+ display: inline-flex;
1250
+ align-items: center;
1251
+ align-self: flex-start;
1252
+ gap: 6px;
1253
+ }
1254
+
1255
+ .fdn-composer:focus-within {
1256
+ border-color: var(--fdn-accent);
1257
+ box-shadow: 0 0 0 1px var(--fdn-accent);
1258
+ }
1259
+
1260
+ .fdn-composer textarea {
1261
+ display: block;
1262
+ width: 100%;
1263
+ min-height: 22px;
1264
+ padding-block: 0;
1265
+ padding-inline: 0 6px;
1266
+ border: 0;
1267
+ outline: 0;
1268
+ resize: none;
1269
+ background: transparent;
1270
+ color: var(--fdn-text);
1271
+ font: inherit;
1272
+ line-height: 1.5;
1273
+ scrollbar-width: thin;
1274
+ }
1275
+
1276
+ /* The composer draws the focus ring; the text box inside it does not draw a second one. */
1277
+ .fdn-composer textarea:focus-visible {
1278
+ outline: none;
1279
+ }
1280
+
1281
+ .fdn-composer textarea::placeholder {
1282
+ color: var(--fdn-text-faint);
1283
+ }
1284
+
1285
+ .fdn-composer-bar {
1286
+ display: flex;
1287
+ align-items: center;
1288
+ gap: 6px;
1289
+ margin-top: 6px;
1290
+ }
1291
+
1292
+ .fdn-composer-accessory {
1293
+ flex: 1;
1294
+ min-width: 0;
1295
+ display: flex;
1296
+ align-items: center;
1297
+ gap: 4px;
1298
+ }
1299
+
1300
+ .fdn-send {
1301
+ display: grid;
1302
+ place-items: center;
1303
+ width: 30px;
1304
+ height: 30px;
1305
+ padding: 0;
1306
+ border: 0;
1307
+ border-radius: 50%;
1308
+ background: var(--fdn-accent);
1309
+ color: var(--fdn-on-accent);
1310
+ cursor: pointer;
1311
+ }
1312
+
1313
+ /* The arrow points the way the text runs. */
1314
+ .fdn-send .fdn-icon:dir(rtl) {
1315
+ transform: scaleX(-1);
1316
+ }
1317
+
1318
+ .fdn-send:disabled {
1319
+ background: var(--fdn-surface-high);
1320
+ color: var(--fdn-text-faint);
1321
+ cursor: default;
1322
+ }
1323
+
1324
+ .fdn-chips {
1325
+ display: flex;
1326
+ flex-wrap: wrap;
1327
+ gap: 4px;
1328
+ margin-bottom: 6px;
1329
+ }
1330
+
1331
+ .fdn-user-bubble .fdn-chips {
1332
+ margin: 6px 0 0;
1333
+ }
1334
+
1335
+ .fdn-chip {
1336
+ display: inline-flex;
1337
+ align-items: center;
1338
+ gap: 4px;
1339
+ max-width: 100%;
1340
+ height: 24px;
1341
+ padding-block: 0;
1342
+ padding-inline: 8px 4px;
1343
+ border: 1px solid var(--fdn-hairline);
1344
+ border-radius: 999px;
1345
+ background: var(--fdn-surface);
1346
+ color: var(--fdn-text-muted);
1347
+ font-size: 12px;
1348
+ }
1349
+
1350
+ .fdn-chip-static {
1351
+ padding-inline-end: 8px;
1352
+ background: var(--fdn-bg);
1353
+ }
1354
+
1355
+ .fdn-chip-off {
1356
+ opacity: 0.55;
1357
+ border-style: dashed;
1358
+ }
1359
+
1360
+ .fdn-chip-off .fdn-chip-title {
1361
+ text-decoration: line-through;
1362
+ }
1363
+
1364
+ .fdn-chip-toggle {
1365
+ display: inline-flex;
1366
+ align-items: center;
1367
+ gap: 4px;
1368
+ min-width: 0;
1369
+ padding-block: 0;
1370
+ padding-inline: 0 4px;
1371
+ border: 0;
1372
+ background: transparent;
1373
+ cursor: pointer;
1374
+ }
1375
+
1376
+ .fdn-chip-title {
1377
+ overflow: hidden;
1378
+ text-overflow: ellipsis;
1379
+ white-space: nowrap;
1380
+ }
1381
+
1382
+ /* Short by intent (a site, a page count); a longer one is cut to one line, never wrapped out of the chip. */
1383
+ .fdn-chip-sub {
1384
+ min-width: 0;
1385
+ max-width: 50%;
1386
+ overflow: hidden;
1387
+ color: var(--fdn-text-faint);
1388
+ text-overflow: ellipsis;
1389
+ white-space: nowrap;
1390
+ }
1391
+
1392
+ .fdn-chip-remove {
1393
+ display: grid;
1394
+ place-items: center;
1395
+ width: 18px;
1396
+ height: 18px;
1397
+ padding: 0;
1398
+ border: 0;
1399
+ border-radius: 50%;
1400
+ background: transparent;
1401
+ cursor: pointer;
1402
+ }
1403
+
1404
+ .fdn-chip-remove:hover {
1405
+ background: var(--fdn-surface-hover);
1406
+ }
1407
+
1408
+ /* A picture on its chip: small, cut to a square. */
1409
+ .fdn-chip-image {
1410
+ width: 16px;
1411
+ height: 16px;
1412
+ border-radius: 3px;
1413
+ object-fit: cover;
1414
+ }
1415
+
1416
+ .fdn-chip-skill .fdn-icon {
1417
+ color: var(--fdn-accent);
1418
+ }
1419
+
1420
+ /* The skills `$` lists: above the composer, as wide as it, the active one marked as the pointer marks one. */
1421
+ .fdn-skill-picker {
1422
+ top: auto;
1423
+ bottom: calc(100% + 4px);
1424
+ inset-inline: 0;
1425
+ min-width: 0;
1426
+ max-width: none;
1427
+ }
1428
+
1429
+ .fdn-skill-list {
1430
+ max-height: min(320px, 50vh);
1431
+ overflow-y: auto;
1432
+ }
1433
+
1434
+ .fdn-skill-option[aria-selected="true"] {
1435
+ background: var(--fdn-surface-hover);
1436
+ }
1437
+
1438
+ .fdn-skill-hint {
1439
+ padding-block-end: 2px;
1440
+ }