@singlebase/elements 0.1.0 → 0.5.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.
Files changed (51) hide show
  1. package/README.md +2 -0
  2. package/dist/{display-8HEcKYR4.js → authui-display-BCZBP7HR.js} +11 -10
  3. package/dist/authui-display-BCZBP7HR.js.map +1 -0
  4. package/dist/{display-CLDNNZQy.cjs → authui-display-CLGFSqRi.cjs} +21 -21
  5. package/dist/authui-display-CLGFSqRi.cjs.map +1 -0
  6. package/dist/authui.cjs +1 -1
  7. package/dist/authui.d.ts +9 -9
  8. package/dist/authui.js +2 -2
  9. package/dist/chat-DRenTJlI.cjs +3001 -0
  10. package/dist/chat-DRenTJlI.cjs.map +1 -0
  11. package/dist/chat-bXaRWel7.js +4926 -0
  12. package/dist/chat-bXaRWel7.js.map +1 -0
  13. package/dist/chat-messages.d.ts +109 -0
  14. package/dist/chat.cjs +2 -0
  15. package/dist/chat.cjs.map +1 -0
  16. package/dist/chat.d.ts +10 -0
  17. package/dist/chat.js +13 -0
  18. package/dist/chat.js.map +1 -0
  19. package/dist/elements/{account-screen.d.ts → authui-account.d.ts} +1 -1
  20. package/dist/elements/{buttons.d.ts → authui-buttons.d.ts} +1 -1
  21. package/dist/elements/{display.d.ts → authui-display.d.ts} +1 -1
  22. package/dist/elements/{form-base.d.ts → authui-form-base.d.ts} +1 -1
  23. package/dist/elements/{guard.d.ts → authui-guard.d.ts} +1 -1
  24. package/dist/elements/{auth-screen.d.ts → authui.d.ts} +3 -3
  25. package/dist/elements/chat.d.ts +312 -0
  26. package/dist/files-BOwtpYyQ.js +168 -0
  27. package/dist/files-BOwtpYyQ.js.map +1 -0
  28. package/dist/files-DW8A4Jl-.cjs +38 -0
  29. package/dist/files-DW8A4Jl-.cjs.map +1 -0
  30. package/dist/index.cjs +1 -1
  31. package/dist/index.d.ts +3 -2
  32. package/dist/index.js +36 -25
  33. package/dist/index.js.map +1 -1
  34. package/dist/singlebase-elements.min.js +6845 -1829
  35. package/dist/singlebase-elements.min.js.map +1 -1
  36. package/dist/styles/chat.d.ts +6 -0
  37. package/dist/styles/tokens.d.ts +1 -1
  38. package/dist/{uploader-eFYKpk8b.cjs → uploader-DGV2y9uT.cjs} +41 -77
  39. package/dist/uploader-DGV2y9uT.cjs.map +1 -0
  40. package/dist/{uploader-D-Da1trc.js → uploader-abQoem5q.js} +309 -463
  41. package/dist/uploader-abQoem5q.js.map +1 -0
  42. package/dist/uploader.cjs +1 -1
  43. package/dist/uploader.js +5 -4
  44. package/dist/uploader.js.map +1 -1
  45. package/dist/utils/markdown.d.ts +108 -0
  46. package/package.json +13 -5
  47. package/dist/display-8HEcKYR4.js.map +0 -1
  48. package/dist/display-CLDNNZQy.cjs.map +0 -1
  49. package/dist/uploader-D-Da1trc.js.map +0 -1
  50. package/dist/uploader-eFYKpk8b.cjs.map +0 -1
  51. /package/dist/elements/{base.d.ts → authui-base.d.ts} +0 -0
@@ -0,0 +1,4926 @@
1
+ var gt = Object.defineProperty;
2
+ var qe = (n) => {
3
+ throw TypeError(n);
4
+ };
5
+ var mt = (n, e, t) => e in n ? gt(n, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : n[e] = t;
6
+ var T = (n, e, t) => mt(n, typeof e != "symbol" ? e + "" : e, t), Ge = (n, e, t) => e.has(n) || qe("Cannot " + t);
7
+ var p = (n, e, t) => (Ge(n, e, "read from private field"), t ? t.call(n) : e.get(n)), h = (n, e, t) => e.has(n) ? qe("Cannot add the same private member more than once") : e instanceof WeakSet ? e.add(n) : e.set(n, t), u = (n, e, t, i) => (Ge(n, e, "write to private field"), i ? i.call(n, t) : e.set(n, t), t);
8
+ import { css as bt, LitElement as ft, html as r, nothing as m, svg as $ } from "lit";
9
+ import { property as w, state as v, customElement as xt } from "lit/decorators.js";
10
+ import { repeat as vt } from "lit/directives/repeat.js";
11
+ import { getDefaultClient as yt } from "@singlebase/core";
12
+ import { f as z, a as Ve, t as kt } from "./files-BOwtpYyQ.js";
13
+ if (typeof CSS < "u" && "registerProperty" in CSS)
14
+ try {
15
+ CSS.registerProperty({
16
+ name: "--sb-ai-angle",
17
+ syntax: "<angle>",
18
+ inherits: !1,
19
+ initialValue: "0deg"
20
+ });
21
+ } catch {
22
+ }
23
+ const wt = bt`
24
+ :host {
25
+ --c-ink: var(--sb-ink, #16181a);
26
+ --c-ink2: var(--sb-ink-2, #41464b);
27
+ --c-muted: var(--sb-muted-ink, #61666c);
28
+ --c-faint: #8a8f95;
29
+ --c-bg: var(--sb-surface, #ffffff);
30
+ --c-bg2: var(--sb-surface-alt, #fafafa);
31
+ --c-hover: var(--sb-hover, #f2f3f4);
32
+ --c-line: var(--sb-border, #e4e6e9);
33
+ --c-line2: var(--sb-divider, #ecedee);
34
+ --c-strong: var(--sb-border-strong, #cdd1d6);
35
+ --c-brand: var(--sb-accent, #16181a);
36
+ --c-on-brand: var(--sb-on-accent, #ffffff);
37
+ --c-danger: var(--sb-danger, #b4231a);
38
+ --c-ok: var(--sb-ok, #0f6b4a);
39
+ --c-mono: var(--sb-mono, "Geist Mono", ui-monospace, monospace);
40
+ --c-r: var(--sb-radius, 4px);
41
+ --c-r2: calc(var(--c-r) * 1.5);
42
+ --c-r3: calc(var(--c-r) * 2);
43
+ --c-r4: calc(var(--c-r) * 3);
44
+ --c-glow: 0.6;
45
+ --c-conic: conic-gradient(
46
+ from var(--sb-ai-angle, 0deg),
47
+ oklch(0.72 0.15 295),
48
+ oklch(0.74 0.13 245),
49
+ oklch(0.8 0.11 190),
50
+ oklch(0.84 0.12 85),
51
+ oklch(0.78 0.12 350),
52
+ oklch(0.72 0.15 295)
53
+ );
54
+ --c-z: var(--sb-chat-z, 1000);
55
+ display: block;
56
+ height: 100%;
57
+ min-height: 0;
58
+ color-scheme: light;
59
+ }
60
+
61
+ :host([theme="dark"]) {
62
+ --sb-hover: #24272b;
63
+ --sb-ink-2: #c9ccd0;
64
+ --sb-divider: #26292d;
65
+ --c-faint: #7c8187;
66
+ color-scheme: dark;
67
+ }
68
+
69
+ :host([glow="vivid"]) {
70
+ --c-glow: 1;
71
+ }
72
+
73
+ :host([embed="inline"]) {
74
+ height: auto;
75
+ }
76
+
77
+ :host([embed="launcher"]) {
78
+ height: 0;
79
+ }
80
+
81
+ * {
82
+ box-sizing: border-box;
83
+ }
84
+
85
+ button {
86
+ font: inherit;
87
+ color: inherit;
88
+ }
89
+
90
+ button:focus-visible,
91
+ input:focus-visible,
92
+ textarea:focus-visible,
93
+ [role="button"]:focus-visible {
94
+ outline: 2px solid var(--c-ink);
95
+ outline-offset: 1px;
96
+ }
97
+
98
+ .mono {
99
+ font-family: var(--c-mono);
100
+ }
101
+
102
+ .label {
103
+ font-family: var(--c-mono);
104
+ font-size: 11px;
105
+ letter-spacing: 0.07em;
106
+ text-transform: uppercase;
107
+ color: var(--c-muted);
108
+ }
109
+
110
+ /* ── frames ───────────────────────────────────────────── */
111
+
112
+ .frame {
113
+ position: relative;
114
+ display: flex;
115
+ height: 100%;
116
+ min-height: 0;
117
+ background: var(--c-bg);
118
+ color: var(--c-ink);
119
+ overflow: hidden;
120
+ }
121
+
122
+ .frame.boxed {
123
+ border: 1px solid var(--c-line);
124
+ border-radius: var(--c-r4);
125
+ }
126
+
127
+ .frame.inline {
128
+ width: 440px;
129
+ height: 660px;
130
+ min-width: 340px;
131
+ min-height: 480px;
132
+ max-width: 100%;
133
+ resize: both;
134
+ box-shadow: 0 1px 2px rgba(22, 24, 26, 0.06);
135
+ }
136
+
137
+ @media (max-width: 559px) {
138
+ .frame.inline {
139
+ width: 100%;
140
+ min-width: 0;
141
+ resize: none;
142
+ }
143
+ }
144
+
145
+ .frame.launcher {
146
+ position: fixed;
147
+ bottom: 96px;
148
+ right: 24px;
149
+ z-index: var(--c-z);
150
+ width: 420px;
151
+ height: min(680px, calc(100vh - 120px));
152
+ max-width: calc(100vw - 48px);
153
+ box-shadow: 0 24px 60px -24px rgba(22, 24, 26, 0.35);
154
+ transform-origin: bottom right;
155
+ animation: scaleIn 0.2s ease-out;
156
+ }
157
+
158
+ :host([position="left"]) .frame.launcher {
159
+ right: auto;
160
+ left: 24px;
161
+ transform-origin: bottom left;
162
+ }
163
+
164
+ .frame.expanded {
165
+ position: fixed;
166
+ inset: 24px;
167
+ width: auto;
168
+ height: auto;
169
+ max-width: none;
170
+ z-index: var(--c-z);
171
+ resize: none;
172
+ box-shadow: 0 24px 60px -24px rgba(22, 24, 26, 0.35);
173
+ animation: scaleIn 0.2s ease-out;
174
+ }
175
+
176
+ .frame.full {
177
+ position: fixed;
178
+ inset: 0;
179
+ width: auto;
180
+ height: auto;
181
+ max-width: none;
182
+ border-radius: 0;
183
+ border: none;
184
+ z-index: var(--c-z);
185
+ resize: none;
186
+ }
187
+
188
+ .root {
189
+ position: relative;
190
+ display: flex;
191
+ flex: 1;
192
+ min-width: 0;
193
+ min-height: 0;
194
+ font-family: var(--sb-font, "Geist", -apple-system, "Segoe UI", Helvetica, sans-serif);
195
+ background: var(--c-bg);
196
+ color: var(--c-ink);
197
+ }
198
+
199
+ /* ── launcher ─────────────────────────────────────────── */
200
+
201
+ .launcher-btn {
202
+ position: fixed;
203
+ bottom: 24px;
204
+ right: 24px;
205
+ z-index: calc(var(--c-z) + 1);
206
+ width: 56px;
207
+ height: 56px;
208
+ border-radius: 999px;
209
+ display: inline-flex;
210
+ align-items: center;
211
+ justify-content: center;
212
+ border: none;
213
+ cursor: pointer;
214
+ background: var(--c-brand);
215
+ color: var(--c-on-brand);
216
+ box-shadow: 0 12px 28px -10px rgba(22, 24, 26, 0.45);
217
+ }
218
+
219
+ :host([position="left"]) .launcher-btn,
220
+ :host([position="left"]) .bubble {
221
+ right: auto;
222
+ left: 24px;
223
+ }
224
+
225
+ .badge {
226
+ position: absolute;
227
+ top: 2px;
228
+ right: 2px;
229
+ width: 12px;
230
+ height: 12px;
231
+ border-radius: 999px;
232
+ background: var(--c-danger);
233
+ border: 2px solid var(--c-bg);
234
+ }
235
+
236
+ .bubble {
237
+ position: fixed;
238
+ bottom: 96px;
239
+ right: 24px;
240
+ z-index: var(--c-z);
241
+ width: 260px;
242
+ display: flex;
243
+ align-items: flex-start;
244
+ gap: 8px;
245
+ padding: 12px 10px 12px 14px;
246
+ background: var(--c-bg);
247
+ color: var(--c-ink);
248
+ border: 1px solid var(--c-line);
249
+ border-radius: calc(var(--c-r) * 2.5);
250
+ box-shadow: 0 12px 32px -12px rgba(22, 24, 26, 0.25);
251
+ font-family: var(--sb-font, "Geist", -apple-system, "Segoe UI", Helvetica, sans-serif);
252
+ animation: aiIn 0.25s ease-out;
253
+ }
254
+
255
+ .bubble-text {
256
+ flex: 1;
257
+ min-width: 0;
258
+ text-align: left;
259
+ font-size: 13.5px;
260
+ line-height: 1.45;
261
+ background: none;
262
+ border: none;
263
+ padding: 0;
264
+ cursor: pointer;
265
+ }
266
+
267
+ /* ── icon buttons ─────────────────────────────────────── */
268
+
269
+ .icon {
270
+ display: inline-flex;
271
+ align-items: center;
272
+ justify-content: center;
273
+ flex: 0 0 auto;
274
+ width: 28px;
275
+ height: 28px;
276
+ padding: 0;
277
+ border: none;
278
+ border-radius: var(--c-r);
279
+ background: transparent;
280
+ color: var(--c-muted);
281
+ cursor: pointer;
282
+ }
283
+
284
+ .icon:hover:not(:disabled),
285
+ .icon.on {
286
+ color: var(--c-ink);
287
+ }
288
+
289
+ .icon:hover:not(:disabled) {
290
+ background: var(--c-hover);
291
+ }
292
+
293
+ .icon.danger:hover:not(:disabled) {
294
+ color: var(--c-danger);
295
+ }
296
+
297
+ .icon:disabled {
298
+ opacity: 0.4;
299
+ cursor: default;
300
+ }
301
+
302
+ .icon.sm {
303
+ width: 24px;
304
+ height: 24px;
305
+ }
306
+
307
+ svg.i {
308
+ width: 16px;
309
+ height: 16px;
310
+ fill: none;
311
+ stroke: currentColor;
312
+ stroke-width: 1.5;
313
+ stroke-linecap: round;
314
+ stroke-linejoin: round;
315
+ }
316
+
317
+ svg.i.filled path {
318
+ fill: currentColor;
319
+ }
320
+
321
+ @media (pointer: coarse) {
322
+ .icon {
323
+ width: 44px;
324
+ height: 44px;
325
+ }
326
+ }
327
+
328
+ /* ── sidebar ──────────────────────────────────────────── */
329
+
330
+ .scrim {
331
+ position: absolute;
332
+ inset: 0;
333
+ z-index: 29;
334
+ background: rgba(22, 24, 26, 0.18);
335
+ }
336
+
337
+ .sidebar {
338
+ display: flex;
339
+ flex-direction: column;
340
+ min-height: 0;
341
+ min-width: 0;
342
+ background: var(--c-bg2);
343
+ border-right: 1px solid var(--c-line);
344
+ }
345
+
346
+ .sidebar.docked {
347
+ position: relative;
348
+ flex: 0 0 272px;
349
+ width: 272px;
350
+ }
351
+
352
+ .sidebar.overlay {
353
+ position: absolute;
354
+ left: 0;
355
+ top: 0;
356
+ bottom: 0;
357
+ z-index: 30;
358
+ width: min(280px, 86%);
359
+ box-shadow: 12px 0 32px -16px rgba(22, 24, 26, 0.25);
360
+ animation: slideIn 0.15s ease-out;
361
+ }
362
+
363
+ .side-head {
364
+ display: flex;
365
+ align-items: center;
366
+ justify-content: space-between;
367
+ gap: 8px;
368
+ padding: 14px 12px 10px 16px;
369
+ }
370
+
371
+ .side-tools {
372
+ display: flex;
373
+ flex-direction: column;
374
+ gap: 8px;
375
+ padding: 0 12px 8px;
376
+ }
377
+
378
+ .new-chat {
379
+ display: flex;
380
+ align-items: center;
381
+ gap: 8px;
382
+ width: 100%;
383
+ min-height: 34px;
384
+ font-size: 13px;
385
+ font-weight: 500;
386
+ color: var(--c-on-brand);
387
+ background: var(--c-brand);
388
+ border: 1px solid var(--c-brand);
389
+ border-radius: var(--c-r2);
390
+ padding: 8px 12px;
391
+ cursor: pointer;
392
+ }
393
+
394
+ .new-chat:hover {
395
+ filter: brightness(1.2);
396
+ }
397
+
398
+ .search {
399
+ width: 100%;
400
+ font: inherit;
401
+ font-size: 13px;
402
+ color: var(--c-ink);
403
+ background: var(--c-bg);
404
+ border: 1px solid var(--c-line);
405
+ border-radius: var(--c-r2);
406
+ padding: 8px 10px;
407
+ outline: none;
408
+ }
409
+
410
+ .search:focus {
411
+ border-color: var(--c-ink);
412
+ }
413
+
414
+ .threads {
415
+ flex: 1;
416
+ min-height: 0;
417
+ overflow-y: auto;
418
+ display: flex;
419
+ flex-direction: column;
420
+ gap: 1px;
421
+ padding: 4px 12px 12px;
422
+ }
423
+
424
+ .group {
425
+ font-family: var(--c-mono);
426
+ font-size: 11px;
427
+ letter-spacing: 0.07em;
428
+ text-transform: uppercase;
429
+ color: var(--c-muted);
430
+ padding: 10px 8px 6px;
431
+ }
432
+
433
+ .thread {
434
+ display: flex;
435
+ align-items: center;
436
+ gap: 4px;
437
+ min-height: 34px;
438
+ width: 100%;
439
+ font-size: 13px;
440
+ color: var(--c-ink);
441
+ border-radius: var(--c-r2);
442
+ padding: 3px 4px 3px 10px;
443
+ cursor: pointer;
444
+ }
445
+
446
+ .thread:hover {
447
+ background: var(--c-hover);
448
+ }
449
+
450
+ .thread.active {
451
+ background: var(--c-line2);
452
+ font-weight: 500;
453
+ }
454
+
455
+ .thread-title {
456
+ flex: 1;
457
+ min-width: 0;
458
+ overflow: hidden;
459
+ text-overflow: ellipsis;
460
+ white-space: nowrap;
461
+ }
462
+
463
+ .thread-actions {
464
+ display: none;
465
+ gap: 0;
466
+ }
467
+
468
+ .thread:hover .thread-actions,
469
+ .thread:focus-within .thread-actions {
470
+ display: flex;
471
+ }
472
+
473
+ .thread-rename {
474
+ flex: 1;
475
+ min-width: 0;
476
+ font: inherit;
477
+ color: var(--c-ink);
478
+ background: var(--c-bg);
479
+ border: 1px solid var(--c-ink);
480
+ border-radius: var(--c-r);
481
+ padding: 3px 6px;
482
+ outline: none;
483
+ }
484
+
485
+ .side-note {
486
+ font-size: 12.5px;
487
+ color: var(--c-muted);
488
+ padding: 6px 10px;
489
+ }
490
+
491
+ .skeleton {
492
+ height: 28px;
493
+ margin: 3px 0;
494
+ border-radius: var(--c-r2);
495
+ background: linear-gradient(90deg, var(--c-hover) 0%, var(--c-line2) 50%, var(--c-hover) 100%);
496
+ background-size: 200% 100%;
497
+ animation: aiShimmer 1.6s linear infinite;
498
+ }
499
+
500
+ /* ── main column ──────────────────────────────────────── */
501
+
502
+ .main {
503
+ container: chat / inline-size;
504
+ position: relative;
505
+ flex: 1;
506
+ min-width: 0;
507
+ min-height: 0;
508
+ display: flex;
509
+ flex-direction: column;
510
+ }
511
+
512
+ .header {
513
+ display: flex;
514
+ align-items: center;
515
+ justify-content: space-between;
516
+ gap: 12px;
517
+ min-height: 52px;
518
+ padding: 10px 8px 10px 12px;
519
+ border-bottom: 1px solid var(--c-line);
520
+ }
521
+
522
+ .header-left {
523
+ display: flex;
524
+ align-items: center;
525
+ gap: 10px;
526
+ min-width: 0;
527
+ }
528
+
529
+ .header-right {
530
+ flex: 0 0 auto;
531
+ display: flex;
532
+ align-items: center;
533
+ gap: 2px;
534
+ }
535
+
536
+ .title {
537
+ min-width: 0;
538
+ font-size: 14px;
539
+ font-weight: 600;
540
+ letter-spacing: -0.01em;
541
+ overflow: hidden;
542
+ text-overflow: ellipsis;
543
+ white-space: nowrap;
544
+ background: none;
545
+ border: none;
546
+ padding: 2px 4px;
547
+ border-radius: var(--c-r);
548
+ cursor: text;
549
+ animation: aiIn 0.25s ease-out;
550
+ }
551
+
552
+ .title:hover:not(:disabled) {
553
+ background: var(--c-hover);
554
+ }
555
+
556
+ .title:disabled {
557
+ cursor: default;
558
+ }
559
+
560
+ .title-input {
561
+ min-width: 0;
562
+ width: 320px;
563
+ max-width: 100%;
564
+ font: inherit;
565
+ font-size: 14px;
566
+ font-weight: 600;
567
+ color: var(--c-ink);
568
+ background: var(--c-bg);
569
+ border: 1px solid var(--c-ink);
570
+ border-radius: var(--c-r);
571
+ padding: 2px 6px;
572
+ outline: none;
573
+ }
574
+
575
+ .divider {
576
+ width: 1px;
577
+ height: 18px;
578
+ background: var(--c-line);
579
+ margin: 0 4px;
580
+ }
581
+
582
+ .menu-wrap {
583
+ position: relative;
584
+ }
585
+
586
+ .menu-scrim {
587
+ position: fixed;
588
+ inset: 0;
589
+ z-index: 40;
590
+ }
591
+
592
+ .menu {
593
+ position: absolute;
594
+ right: 0;
595
+ top: 34px;
596
+ z-index: 41;
597
+ width: 220px;
598
+ display: flex;
599
+ flex-direction: column;
600
+ padding: 4px;
601
+ background: var(--c-bg);
602
+ border: 1px solid var(--c-line);
603
+ border-radius: var(--c-r2);
604
+ box-shadow: 0 12px 32px -12px rgba(22, 24, 26, 0.22);
605
+ animation: aiIn 0.15s ease-out;
606
+ }
607
+
608
+ .menu .label {
609
+ font-size: 10.5px;
610
+ padding: 8px 10px 6px;
611
+ }
612
+
613
+ .menu-item {
614
+ display: flex;
615
+ align-items: baseline;
616
+ justify-content: space-between;
617
+ gap: 10px;
618
+ width: 100%;
619
+ text-align: left;
620
+ font-size: 13px;
621
+ background: none;
622
+ border: none;
623
+ border-radius: var(--c-r);
624
+ padding: 8px 10px;
625
+ cursor: pointer;
626
+ }
627
+
628
+ .menu-item:hover {
629
+ background: var(--c-hover);
630
+ }
631
+
632
+ .menu-item .ext {
633
+ font-family: var(--c-mono);
634
+ font-size: 11px;
635
+ color: var(--c-muted);
636
+ }
637
+
638
+ .scroller {
639
+ position: relative;
640
+ flex: 1;
641
+ min-height: 0;
642
+ overflow-y: auto;
643
+ }
644
+
645
+ .banner {
646
+ margin: 10px 16px 0;
647
+ padding: 8px 12px;
648
+ font-size: 12.5px;
649
+ color: var(--c-ink2);
650
+ background: var(--c-bg2);
651
+ border: 1px solid var(--c-line);
652
+ border-radius: var(--c-r2);
653
+ }
654
+
655
+ /* ── welcome ──────────────────────────────────────────── */
656
+
657
+ .welcome {
658
+ max-width: 640px;
659
+ min-height: 100%;
660
+ margin: 0 auto;
661
+ display: flex;
662
+ flex-direction: column;
663
+ justify-content: center;
664
+ gap: 20px;
665
+ padding: 28px 18px;
666
+ }
667
+
668
+ .welcome-head {
669
+ display: flex;
670
+ flex-direction: column;
671
+ gap: 8px;
672
+ }
673
+
674
+ .welcome-logo {
675
+ width: 32px;
676
+ height: 32px;
677
+ object-fit: contain;
678
+ border-radius: var(--c-r2);
679
+ }
680
+
681
+ .welcome h2 {
682
+ margin: 0;
683
+ font-size: 24px;
684
+ font-weight: 600;
685
+ letter-spacing: -0.01em;
686
+ }
687
+
688
+ .welcome p {
689
+ margin: 0;
690
+ font-size: 14px;
691
+ line-height: 1.55;
692
+ color: var(--c-muted);
693
+ text-wrap: pretty;
694
+ }
695
+
696
+ .prompts {
697
+ display: grid;
698
+ grid-template-columns: repeat(2, minmax(0, 1fr));
699
+ gap: 8px;
700
+ }
701
+
702
+ .prompt {
703
+ display: flex;
704
+ flex-direction: column;
705
+ gap: 4px;
706
+ text-align: left;
707
+ background: var(--c-bg);
708
+ border: 1px solid var(--c-line);
709
+ border-radius: var(--c-r2);
710
+ padding: 12px 14px;
711
+ cursor: pointer;
712
+ transition:
713
+ border-color 0.15s,
714
+ box-shadow 0.15s;
715
+ }
716
+
717
+ .prompt:hover {
718
+ border-color: var(--c-ink);
719
+ box-shadow: 0 6px 18px -10px rgba(22, 24, 26, 0.25);
720
+ }
721
+
722
+ .prompt .label {
723
+ font-size: 10.5px;
724
+ letter-spacing: 0.06em;
725
+ }
726
+
727
+ .prompt-text {
728
+ font-size: 13.5px;
729
+ font-weight: 500;
730
+ line-height: 1.4;
731
+ }
732
+
733
+ @container chat (max-width: 480px) {
734
+ .prompts {
735
+ grid-template-columns: minmax(0, 1fr);
736
+ }
737
+ }
738
+
739
+ /* ── messages ─────────────────────────────────────────── */
740
+
741
+ .thread-view {
742
+ max-width: 760px;
743
+ margin: 0 auto;
744
+ display: flex;
745
+ flex-direction: column;
746
+ gap: 30px;
747
+ padding: 20px 16px 28px;
748
+ }
749
+
750
+ .msg {
751
+ position: relative;
752
+ display: flex;
753
+ flex-direction: column;
754
+ border-radius: var(--c-r3);
755
+ }
756
+
757
+ .msg.user {
758
+ align-self: flex-end;
759
+ max-width: 80%;
760
+ align-items: flex-end;
761
+ gap: 6px;
762
+ margin-bottom: -22px;
763
+ animation: aiIn 0.25s ease-out;
764
+ }
765
+
766
+ .bubble-user {
767
+ padding: 10px 14px;
768
+ font-size: 14.5px;
769
+ line-height: 1.6;
770
+ white-space: pre-wrap;
771
+ overflow-wrap: anywhere;
772
+ background: var(--c-hover);
773
+ border-radius: calc(var(--c-r) * 2.5) calc(var(--c-r) * 2.5) 2px calc(var(--c-r) * 2.5);
774
+ }
775
+
776
+ .attachments {
777
+ display: flex;
778
+ flex-wrap: wrap;
779
+ justify-content: flex-end;
780
+ gap: 6px;
781
+ }
782
+
783
+ .doc-chip {
784
+ display: inline-flex;
785
+ align-items: center;
786
+ gap: 8px;
787
+ padding: 6px 10px;
788
+ font-size: 12.5px;
789
+ border-radius: var(--c-r2);
790
+ border: 1px solid var(--c-line);
791
+ background: var(--c-bg);
792
+ }
793
+
794
+ .doc-chip .ext {
795
+ font-family: var(--c-mono);
796
+ font-size: 10px;
797
+ letter-spacing: 0.04em;
798
+ color: var(--c-muted);
799
+ }
800
+
801
+ .doc-chip .name {
802
+ max-width: 180px;
803
+ overflow: hidden;
804
+ text-overflow: ellipsis;
805
+ white-space: nowrap;
806
+ }
807
+
808
+ .toolbar {
809
+ display: flex;
810
+ align-items: center;
811
+ gap: 2px;
812
+ opacity: 0;
813
+ transition: opacity 0.15s;
814
+ }
815
+
816
+ .msg:hover .toolbar,
817
+ .msg:focus-within .toolbar,
818
+ .toolbar.pinned {
819
+ opacity: 1;
820
+ }
821
+
822
+ @media (hover: none) {
823
+ .toolbar {
824
+ opacity: 1;
825
+ }
826
+ }
827
+
828
+ .msg.bot .toolbar {
829
+ margin-left: -6px;
830
+ }
831
+
832
+ .time {
833
+ font-family: var(--c-mono);
834
+ font-size: 11px;
835
+ color: var(--c-faint);
836
+ padding: 0 6px;
837
+ font-variant-numeric: tabular-nums;
838
+ }
839
+
840
+ .note {
841
+ font-size: 12px;
842
+ color: var(--c-muted);
843
+ }
844
+
845
+ .spacer {
846
+ flex: 1;
847
+ }
848
+
849
+ .saved {
850
+ display: inline-flex;
851
+ align-items: center;
852
+ gap: 4px;
853
+ font-family: var(--c-mono);
854
+ font-size: 10.5px;
855
+ letter-spacing: 0.05em;
856
+ text-transform: uppercase;
857
+ color: var(--c-ink);
858
+ }
859
+
860
+ .saved svg {
861
+ width: 12px;
862
+ height: 12px;
863
+ fill: currentColor;
864
+ stroke: currentColor;
865
+ stroke-width: 1.5;
866
+ }
867
+
868
+ .bot-body {
869
+ position: relative;
870
+ z-index: 1;
871
+ display: flex;
872
+ flex-direction: column;
873
+ gap: 12px;
874
+ }
875
+
876
+ .edit-box {
877
+ width: 440px;
878
+ max-width: 100%;
879
+ display: flex;
880
+ flex-direction: column;
881
+ gap: 8px;
882
+ padding: 8px;
883
+ border: 1px solid var(--c-ink);
884
+ border-radius: var(--c-r3);
885
+ background: var(--c-bg);
886
+ }
887
+
888
+ .edit-box textarea {
889
+ width: 100%;
890
+ resize: vertical;
891
+ font: inherit;
892
+ font-size: 14px;
893
+ line-height: 1.5;
894
+ color: var(--c-ink);
895
+ background: transparent;
896
+ border: none;
897
+ outline: none;
898
+ padding: 4px;
899
+ }
900
+
901
+ .row-end {
902
+ display: flex;
903
+ justify-content: flex-end;
904
+ gap: 8px;
905
+ }
906
+
907
+ .btn {
908
+ font-size: 12.5px;
909
+ font-weight: 500;
910
+ border-radius: var(--c-r);
911
+ padding: 6px 12px;
912
+ cursor: pointer;
913
+ background: transparent;
914
+ color: var(--c-muted);
915
+ border: 1px solid var(--c-line);
916
+ }
917
+
918
+ .btn:hover {
919
+ color: var(--c-ink);
920
+ background: var(--c-bg2);
921
+ }
922
+
923
+ .btn.primary {
924
+ background: var(--c-brand);
925
+ color: var(--c-on-brand);
926
+ border-color: var(--c-brand);
927
+ }
928
+
929
+ .btn.primary:hover {
930
+ filter: brightness(1.2);
931
+ }
932
+
933
+ .error-card {
934
+ display: flex;
935
+ align-items: center;
936
+ justify-content: space-between;
937
+ gap: 12px;
938
+ padding: 10px 12px;
939
+ font-size: 13px;
940
+ color: var(--c-danger);
941
+ border: 1px solid var(--sb-danger-border, #f3d6d3);
942
+ background: var(--sb-danger-bg, #fdf1f0);
943
+ border-radius: var(--c-r2);
944
+ }
945
+
946
+ .followups {
947
+ display: flex;
948
+ flex-direction: column;
949
+ align-items: flex-start;
950
+ gap: 6px;
951
+ }
952
+
953
+ .followup {
954
+ display: inline-flex;
955
+ align-items: baseline;
956
+ gap: 8px;
957
+ text-align: left;
958
+ font-size: 13px;
959
+ background: var(--c-bg);
960
+ border: 1px solid var(--c-line);
961
+ border-radius: var(--c-r2);
962
+ padding: 6px 12px;
963
+ cursor: pointer;
964
+ animation: aiIn 0.25s ease-out;
965
+ }
966
+
967
+ .followup:hover {
968
+ background: var(--c-hover);
969
+ }
970
+
971
+ .followup .arrow {
972
+ font-family: var(--c-mono);
973
+ color: var(--c-muted);
974
+ }
975
+
976
+ .jump {
977
+ position: absolute;
978
+ left: 50%;
979
+ bottom: 8px;
980
+ transform: translateX(-50%);
981
+ z-index: 5;
982
+ font-size: 12.5px;
983
+ font-weight: 500;
984
+ color: var(--c-on-brand);
985
+ background: var(--c-brand);
986
+ border: none;
987
+ border-radius: 999px;
988
+ padding: 6px 14px;
989
+ cursor: pointer;
990
+ box-shadow: 0 8px 20px -10px rgba(22, 24, 26, 0.4);
991
+ animation: aiIn 0.2s ease-out;
992
+ }
993
+
994
+ /* ── rendered answer ──────────────────────────────────── */
995
+
996
+ .answer {
997
+ display: flex;
998
+ flex-direction: column;
999
+ gap: 14px;
1000
+ font-size: 14.5px;
1001
+ line-height: 1.7;
1002
+ }
1003
+
1004
+ .answer p {
1005
+ margin: 0;
1006
+ text-wrap: pretty;
1007
+ overflow-wrap: anywhere;
1008
+ }
1009
+
1010
+ .answer .raw {
1011
+ white-space: pre-wrap;
1012
+ }
1013
+
1014
+ .answer h3 {
1015
+ margin: 6px 0 0;
1016
+ font-size: 15.5px;
1017
+ font-weight: 600;
1018
+ letter-spacing: -0.01em;
1019
+ line-height: 1.4;
1020
+ }
1021
+
1022
+ .answer ul,
1023
+ .answer ol {
1024
+ margin: 0;
1025
+ padding-left: 20px;
1026
+ display: flex;
1027
+ flex-direction: column;
1028
+ gap: 6px;
1029
+ }
1030
+
1031
+ .answer li {
1032
+ line-height: 1.65;
1033
+ padding-left: 2px;
1034
+ }
1035
+
1036
+ .answer strong {
1037
+ font-weight: 600;
1038
+ }
1039
+
1040
+ .answer a {
1041
+ color: var(--c-ink);
1042
+ text-underline-offset: 3px;
1043
+ }
1044
+
1045
+ .answer code.inline {
1046
+ font-family: var(--c-mono);
1047
+ font-size: 12.5px;
1048
+ background: var(--c-hover);
1049
+ border-radius: calc(var(--c-r) * 0.75);
1050
+ padding: 1px 5px;
1051
+ }
1052
+
1053
+ .quote {
1054
+ font-size: 13.5px;
1055
+ line-height: 1.6;
1056
+ color: var(--c-ink2);
1057
+ background: var(--c-bg2);
1058
+ border: 1px solid var(--c-line);
1059
+ border-radius: var(--c-r2);
1060
+ padding: 10px 14px;
1061
+ }
1062
+
1063
+ .code {
1064
+ border: 1px solid var(--c-line);
1065
+ border-radius: var(--c-r2);
1066
+ overflow: hidden;
1067
+ background: var(--c-bg2);
1068
+ }
1069
+
1070
+ .code-head {
1071
+ display: flex;
1072
+ align-items: center;
1073
+ justify-content: space-between;
1074
+ padding: 7px 12px;
1075
+ border-bottom: 1px solid var(--c-line);
1076
+ }
1077
+
1078
+ .code-head .label {
1079
+ font-size: 11px;
1080
+ }
1081
+
1082
+ .text-btn {
1083
+ font-size: 12px;
1084
+ color: var(--c-muted);
1085
+ background: none;
1086
+ border: none;
1087
+ padding: 0;
1088
+ cursor: pointer;
1089
+ }
1090
+
1091
+ .text-btn:hover {
1092
+ color: var(--c-ink);
1093
+ }
1094
+
1095
+ .text-btn.underline {
1096
+ text-decoration: underline;
1097
+ text-underline-offset: 3px;
1098
+ }
1099
+
1100
+ .code pre {
1101
+ margin: 0;
1102
+ padding: 12px 14px;
1103
+ overflow-x: auto;
1104
+ font-family: var(--c-mono);
1105
+ font-size: 13px;
1106
+ line-height: 1.6;
1107
+ }
1108
+
1109
+ .table {
1110
+ border: 1px solid var(--c-line);
1111
+ border-radius: var(--c-r2);
1112
+ overflow-x: auto;
1113
+ }
1114
+
1115
+ .table table {
1116
+ width: 100%;
1117
+ border-collapse: collapse;
1118
+ font-size: 13px;
1119
+ font-variant-numeric: tabular-nums;
1120
+ }
1121
+
1122
+ .table th {
1123
+ text-align: left;
1124
+ font-size: 12px;
1125
+ font-weight: 500;
1126
+ color: var(--c-muted);
1127
+ background: var(--c-bg2);
1128
+ border-bottom: 1px solid var(--c-line);
1129
+ padding: 9px 12px;
1130
+ white-space: nowrap;
1131
+ }
1132
+
1133
+ .table td {
1134
+ padding: 9px 12px;
1135
+ border-top: 1px solid var(--c-line2);
1136
+ white-space: nowrap;
1137
+ }
1138
+
1139
+ .table th:first-child,
1140
+ .table td:first-child {
1141
+ min-width: 120px;
1142
+ }
1143
+
1144
+ .cite {
1145
+ display: inline-flex;
1146
+ align-items: center;
1147
+ justify-content: center;
1148
+ min-width: 17px;
1149
+ height: 17px;
1150
+ padding: 0 4px;
1151
+ margin: 0 1px 0 3px;
1152
+ vertical-align: 2px;
1153
+ font: 500 10px var(--c-mono);
1154
+ border-radius: calc(var(--c-r) * 0.75);
1155
+ cursor: pointer;
1156
+ border: 1px solid var(--c-strong);
1157
+ background: var(--c-hover);
1158
+ color: var(--c-ink);
1159
+ }
1160
+
1161
+ .cite:hover,
1162
+ .cite.active {
1163
+ background: var(--c-ink);
1164
+ color: var(--c-bg);
1165
+ border-color: var(--c-ink);
1166
+ }
1167
+
1168
+ .chart {
1169
+ margin: 0;
1170
+ display: flex;
1171
+ flex-direction: column;
1172
+ gap: 14px;
1173
+ border: 1px solid var(--c-line);
1174
+ border-radius: var(--c-r2);
1175
+ padding: 14px 16px 12px;
1176
+ background: var(--c-bg);
1177
+ }
1178
+
1179
+ .chart-head {
1180
+ display: flex;
1181
+ flex-wrap: wrap;
1182
+ align-items: baseline;
1183
+ justify-content: space-between;
1184
+ gap: 8px 16px;
1185
+ }
1186
+
1187
+ .chart-title {
1188
+ font-size: 13px;
1189
+ font-weight: 600;
1190
+ }
1191
+
1192
+ .legend {
1193
+ display: flex;
1194
+ flex-wrap: wrap;
1195
+ gap: 4px 12px;
1196
+ }
1197
+
1198
+ .legend span {
1199
+ display: inline-flex;
1200
+ align-items: center;
1201
+ gap: 6px;
1202
+ font-size: 12px;
1203
+ color: var(--c-ink2);
1204
+ }
1205
+
1206
+ .swatch {
1207
+ width: 8px;
1208
+ height: 8px;
1209
+ border-radius: 2px;
1210
+ }
1211
+
1212
+ .bars {
1213
+ display: flex;
1214
+ flex-direction: column;
1215
+ gap: 10px;
1216
+ }
1217
+
1218
+ .bar-row {
1219
+ display: grid;
1220
+ grid-template-columns: 92px minmax(0, 1fr) 64px;
1221
+ align-items: center;
1222
+ gap: 12px;
1223
+ }
1224
+
1225
+ .bar-label {
1226
+ font-size: 12.5px;
1227
+ color: var(--c-ink2);
1228
+ overflow: hidden;
1229
+ text-overflow: ellipsis;
1230
+ white-space: nowrap;
1231
+ }
1232
+
1233
+ .bar-track {
1234
+ display: flex;
1235
+ height: 12px;
1236
+ background: var(--c-hover);
1237
+ border-radius: 2px;
1238
+ overflow: hidden;
1239
+ }
1240
+
1241
+ .bar-fill {
1242
+ display: flex;
1243
+ height: 100%;
1244
+ transform-origin: left;
1245
+ animation: aiGrow 0.8s cubic-bezier(0.2, 0.8, 0.2, 1);
1246
+ }
1247
+
1248
+ .bar-value {
1249
+ font-family: var(--c-mono);
1250
+ font-size: 11.5px;
1251
+ text-align: right;
1252
+ font-variant-numeric: tabular-nums;
1253
+ }
1254
+
1255
+ .line-chart {
1256
+ display: flex;
1257
+ flex-direction: column;
1258
+ gap: 6px;
1259
+ padding-left: 48px;
1260
+ }
1261
+
1262
+ .plot {
1263
+ position: relative;
1264
+ height: 170px;
1265
+ }
1266
+
1267
+ .tick {
1268
+ position: absolute;
1269
+ left: 0;
1270
+ right: 0;
1271
+ border-top: 1px dashed var(--c-line2);
1272
+ }
1273
+
1274
+ .tick.base {
1275
+ border-top: 1px solid var(--c-strong);
1276
+ }
1277
+
1278
+ .tick span,
1279
+ .x-labels span {
1280
+ font-family: var(--c-mono);
1281
+ font-size: 10.5px;
1282
+ color: var(--c-faint);
1283
+ white-space: nowrap;
1284
+ font-variant-numeric: tabular-nums;
1285
+ }
1286
+
1287
+ .tick span {
1288
+ position: absolute;
1289
+ right: calc(100% + 8px);
1290
+ top: -7px;
1291
+ }
1292
+
1293
+ .plot svg {
1294
+ position: absolute;
1295
+ inset: 0;
1296
+ width: 100%;
1297
+ height: 100%;
1298
+ overflow: visible;
1299
+ }
1300
+
1301
+ .plot polyline {
1302
+ fill: none;
1303
+ stroke-width: 2;
1304
+ vector-effect: non-scaling-stroke;
1305
+ stroke-linejoin: round;
1306
+ stroke-linecap: round;
1307
+ stroke-dasharray: 1;
1308
+ animation: aiDraw 1s ease-out;
1309
+ }
1310
+
1311
+ .x-labels {
1312
+ display: flex;
1313
+ justify-content: space-between;
1314
+ gap: 4px;
1315
+ }
1316
+
1317
+ .chart-pending {
1318
+ display: flex;
1319
+ align-items: center;
1320
+ justify-content: center;
1321
+ height: 190px;
1322
+ border: 1px solid var(--c-line);
1323
+ border-radius: var(--c-r2);
1324
+ background: linear-gradient(90deg, var(--c-bg2) 0%, var(--c-hover) 50%, var(--c-bg2) 100%);
1325
+ background-size: 200% 100%;
1326
+ animation: aiShimmer 1.6s linear infinite;
1327
+ }
1328
+
1329
+ .gallery {
1330
+ display: grid;
1331
+ grid-template-columns: minmax(0, 1fr);
1332
+ gap: 10px;
1333
+ max-width: 520px;
1334
+ }
1335
+
1336
+ .gallery.many {
1337
+ grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
1338
+ max-width: 100%;
1339
+ }
1340
+
1341
+ .gallery figure {
1342
+ margin: 0;
1343
+ display: flex;
1344
+ flex-direction: column;
1345
+ gap: 6px;
1346
+ min-width: 0;
1347
+ }
1348
+
1349
+ .gallery img {
1350
+ width: 100%;
1351
+ aspect-ratio: 16 / 10;
1352
+ max-height: 320px;
1353
+ object-fit: contain;
1354
+ border-radius: var(--c-r2);
1355
+ border: 1px solid var(--c-line);
1356
+ background: var(--c-bg2);
1357
+ }
1358
+
1359
+ .img-missing {
1360
+ aspect-ratio: 16 / 9;
1361
+ display: flex;
1362
+ align-items: center;
1363
+ justify-content: center;
1364
+ border-radius: var(--c-r2);
1365
+ border: 1px dashed var(--c-strong);
1366
+ background: repeating-linear-gradient(135deg, var(--c-bg2) 0 10px, var(--c-hover) 10px 20px);
1367
+ }
1368
+
1369
+ figcaption {
1370
+ font-family: var(--c-mono);
1371
+ font-size: 11px;
1372
+ color: var(--c-muted);
1373
+ overflow: hidden;
1374
+ text-overflow: ellipsis;
1375
+ white-space: nowrap;
1376
+ }
1377
+
1378
+ .caret {
1379
+ display: inline-block;
1380
+ width: 7px;
1381
+ height: 15px;
1382
+ margin-top: -6px;
1383
+ background: var(--c-brand);
1384
+ animation: rgcaret 1s steps(1) infinite;
1385
+ }
1386
+
1387
+ /* ── sources ──────────────────────────────────────────── */
1388
+
1389
+ .retrieval {
1390
+ display: flex;
1391
+ flex-direction: column;
1392
+ border: 1px solid var(--c-line);
1393
+ border-radius: var(--c-r2);
1394
+ background: var(--c-bg2);
1395
+ }
1396
+
1397
+ .retrieval-toggle {
1398
+ display: flex;
1399
+ align-items: center;
1400
+ gap: 10px;
1401
+ width: 100%;
1402
+ text-align: left;
1403
+ font-size: 12.5px;
1404
+ color: var(--c-ink2);
1405
+ background: none;
1406
+ border: none;
1407
+ padding: 9px 12px;
1408
+ cursor: pointer;
1409
+ }
1410
+
1411
+ .retrieval-toggle .chev,
1412
+ .retrieval-toggle .ms {
1413
+ font-family: var(--c-mono);
1414
+ font-size: 11px;
1415
+ color: var(--c-muted);
1416
+ }
1417
+
1418
+ .retrieval-list {
1419
+ display: flex;
1420
+ flex-direction: column;
1421
+ border-top: 1px solid var(--c-line);
1422
+ padding: 4px 12px;
1423
+ }
1424
+
1425
+ .passage {
1426
+ display: grid;
1427
+ grid-template-columns: 22px minmax(0, 1fr) 64px;
1428
+ align-items: center;
1429
+ gap: 10px;
1430
+ width: 100%;
1431
+ text-align: left;
1432
+ background: none;
1433
+ border: none;
1434
+ border-bottom: 1px solid var(--c-line2);
1435
+ padding: 8px 0;
1436
+ cursor: pointer;
1437
+ }
1438
+
1439
+ .passage:last-child {
1440
+ border-bottom: none;
1441
+ }
1442
+
1443
+ .passage .n,
1444
+ .passage .score {
1445
+ font-family: var(--c-mono);
1446
+ font-size: 11px;
1447
+ color: var(--c-muted);
1448
+ font-variant-numeric: tabular-nums;
1449
+ }
1450
+
1451
+ .passage .what {
1452
+ display: flex;
1453
+ flex-direction: column;
1454
+ gap: 1px;
1455
+ min-width: 0;
1456
+ }
1457
+
1458
+ .passage .what span:first-child {
1459
+ font-size: 12.5px;
1460
+ overflow: hidden;
1461
+ text-overflow: ellipsis;
1462
+ white-space: nowrap;
1463
+ }
1464
+
1465
+ .passage .what span:last-child {
1466
+ font-size: 11.5px;
1467
+ color: var(--c-muted);
1468
+ }
1469
+
1470
+ .relevance {
1471
+ display: flex;
1472
+ flex-direction: column;
1473
+ gap: 3px;
1474
+ align-items: flex-end;
1475
+ }
1476
+
1477
+ .relevance-track {
1478
+ width: 64px;
1479
+ height: 3px;
1480
+ background: var(--c-line);
1481
+ border-radius: 99px;
1482
+ overflow: hidden;
1483
+ }
1484
+
1485
+ .relevance-fill {
1486
+ display: block;
1487
+ height: 100%;
1488
+ background: var(--c-brand);
1489
+ }
1490
+
1491
+ .cards {
1492
+ display: flex;
1493
+ flex-direction: column;
1494
+ gap: 8px;
1495
+ }
1496
+
1497
+ .card-grid {
1498
+ display: grid;
1499
+ grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
1500
+ gap: 8px;
1501
+ }
1502
+
1503
+ .source-card {
1504
+ display: flex;
1505
+ flex-direction: column;
1506
+ gap: 6px;
1507
+ min-width: 0;
1508
+ text-align: left;
1509
+ padding: 10px 12px;
1510
+ border-radius: var(--c-r2);
1511
+ cursor: pointer;
1512
+ background: var(--c-bg);
1513
+ border: 1px solid var(--c-line);
1514
+ }
1515
+
1516
+ .source-card:hover,
1517
+ .source-card.active {
1518
+ border-color: var(--c-ink);
1519
+ }
1520
+
1521
+ .source-card .top {
1522
+ display: flex;
1523
+ align-items: center;
1524
+ gap: 8px;
1525
+ min-width: 0;
1526
+ }
1527
+
1528
+ .num {
1529
+ min-width: 16px;
1530
+ height: 16px;
1531
+ padding: 0 4px;
1532
+ border-radius: calc(var(--c-r) * 0.75);
1533
+ border: 1px solid var(--c-strong);
1534
+ display: inline-flex;
1535
+ align-items: center;
1536
+ justify-content: center;
1537
+ font-family: var(--c-mono);
1538
+ font-size: 10px;
1539
+ background: var(--c-bg);
1540
+ }
1541
+
1542
+ .source-card .t {
1543
+ font-size: 13px;
1544
+ font-weight: 500;
1545
+ overflow: hidden;
1546
+ text-overflow: ellipsis;
1547
+ white-space: nowrap;
1548
+ }
1549
+
1550
+ .source-card .s {
1551
+ font-size: 12px;
1552
+ line-height: 1.45;
1553
+ color: var(--c-muted);
1554
+ display: -webkit-box;
1555
+ -webkit-line-clamp: 2;
1556
+ -webkit-box-orient: vertical;
1557
+ overflow: hidden;
1558
+ }
1559
+
1560
+ .panel {
1561
+ display: flex;
1562
+ flex-direction: column;
1563
+ min-height: 0;
1564
+ min-width: 0;
1565
+ background: var(--c-bg);
1566
+ border-left: 1px solid var(--c-line);
1567
+ animation: aiIn 0.15s ease-out;
1568
+ }
1569
+
1570
+ .panel.docked {
1571
+ position: relative;
1572
+ flex: 0 0 400px;
1573
+ width: 400px;
1574
+ }
1575
+
1576
+ .panel.overlay {
1577
+ position: absolute;
1578
+ right: 0;
1579
+ top: 0;
1580
+ bottom: 0;
1581
+ z-index: 30;
1582
+ width: min(420px, 100%);
1583
+ box-shadow: -12px 0 32px -16px rgba(22, 24, 26, 0.25);
1584
+ }
1585
+
1586
+ .panel-head {
1587
+ display: flex;
1588
+ align-items: center;
1589
+ justify-content: space-between;
1590
+ gap: 8px;
1591
+ padding: 14px 18px;
1592
+ border-bottom: 1px solid var(--c-line);
1593
+ }
1594
+
1595
+ .panel-body {
1596
+ flex: 1;
1597
+ min-height: 0;
1598
+ overflow-y: auto;
1599
+ display: flex;
1600
+ flex-direction: column;
1601
+ gap: 16px;
1602
+ padding: 18px;
1603
+ }
1604
+
1605
+ .panel-body h3 {
1606
+ margin: 0;
1607
+ font-size: 16px;
1608
+ font-weight: 600;
1609
+ letter-spacing: -0.01em;
1610
+ }
1611
+
1612
+ .panel-meta {
1613
+ display: flex;
1614
+ flex-direction: column;
1615
+ gap: 4px;
1616
+ }
1617
+
1618
+ .panel-meta .path {
1619
+ font-family: var(--c-mono);
1620
+ font-size: 11px;
1621
+ color: var(--c-muted);
1622
+ overflow-wrap: anywhere;
1623
+ }
1624
+
1625
+ .panel-meta .meta {
1626
+ font-size: 12px;
1627
+ color: var(--c-muted);
1628
+ }
1629
+
1630
+ .passage-box {
1631
+ display: flex;
1632
+ flex-direction: column;
1633
+ gap: 8px;
1634
+ padding: 12px 14px;
1635
+ border-radius: var(--c-r2);
1636
+ background: var(--c-hover);
1637
+ border: 1px solid var(--c-strong);
1638
+ }
1639
+
1640
+ .passage-box .text {
1641
+ font-size: 13px;
1642
+ line-height: 1.6;
1643
+ color: var(--c-ink2);
1644
+ white-space: pre-wrap;
1645
+ overflow-wrap: anywhere;
1646
+ }
1647
+
1648
+ .passage-foot {
1649
+ display: flex;
1650
+ align-items: center;
1651
+ justify-content: space-between;
1652
+ gap: 8px;
1653
+ padding-top: 8px;
1654
+ border-top: 1px solid var(--c-line);
1655
+ }
1656
+
1657
+ .copy-ref {
1658
+ display: inline-flex;
1659
+ align-items: center;
1660
+ gap: 6px;
1661
+ font-size: 12px;
1662
+ background: var(--c-bg);
1663
+ border: 1px solid var(--c-line);
1664
+ border-radius: var(--c-r);
1665
+ padding: 4px 8px;
1666
+ cursor: pointer;
1667
+ }
1668
+
1669
+ .copy-ref:hover {
1670
+ border-color: var(--c-strong);
1671
+ }
1672
+
1673
+ .panel-foot {
1674
+ display: flex;
1675
+ flex-direction: column;
1676
+ gap: 6px;
1677
+ padding: 12px 18px 16px;
1678
+ border-top: 1px solid var(--c-line);
1679
+ }
1680
+
1681
+ .chips {
1682
+ display: flex;
1683
+ flex-wrap: wrap;
1684
+ gap: 6px;
1685
+ }
1686
+
1687
+ .chip {
1688
+ font-size: 12px;
1689
+ background: var(--c-bg);
1690
+ border: 1px solid var(--c-line);
1691
+ border-radius: var(--c-r);
1692
+ padding: 4px 8px;
1693
+ cursor: pointer;
1694
+ max-width: 100%;
1695
+ overflow: hidden;
1696
+ text-overflow: ellipsis;
1697
+ white-space: nowrap;
1698
+ }
1699
+
1700
+ .chip:hover {
1701
+ border-color: var(--c-ink);
1702
+ }
1703
+
1704
+ /* ── composer ─────────────────────────────────────────── */
1705
+
1706
+ .composer-wrap {
1707
+ padding: 0 12px 12px;
1708
+ }
1709
+
1710
+ .composer-col {
1711
+ max-width: 760px;
1712
+ margin: 0 auto;
1713
+ display: flex;
1714
+ flex-direction: column;
1715
+ gap: 8px;
1716
+ }
1717
+
1718
+ .composer-box {
1719
+ position: relative;
1720
+ }
1721
+
1722
+ .composer {
1723
+ position: relative;
1724
+ z-index: 1;
1725
+ display: flex;
1726
+ flex-direction: column;
1727
+ gap: 4px;
1728
+ padding: 8px;
1729
+ border-radius: calc(var(--c-r) * 2.25);
1730
+ background: var(--c-bg);
1731
+ border: 1px solid var(--c-strong);
1732
+ box-shadow:
1733
+ 0 1px 2px rgba(22, 24, 26, 0.04),
1734
+ 0 12px 32px -18px rgba(22, 24, 26, 0.22);
1735
+ transition: border-color 0.15s;
1736
+ }
1737
+
1738
+ .composer:focus-within {
1739
+ border-color: var(--c-ink);
1740
+ }
1741
+
1742
+ .composer.busy {
1743
+ border-color: transparent;
1744
+ }
1745
+
1746
+ :host([glow="off"]) .composer.busy {
1747
+ border-color: var(--c-strong);
1748
+ }
1749
+
1750
+ .composer textarea {
1751
+ width: 100%;
1752
+ resize: none;
1753
+ font: inherit;
1754
+ font-size: 14.5px;
1755
+ line-height: 1.5;
1756
+ color: var(--c-ink);
1757
+ background: transparent;
1758
+ border: none;
1759
+ outline: none;
1760
+ padding: 6px 6px 2px;
1761
+ max-height: 176px;
1762
+ }
1763
+
1764
+ .composer textarea::placeholder {
1765
+ color: var(--c-faint);
1766
+ }
1767
+
1768
+ .composer-row {
1769
+ display: flex;
1770
+ align-items: center;
1771
+ justify-content: space-between;
1772
+ gap: 8px;
1773
+ }
1774
+
1775
+ .attach {
1776
+ display: inline-flex;
1777
+ align-items: center;
1778
+ gap: 6px;
1779
+ font-size: 12.5px;
1780
+ color: var(--c-muted);
1781
+ background: none;
1782
+ border: none;
1783
+ border-radius: var(--c-r);
1784
+ padding: 6px 8px;
1785
+ cursor: pointer;
1786
+ }
1787
+
1788
+ .attach:hover {
1789
+ background: var(--c-hover);
1790
+ color: var(--c-ink);
1791
+ }
1792
+
1793
+ .send {
1794
+ display: inline-flex;
1795
+ align-items: center;
1796
+ justify-content: center;
1797
+ width: 32px;
1798
+ height: 32px;
1799
+ padding: 0;
1800
+ border-radius: var(--c-r2);
1801
+ border: 1px solid var(--c-brand);
1802
+ cursor: pointer;
1803
+ background: var(--c-brand);
1804
+ color: var(--c-on-brand);
1805
+ transition: background 0.15s;
1806
+ }
1807
+
1808
+ .send:disabled {
1809
+ cursor: default;
1810
+ background: var(--c-line);
1811
+ border-color: var(--c-line);
1812
+ color: var(--c-faint);
1813
+ }
1814
+
1815
+ .send.stop {
1816
+ background: var(--c-bg);
1817
+ color: var(--c-ink);
1818
+ border-color: var(--c-ink);
1819
+ }
1820
+
1821
+ .send.stop svg {
1822
+ fill: currentColor;
1823
+ stroke: none;
1824
+ }
1825
+
1826
+ .pending-files {
1827
+ display: flex;
1828
+ flex-wrap: wrap;
1829
+ gap: 6px;
1830
+ padding: 2px 2px 4px;
1831
+ }
1832
+
1833
+ .pending-file {
1834
+ display: inline-flex;
1835
+ align-items: center;
1836
+ gap: 8px;
1837
+ padding: 4px 8px 4px 4px;
1838
+ font-size: 12.5px;
1839
+ border-radius: var(--c-r2);
1840
+ border: 1px solid var(--c-line);
1841
+ background: var(--c-bg2);
1842
+ animation: aiIn 0.2s ease-out;
1843
+ }
1844
+
1845
+ .pending-file .ext {
1846
+ width: 28px;
1847
+ height: 28px;
1848
+ display: inline-flex;
1849
+ align-items: center;
1850
+ justify-content: center;
1851
+ border-radius: var(--c-r);
1852
+ background: var(--c-bg);
1853
+ border: 1px solid var(--c-line);
1854
+ font-family: var(--c-mono);
1855
+ font-size: 9px;
1856
+ letter-spacing: 0.03em;
1857
+ color: var(--c-muted);
1858
+ }
1859
+
1860
+ .pending-file .meta {
1861
+ display: flex;
1862
+ flex-direction: column;
1863
+ gap: 1px;
1864
+ min-width: 0;
1865
+ }
1866
+
1867
+ .pending-file .name {
1868
+ max-width: 160px;
1869
+ overflow: hidden;
1870
+ text-overflow: ellipsis;
1871
+ white-space: nowrap;
1872
+ }
1873
+
1874
+ .pending-file .size {
1875
+ font-family: var(--c-mono);
1876
+ font-size: 10.5px;
1877
+ color: var(--c-muted);
1878
+ }
1879
+
1880
+ .pending-file button {
1881
+ font-size: 15px;
1882
+ line-height: 1;
1883
+ color: var(--c-muted);
1884
+ background: none;
1885
+ border: none;
1886
+ padding: 0 0 0 2px;
1887
+ cursor: pointer;
1888
+ }
1889
+
1890
+ .pending-file button:hover {
1891
+ color: var(--c-danger);
1892
+ }
1893
+
1894
+ .footnote,
1895
+ .branding {
1896
+ text-align: center;
1897
+ font-size: 11.5px;
1898
+ color: var(--c-muted);
1899
+ }
1900
+
1901
+ .branding {
1902
+ padding: 0 12px 10px;
1903
+ margin-top: -4px;
1904
+ }
1905
+
1906
+ .branding a {
1907
+ font-family: var(--c-mono);
1908
+ font-size: 10.5px;
1909
+ letter-spacing: 0.06em;
1910
+ text-transform: uppercase;
1911
+ color: var(--c-muted);
1912
+ text-decoration: none;
1913
+ }
1914
+
1915
+ .branding a:hover {
1916
+ color: var(--c-ink);
1917
+ }
1918
+
1919
+ .toast {
1920
+ position: absolute;
1921
+ left: 50%;
1922
+ bottom: 124px;
1923
+ transform: translateX(-50%);
1924
+ z-index: 35;
1925
+ display: flex;
1926
+ align-items: center;
1927
+ gap: 14px;
1928
+ padding: 9px 14px;
1929
+ background: var(--c-ink);
1930
+ color: var(--c-bg);
1931
+ font-size: 13px;
1932
+ border-radius: var(--c-r2);
1933
+ box-shadow: 0 12px 32px -12px rgba(22, 24, 26, 0.25);
1934
+ white-space: nowrap;
1935
+ animation: aiIn 0.2s ease-out;
1936
+ }
1937
+
1938
+ .toast button {
1939
+ font-size: 13px;
1940
+ font-weight: 500;
1941
+ color: var(--c-bg);
1942
+ background: none;
1943
+ border: none;
1944
+ padding: 0;
1945
+ cursor: pointer;
1946
+ text-decoration: underline;
1947
+ text-underline-offset: 3px;
1948
+ }
1949
+
1950
+ .drop {
1951
+ position: absolute;
1952
+ inset: 10px;
1953
+ z-index: 36;
1954
+ display: flex;
1955
+ flex-direction: column;
1956
+ align-items: center;
1957
+ justify-content: center;
1958
+ gap: 6px;
1959
+ text-align: center;
1960
+ padding: 16px;
1961
+ border: 1.5px dashed var(--c-ink);
1962
+ border-radius: var(--c-r3);
1963
+ background: color-mix(in srgb, var(--c-bg) 92%, transparent);
1964
+ }
1965
+
1966
+ .drop strong {
1967
+ font-size: 15px;
1968
+ font-weight: 600;
1969
+ }
1970
+
1971
+ .drop span {
1972
+ font-size: 12.5px;
1973
+ color: var(--c-muted);
1974
+ }
1975
+
1976
+ /* ── AI glow ──────────────────────────────────────────── */
1977
+
1978
+ .halo {
1979
+ position: absolute;
1980
+ inset: -18px -24px;
1981
+ z-index: 0;
1982
+ pointer-events: none;
1983
+ opacity: var(--c-glow);
1984
+ }
1985
+
1986
+ .halo::before {
1987
+ content: "";
1988
+ position: absolute;
1989
+ inset: 0;
1990
+ border-radius: 20px;
1991
+ background: var(--c-conic);
1992
+ filter: blur(32px);
1993
+ opacity: 0.45;
1994
+ animation:
1995
+ aiSpin 5s linear infinite,
1996
+ aiBreathe 2.6s ease-in-out infinite;
1997
+ }
1998
+
1999
+ .arrived {
2000
+ position: absolute;
2001
+ inset: -12px -16px;
2002
+ z-index: 0;
2003
+ pointer-events: none;
2004
+ border-radius: var(--c-r4);
2005
+ animation: aiDone 2.6s ease-out forwards;
2006
+ }
2007
+
2008
+ .arrived .wash {
2009
+ position: absolute;
2010
+ inset: 0;
2011
+ border-radius: inherit;
2012
+ background: var(--c-conic);
2013
+ filter: blur(26px);
2014
+ opacity: calc(0.22 * var(--c-glow) + 0.06);
2015
+ animation: aiSpin 2.6s linear infinite;
2016
+ }
2017
+
2018
+ .ring {
2019
+ position: absolute;
2020
+ inset: 0;
2021
+ border-radius: inherit;
2022
+ padding: 1px;
2023
+ background: var(--c-conic);
2024
+ -webkit-mask:
2025
+ linear-gradient(#000 0 0) content-box,
2026
+ linear-gradient(#000 0 0);
2027
+ -webkit-mask-composite: xor;
2028
+ mask-composite: exclude;
2029
+ animation: aiSpin 2.6s linear infinite;
2030
+ pointer-events: none;
2031
+ }
2032
+
2033
+ .arrived .sweep {
2034
+ position: absolute;
2035
+ inset: 0;
2036
+ border-radius: inherit;
2037
+ overflow: hidden;
2038
+ }
2039
+
2040
+ .arrived .sweep::before {
2041
+ content: "";
2042
+ position: absolute;
2043
+ inset: 0;
2044
+ background: linear-gradient(
2045
+ 100deg,
2046
+ transparent 25%,
2047
+ oklch(0.88 0.07 260 / 0.5) 50%,
2048
+ transparent 75%
2049
+ );
2050
+ animation: aiSweep 1.6s cubic-bezier(0.3, 0.6, 0.3, 1) forwards;
2051
+ }
2052
+
2053
+ .pill {
2054
+ position: relative;
2055
+ display: inline-flex;
2056
+ align-self: flex-start;
2057
+ align-items: center;
2058
+ gap: 9px;
2059
+ padding: 6px 14px 6px 10px;
2060
+ border-radius: 999px;
2061
+ background: var(--c-bg);
2062
+ box-shadow: 0 0 24px -6px oklch(0.7 0.15 280 / 0.5);
2063
+ animation: aiIn 0.25s ease-out;
2064
+ }
2065
+
2066
+ .pill .ring {
2067
+ border-radius: 999px;
2068
+ animation-duration: 2.4s;
2069
+ }
2070
+
2071
+ .pill .dot {
2072
+ width: 9px;
2073
+ height: 9px;
2074
+ border-radius: 50%;
2075
+ background: var(--c-conic);
2076
+ animation:
2077
+ aiSpin 1.6s linear infinite,
2078
+ aiPulse 1.6s ease-in-out infinite;
2079
+ }
2080
+
2081
+ .pill .shimmer {
2082
+ font-size: 12.5px;
2083
+ font-weight: 500;
2084
+ background: linear-gradient(90deg, var(--c-faint) 0%, var(--c-ink) 45%, var(--c-faint) 90%);
2085
+ background-size: 200% 100%;
2086
+ -webkit-background-clip: text;
2087
+ background-clip: text;
2088
+ color: transparent;
2089
+ animation: aiShimmer 1.8s linear infinite;
2090
+ }
2091
+
2092
+ .composer-glow {
2093
+ position: absolute;
2094
+ inset: -4px;
2095
+ z-index: 0;
2096
+ border-radius: var(--c-r4);
2097
+ background: var(--c-conic);
2098
+ filter: blur(14px);
2099
+ opacity: calc(0.32 + 0.23 * (var(--c-glow) - 0.6) / 0.4);
2100
+ animation: aiSpin 4s linear infinite;
2101
+ pointer-events: none;
2102
+ }
2103
+
2104
+ .composer-ring {
2105
+ position: absolute;
2106
+ inset: 0;
2107
+ z-index: 2;
2108
+ border-radius: calc(var(--c-r) * 2.25);
2109
+ pointer-events: none;
2110
+ }
2111
+
2112
+ .composer-ring .ring {
2113
+ animation-duration: 3s;
2114
+ }
2115
+
2116
+ :host([glow="off"]) .halo,
2117
+ :host([glow="off"]) .arrived,
2118
+ :host([glow="off"]) .composer-glow,
2119
+ :host([glow="off"]) .composer-ring,
2120
+ :host([glow="off"]) .pill .ring {
2121
+ display: none;
2122
+ }
2123
+
2124
+ :host([glow="off"]) .pill {
2125
+ box-shadow: inset 0 0 0 1px var(--c-line);
2126
+ }
2127
+
2128
+ :host([glow="off"]) .pill .dot {
2129
+ background: var(--c-ink);
2130
+ }
2131
+
2132
+ @keyframes aiSpin {
2133
+ to {
2134
+ --sb-ai-angle: 360deg;
2135
+ }
2136
+ }
2137
+
2138
+ @keyframes aiShimmer {
2139
+ from {
2140
+ background-position: 200% 0;
2141
+ }
2142
+ to {
2143
+ background-position: -200% 0;
2144
+ }
2145
+ }
2146
+
2147
+ @keyframes aiBreathe {
2148
+ 0%,
2149
+ 100% {
2150
+ transform: scale(0.97);
2151
+ }
2152
+ 50% {
2153
+ transform: scale(1.03);
2154
+ }
2155
+ }
2156
+
2157
+ @keyframes aiPulse {
2158
+ 0%,
2159
+ 100% {
2160
+ transform: scale(0.8);
2161
+ }
2162
+ 50% {
2163
+ transform: scale(1.15);
2164
+ }
2165
+ }
2166
+
2167
+ @keyframes aiDone {
2168
+ 0% {
2169
+ opacity: 0;
2170
+ }
2171
+ 12% {
2172
+ opacity: 1;
2173
+ }
2174
+ 100% {
2175
+ opacity: 0;
2176
+ }
2177
+ }
2178
+
2179
+ @keyframes aiSweep {
2180
+ from {
2181
+ transform: translateX(-100%);
2182
+ }
2183
+ to {
2184
+ transform: translateX(100%);
2185
+ }
2186
+ }
2187
+
2188
+ @keyframes aiIn {
2189
+ from {
2190
+ opacity: 0;
2191
+ transform: translateY(4px);
2192
+ }
2193
+ to {
2194
+ opacity: 1;
2195
+ transform: none;
2196
+ }
2197
+ }
2198
+
2199
+ @keyframes scaleIn {
2200
+ from {
2201
+ opacity: 0;
2202
+ transform: translateY(12px) scale(0.98);
2203
+ }
2204
+ to {
2205
+ opacity: 1;
2206
+ transform: none;
2207
+ }
2208
+ }
2209
+
2210
+ @keyframes slideIn {
2211
+ from {
2212
+ opacity: 0;
2213
+ transform: translateX(-8px);
2214
+ }
2215
+ to {
2216
+ opacity: 1;
2217
+ transform: none;
2218
+ }
2219
+ }
2220
+
2221
+ @keyframes aiGrow {
2222
+ from {
2223
+ transform: scaleX(0);
2224
+ }
2225
+ }
2226
+
2227
+ @keyframes aiDraw {
2228
+ from {
2229
+ stroke-dashoffset: 1;
2230
+ }
2231
+ to {
2232
+ stroke-dashoffset: 0;
2233
+ }
2234
+ }
2235
+
2236
+ @keyframes rgcaret {
2237
+ 0%,
2238
+ 100% {
2239
+ opacity: 1;
2240
+ }
2241
+ 50% {
2242
+ opacity: 0;
2243
+ }
2244
+ }
2245
+
2246
+ @media (prefers-reduced-motion: reduce) {
2247
+ *,
2248
+ *::before,
2249
+ *::after {
2250
+ animation-duration: 0.01ms !important;
2251
+ animation-iteration-count: 1 !important;
2252
+ }
2253
+ .caret {
2254
+ display: none;
2255
+ }
2256
+ }
2257
+
2258
+ @media print {
2259
+ .sidebar,
2260
+ .scrim,
2261
+ .header-right,
2262
+ .composer-wrap,
2263
+ .branding,
2264
+ .toolbar,
2265
+ .followups,
2266
+ .panel,
2267
+ .toast {
2268
+ display: none !important;
2269
+ }
2270
+ .frame,
2271
+ .scroller {
2272
+ overflow: visible;
2273
+ height: auto;
2274
+ }
2275
+ }
2276
+ `, $t = {
2277
+ eyebrowChat: "Chat",
2278
+ eyebrowRag: "Grounded answers",
2279
+ eyebrowRich: "Charts · tables · images",
2280
+ headingChat: "What can I help with?",
2281
+ headingRag: "Ask your knowledge base",
2282
+ headingRich: "Ask for a chart or a table",
2283
+ descriptionChat: "Ask anything. Attach text files to give it more context.",
2284
+ descriptionRag: "Answers are grounded in your sources, with a citation for every claim. Attach text files to search them too.",
2285
+ descriptionRich: "Answers come back with charts, tables and images when they help. Attach CSV or JSON files to use your own data.",
2286
+ placeholderChat: "Message {name}…",
2287
+ placeholderRag: "Ask about your sources…",
2288
+ placeholderRich: "Ask for a chart, table or breakdown…",
2289
+ footnote: "{name} can make mistakes. Check important details.",
2290
+ attach: "Attach files",
2291
+ send: "Send message",
2292
+ stop: "Stop generating",
2293
+ removeFile: "Remove file",
2294
+ dropTitle: "Drop files to attach",
2295
+ dropSub: "Text, Markdown, CSV and JSON files are added as context.",
2296
+ thinking: "Thinking",
2297
+ searching: "Searching sources",
2298
+ building: "Building charts and tables",
2299
+ chats: "Chats",
2300
+ newChat: "New chat",
2301
+ searchChats: "Search chats",
2302
+ groupBookmarked: "Bookmarked",
2303
+ groupToday: "Today",
2304
+ groupYesterday: "Yesterday",
2305
+ groupWeek: "Previous 7 days",
2306
+ groupOlder: "Older",
2307
+ noChats: "No chats yet.",
2308
+ noMatch: "No chats match “{query}”.",
2309
+ loadingChats: "Loading chats",
2310
+ showChats: "Show chats",
2311
+ hideSidebar: "Hide sidebar",
2312
+ untitled: "New chat",
2313
+ renameChat: "Rename chat",
2314
+ bookmarkChat: "Bookmark chat",
2315
+ unbookmarkChat: "Remove chat bookmark",
2316
+ exportChat: "Export chat",
2317
+ deleteChat: "Delete chat",
2318
+ expand: "Expand",
2319
+ restore: "Restore size",
2320
+ minimize: "Minimize chat",
2321
+ exportHeading: "Export this chat",
2322
+ exportMarkdown: "Markdown",
2323
+ exportJson: "JSON",
2324
+ exportText: "Plain text",
2325
+ exportCopy: "Copy as Markdown",
2326
+ copy: "Copy",
2327
+ copied: "Copied",
2328
+ edit: "Edit and resend",
2329
+ saveResend: "Save & resend",
2330
+ cancel: "Cancel",
2331
+ regenerate: "Regenerate",
2332
+ helpful: "Helpful",
2333
+ notHelpful: "Not helpful",
2334
+ markedHelpful: "Marked helpful",
2335
+ thanksFeedback: "Thanks for the feedback",
2336
+ bookmarkMessage: "Bookmark message",
2337
+ unbookmarkMessage: "Remove bookmark",
2338
+ deleteMessage: "Delete message",
2339
+ saved: "Saved",
2340
+ stopped: "Stopped",
2341
+ emptyReply: "(empty response)",
2342
+ newReply: "New reply",
2343
+ you: "You",
2344
+ sourcesCited: "Cited sources",
2345
+ sourcesRetrieved: "Sources",
2346
+ searchedSources: "Searched {n} sources",
2347
+ sourceLabel: "Source {n}",
2348
+ openSource: "Open source {n}",
2349
+ citedPassage: "Cited passage",
2350
+ copyReference: "Copy passage with reference",
2351
+ alsoCited: "Also cited",
2352
+ close: "Close",
2353
+ undo: "Undo",
2354
+ chatDeleted: "Chat deleted",
2355
+ messageDeleted: "Message deleted",
2356
+ messageBookmarked: "Message bookmarked",
2357
+ bookmarkRemoved: "Bookmark removed",
2358
+ chatBookmarked: "Chat bookmarked",
2359
+ chatUnbookmarked: "Chat removed from bookmarks",
2360
+ exported: "Exported {name}",
2361
+ copiedMarkdown: "Copied as Markdown",
2362
+ fileTooLarge: "{name} is larger than {size}.",
2363
+ fileType: "{name} isn't a text file.",
2364
+ tooManyFiles: "Attach up to {n} files at a time.",
2365
+ errGeneric: "Something went wrong.",
2366
+ errNotFound: "This chat no longer exists. Retry to start a new one.",
2367
+ errNoClient: "Chat isn't connected. Create a SinglebaseClient() on this page.",
2368
+ errLoad: "Couldn't load this chat.",
2369
+ retry: "Retry",
2370
+ offline: "You're offline. Messages will send when you reconnect.",
2371
+ bubbleText: "Hi! Questions? Ask me here.",
2372
+ openChat: "Open chat",
2373
+ closeChat: "Close chat",
2374
+ dismiss: "Dismiss",
2375
+ brandingLabel: "Chat by Singlebase"
2376
+ };
2377
+ function Tt(n) {
2378
+ return { ...$t, ...n ?? {} };
2379
+ }
2380
+ const Ct = /^\|.*\|$/, St = /^\|[\s:|-]+\|$/, Xe = /^!\[([^\]]*)\]\(([^)]*)\)$/, Ye = /^([-*]|\d+\.)\s+/;
2381
+ function zt(n) {
2382
+ const e = [], t = (n ?? "").replace(/\r/g, "").split("```");
2383
+ return t.forEach((i, s) => {
2384
+ if (s % 2 === 1) {
2385
+ const a = i.indexOf(`
2386
+ `), o = (a > -1 ? i.slice(0, a) : i).trim().toLowerCase(), l = (a > -1 ? i.slice(a + 1) : "").replace(/\n$/, ""), c = s === t.length - 1;
2387
+ if (o === "chart") {
2388
+ const x = c ? null : Ot(l);
2389
+ e.push(x ? { type: "chart", spec: x } : { type: "chartPending" });
2390
+ } else
2391
+ e.push({ type: "code", lang: o || "code", text: l });
2392
+ return;
2393
+ }
2394
+ for (const a of i.split(/\n{2,}/)) {
2395
+ const o = a.trim();
2396
+ o && e.push(...pt(o));
2397
+ }
2398
+ }), e;
2399
+ }
2400
+ function pt(n) {
2401
+ const e = n.split(`
2402
+ `).map((i) => i.trim()).filter(Boolean);
2403
+ if (e.length > 1 && e.every((i) => Ct.test(i))) {
2404
+ const i = e.filter((s) => !St.test(s)).map(
2405
+ (s) => s.replace(/^\||\|$/g, "").split("|").map((a) => a.trim())
2406
+ );
2407
+ return [{ type: "table", head: i[0] ?? [], rows: i.slice(1) }];
2408
+ }
2409
+ if (e.every((i) => Xe.test(i)))
2410
+ return [
2411
+ {
2412
+ type: "img",
2413
+ images: e.map((i) => {
2414
+ const s = i.match(Xe);
2415
+ return { alt: s[1], src: s[2] };
2416
+ })
2417
+ }
2418
+ ];
2419
+ if (e.every((i) => i.startsWith(">")))
2420
+ return [{ type: "quote", text: e.map((i) => i.replace(/^>\s?/, "")).join(" ") }];
2421
+ if (e.every((i) => Ye.test(i)))
2422
+ return [
2423
+ {
2424
+ type: "list",
2425
+ ordered: /^\d+\./.test(e[0]),
2426
+ items: e.map((i) => i.replace(Ye, ""))
2427
+ }
2428
+ ];
2429
+ const t = e[0].match(/^(#{1,4})\s+(.*)$/);
2430
+ if (t) {
2431
+ const i = e.slice(1).join(`
2432
+ `);
2433
+ return [
2434
+ { type: "h", level: t[1].length, text: t[2] },
2435
+ ...i ? pt(i) : []
2436
+ ];
2437
+ }
2438
+ return [{ type: "p", text: e.join(" ") }];
2439
+ }
2440
+ function Ot(n) {
2441
+ let e;
2442
+ try {
2443
+ e = JSON.parse(n);
2444
+ } catch {
2445
+ return null;
2446
+ }
2447
+ if (!e || typeof e != "object") return null;
2448
+ const t = (Array.isArray(e.series) ? e.series : []).filter((s) => s && Array.isArray(s.values)).map((s, a) => ({
2449
+ name: String(s.name ?? `Series ${a + 1}`),
2450
+ values: s.values.map((o) => Number(o) || 0)
2451
+ }));
2452
+ if (!t.length) return null;
2453
+ const i = Array.isArray(e.labels) ? e.labels.map(String) : t[0].values.map((s, a) => String(a + 1));
2454
+ return {
2455
+ type: e.type === "line" ? "line" : "bar",
2456
+ title: String(e.title ?? ""),
2457
+ unit: String(e.unit ?? ""),
2458
+ labels: i,
2459
+ series: t
2460
+ };
2461
+ }
2462
+ const Qe = /\*\*([^*]+)\*\*|`([^`]+)`|\[([^\]]+)\]\((https?:\/\/[^)\s]+)\)|\s?\[(\d+(?:\s*,\s*\d+)*)\]/g;
2463
+ function Mt(n, e = 0) {
2464
+ const t = [];
2465
+ let i = 0, s;
2466
+ Qe.lastIndex = 0;
2467
+ const a = (o) => {
2468
+ if (!o) return;
2469
+ const l = t[t.length - 1];
2470
+ (l == null ? void 0 : l.type) === "text" ? l.text += o : t.push({ type: "text", text: o });
2471
+ };
2472
+ for (; s = Qe.exec(n); ) {
2473
+ if (a(n.slice(i, s.index)), s[1] !== void 0) t.push({ type: "bold", text: s[1] });
2474
+ else if (s[2] !== void 0) t.push({ type: "code", text: s[2] });
2475
+ else if (s[3] !== void 0) t.push({ type: "link", text: s[3], href: s[4] });
2476
+ else {
2477
+ const l = s[5].split(",").map((c) => Number(c.trim())).filter((c) => c >= 1 && c <= e);
2478
+ e ? l.forEach((c) => t.push({ type: "cite", n: c })) : a(s[0]);
2479
+ }
2480
+ i = s.index + s[0].length;
2481
+ }
2482
+ return a(n.slice(i)), t;
2483
+ }
2484
+ function Ze(n) {
2485
+ const e = /* @__PURE__ */ new Set();
2486
+ for (const t of (n ?? "").match(/\[(\d+(?:\s*,\s*\d+)*)\]/g) ?? [])
2487
+ t.replace(/[[\]]/g, "").split(",").forEach((i) => e.add(Number(i.trim())));
2488
+ return e;
2489
+ }
2490
+ function et(n) {
2491
+ return {
2492
+ head: ["", ...n.series.map((e) => e.name)],
2493
+ rows: n.labels.map((e, t) => [
2494
+ e,
2495
+ ...n.series.map((i) => i.values[t] === void 0 ? "" : `${i.values[t]}${n.unit}`)
2496
+ ])
2497
+ };
2498
+ }
2499
+ const He = (n) => n.replace(/\*\*/g, "").replace(/`/g, "").replace(/\[([^\]]+)\]\((https?:\/\/[^)\s]+)\)/g, "$1");
2500
+ function _t(n, e) {
2501
+ if (e === "markdown")
2502
+ return n.flatMap((t) => {
2503
+ if (t.type === "chart") {
2504
+ const i = et(t.spec);
2505
+ return [
2506
+ ...t.spec.title ? [{ type: "p", text: `**${t.spec.title}**` }] : [],
2507
+ { type: "table", ...i }
2508
+ ];
2509
+ }
2510
+ return t.type === "img" ? t.images.map((i) => ({
2511
+ type: "p",
2512
+ text: `Image: ${i.alt || "untitled"}`
2513
+ })) : [t];
2514
+ });
2515
+ if (e === "text") {
2516
+ const t = n.map((i) => {
2517
+ switch (i.type) {
2518
+ case "chart": {
2519
+ const s = et(i.spec);
2520
+ return [i.spec.title, ...[s.head, ...s.rows].map((a) => a.join(" · "))].filter(Boolean).join(`
2521
+ `);
2522
+ }
2523
+ case "chartPending":
2524
+ return "";
2525
+ case "img":
2526
+ return i.images.map((s) => `Image: ${s.alt || "untitled"}`).join(`
2527
+ `);
2528
+ case "table":
2529
+ return [i.head, ...i.rows].map((s) => s.map(He).join(" · ")).join(`
2530
+ `);
2531
+ case "list":
2532
+ return i.items.map((s) => `- ${He(s)}`).join(`
2533
+ `);
2534
+ case "code":
2535
+ case "raw":
2536
+ return i.text;
2537
+ default:
2538
+ return He(i.text);
2539
+ }
2540
+ }).filter(Boolean).join(`
2541
+
2542
+ `);
2543
+ return t ? [{ type: "raw", text: t }] : [];
2544
+ }
2545
+ return n;
2546
+ }
2547
+ function tt(n) {
2548
+ const e = n ?? "", t = e.search(/FOLLOWUPS:/i);
2549
+ if (t < 0) return { text: e.trim(), followups: [] };
2550
+ const s = e.slice(t).replace(/^FOLLOWUPS:/i, "").split(/\||\n/).map((a) => a.replace(/^\s*(?:[-*↳→]|\d+[.)])\s*/, "").trim()).filter(Boolean).slice(0, 3);
2551
+ return { text: e.slice(0, t).trim(), followups: s };
2552
+ }
2553
+ function It(n) {
2554
+ return (n ?? "").replace(/```(\w*)[\s\S]*?(```|$)/g, (e, t) => t === "chart" ? "[Chart] " : "[Code] ").replace(/!\[([^\]]*)\]\([^)]*\)/g, "[Image: $1]").replace(/\[([^\]]+)\]\((https?:\/\/[^)\s]+)\)/g, "$1").replace(/[*#>`]/g, "").replace(/\|/g, " ").replace(/\s?\[\d+(?:\s*,\s*\d+)*\]/g, "").replace(/\s+/g, " ").trim();
2555
+ }
2556
+ function Lt(n, e = 48) {
2557
+ const t = It(n);
2558
+ if (t.length <= e) return t;
2559
+ const i = t.slice(0, e), s = i.lastIndexOf(" ");
2560
+ return (s > e / 2 ? i.slice(0, s) : i).trim();
2561
+ }
2562
+ function jt(n) {
2563
+ return String(n ?? "").split(`
2564
+ `)[0].trim().replace(/^["'“”‘’]+|["'“”‘’]+$/g, "").replace(/^title:\s*/i, "").replace(/[.!?:;,]+$/, "").trim().slice(0, 80);
2565
+ }
2566
+ function it(n, e = !1) {
2567
+ return /^https?:\/\//i.test(n) ? !0 : e && /^(blob:|data:image\/)/i.test(n);
2568
+ }
2569
+ var ht = Object.defineProperty, At = Object.getOwnPropertyDescriptor, Et = (n, e, t) => e in n ? ht(n, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : n[e] = t, g = (n, e, t, i) => {
2570
+ for (var s = i > 1 ? void 0 : i ? At(e, t) : e, a = n.length - 1, o; a >= 0; a--)
2571
+ (o = n[a]) && (s = (i ? o(e, t, s) : o(s)) || s);
2572
+ return i && s && ht(e, t, s), s;
2573
+ }, Nt = (n, e, t) => Et(n, e + "", t);
2574
+ const st = [
2575
+ "embed",
2576
+ "mode",
2577
+ "renderAs",
2578
+ "glow",
2579
+ "position",
2580
+ "sidebar",
2581
+ "showTitle",
2582
+ "assistantName",
2583
+ "logoUrl",
2584
+ "heading",
2585
+ "description",
2586
+ "prompts",
2587
+ "bubbleText",
2588
+ "greetingBubble",
2589
+ "unreadBadge",
2590
+ "allowUpload",
2591
+ "allowExport",
2592
+ "branding",
2593
+ "followups",
2594
+ "autoTitle",
2595
+ "model",
2596
+ "params",
2597
+ "systemMessage",
2598
+ "retrieval",
2599
+ "metadata",
2600
+ "messages",
2601
+ "theme"
2602
+ ], We = {
2603
+ fromAttribute: (n) => {
2604
+ if (n)
2605
+ try {
2606
+ return JSON.parse(n);
2607
+ } catch {
2608
+ console.warn("[singlebase-chat] an attribute holds invalid JSON; ignoring it");
2609
+ return;
2610
+ }
2611
+ },
2612
+ toAttribute: (n) => JSON.stringify(n ?? null)
2613
+ }, I = {
2614
+ fromAttribute: (n) => n === null ? !0 : n !== "false",
2615
+ toAttribute: (n) => n ? null : "false"
2616
+ }, Bt = {
2617
+ fromAttribute: (n) => n === null ? void 0 : n !== "false",
2618
+ toAttribute: (n) => n === void 0 ? null : String(n)
2619
+ }, Dt = 272, Rt = 820, Ut = 940, at = 5, rt = 512 * 1024, Ft = /\.(md|markdown|txt|csv|tsv|json|html?|ya?ml|xml|log)$/i, Kt = 5e3, Pt = 2600, _ = [
2620
+ "var(--c-ink)",
2621
+ "oklch(0.58 0.13 255)",
2622
+ "oklch(0.63 0.1 175)",
2623
+ "oklch(0.74 0.12 70)"
2624
+ ], nt = {
2625
+ chat: "Be helpful and concise. Use Markdown when it helps: headings, lists, **bold**, code blocks and tables.",
2626
+ rag: "Answer ONLY from the sources provided with each message, numbered in the order given. Put a citation like [1] right after each claim it supports. If the sources don't cover the question, say so plainly.",
2627
+ rich: 'Lead with one sentence stating the key finding, with key numbers in **bold**. For trends and comparisons, include a chart as a fenced code block with the language "chart" containing only JSON: {"type":"bar"|"line","title":string,"unit":string,"labels":[string],"series":[{"name":string,"values":[number]}]}. Use Markdown tables for exact values. Keep prose short.'
2628
+ }, Ht = "After the answer, on a final line write FOLLOWUPS: followed by three short follow-up questions the user might ask next, separated by |.", ot = {
2629
+ chat: [
2630
+ ["Write", "Draft a short welcome email for new users"],
2631
+ ["Explain", "Explain how refresh tokens work, simply"],
2632
+ ["Code", "Write a JavaScript debounce function"],
2633
+ ["Plan", "Outline a one-week plan to learn TypeScript"]
2634
+ ],
2635
+ rag: [
2636
+ ["Overview", "What topics do these sources cover?"],
2637
+ ["Summarize", "Summarize the most important points"],
2638
+ ["Find", "Where is the refund policy described?"],
2639
+ ["Explain", "Explain the setup steps in plain language"]
2640
+ ],
2641
+ rich: [
2642
+ ["Bar chart", "Compare the five most spoken languages in a bar chart"],
2643
+ ["Line chart", "Show world population from 1950 to 2020"],
2644
+ ["Table", "List the planets with their diameters in a table"],
2645
+ ["Breakdown", "Break down a $4,000 monthly budget by category"]
2646
+ ]
2647
+ }, C = (n, e = "") => r`<svg class="i ${e}" viewBox="0 0 16 16" aria-hidden="true">${n}</svg>`, y = {
2648
+ sidebar: () => C(
2649
+ $`<rect x="2" y="2.5" width="12" height="11" rx="1.5"></rect><path d="M6 2.5v11"></path>`
2650
+ ),
2651
+ plus: () => C($`<path d="M8 3v10M3 8h10"></path>`),
2652
+ bookmark: (n = !1) => C($`<path d="M4.5 2.5h7v11L8 11l-3.5 2.5z"></path>`, n ? "filled" : ""),
2653
+ download: () => C($`<path d="M8 2.5v8M4.5 7.5L8 11l3.5-3.5M2.5 13.5h11"></path>`),
2654
+ trash: () => C($`<path d="M2.5 4.5h11M6.5 4.5v-2h3v2M4 4.5l.7 9h6.6l.7-9"></path>`),
2655
+ pencil: () => C($`<path d="M10.5 2.5l3 3L6 13H3v-3z"></path>`),
2656
+ copy: () => C(
2657
+ $`<rect x="5.5" y="5.5" width="8" height="8" rx="1.5"></rect><path d="M10.5 5.5v-2a1 1 0 0 0-1-1h-6a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h2"></path>`
2658
+ ),
2659
+ refresh: () => C($`<path d="M13.5 8A5.5 5.5 0 1 1 11.9 4.1M13.5 2v3.5H10"></path>`),
2660
+ thumb: (n = !1) => r`<svg
2661
+ class="i"
2662
+ viewBox="0 0 16 16"
2663
+ aria-hidden="true"
2664
+ style=${n ? "transform:rotate(180deg)" : ""}
2665
+ >
2666
+ <path
2667
+ d="M5 7v6.5H2.5V7zM5 7l2.5-4.5a1.3 1.3 0 0 1 1.9 1.4L9 6.5h3.6a1 1 0 0 1 1 1.2l-1 4.8a1 1 0 0 1-1 .8H5"
2668
+ ></path>
2669
+ </svg>`,
2670
+ expand: () => C($`<path d="M9.5 2.5h4v4M13.5 2.5L9 7M6.5 13.5h-4v-4M2.5 13.5L7 9"></path>`),
2671
+ restore: () => C($`<path d="M13.5 6.5h-4v-4M9.5 6.5l4-4M2.5 9.5h4v4M6.5 9.5l-4 4"></path>`),
2672
+ minimize: () => C($`<path d="M4 8h8"></path>`),
2673
+ close: () => C($`<path d="M4 4l8 8M12 4l-8 8"></path>`),
2674
+ clip: () => C(
2675
+ $`<path d="M13 7.5l-5.3 5.3a3 3 0 0 1-4.3-4.3L9 2.9a2 2 0 0 1 2.9 2.9L6.4 11.3a1 1 0 0 1-1.4-1.4L10 5"></path>`
2676
+ ),
2677
+ up: () => C($`<path d="M8 13V3M3.5 7.5L8 3l4.5 4.5"></path>`),
2678
+ stop: () => C($`<rect x="4.5" y="4.5" width="7" height="7" rx="1"></rect>`),
2679
+ chat: () => r`<svg
2680
+ width="22"
2681
+ height="22"
2682
+ viewBox="0 0 22 22"
2683
+ aria-hidden="true"
2684
+ style="fill:none;stroke:currentColor;stroke-width:1.6;stroke-linecap:round;stroke-linejoin:round"
2685
+ >
2686
+ <path
2687
+ d="M4 5.5A2.5 2.5 0 0 1 6.5 3h9A2.5 2.5 0 0 1 18 5.5v7a2.5 2.5 0 0 1-2.5 2.5H9l-4 3.5V15H6.5"
2688
+ ></path>
2689
+ </svg>`,
2690
+ chevronDown: () => r`<svg
2691
+ width="20"
2692
+ height="20"
2693
+ viewBox="0 0 20 20"
2694
+ aria-hidden="true"
2695
+ style="fill:none;stroke:currentColor;stroke-width:1.6;stroke-linecap:round"
2696
+ >
2697
+ <path d="M5 8l5 5 5-5"></path>
2698
+ </svg>`
2699
+ };
2700
+ let Jt = 0;
2701
+ const Je = () => `m${Date.now().toString(36)}${(Jt++).toString(36)}`;
2702
+ function lt(n) {
2703
+ var t;
2704
+ const e = n;
2705
+ return (e == null ? void 0 : e.message) === "NOT_FOUND" || (e == null ? void 0 : e.code) === "NOT_FOUND" || ((t = e == null ? void 0 : e.details) == null ? void 0 : t.status) === 404;
2706
+ }
2707
+ function Wt(n) {
2708
+ const e = n;
2709
+ return (e == null ? void 0 : e.code) || (e == null ? void 0 : e.message) || "UNKNOWN";
2710
+ }
2711
+ const qt = () => typeof matchMedia < "u" && matchMedia("(prefers-reduced-motion: reduce)").matches, Fe = (n, e) => (Number.isInteger(n) ? n.toLocaleString("en-US") : n.toFixed(1)) + e, ct = (n) => {
2712
+ const e = n.lastIndexOf(".");
2713
+ return e > 0 ? n.slice(e + 1, e + 5).toUpperCase() : "FILE";
2714
+ };
2715
+ function Ke(n, e) {
2716
+ const t = n ?? {}, i = t.metadata && typeof t.metadata == "object" ? t.metadata : {}, s = (...l) => l.find((c) => typeof c == "string" && c.trim()), a = s(t.content, t.text, t.page_content, t.body, t.snippet, t.chunk, i.content) ?? JSON.stringify(t, null, 2), o = [t.score, t.relevance, t._score, i.score].find((l) => typeof l == "number");
2717
+ return {
2718
+ n: e,
2719
+ title: s(t.title, t.name, t.filename, i.title, i.name) ?? `Source ${e}`,
2720
+ path: s(t.path, t.url, t.key, t.source, i.path, i.url) ?? "",
2721
+ collection: s(t.collection, t.namespace, t.dbname, i.collection) ?? "",
2722
+ updated: s(t.updated, t._modified_at, i.updated) ?? "",
2723
+ text: a,
2724
+ score: o === void 0 ? null : Math.max(0, Math.min(1, o))
2725
+ };
2726
+ }
2727
+ function Gt(n) {
2728
+ const e = [], t = [];
2729
+ for (const i of n)
2730
+ if (/\.csv$/i.test(i.name)) e.push({ type: "csv", data: i.content });
2731
+ else if (/\.json$/i.test(i.name))
2732
+ try {
2733
+ e.push({ type: "json", data: JSON.parse(i.content) });
2734
+ } catch {
2735
+ t.push({ title: i.name, content: i.content });
2736
+ }
2737
+ else t.push({ title: i.name, content: i.content });
2738
+ return t.length && e.push({ type: "docs", payload: { documents: t } }), e;
2739
+ }
2740
+ function Pe(n) {
2741
+ const e = n ? Date.parse(n) : NaN;
2742
+ if (Number.isNaN(e)) return "older";
2743
+ const t = /* @__PURE__ */ new Date();
2744
+ t.setHours(0, 0, 0, 0);
2745
+ const i = 864e5;
2746
+ return e >= t.getTime() ? "today" : e >= t.getTime() - i ? "yesterday" : e >= t.getTime() - 7 * i ? "week" : "older";
2747
+ }
2748
+ var j, A, E, N, B, D, R, U, F, K, P, H, J, W, q, G, V, X, Y, Q, Z, ee, te, ie, se, ae, re, ne, oe, le, ce, de, pe, he, ue, ge, me, be, fe, xe, ve, ye, ke, we, $e, Te, Ce, Se, ze, Oe, Me, _e, Ie, Le, je, Ae, Ee, Ne, Be, De, Re, dt;
2749
+ let d = (dt = class extends ft {
2750
+ constructor() {
2751
+ super(...arguments);
2752
+ h(this, j, null);
2753
+ h(this, A, {});
2754
+ h(this, E);
2755
+ h(this, N, "chat");
2756
+ h(this, B, "rich");
2757
+ h(this, D, "subtle");
2758
+ h(this, R, !0);
2759
+ h(this, U, !0);
2760
+ h(this, F, "");
2761
+ h(this, K, {});
2762
+ h(this, P, "");
2763
+ h(this, H, []);
2764
+ h(this, J, {});
2765
+ h(this, W, "page");
2766
+ h(this, q, "right");
2767
+ h(this, G);
2768
+ h(this, V, !0);
2769
+ h(this, X, "");
2770
+ h(this, Y, "Assistant");
2771
+ h(this, Q, "");
2772
+ h(this, Z, "");
2773
+ h(this, ee, "");
2774
+ h(this, te, "");
2775
+ h(this, ie, "");
2776
+ h(this, se, !1);
2777
+ h(this, ae, !1);
2778
+ h(this, re, !0);
2779
+ h(this, ne, !0);
2780
+ h(this, oe, !0);
2781
+ h(this, le, []);
2782
+ h(this, ce, "idle");
2783
+ h(this, de, null);
2784
+ h(this, pe, "");
2785
+ h(this, he, !1);
2786
+ h(this, ue, []);
2787
+ h(this, ge, !1);
2788
+ h(this, me, "");
2789
+ h(this, be, !1);
2790
+ h(this, fe, "");
2791
+ h(this, xe, []);
2792
+ h(this, ve, "");
2793
+ h(this, ye, null);
2794
+ h(this, ke, 0);
2795
+ h(this, we, null);
2796
+ h(this, $e, !1);
2797
+ h(this, Te, "");
2798
+ h(this, Ce, "");
2799
+ h(this, Se, !1);
2800
+ h(this, ze, "");
2801
+ h(this, Oe, null);
2802
+ h(this, Me, "");
2803
+ h(this, _e, /* @__PURE__ */ new Set());
2804
+ h(this, Ie, "");
2805
+ h(this, Le, !1);
2806
+ h(this, je, !1);
2807
+ h(this, Ae, !1);
2808
+ h(this, Ee, !1);
2809
+ h(this, Ne, !1);
2810
+ h(this, Be, !1);
2811
+ h(this, De, !1);
2812
+ h(this, Re, !1);
2813
+ T(this, "run", 0);
2814
+ T(this, "abort", null);
2815
+ T(this, "revealTimer");
2816
+ T(this, "timers", /* @__PURE__ */ new Set());
2817
+ T(this, "toastTimer");
2818
+ T(this, "stick", !0);
2819
+ T(this, "renamed", /* @__PURE__ */ new Set());
2820
+ T(this, "observer", null);
2821
+ T(this, "observed", null);
2822
+ T(this, "media", null);
2823
+ T(this, "focusNext", "");
2824
+ T(this, "bubbleScheduled", !1);
2825
+ T(this, "onNetwork", () => {
2826
+ this.offline = navigator.onLine === !1;
2827
+ });
2828
+ T(this, "onMedia", () => {
2829
+ var e;
2830
+ this.mobile = !!((e = this.media) != null && e.matches);
2831
+ });
2832
+ }
2833
+ get client() {
2834
+ return p(this, j);
2835
+ }
2836
+ set client(e) {
2837
+ u(this, j, e);
2838
+ }
2839
+ get messages() {
2840
+ return p(this, A);
2841
+ }
2842
+ set messages(e) {
2843
+ u(this, A, e);
2844
+ }
2845
+ get theme() {
2846
+ return p(this, E);
2847
+ }
2848
+ set theme(e) {
2849
+ u(this, E, e);
2850
+ }
2851
+ get mode() {
2852
+ return p(this, N);
2853
+ }
2854
+ set mode(e) {
2855
+ u(this, N, e);
2856
+ }
2857
+ get renderAs() {
2858
+ return p(this, B);
2859
+ }
2860
+ set renderAs(e) {
2861
+ u(this, B, e);
2862
+ }
2863
+ get glow() {
2864
+ return p(this, D);
2865
+ }
2866
+ set glow(e) {
2867
+ u(this, D, e);
2868
+ }
2869
+ get followups() {
2870
+ return p(this, R);
2871
+ }
2872
+ set followups(e) {
2873
+ u(this, R, e);
2874
+ }
2875
+ get autoTitle() {
2876
+ return p(this, U);
2877
+ }
2878
+ set autoTitle(e) {
2879
+ u(this, U, e);
2880
+ }
2881
+ get model() {
2882
+ return p(this, F);
2883
+ }
2884
+ set model(e) {
2885
+ u(this, F, e);
2886
+ }
2887
+ get params() {
2888
+ return p(this, K);
2889
+ }
2890
+ set params(e) {
2891
+ u(this, K, e);
2892
+ }
2893
+ get systemMessage() {
2894
+ return p(this, P);
2895
+ }
2896
+ set systemMessage(e) {
2897
+ u(this, P, e);
2898
+ }
2899
+ get retrieval() {
2900
+ return p(this, H);
2901
+ }
2902
+ set retrieval(e) {
2903
+ u(this, H, e);
2904
+ }
2905
+ get metadata() {
2906
+ return p(this, J);
2907
+ }
2908
+ set metadata(e) {
2909
+ u(this, J, e);
2910
+ }
2911
+ get embed() {
2912
+ return p(this, W);
2913
+ }
2914
+ set embed(e) {
2915
+ u(this, W, e);
2916
+ }
2917
+ get position() {
2918
+ return p(this, q);
2919
+ }
2920
+ set position(e) {
2921
+ u(this, q, e);
2922
+ }
2923
+ get sidebar() {
2924
+ return p(this, G);
2925
+ }
2926
+ set sidebar(e) {
2927
+ u(this, G, e);
2928
+ }
2929
+ get showTitle() {
2930
+ return p(this, V);
2931
+ }
2932
+ set showTitle(e) {
2933
+ u(this, V, e);
2934
+ }
2935
+ get chatIdAttr() {
2936
+ return p(this, X);
2937
+ }
2938
+ set chatIdAttr(e) {
2939
+ u(this, X, e);
2940
+ }
2941
+ get assistantName() {
2942
+ return p(this, Y);
2943
+ }
2944
+ set assistantName(e) {
2945
+ u(this, Y, e);
2946
+ }
2947
+ get logoUrl() {
2948
+ return p(this, Q);
2949
+ }
2950
+ set logoUrl(e) {
2951
+ u(this, Q, e);
2952
+ }
2953
+ get heading() {
2954
+ return p(this, Z);
2955
+ }
2956
+ set heading(e) {
2957
+ u(this, Z, e);
2958
+ }
2959
+ get description() {
2960
+ return p(this, ee);
2961
+ }
2962
+ set description(e) {
2963
+ u(this, ee, e);
2964
+ }
2965
+ get prompts() {
2966
+ return p(this, te);
2967
+ }
2968
+ set prompts(e) {
2969
+ u(this, te, e);
2970
+ }
2971
+ get bubbleText() {
2972
+ return p(this, ie);
2973
+ }
2974
+ set bubbleText(e) {
2975
+ u(this, ie, e);
2976
+ }
2977
+ get greetingBubble() {
2978
+ return p(this, se);
2979
+ }
2980
+ set greetingBubble(e) {
2981
+ u(this, se, e);
2982
+ }
2983
+ get unreadBadge() {
2984
+ return p(this, ae);
2985
+ }
2986
+ set unreadBadge(e) {
2987
+ u(this, ae, e);
2988
+ }
2989
+ get allowUpload() {
2990
+ return p(this, re);
2991
+ }
2992
+ set allowUpload(e) {
2993
+ u(this, re, e);
2994
+ }
2995
+ get allowExport() {
2996
+ return p(this, ne);
2997
+ }
2998
+ set allowExport(e) {
2999
+ u(this, ne, e);
3000
+ }
3001
+ get branding() {
3002
+ return p(this, oe);
3003
+ }
3004
+ set branding(e) {
3005
+ u(this, oe, e);
3006
+ }
3007
+ get chatList() {
3008
+ return p(this, le);
3009
+ }
3010
+ set chatList(e) {
3011
+ u(this, le, e);
3012
+ }
3013
+ get listState() {
3014
+ return p(this, ce);
3015
+ }
3016
+ set listState(e) {
3017
+ u(this, ce, e);
3018
+ }
3019
+ get activeId() {
3020
+ return p(this, de);
3021
+ }
3022
+ set activeId(e) {
3023
+ u(this, de, e);
3024
+ }
3025
+ get chatTitle() {
3026
+ return p(this, pe);
3027
+ }
3028
+ set chatTitle(e) {
3029
+ u(this, pe, e);
3030
+ }
3031
+ get bookmarked() {
3032
+ return p(this, he);
3033
+ }
3034
+ set bookmarked(e) {
3035
+ u(this, he, e);
3036
+ }
3037
+ get msgs() {
3038
+ return p(this, ue);
3039
+ }
3040
+ set msgs(e) {
3041
+ u(this, ue, e);
3042
+ }
3043
+ get loadingThread() {
3044
+ return p(this, ge);
3045
+ }
3046
+ set loadingThread(e) {
3047
+ u(this, ge, e);
3048
+ }
3049
+ get threadError() {
3050
+ return p(this, me);
3051
+ }
3052
+ set threadError(e) {
3053
+ u(this, me, e);
3054
+ }
3055
+ get busy() {
3056
+ return p(this, be);
3057
+ }
3058
+ set busy(e) {
3059
+ u(this, be, e);
3060
+ }
3061
+ get draft() {
3062
+ return p(this, fe);
3063
+ }
3064
+ set draft(e) {
3065
+ u(this, fe, e);
3066
+ }
3067
+ get files() {
3068
+ return p(this, xe);
3069
+ }
3070
+ set files(e) {
3071
+ u(this, xe, e);
3072
+ }
3073
+ get search() {
3074
+ return p(this, ve);
3075
+ }
3076
+ set search(e) {
3077
+ u(this, ve, e);
3078
+ }
3079
+ get sidebarOpen() {
3080
+ return p(this, ye);
3081
+ }
3082
+ set sidebarOpen(e) {
3083
+ u(this, ye, e);
3084
+ }
3085
+ get width() {
3086
+ return p(this, ke);
3087
+ }
3088
+ set width(e) {
3089
+ u(this, ke, e);
3090
+ }
3091
+ get panel() {
3092
+ return p(this, we);
3093
+ }
3094
+ set panel(e) {
3095
+ u(this, we, e);
3096
+ }
3097
+ get menuOpen() {
3098
+ return p(this, $e);
3099
+ }
3100
+ set menuOpen(e) {
3101
+ u(this, $e, e);
3102
+ }
3103
+ get editingKey() {
3104
+ return p(this, Te);
3105
+ }
3106
+ set editingKey(e) {
3107
+ u(this, Te, e);
3108
+ }
3109
+ get editDraft() {
3110
+ return p(this, Ce);
3111
+ }
3112
+ set editDraft(e) {
3113
+ u(this, Ce, e);
3114
+ }
3115
+ get editingTitle() {
3116
+ return p(this, Se);
3117
+ }
3118
+ set editingTitle(e) {
3119
+ u(this, Se, e);
3120
+ }
3121
+ get renamingId() {
3122
+ return p(this, ze);
3123
+ }
3124
+ set renamingId(e) {
3125
+ u(this, ze, e);
3126
+ }
3127
+ get toast() {
3128
+ return p(this, Oe);
3129
+ }
3130
+ set toast(e) {
3131
+ u(this, Oe, e);
3132
+ }
3133
+ get copiedKey() {
3134
+ return p(this, Me);
3135
+ }
3136
+ set copiedKey(e) {
3137
+ u(this, Me, e);
3138
+ }
3139
+ get retrievalOpen() {
3140
+ return p(this, _e);
3141
+ }
3142
+ set retrievalOpen(e) {
3143
+ u(this, _e, e);
3144
+ }
3145
+ get arrivedKey() {
3146
+ return p(this, Ie);
3147
+ }
3148
+ set arrivedKey(e) {
3149
+ u(this, Ie, e);
3150
+ }
3151
+ get dragging() {
3152
+ return p(this, Le);
3153
+ }
3154
+ set dragging(e) {
3155
+ u(this, Le, e);
3156
+ }
3157
+ get showJump() {
3158
+ return p(this, je);
3159
+ }
3160
+ set showJump(e) {
3161
+ u(this, je, e);
3162
+ }
3163
+ get offline() {
3164
+ return p(this, Ae);
3165
+ }
3166
+ set offline(e) {
3167
+ u(this, Ae, e);
3168
+ }
3169
+ get isOpen() {
3170
+ return p(this, Ee);
3171
+ }
3172
+ set isOpen(e) {
3173
+ u(this, Ee, e);
3174
+ }
3175
+ get expanded() {
3176
+ return p(this, Ne);
3177
+ }
3178
+ set expanded(e) {
3179
+ u(this, Ne, e);
3180
+ }
3181
+ get bubble() {
3182
+ return p(this, Be);
3183
+ }
3184
+ set bubble(e) {
3185
+ u(this, Be, e);
3186
+ }
3187
+ get seen() {
3188
+ return p(this, De);
3189
+ }
3190
+ set seen(e) {
3191
+ u(this, De, e);
3192
+ }
3193
+ get mobile() {
3194
+ return p(this, Re);
3195
+ }
3196
+ set mobile(e) {
3197
+ u(this, Re, e);
3198
+ }
3199
+ get msg() {
3200
+ return Tt(this.messages);
3201
+ }
3202
+ /** An explicit `.client`, else the page default. */
3203
+ get resolvedClient() {
3204
+ return this.client ?? yt() ?? null;
3205
+ }
3206
+ /** The open conversation's id, or null for a new chat. */
3207
+ get chatId() {
3208
+ return this.activeId;
3209
+ }
3210
+ /** The open conversation's messages. */
3211
+ get thread() {
3212
+ return this.msgs;
3213
+ }
3214
+ /** The loaded chat list. */
3215
+ get chats() {
3216
+ return this.chatList;
3217
+ }
3218
+ set config(e) {
3219
+ const t = this;
3220
+ for (const i of st)
3221
+ e && i in e && (t[i] = e[i]);
3222
+ }
3223
+ get config() {
3224
+ const e = this;
3225
+ return Object.fromEntries(st.map((t) => [t, e[t]]));
3226
+ }
3227
+ // ── lifecycle ─────────────────────────────────────────────
3228
+ connectedCallback() {
3229
+ var e, t;
3230
+ super.connectedCallback(), this.offline = typeof navigator < "u" && navigator.onLine === !1, window.addEventListener("online", this.onNetwork), window.addEventListener("offline", this.onNetwork), this.media = typeof matchMedia < "u" ? matchMedia("(max-width: 559px)") : null, this.mobile = !!((e = this.media) != null && e.matches), (t = this.media) == null || t.addEventListener("change", this.onMedia);
3231
+ }
3232
+ disconnectedCallback() {
3233
+ var e, t;
3234
+ super.disconnectedCallback(), window.removeEventListener("online", this.onNetwork), window.removeEventListener("offline", this.onNetwork), (e = this.media) == null || e.removeEventListener("change", this.onMedia), (t = this.observer) == null || t.disconnect(), this.observer = null, this.observed = null, this.flushToast(), this.halt(), this.timers.forEach(clearTimeout), this.timers.clear();
3235
+ }
3236
+ willUpdate(e) {
3237
+ if (e.has("retrieval") && !Array.isArray(this.retrieval)) {
3238
+ const t = this.retrieval;
3239
+ this.retrieval = t && typeof t == "object" ? [t] : [];
3240
+ }
3241
+ e.has("params") && (!this.params || typeof this.params != "object") && (this.params = {}), e.has("metadata") && (!this.metadata || typeof this.metadata != "object") && (this.metadata = {}), e.has("sidebar") && this.sidebar !== void 0 && (this.sidebarOpen = this.sidebar), this.embed === "launcher" && this.greetingBubble && !this.bubbleScheduled && (this.bubbleScheduled = !0, this.later(() => {
3242
+ !this.isOpen && !this.seen && (this.bubble = !0);
3243
+ }, 1200));
3244
+ }
3245
+ firstUpdated() {
3246
+ this.chatIdAttr && this.openChat(this.chatIdAttr);
3247
+ }
3248
+ updated() {
3249
+ var t;
3250
+ const e = this.renderRoot.querySelector(".root");
3251
+ if (e !== this.observed && ((t = this.observer) == null || t.disconnect(), this.observed = e, e && typeof ResizeObserver < "u" && (this.observer ?? (this.observer = new ResizeObserver(([i]) => {
3252
+ const s = Math.round(i.contentRect.width);
3253
+ s !== this.width && (this.width = s, this.sidebarOpen === null && (this.sidebarOpen = this.sidebar ?? this.docked));
3254
+ })), this.observer.observe(e))), this.sidebarOpen && this.listState === "idle" && this.resolvedClient && this.loadChats(), this.focusNext) {
3255
+ const i = this.renderRoot.querySelector(
3256
+ this.focusNext
3257
+ );
3258
+ this.focusNext = "", i && (i.focus(), "select" in i && i.tagName === "INPUT" && i.select());
3259
+ }
3260
+ }
3261
+ later(e, t) {
3262
+ const i = setTimeout(() => {
3263
+ this.timers.delete(i), e();
3264
+ }, t);
3265
+ this.timers.add(i);
3266
+ }
3267
+ emit(e, t) {
3268
+ this.dispatchEvent(new CustomEvent(e, { detail: t, bubbles: !0, composed: !0 }));
3269
+ }
3270
+ get docked() {
3271
+ return this.embed === "page" && this.width >= Rt;
3272
+ }
3273
+ get panelDocked() {
3274
+ const e = this.docked && this.sidebarOpen ? Dt : 0;
3275
+ return this.width - e >= Ut;
3276
+ }
3277
+ // ── public API ────────────────────────────────────────────
3278
+ /** Starts a new, empty conversation. */
3279
+ newChat() {
3280
+ this.halt(), this.activeId = null, this.chatTitle = "", this.bookmarked = !1, this.msgs = [], this.threadError = "", this.resetViewState(), this.focusNext = "textarea.input";
3281
+ }
3282
+ /** Opens a saved conversation. */
3283
+ async openChat(e) {
3284
+ const t = this.resolvedClient;
3285
+ if (!e) return;
3286
+ this.halt();
3287
+ const i = this.chatList.find((a) => a._id === e);
3288
+ if (this.activeId = e, this.chatTitle = (i == null ? void 0 : i.title) ?? "", this.bookmarked = !!(i != null && i.bookmarked), this.msgs = [], this.threadError = "", this.resetViewState(), !t) {
3289
+ this.threadError = this.msg.errNoClient;
3290
+ return;
3291
+ }
3292
+ const s = ++this.run;
3293
+ this.loadingThread = !0;
3294
+ try {
3295
+ const a = await t.llm.call("get_chat", {
3296
+ _id: e
3297
+ });
3298
+ if (s !== this.run) return;
3299
+ this.chatTitle = (a == null ? void 0 : a.title) ?? "", this.bookmarked = !!(a != null && a.bookmarked), this.msgs = ((a == null ? void 0 : a.messages) ?? []).filter((o) => o && (o.role === "user" || o.role === "assistant")).map((o) => this.fromServer(o)), this.upsertChat({ ...i, ...a, _id: e }), this.stick = !0, this.scrollToBottom();
3300
+ } catch (a) {
3301
+ if (s !== this.run) return;
3302
+ lt(a) ? (this.chatList = this.chatList.filter((o) => o._id !== e), this.newChat(), this.showToast(this.msg.errNotFound)) : this.threadError = this.msg.errLoad;
3303
+ } finally {
3304
+ s === this.run && (this.loadingThread = !1);
3305
+ }
3306
+ }
3307
+ /** Sends a message; with no argument, sends the composer's text. */
3308
+ async send(e) {
3309
+ const t = (typeof e == "string" ? e : this.draft).trim();
3310
+ if (!t || this.busy) return;
3311
+ const i = this.files;
3312
+ this.draft = "", this.files = [];
3313
+ const s = this.renderRoot.querySelector("textarea.input");
3314
+ s && (s.style.height = "auto"), await this.runTurn(this.userMessage(t, i));
3315
+ }
3316
+ /** Stops waiting for, or revealing, the current reply. */
3317
+ stop() {
3318
+ if (!this.busy) return;
3319
+ const e = this.msgs[this.msgs.length - 1];
3320
+ this.halt(), (e == null ? void 0 : e.role) === "assistant" && (e.phase === "pending" || e.phase === "streaming") && (e.phase = "done", e.stopped = !0, e.followups = [], this.msgs = [...this.msgs]);
3321
+ }
3322
+ /** Downloads the open conversation, or copies it as Markdown. */
3323
+ exportChat(e = "md") {
3324
+ var M;
3325
+ if (!this.msgs.length) return;
3326
+ this.menuOpen = !1;
3327
+ const t = this.chatTitle || this.msg.untitled, i = (k) => k.role === "user" ? this.msg.you : this.assistantName, s = (k) => new Date(k || Date.now()).toLocaleString(), a = (k) => k.sources.map((L, ut) => {
3328
+ const Ue = Ke(L, ut + 1);
3329
+ return `[${Ue.n}] ${Ue.title}${Ue.path ? ` — ${Ue.path}` : ""}`;
3330
+ }), o = (k) => (k.attachments ?? []).map((L) => L.name);
3331
+ let l, c = "text/markdown", x = "md";
3332
+ if (e === "json" ? (l = JSON.stringify(
3333
+ {
3334
+ exportedAt: (/* @__PURE__ */ new Date()).toISOString(),
3335
+ id: this.activeId,
3336
+ title: t,
3337
+ mode: this.mode,
3338
+ bookmarked: this.bookmarked,
3339
+ messages: this.msgs.map((k) => ({
3340
+ role: k.role,
3341
+ text: k.content,
3342
+ at: new Date(k.at || Date.now()).toISOString(),
3343
+ bookmarked: k.bookmarked,
3344
+ attachments: o(k),
3345
+ sources: a(k)
3346
+ }))
3347
+ },
3348
+ null,
3349
+ 2
3350
+ ), c = "application/json", x = "json") : e === "txt" ? (l = `${t}
3351
+ ${"=".repeat(t.length)}
3352
+
3353
+ ` + this.msgs.map(
3354
+ (k) => [
3355
+ `${i(k)} · ${s(k.at)}`,
3356
+ o(k).length ? `Attachments: ${o(k).join(", ")}` : "",
3357
+ k.content,
3358
+ a(k).length ? `Sources:
3359
+ ${a(k).join(`
3360
+ `)}` : ""
3361
+ ].filter(Boolean).join(`
3362
+ `)
3363
+ ).join(`
3364
+
3365
+ `), c = "text/plain", x = "txt") : l = `# ${t}
3366
+
3367
+ ` + this.msgs.map(
3368
+ (k) => [
3369
+ `### ${i(k)} · ${s(k.at)}`,
3370
+ o(k).length ? `Attachments: ${o(k).join(", ")}` : "",
3371
+ k.content,
3372
+ a(k).length ? `**Sources**
3373
+
3374
+ ${a(k).map((L) => `- ${L}`).join(`
3375
+ `)}` : ""
3376
+ ].filter(Boolean).join(`
3377
+
3378
+ `)
3379
+ ).join(`
3380
+
3381
+ ---
3382
+
3383
+ `) + `
3384
+ `, this.emit("singlebase-chat-export", { chatId: this.activeId, format: e }), e === "copy") {
3385
+ (M = navigator.clipboard) == null || M.writeText(l).catch(() => {
3386
+ }), this.showToast(this.msg.copiedMarkdown);
3387
+ return;
3388
+ }
3389
+ const O = `${t.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "") || "chat"}-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}.${x}`, S = URL.createObjectURL(new Blob([l], { type: c })), b = document.createElement("a");
3390
+ b.href = S, b.download = O, document.body.appendChild(b), b.click(), b.remove(), setTimeout(() => URL.revokeObjectURL(S), 2e3), this.showToast(z(this.msg.exported, { name: O }));
3391
+ }
3392
+ /** Inline and launcher: fill the window. */
3393
+ expand() {
3394
+ this.expanded = !0, this.emit("singlebase-chat-expand", { expanded: !0 });
3395
+ }
3396
+ collapse() {
3397
+ this.expanded = !1, this.emit("singlebase-chat-expand", { expanded: !1 });
3398
+ }
3399
+ /** Launcher: open the panel. */
3400
+ open() {
3401
+ this.isOpen = !0, this.seen = !0, this.bubble = !1, this.focusNext = "textarea.input", this.emit("singlebase-chat-open", {});
3402
+ }
3403
+ /** Launcher: close the panel. */
3404
+ close() {
3405
+ this.isOpen = !1, this.expanded = !1, this.emit("singlebase-chat-close", {});
3406
+ }
3407
+ // ── turns ─────────────────────────────────────────────────
3408
+ userMessage(e, t = []) {
3409
+ return {
3410
+ key: Je(),
3411
+ id: null,
3412
+ role: "user",
3413
+ content: e,
3414
+ at: Date.now(),
3415
+ bookmarked: !1,
3416
+ sources: [],
3417
+ followups: [],
3418
+ phase: "done",
3419
+ attachments: t
3420
+ };
3421
+ }
3422
+ systemPrompt() {
3423
+ return [
3424
+ this.systemMessage,
3425
+ nt[this.mode] ?? nt.chat,
3426
+ this.followups ? Ht : ""
3427
+ ].filter(Boolean).join(`
3428
+
3429
+ `);
3430
+ }
3431
+ payloadFor(e) {
3432
+ const t = { message: e.content, format: "markdown" };
3433
+ this.activeId ? t._id = this.activeId : (t.title = Lt(e.content), t.system_message = this.systemPrompt()), this.model && (t.model = this.model), Object.keys(this.params ?? {}).length && (t.params = this.params);
3434
+ const i = (e.attachments ?? []).map((a) => a.name);
3435
+ (Object.keys(this.metadata ?? {}).length || i.length) && (t.metadata = { ...this.metadata, ...i.length ? { attachments: i } : {} });
3436
+ const s = [...this.retrieval ?? [], ...Gt(e.attachments ?? [])];
3437
+ return s.length && (t.retrieval = s), t;
3438
+ }
3439
+ async runTurn(e) {
3440
+ const t = {
3441
+ key: Je(),
3442
+ id: null,
3443
+ role: "assistant",
3444
+ content: "",
3445
+ at: Date.now(),
3446
+ bookmarked: !1,
3447
+ sources: [],
3448
+ followups: [],
3449
+ phase: "pending"
3450
+ };
3451
+ this.msgs = [...this.msgs, e, t], this.busy = !0, this.panel = null, this.stick = !0, this.scrollToBottom(), this.emit("singlebase-chat-send", { chatId: this.activeId, text: e.content });
3452
+ const i = this.resolvedClient;
3453
+ if (!i) {
3454
+ this.failTurn(t, this.msg.errNoClient, "NO_CLIENT"), this.busy = !1;
3455
+ return;
3456
+ }
3457
+ const s = ++this.run, a = new AbortController();
3458
+ this.abort = a;
3459
+ const o = !this.activeId, l = this.payloadFor(e);
3460
+ try {
3461
+ const c = await i.llm.call("chat", l, { signal: a.signal }), x = (c == null ? void 0 : c._id) || (c == null ? void 0 : c.chat_id) || this.activeId;
3462
+ if (o && x && this.upsertChat({
3463
+ _id: x,
3464
+ title: (c == null ? void 0 : c.title) || l.title,
3465
+ bookmarked: !!(c != null && c.bookmarked),
3466
+ _modified_at: (/* @__PURE__ */ new Date()).toISOString()
3467
+ }), s !== this.run) return;
3468
+ x && (this.activeId = x), o ? (this.chatTitle = (c == null ? void 0 : c.title) || l.title, this.bookmarked = !!(c != null && c.bookmarked)) : x && this.touchChat(x);
3469
+ const f = (c == null ? void 0 : c.message) ?? {}, O = typeof f.content == "string" ? f.content : (c == null ? void 0 : c.json) !== void 0 ? JSON.stringify(c.json, null, 2) : "", { text: S, followups: b } = tt(O);
3470
+ e.id = f.reply_to ?? null, Object.assign(t, {
3471
+ id: f._id ?? null,
3472
+ content: S,
3473
+ sources: Array.isArray(f.sources) ? f.sources : [],
3474
+ followups: this.followups ? b : [],
3475
+ execTime: typeof f.exec_time == "number" ? f.exec_time : void 0,
3476
+ model: f.model,
3477
+ at: Date.now()
3478
+ }), this.emit("singlebase-chat-response", { chatId: x, message: t }), await this.reveal(t, s), o && x && this.autoTitle && this.retitle(x, e.content, t.content);
3479
+ } catch (c) {
3480
+ if (s !== this.run) return;
3481
+ const x = lt(c);
3482
+ x && (this.chatList = this.chatList.filter((f) => f._id !== this.activeId), this.activeId = null), this.failTurn(t, x ? this.msg.errNotFound : this.msg.errGeneric, Wt(c));
3483
+ } finally {
3484
+ s === this.run && (this.busy = !1, this.abort = null, this.stick && this.scrollToBottom());
3485
+ }
3486
+ }
3487
+ failTurn(e, t, i) {
3488
+ e.phase = "error", e.error = t, this.msgs = [...this.msgs], this.emit("singlebase-chat-error", { chatId: this.activeId, code: i, message: t });
3489
+ }
3490
+ /**
3491
+ * The service answers in one piece; this reveals it progressively so it
3492
+ * reads like a stream. Capped at about a second and a half.
3493
+ */
3494
+ reveal(e, t) {
3495
+ const i = e.content.length, s = () => {
3496
+ e.phase = "done", this.msgs = [...this.msgs], this.arrivedKey = e.key, this.later(() => {
3497
+ this.arrivedKey === e.key && (this.arrivedKey = "");
3498
+ }, Pt), this.stick ? this.scrollToBottom() : this.showJump = !0;
3499
+ };
3500
+ if (!i || qt())
3501
+ return s(), Promise.resolve();
3502
+ const a = e.content, o = Math.max(4, Math.ceil(i / 90));
3503
+ let l = 0;
3504
+ return e.phase = "streaming", e.content = "", new Promise((c) => {
3505
+ this.revealTimer = setInterval(() => {
3506
+ if (t !== this.run) {
3507
+ clearInterval(this.revealTimer), c();
3508
+ return;
3509
+ }
3510
+ if (l = Math.min(i, l + o), e.content = a.slice(0, l), l >= i) {
3511
+ clearInterval(this.revealTimer), s(), c();
3512
+ return;
3513
+ }
3514
+ this.msgs = [...this.msgs], this.stick && this.scrollToBottom();
3515
+ }, 16);
3516
+ });
3517
+ }
3518
+ /** Cancels any request or reveal in flight. */
3519
+ halt() {
3520
+ var e;
3521
+ this.run++, (e = this.abort) == null || e.abort(), this.abort = null, clearInterval(this.revealTimer), this.busy = !1;
3522
+ }
3523
+ async retitle(e, t, i) {
3524
+ const s = this.resolvedClient;
3525
+ if (!(!s || this.renamed.has(e)))
3526
+ try {
3527
+ const a = await s.llm.call("generate", {
3528
+ user_input: `user: ${t}
3529
+ assistant: ${i.slice(0, 1500)}`,
3530
+ custom_instructions: "Write a concise title (3–6 words, sentence case, no quotes, no trailing punctuation) for this conversation.",
3531
+ format: "text"
3532
+ }), o = jt(a == null ? void 0 : a.result);
3533
+ if (!o || this.renamed.has(e)) return;
3534
+ await s.llm.call("update_chat", { _id: e, title: o }), this.applyTitle(e, o, !0);
3535
+ } catch {
3536
+ }
3537
+ }
3538
+ applyTitle(e, t, i) {
3539
+ this.chatList = this.chatList.map((s) => s._id === e ? { ...s, title: t } : s), this.activeId === e && (this.chatTitle = t), this.emit("singlebase-chat-title", { chatId: e, title: t, auto: i });
3540
+ }
3541
+ /**
3542
+ * Enter and blur both land here. Saving on Enter directly (not via blur())
3543
+ * matters: blur never fires on an input that doesn't have focus.
3544
+ */
3545
+ commitTitle(e) {
3546
+ this.editingTitle && (this.editingTitle = !1, this.activeId && this.renameChat(this.activeId, e));
3547
+ }
3548
+ commitRename(e, t) {
3549
+ this.renamingId === e && (this.renamingId = "", this.renameChat(e, t));
3550
+ }
3551
+ async renameChat(e, t) {
3552
+ var a, o;
3553
+ const i = t.trim().slice(0, 80), s = ((a = this.chatList.find((l) => l._id === e)) == null ? void 0 : a.title) ?? this.chatTitle;
3554
+ if (!(!i || i === s)) {
3555
+ this.renamed.add(e), this.applyTitle(e, i, !1);
3556
+ try {
3557
+ await ((o = this.resolvedClient) == null ? void 0 : o.llm.call("update_chat", { _id: e, title: i }));
3558
+ } catch {
3559
+ this.applyTitle(e, s ?? "", !1), this.showToast(this.msg.errGeneric);
3560
+ }
3561
+ }
3562
+ }
3563
+ fromServer(e) {
3564
+ const t = e.role === "assistant", { text: i, followups: s } = t ? tt(String(e.content ?? "")) : { text: String(e.content ?? ""), followups: [] };
3565
+ return {
3566
+ key: Je(),
3567
+ id: e._id ?? null,
3568
+ role: t ? "assistant" : "user",
3569
+ content: i,
3570
+ at: Date.parse(e._created_at ?? "") || 0,
3571
+ bookmarked: !!e.bookmarked,
3572
+ sources: Array.isArray(e.sources) ? e.sources : [],
3573
+ followups: this.followups ? s : [],
3574
+ phase: "done",
3575
+ execTime: typeof e.exec_time == "number" ? e.exec_time : void 0,
3576
+ model: e.model
3577
+ };
3578
+ }
3579
+ // ── chat list ─────────────────────────────────────────────
3580
+ async loadChats() {
3581
+ const e = this.resolvedClient;
3582
+ if (e) {
3583
+ this.listState = "loading";
3584
+ try {
3585
+ const t = await e.llm.call("list_chats", { limit: 100 });
3586
+ this.chatList = [...(t == null ? void 0 : t.items) ?? []], this.listState = "ready";
3587
+ } catch {
3588
+ this.listState = "error";
3589
+ }
3590
+ }
3591
+ }
3592
+ upsertChat(e) {
3593
+ const t = this.chatList.filter((s) => s._id !== e._id), i = this.chatList.find((s) => s._id === e._id);
3594
+ this.chatList = [{ ...i, ...e }, ...t];
3595
+ }
3596
+ touchChat(e) {
3597
+ const t = this.chatList.find((i) => i._id === e);
3598
+ t && this.upsertChat({ ...t, _modified_at: (/* @__PURE__ */ new Date()).toISOString() });
3599
+ }
3600
+ // ── actions ───────────────────────────────────────────────
3601
+ resetViewState() {
3602
+ this.panel = null, this.menuOpen = !1, this.editingKey = "", this.editingTitle = !1, this.showJump = !1, this.retrievalOpen = /* @__PURE__ */ new Set(), this.sidebarOpen && !this.docked && (this.sidebarOpen = !1);
3603
+ }
3604
+ async deleteOnServer(e) {
3605
+ const t = this.resolvedClient, i = this.activeId;
3606
+ if (!(!t || !i))
3607
+ for (const s of e)
3608
+ s && await t.llm.call("delete_chat_message", { _id: i, message_id: s }).catch(() => {
3609
+ });
3610
+ }
3611
+ async regenerate() {
3612
+ if (this.busy) return;
3613
+ const e = this.msgs.map((s) => s.role).lastIndexOf("assistant"), t = this.msgs[e - 1];
3614
+ if (e < 1 || (t == null ? void 0 : t.role) !== "user") return;
3615
+ const i = this.msgs.slice(e - 1);
3616
+ this.msgs = this.msgs.slice(0, e - 1), await this.deleteOnServer(i.map((s) => s.id)), await this.runTurn(this.userMessage(t.content, t.attachments));
3617
+ }
3618
+ async retry(e) {
3619
+ if (this.busy) return;
3620
+ const t = this.msgs.indexOf(e), i = this.msgs[t - 1];
3621
+ (i == null ? void 0 : i.role) === "user" && (this.msgs = this.msgs.slice(0, t - 1), await this.runTurn(this.userMessage(i.content, i.attachments)));
3622
+ }
3623
+ async saveEdit(e) {
3624
+ const t = this.editDraft.trim(), i = this.msgs.indexOf(e);
3625
+ if (this.editingKey = "", !t || i < 0 || this.busy) return;
3626
+ const s = this.msgs.slice(i);
3627
+ this.msgs = this.msgs.slice(0, i), await this.deleteOnServer(s.map((a) => a.id)), await this.runTurn(this.userMessage(t, e.attachments));
3628
+ }
3629
+ copy(e, t) {
3630
+ var i;
3631
+ (i = navigator.clipboard) == null || i.writeText(t).catch(() => {
3632
+ }), this.copiedKey = e, this.later(() => {
3633
+ this.copiedKey === e && (this.copiedKey = "");
3634
+ }, 1400);
3635
+ }
3636
+ async toggleMessageBookmark(e) {
3637
+ var i;
3638
+ const t = this.activeId;
3639
+ if (!(!t || !e.id)) {
3640
+ e.bookmarked = !e.bookmarked, this.msgs = [...this.msgs], this.showToast(e.bookmarked ? this.msg.messageBookmarked : this.msg.bookmarkRemoved), this.emit("singlebase-chat-bookmark", { chatId: t, messageId: e.id, bookmarked: e.bookmarked });
3641
+ try {
3642
+ await ((i = this.resolvedClient) == null ? void 0 : i.llm.call("bookmark_chat_message", {
3643
+ _id: t,
3644
+ message_id: e.id,
3645
+ bookmarked: e.bookmarked
3646
+ }));
3647
+ } catch {
3648
+ e.bookmarked = !e.bookmarked, this.msgs = [...this.msgs], this.showToast(this.msg.errGeneric);
3649
+ }
3650
+ }
3651
+ }
3652
+ async toggleChatBookmark(e) {
3653
+ var a, o;
3654
+ const t = ((a = this.chatList.find((l) => l._id === e)) == null ? void 0 : a.bookmarked) ?? (e === this.activeId ? this.bookmarked : !1), i = !t, s = (l) => {
3655
+ this.chatList = this.chatList.map(
3656
+ (c) => c._id === e ? { ...c, bookmarked: l } : c
3657
+ ), e === this.activeId && (this.bookmarked = l);
3658
+ };
3659
+ s(i), this.showToast(i ? this.msg.chatBookmarked : this.msg.chatUnbookmarked), this.emit("singlebase-chat-bookmark", { chatId: e, bookmarked: i });
3660
+ try {
3661
+ await ((o = this.resolvedClient) == null ? void 0 : o.llm.call("bookmark_chat", { _id: e, bookmarked: i }));
3662
+ } catch {
3663
+ s(t), this.showToast(this.msg.errGeneric);
3664
+ }
3665
+ }
3666
+ /** Removed at once; the server call waits out the undo window. */
3667
+ deleteMessage(e) {
3668
+ var s;
3669
+ const t = this.activeId, i = this.msgs.indexOf(e);
3670
+ i < 0 || (this.msgs = this.msgs.filter((a) => a !== e), ((s = this.panel) == null ? void 0 : s.key) === e.key && (this.panel = null), this.showToast(this.msg.messageDeleted, {
3671
+ undo: () => {
3672
+ if (this.activeId !== t) return;
3673
+ const a = [...this.msgs];
3674
+ a.splice(i, 0, e), this.msgs = a;
3675
+ },
3676
+ commit: () => {
3677
+ var a;
3678
+ this.emit("singlebase-chat-message-delete", { chatId: t, messageId: e.id }), t && e.id && ((a = this.resolvedClient) == null || a.llm.call("delete_chat_message", { _id: t, message_id: e.id }).catch(() => {
3679
+ }));
3680
+ }
3681
+ }));
3682
+ }
3683
+ deleteChat(e) {
3684
+ const t = this.chatList.findIndex((o) => o._id === e), i = this.chatList[t] ?? {
3685
+ _id: e,
3686
+ title: this.chatTitle,
3687
+ bookmarked: this.bookmarked
3688
+ }, s = e === this.activeId, a = s ? { title: this.chatTitle, bookmarked: this.bookmarked, msgs: this.msgs } : null;
3689
+ this.chatList = this.chatList.filter((o) => o._id !== e), s && this.newChat(), this.showToast(this.msg.chatDeleted, {
3690
+ undo: () => {
3691
+ const o = [...this.chatList];
3692
+ o.splice(Math.max(0, t), 0, i), this.chatList = o, a && !this.activeId && !this.msgs.length && (this.activeId = e, this.chatTitle = a.title, this.bookmarked = a.bookmarked, this.msgs = a.msgs);
3693
+ },
3694
+ commit: () => {
3695
+ var o;
3696
+ this.emit("singlebase-chat-delete", { chatId: e }), (o = this.resolvedClient) == null || o.llm.call("delete_chat", { _id: e }).catch(() => {
3697
+ });
3698
+ }
3699
+ });
3700
+ }
3701
+ feedback(e, t) {
3702
+ e.feedback = t, this.msgs = [...this.msgs], this.emit("singlebase-chat-feedback", {
3703
+ chatId: this.activeId,
3704
+ messageId: e.id,
3705
+ value: t,
3706
+ text: e.content
3707
+ });
3708
+ }
3709
+ // ── toasts ────────────────────────────────────────────────
3710
+ showToast(e, t = {}) {
3711
+ this.flushToast();
3712
+ const i = { key: Date.now(), text: e, ...t };
3713
+ this.toast = i, this.toastTimer = setTimeout(() => {
3714
+ this.toast === i && this.flushToast();
3715
+ }, Kt);
3716
+ }
3717
+ /** Ends the current toast, committing whatever it was holding back. */
3718
+ flushToast() {
3719
+ var t;
3720
+ const e = this.toast;
3721
+ clearTimeout(this.toastTimer), this.toast = null, (t = e == null ? void 0 : e.commit) == null || t.call(e);
3722
+ }
3723
+ undo() {
3724
+ var t;
3725
+ const e = this.toast;
3726
+ clearTimeout(this.toastTimer), this.toast = null, (t = e == null ? void 0 : e.undo) == null || t.call(e);
3727
+ }
3728
+ // ── files ─────────────────────────────────────────────────
3729
+ async addFiles(e) {
3730
+ const t = Array.from(e ?? []);
3731
+ if (!t.length) return;
3732
+ const i = [];
3733
+ for (const s of t) {
3734
+ if (this.files.length + i.length >= at) {
3735
+ this.showToast(z(this.msg.tooManyFiles, { n: at }));
3736
+ break;
3737
+ }
3738
+ if (!Ft.test(s.name) && !s.type.startsWith("text/")) {
3739
+ this.showToast(z(this.msg.fileType, { name: s.name }));
3740
+ continue;
3741
+ }
3742
+ if (s.size > rt) {
3743
+ this.showToast(
3744
+ z(this.msg.fileTooLarge, { name: s.name, size: Ve(rt) })
3745
+ );
3746
+ continue;
3747
+ }
3748
+ i.push({ name: s.name, size: s.size, content: await s.text() });
3749
+ }
3750
+ i.length && (this.files = [...this.files, ...i], this.emit("singlebase-chat-files", {
3751
+ files: i.map(({ name: s, size: a }) => ({ name: s, size: a }))
3752
+ }));
3753
+ }
3754
+ // ── scrolling ─────────────────────────────────────────────
3755
+ async scrollToBottom() {
3756
+ await this.updateComplete;
3757
+ const e = this.renderRoot.querySelector(".scroller");
3758
+ e && (e.scrollTop = e.scrollHeight), this.showJump = !1;
3759
+ }
3760
+ onScroll(e) {
3761
+ const t = e.currentTarget;
3762
+ this.stick = t.scrollHeight - t.scrollTop - t.clientHeight < 80, this.stick && (this.showJump = !1);
3763
+ }
3764
+ jumpToLatest() {
3765
+ this.stick = !0, this.scrollToBottom();
3766
+ }
3767
+ // ── keyboard ──────────────────────────────────────────────
3768
+ onKeydown(e) {
3769
+ if (e.key === "Escape") {
3770
+ if (this.menuOpen) this.menuOpen = !1;
3771
+ else if (this.panel) this.panel = null;
3772
+ else if (this.sidebarOpen && !this.docked) this.sidebarOpen = !1;
3773
+ else if (this.expanded) this.collapse();
3774
+ else if (this.embed === "launcher" && this.isOpen) this.close();
3775
+ else return;
3776
+ e.stopPropagation();
3777
+ }
3778
+ }
3779
+ onComposerKey(e) {
3780
+ e.key === "Enter" && !e.shiftKey && !e.isComposing && (e.preventDefault(), this.send());
3781
+ }
3782
+ onComposerInput(e) {
3783
+ const t = e.target;
3784
+ t.style.height = "auto", t.style.height = `${Math.min(176, t.scrollHeight)}px`, this.draft = t.value;
3785
+ }
3786
+ // ── drag and drop ─────────────────────────────────────────
3787
+ onDragEnter(e) {
3788
+ var t;
3789
+ !this.allowUpload || !Array.from(((t = e.dataTransfer) == null ? void 0 : t.types) ?? []).includes("Files") || (e.preventDefault(), this.dragging = !0);
3790
+ }
3791
+ onDragLeave(e) {
3792
+ e.currentTarget.contains(e.relatedTarget) || (this.dragging = !1);
3793
+ }
3794
+ onDrop(e) {
3795
+ var t;
3796
+ e.preventDefault(), this.dragging = !1, this.allowUpload && this.addFiles((t = e.dataTransfer) == null ? void 0 : t.files);
3797
+ }
3798
+ // ── render ────────────────────────────────────────────────
3799
+ render() {
3800
+ if (this.embed === "launcher") return this.renderLauncher();
3801
+ const e = [
3802
+ "frame",
3803
+ this.embed === "inline" ? "inline boxed" : "",
3804
+ this.expanded ? "expanded boxed" : ""
3805
+ ].join(" ");
3806
+ return r`<div class=${e} part="frame">${this.renderWorkspace()}</div>`;
3807
+ }
3808
+ renderLauncher() {
3809
+ const e = this.msg, t = [
3810
+ "frame launcher boxed",
3811
+ this.expanded ? "expanded" : "",
3812
+ this.mobile ? "full" : ""
3813
+ ].join(" "), i = this.isOpen ? r`<div class=${t} role="dialog" aria-label=${this.assistantName} part="frame">
3814
+ ${this.renderWorkspace()}
3815
+ </div>` : m, s = this.bubble && !this.isOpen ? r`<div class="bubble" part="bubble">
3816
+ <button type="button" class="bubble-text" @click=${() => this.open()}>
3817
+ ${this.bubbleText || e.bubbleText}
3818
+ </button>
3819
+ <button
3820
+ type="button"
3821
+ class="icon sm"
3822
+ aria-label=${e.dismiss}
3823
+ title=${e.dismiss}
3824
+ @click=${() => this.bubble = !1}
3825
+ >
3826
+ ${y.close()}
3827
+ </button>
3828
+ </div>` : m, o = this.isOpen && (this.expanded || this.mobile) ? m : r`<button
3829
+ type="button"
3830
+ class="launcher-btn"
3831
+ part="launcher"
3832
+ aria-label=${this.isOpen ? e.closeChat : e.openChat}
3833
+ aria-expanded=${this.isOpen ? "true" : "false"}
3834
+ @click=${() => this.isOpen ? this.close() : this.open()}
3835
+ >
3836
+ ${this.isOpen ? y.chevronDown() : y.chat()}
3837
+ ${this.unreadBadge && !this.seen && !this.isOpen ? r`<span class="badge"></span>` : m}
3838
+ </button>`;
3839
+ return r`${i}${s}${o}`;
3840
+ }
3841
+ renderWorkspace() {
3842
+ const e = !this.docked;
3843
+ return r`<div class="root" @keydown=${this.onKeydown}>
3844
+ ${this.sidebarOpen && e ? r`<div class="scrim" @click=${() => this.sidebarOpen = !1}></div>` : m}
3845
+ ${this.sidebarOpen ? this.renderSidebar(e) : m}
3846
+ <main
3847
+ class="main"
3848
+ @dragenter=${this.onDragEnter}
3849
+ @dragover=${(t) => t.preventDefault()}
3850
+ >
3851
+ ${this.renderHeader()}
3852
+ ${this.offline ? r`<div class="banner" role="status">${this.msg.offline}</div>` : m}
3853
+ <div
3854
+ class="scroller"
3855
+ role="log"
3856
+ aria-live="polite"
3857
+ aria-busy=${this.busy ? "true" : "false"}
3858
+ part="messages"
3859
+ @scroll=${this.onScroll}
3860
+ >
3861
+ ${this.msgs.length || this.loadingThread || this.threadError ? this.renderThread() : this.renderWelcome()}
3862
+ </div>
3863
+ ${this.showJump ? r`<button type="button" class="jump" @click=${this.jumpToLatest}>
3864
+ ↓ ${this.msg.newReply}
3865
+ </button>` : m}
3866
+ ${this.renderComposer()}
3867
+ ${this.branding ? r`<div class="branding" part="branding">
3868
+ <a href="https://singlebase.cloud" target="_blank" rel="noopener noreferrer"
3869
+ >${this.msg.brandingLabel}</a
3870
+ >
3871
+ </div>` : m}
3872
+ ${this.toast ? r`<div class="toast" role="status">
3873
+ <span>${this.toast.text}</span>
3874
+ ${this.toast.undo ? r`<button type="button" @click=${this.undo}>${this.msg.undo}</button>` : m}
3875
+ </div>` : m}
3876
+ ${this.dragging ? r`<div
3877
+ class="drop"
3878
+ @dragover=${(t) => t.preventDefault()}
3879
+ @dragleave=${this.onDragLeave}
3880
+ @drop=${this.onDrop}
3881
+ >
3882
+ <strong>${this.msg.dropTitle}</strong><span>${this.msg.dropSub}</span>
3883
+ </div>` : m}
3884
+ </main>
3885
+ ${this.renderPanel()}
3886
+ </div>`;
3887
+ }
3888
+ renderSidebar(e) {
3889
+ const t = this.msg, i = this.search.trim().toLowerCase(), s = this.chatList.filter(
3890
+ (l) => !i || (l.title ?? "").toLowerCase().includes(i)
3891
+ ), a = [
3892
+ [t.groupBookmarked, s.filter((l) => l.bookmarked)],
3893
+ [
3894
+ t.groupToday,
3895
+ s.filter((l) => !l.bookmarked && Pe(l._modified_at ?? l._created_at) === "today")
3896
+ ],
3897
+ [
3898
+ t.groupYesterday,
3899
+ s.filter(
3900
+ (l) => !l.bookmarked && Pe(l._modified_at ?? l._created_at) === "yesterday"
3901
+ )
3902
+ ],
3903
+ [
3904
+ t.groupWeek,
3905
+ s.filter((l) => !l.bookmarked && Pe(l._modified_at ?? l._created_at) === "week")
3906
+ ],
3907
+ [
3908
+ t.groupOlder,
3909
+ s.filter((l) => !l.bookmarked && Pe(l._modified_at ?? l._created_at) === "older")
3910
+ ]
3911
+ ];
3912
+ let o;
3913
+ return this.listState === "loading" && !this.chatList.length ? o = r`<div aria-label=${t.loadingChats}>
3914
+ ${[1, 2, 3, 4].map(() => r`<div class="skeleton"></div>`)}
3915
+ </div>` : s.length ? o = a.filter(([, l]) => l.length).map(
3916
+ ([l, c]) => r`<div class="group">${l}</div>
3917
+ ${c.map((x) => this.renderThreadRow(x))}`
3918
+ ) : o = r`<span class="side-note"
3919
+ >${i ? z(t.noMatch, { query: this.search.trim() }) : t.noChats}</span
3920
+ >`, r`<aside
3921
+ class="sidebar ${e ? "overlay" : "docked"}"
3922
+ part="sidebar"
3923
+ aria-label=${t.chats}
3924
+ >
3925
+ <div class="side-head">
3926
+ <span class="label">${t.chats}</span>
3927
+ <button
3928
+ type="button"
3929
+ class="icon"
3930
+ title=${t.hideSidebar}
3931
+ aria-label=${t.hideSidebar}
3932
+ @click=${() => this.sidebarOpen = !1}
3933
+ >
3934
+ ${y.sidebar()}
3935
+ </button>
3936
+ </div>
3937
+ <div class="side-tools">
3938
+ <button type="button" class="new-chat" @click=${() => this.newChat()}>
3939
+ ${y.plus()}<span>${t.newChat}</span>
3940
+ </button>
3941
+ <input
3942
+ class="search"
3943
+ type="search"
3944
+ placeholder=${t.searchChats}
3945
+ aria-label=${t.searchChats}
3946
+ .value=${this.search}
3947
+ @input=${(l) => this.search = l.target.value}
3948
+ />
3949
+ </div>
3950
+ <div class="threads">${o}</div>
3951
+ </aside>`;
3952
+ }
3953
+ renderThreadRow(e) {
3954
+ const t = this.msg, i = e._id === this.activeId, s = e.title || t.untitled;
3955
+ if (this.renamingId === e._id)
3956
+ return r`<div class="thread active">
3957
+ <input
3958
+ class="thread-rename"
3959
+ maxlength="80"
3960
+ .value=${s}
3961
+ aria-label=${t.renameChat}
3962
+ @keydown=${(o) => {
3963
+ o.key === "Enter" && this.commitRename(e._id, o.target.value), o.key === "Escape" && (o.stopPropagation(), this.renamingId = "");
3964
+ }}
3965
+ @blur=${(o) => this.commitRename(e._id, o.target.value)}
3966
+ />
3967
+ </div>`;
3968
+ const a = (o) => (l) => {
3969
+ l.stopPropagation(), o();
3970
+ };
3971
+ return r`<div
3972
+ class="thread ${i ? "active" : ""}"
3973
+ role="button"
3974
+ tabindex="0"
3975
+ aria-current=${i ? "true" : "false"}
3976
+ @click=${() => this.openChat(e._id)}
3977
+ @keydown=${(o) => o.key === "Enter" && this.openChat(e._id)}
3978
+ >
3979
+ <span class="thread-title">${s}</span>
3980
+ <span class="thread-actions">
3981
+ <button
3982
+ type="button"
3983
+ class="icon sm ${e.bookmarked ? "on" : ""}"
3984
+ title=${e.bookmarked ? t.unbookmarkChat : t.bookmarkChat}
3985
+ aria-label=${e.bookmarked ? t.unbookmarkChat : t.bookmarkChat}
3986
+ @click=${a(() => this.toggleChatBookmark(e._id))}
3987
+ >
3988
+ ${y.bookmark(!!e.bookmarked)}
3989
+ </button>
3990
+ <button
3991
+ type="button"
3992
+ class="icon sm"
3993
+ title=${t.renameChat}
3994
+ aria-label=${t.renameChat}
3995
+ @click=${a(() => {
3996
+ this.renamingId = e._id, this.focusNext = "input.thread-rename";
3997
+ })}
3998
+ >
3999
+ ${y.pencil()}
4000
+ </button>
4001
+ <button
4002
+ type="button"
4003
+ class="icon sm danger"
4004
+ title=${t.deleteChat}
4005
+ aria-label=${t.deleteChat}
4006
+ @click=${a(() => this.deleteChat(e._id))}
4007
+ >
4008
+ ${y.trash()}
4009
+ </button>
4010
+ </span>
4011
+ </div>`;
4012
+ }
4013
+ renderHeader() {
4014
+ const e = this.msg, t = !!this.activeId, i = (this.embed === "inline" || this.embed === "launcher") && !this.mobile, s = this.embed === "launcher" ? () => this.close() : this.expanded ? () => this.collapse() : null;
4015
+ let a = m;
4016
+ return this.showTitle && (a = this.editingTitle ? r`<input
4017
+ class="title-input"
4018
+ maxlength="80"
4019
+ .value=${this.chatTitle}
4020
+ aria-label=${e.renameChat}
4021
+ @keydown=${(o) => {
4022
+ o.key === "Enter" && this.commitTitle(o.target.value), o.key === "Escape" && (o.stopPropagation(), this.editingTitle = !1);
4023
+ }}
4024
+ @blur=${(o) => this.commitTitle(o.target.value)}
4025
+ />` : r`<button
4026
+ type="button"
4027
+ class="title"
4028
+ part="title"
4029
+ ?disabled=${!t}
4030
+ title=${t ? e.renameChat : ""}
4031
+ @click=${() => {
4032
+ this.editingTitle = !0, this.focusNext = "input.title-input";
4033
+ }}
4034
+ >
4035
+ ${this.chatTitle || e.untitled}
4036
+ </button>`), r`<header class="header" part="header">
4037
+ <div class="header-left">
4038
+ ${this.sidebarOpen && this.docked ? m : r`<button
4039
+ type="button"
4040
+ class="icon"
4041
+ title=${e.showChats}
4042
+ aria-label=${e.showChats}
4043
+ @click=${() => this.sidebarOpen = !0}
4044
+ >
4045
+ ${y.sidebar()}
4046
+ </button>`}
4047
+ ${a}
4048
+ </div>
4049
+ <div class="header-right">
4050
+ <button
4051
+ type="button"
4052
+ class="icon ${this.bookmarked ? "on" : ""}"
4053
+ ?disabled=${!t}
4054
+ title=${this.bookmarked ? e.unbookmarkChat : e.bookmarkChat}
4055
+ aria-label=${this.bookmarked ? e.unbookmarkChat : e.bookmarkChat}
4056
+ @click=${() => this.activeId && this.toggleChatBookmark(this.activeId)}
4057
+ >
4058
+ ${y.bookmark(this.bookmarked)}
4059
+ </button>
4060
+ ${this.allowExport ? r`<div class="menu-wrap">
4061
+ <button
4062
+ type="button"
4063
+ class="icon ${this.menuOpen ? "on" : ""}"
4064
+ ?disabled=${!this.msgs.length}
4065
+ title=${e.exportChat}
4066
+ aria-label=${e.exportChat}
4067
+ aria-haspopup="menu"
4068
+ aria-expanded=${this.menuOpen ? "true" : "false"}
4069
+ @click=${() => this.menuOpen = !this.menuOpen}
4070
+ >
4071
+ ${y.download()}
4072
+ </button>
4073
+ ${this.menuOpen ? this.renderExportMenu() : m}
4074
+ </div>` : m}
4075
+ <button
4076
+ type="button"
4077
+ class="icon danger"
4078
+ ?disabled=${!t}
4079
+ title=${e.deleteChat}
4080
+ aria-label=${e.deleteChat}
4081
+ @click=${() => this.activeId && this.deleteChat(this.activeId)}
4082
+ >
4083
+ ${y.trash()}
4084
+ </button>
4085
+ ${i || s ? r`<span class="divider"></span> ${i ? r`<button
4086
+ type="button"
4087
+ class="icon"
4088
+ title=${this.expanded ? e.restore : e.expand}
4089
+ aria-label=${this.expanded ? e.restore : e.expand}
4090
+ @click=${() => this.expanded ? this.collapse() : this.expand()}
4091
+ >
4092
+ ${this.expanded ? y.restore() : y.expand()}
4093
+ </button>` : m}
4094
+ ${s ? r`<button
4095
+ type="button"
4096
+ class="icon"
4097
+ title=${e.minimize}
4098
+ aria-label=${e.minimize}
4099
+ @click=${s}
4100
+ >
4101
+ ${y.minimize()}
4102
+ </button>` : m}` : m}
4103
+ </div>
4104
+ </header>`;
4105
+ }
4106
+ renderExportMenu() {
4107
+ const e = this.msg, t = [
4108
+ [e.exportMarkdown, ".md", "md"],
4109
+ [e.exportJson, ".json", "json"],
4110
+ [e.exportText, ".txt", "txt"],
4111
+ [e.exportCopy, "", "copy"]
4112
+ ];
4113
+ return r`<div class="menu-scrim" @click=${() => this.menuOpen = !1}></div>
4114
+ <div class="menu" role="menu">
4115
+ <span class="label">${e.exportHeading}</span>
4116
+ ${t.map(
4117
+ ([i, s, a]) => r`<button
4118
+ type="button"
4119
+ role="menuitem"
4120
+ class="menu-item"
4121
+ @click=${() => this.exportChat(a)}
4122
+ >
4123
+ <span>${i}</span><span class="ext">${s}</span>
4124
+ </button>`
4125
+ )}
4126
+ </div>`;
4127
+ }
4128
+ promptList() {
4129
+ const e = this.prompts;
4130
+ return Array.isArray(e) && e.length ? e.map((t) => typeof t == "string" ? { text: t } : t).filter((t) => t == null ? void 0 : t.text).slice(0, 4) : typeof e == "string" && e.trim() ? e.split("|").map((t) => t.trim()).filter(Boolean).slice(0, 4).map((t) => ({ text: t })) : (ot[this.mode] ?? ot.chat).map(([t, i]) => ({
4131
+ label: t,
4132
+ text: i
4133
+ }));
4134
+ }
4135
+ renderWelcome() {
4136
+ const e = this.msg, t = this.mode === "rag" ? "Rag" : this.mode === "rich" ? "Rich" : "Chat", i = (s) => e[`${s}${t}`];
4137
+ return r`<div class="welcome" part="welcome">
4138
+ <div class="welcome-head">
4139
+ ${this.logoUrl && it(this.logoUrl, !0) ? r`<img class="welcome-logo" src=${this.logoUrl} alt="" />` : m}
4140
+ <span class="label">${i("eyebrow")}</span>
4141
+ <h2>${this.heading || i("heading")}</h2>
4142
+ <p>${this.description || i("description")}</p>
4143
+ </div>
4144
+ <div class="prompts">
4145
+ ${this.promptList().map(
4146
+ (s) => r`<button
4147
+ type="button"
4148
+ class="prompt"
4149
+ part="prompt"
4150
+ @click=${() => this.send(s.text)}
4151
+ >
4152
+ <span class="label">${s.label || "Suggested"}</span>
4153
+ <span class="prompt-text">${s.text}</span>
4154
+ </button>`
4155
+ )}
4156
+ </div>
4157
+ </div>`;
4158
+ }
4159
+ renderThread() {
4160
+ const e = this.msgs.map((t) => t.role).lastIndexOf("assistant");
4161
+ return r`<div class="thread-view">
4162
+ ${this.threadError ? r`<div class="error-card" role="alert">
4163
+ <span>${this.threadError}</span>
4164
+ ${this.activeId ? r`<button
4165
+ type="button"
4166
+ class="btn"
4167
+ @click=${() => this.openChat(this.activeId)}
4168
+ >
4169
+ ${this.msg.retry}
4170
+ </button>` : m}
4171
+ </div>` : m}
4172
+ ${this.loadingThread ? r`${[1, 2].map(() => r`<div class="skeleton" style="height:48px"></div>`)}` : m}
4173
+ ${vt(
4174
+ this.msgs,
4175
+ (t) => t.key,
4176
+ (t, i) => t.role === "user" ? this.renderUser(t) : this.renderBot(t, i === e)
4177
+ )}
4178
+ </div>`;
4179
+ }
4180
+ renderUser(e) {
4181
+ const t = this.msg, i = e.at ? new Date(e.at).toLocaleTimeString([], { hour: "numeric", minute: "2-digit" }) : "", s = e.attachments ?? [];
4182
+ return r`<div class="msg user" part="message user">
4183
+ ${s.length ? r`<div class="attachments">
4184
+ ${s.map((a) => r`<span class="doc-chip"><span class="ext">${ct(a.name)}</span><span class="name">${a.name}</span></span>`)}
4185
+ </div>` : m}
4186
+ ${this.editingKey === e.key ? r`<div class="edit-box">
4187
+ <textarea
4188
+ rows="3"
4189
+ class="edit-input"
4190
+ .value=${this.editDraft}
4191
+ @input=${(a) => this.editDraft = a.target.value}
4192
+ @keydown=${(a) => {
4193
+ a.key === "Escape" && (a.stopPropagation(), this.editingKey = "");
4194
+ }}
4195
+ ></textarea>
4196
+ <div class="row-end">
4197
+ <button type="button" class="btn" @click=${() => this.editingKey = ""}>
4198
+ ${t.cancel}
4199
+ </button>
4200
+ <button type="button" class="btn primary" @click=${() => this.saveEdit(e)}>
4201
+ ${t.saveResend}
4202
+ </button>
4203
+ </div>
4204
+ </div>` : r`<div class="bubble-user">${e.content}</div>
4205
+ <div class="toolbar">
4206
+ ${e.bookmarked ? r`<span class="saved">${y.bookmark(!0)}${t.saved}</span>` : m}
4207
+ <span class="time">${i}</span>
4208
+ ${this.busy ? m : r`<button
4209
+ type="button"
4210
+ class="icon"
4211
+ title=${t.edit}
4212
+ aria-label=${t.edit}
4213
+ @click=${() => {
4214
+ this.editingKey = e.key, this.editDraft = e.content, this.focusNext = "textarea.edit-input";
4215
+ }}
4216
+ >
4217
+ ${y.pencil()}
4218
+ </button>`}
4219
+ <button
4220
+ type="button"
4221
+ class="icon"
4222
+ title=${this.copiedKey === e.key ? t.copied : t.copy}
4223
+ aria-label=${t.copy}
4224
+ @click=${() => this.copy(e.key, e.content)}
4225
+ >
4226
+ ${y.copy()}
4227
+ </button>
4228
+ ${e.id ? r`<button
4229
+ type="button"
4230
+ class="icon ${e.bookmarked ? "on" : ""}"
4231
+ title=${e.bookmarked ? t.unbookmarkMessage : t.bookmarkMessage}
4232
+ aria-label=${e.bookmarked ? t.unbookmarkMessage : t.bookmarkMessage}
4233
+ @click=${() => this.toggleMessageBookmark(e)}
4234
+ >
4235
+ ${y.bookmark(e.bookmarked)}
4236
+ </button>` : m}
4237
+ <button
4238
+ type="button"
4239
+ class="icon danger"
4240
+ title=${t.deleteMessage}
4241
+ aria-label=${t.deleteMessage}
4242
+ @click=${() => this.deleteMessage(e)}
4243
+ >
4244
+ ${y.trash()}
4245
+ </button>
4246
+ </div>`}
4247
+ </div>`;
4248
+ }
4249
+ pillLabel() {
4250
+ return this.mode === "rag" ? this.msg.searching : this.mode === "rich" ? this.msg.building : this.msg.thinking;
4251
+ }
4252
+ renderBot(e, t) {
4253
+ const i = this.msg, s = e.phase === "pending", a = e.phase === "done", o = e.sources.length, l = Ze(e.content), c = e.sources.map((b, M) => Ke(b, M + 1)), x = l.size ? c.filter((b) => l.has(b.n)) : c, f = e.at ? new Date(e.at).toLocaleTimeString([], { hour: "numeric", minute: "2-digit" }) : "", O = e.content + (x.length ? `
4254
+
4255
+ Sources:
4256
+ ${x.map((b) => `[${b.n}] ${b.title}`).join(`
4257
+ `)}` : ""), S = this.retrievalOpen.has(e.key);
4258
+ return r`<div class="msg bot" part="message assistant">
4259
+ ${s ? r`<div class="halo"></div>` : m}
4260
+ ${this.arrivedKey === e.key ? r`<div class="arrived">
4261
+ <div class="wash"></div>
4262
+ <div class="ring"></div>
4263
+ <div class="sweep"></div>
4264
+ </div>` : m}
4265
+ <div class="bot-body">
4266
+ ${e.bookmarked ? r`<span class="saved">${y.bookmark(!0)}${i.saved}</span>` : m}
4267
+ ${s ? r`<div class="pill" role="status">
4268
+ <span class="ring"></span><span class="dot"></span>
4269
+ <span class="shimmer">${this.pillLabel()}</span>
4270
+ </div>` : m}
4271
+ ${o && !s ? r`<div class="retrieval">
4272
+ <button
4273
+ type="button"
4274
+ class="retrieval-toggle"
4275
+ aria-expanded=${S ? "true" : "false"}
4276
+ @click=${() => {
4277
+ const b = new Set(this.retrievalOpen);
4278
+ b.has(e.key) ? b.delete(e.key) : b.add(e.key), this.retrievalOpen = b;
4279
+ }}
4280
+ >
4281
+ <span class="chev">${S ? "▾" : "▸"}</span>
4282
+ <span style="flex:1">${z(i.searchedSources, { n: o })}</span>
4283
+ ${e.execTime !== void 0 ? r`<span class="ms">${e.execTime.toFixed(1)}s</span>` : m}
4284
+ </button>
4285
+ ${S ? r`<div class="retrieval-list">
4286
+ ${c.map(
4287
+ (b) => r`<button
4288
+ type="button"
4289
+ class="passage"
4290
+ @click=${() => this.panel = { key: e.key, n: b.n }}
4291
+ >
4292
+ <span class="n">${b.n}</span>
4293
+ <span class="what"
4294
+ ><span>${b.title}</span><span>${b.collection || b.path}</span></span
4295
+ >
4296
+ ${b.score !== null ? r`<span class="relevance"
4297
+ ><span class="score">${b.score.toFixed(2)}</span>
4298
+ <span class="relevance-track"
4299
+ ><span
4300
+ class="relevance-fill"
4301
+ style="width:${Math.round(b.score * 100)}%"
4302
+ ></span></span
4303
+ ></span>` : r`<span></span>`}
4304
+ </button>`
4305
+ )}
4306
+ </div>` : m}
4307
+ </div>` : m}
4308
+ ${s ? m : this.renderAnswer(e)}
4309
+ ${e.phase === "streaming" ? r`<span class="caret"></span>` : m}
4310
+ ${e.phase === "error" ? r`<div class="error-card" role="alert">
4311
+ <span>${e.error}</span>
4312
+ <button type="button" class="btn" @click=${() => this.retry(e)}>
4313
+ ${i.retry}
4314
+ </button>
4315
+ </div>` : m}
4316
+ ${a && x.length ? r`<div class="cards">
4317
+ <span class="label">${l.size ? i.sourcesCited : i.sourcesRetrieved}</span>
4318
+ <div class="card-grid">
4319
+ ${x.map(
4320
+ (b) => {
4321
+ var M;
4322
+ return r`<button
4323
+ type="button"
4324
+ class="source-card ${((M = this.panel) == null ? void 0 : M.key) === e.key && this.panel.n === b.n ? "active" : ""}"
4325
+ @click=${() => this.panel = { key: e.key, n: b.n }}
4326
+ >
4327
+ <span class="top"
4328
+ ><span class="num">${b.n}</span
4329
+ >${b.collection ? r`<span class="label">${b.collection}</span>` : m}</span
4330
+ >
4331
+ <span class="t">${b.title}</span>
4332
+ <span class="s">${b.text}</span>
4333
+ </button>`;
4334
+ }
4335
+ )}
4336
+ </div>
4337
+ </div>` : m}
4338
+ ${a ? r`<div class="toolbar ${t ? "pinned" : ""}">
4339
+ <button
4340
+ type="button"
4341
+ class="icon"
4342
+ title=${this.copiedKey === e.key ? i.copied : i.copy}
4343
+ aria-label=${i.copy}
4344
+ @click=${() => this.copy(e.key, O)}
4345
+ >
4346
+ ${y.copy()}
4347
+ </button>
4348
+ ${t && !this.busy ? r`<button
4349
+ type="button"
4350
+ class="icon"
4351
+ title=${i.regenerate}
4352
+ aria-label=${i.regenerate}
4353
+ @click=${() => this.regenerate()}
4354
+ >
4355
+ ${y.refresh()}
4356
+ </button>` : m}
4357
+ ${e.id ? r`<button
4358
+ type="button"
4359
+ class="icon ${e.bookmarked ? "on" : ""}"
4360
+ title=${e.bookmarked ? i.unbookmarkMessage : i.bookmarkMessage}
4361
+ aria-label=${e.bookmarked ? i.unbookmarkMessage : i.bookmarkMessage}
4362
+ @click=${() => this.toggleMessageBookmark(e)}
4363
+ >
4364
+ ${y.bookmark(e.bookmarked)}
4365
+ </button>` : m}
4366
+ <button
4367
+ type="button"
4368
+ class="icon danger"
4369
+ title=${i.deleteMessage}
4370
+ aria-label=${i.deleteMessage}
4371
+ @click=${() => this.deleteMessage(e)}
4372
+ >
4373
+ ${y.trash()}
4374
+ </button>
4375
+ <span class="time">${f}</span>
4376
+ ${e.stopped ? r`<span class="note">${i.stopped}</span>` : m}
4377
+ <span class="spacer"></span>
4378
+ ${e.feedback ? r`<span class="note"
4379
+ >${e.feedback === "up" ? i.markedHelpful : i.thanksFeedback}</span
4380
+ >` : r`<button
4381
+ type="button"
4382
+ class="icon"
4383
+ title=${i.helpful}
4384
+ aria-label=${i.helpful}
4385
+ @click=${() => this.feedback(e, "up")}
4386
+ >
4387
+ ${y.thumb()}
4388
+ </button>
4389
+ <button
4390
+ type="button"
4391
+ class="icon"
4392
+ title=${i.notHelpful}
4393
+ aria-label=${i.notHelpful}
4394
+ @click=${() => this.feedback(e, "down")}
4395
+ >
4396
+ ${y.thumb(!0)}
4397
+ </button>`}
4398
+ </div>` : m}
4399
+ ${a && t && !this.busy && e.followups.length ? r`<div class="followups">
4400
+ ${e.followups.map(
4401
+ (b) => r`<button type="button" class="followup" @click=${() => this.send(b)}>
4402
+ <span class="arrow">↳</span><span>${b}</span>
4403
+ </button>`
4404
+ )}
4405
+ </div>` : m}
4406
+ </div>
4407
+ </div>`;
4408
+ }
4409
+ renderAnswer(e) {
4410
+ if (e.phase === "error" && !e.content) return m;
4411
+ if (e.phase === "done" && !e.content)
4412
+ return e.stopped ? m : r`<div class="answer"><p class="note">${this.msg.emptyReply}</p></div>`;
4413
+ const t = _t(zt(e.content), this.renderAs), i = this.renderAs === "text" ? 0 : e.sources.length;
4414
+ return r`<div class="answer" part="answer">
4415
+ ${t.map((s, a) => this.renderBlock(s, e, i, a))}
4416
+ </div>`;
4417
+ }
4418
+ renderInline(e, t, i) {
4419
+ return Mt(e, i).map((s) => {
4420
+ var a;
4421
+ switch (s.type) {
4422
+ case "bold":
4423
+ return r`<strong>${s.text}</strong>`;
4424
+ case "code":
4425
+ return r`<code class="inline">${s.text}</code>`;
4426
+ case "link":
4427
+ return r`<a href=${s.href} target="_blank" rel="noopener noreferrer nofollow"
4428
+ >${s.text}</a
4429
+ >`;
4430
+ case "cite": {
4431
+ const o = ((a = this.panel) == null ? void 0 : a.key) === t.key && this.panel.n === s.n ? "cite active" : "cite", l = z(this.msg.openSource, { n: s.n });
4432
+ return r`<button type="button" class=${o} aria-label=${l} @click=${() => this.panel = { key: t.key, n: s.n }}>${s.n}</button>`;
4433
+ }
4434
+ default:
4435
+ return s.text;
4436
+ }
4437
+ });
4438
+ }
4439
+ renderBlock(e, t, i, s) {
4440
+ switch (e.type) {
4441
+ case "p":
4442
+ return r`<p>${this.renderInline(e.text, t, i)}</p>`;
4443
+ case "raw":
4444
+ return r`<p class="raw">${e.text}</p>`;
4445
+ case "h":
4446
+ return r`<h3>${this.renderInline(e.text, t, i)}</h3>`;
4447
+ case "list": {
4448
+ const a = e.items.map(
4449
+ (o) => r`<li>${this.renderInline(o, t, i)}</li>`
4450
+ );
4451
+ return e.ordered ? r`<ol>
4452
+ ${a}
4453
+ </ol>` : r`<ul>
4454
+ ${a}
4455
+ </ul>`;
4456
+ }
4457
+ case "quote":
4458
+ return r`<div class="quote">${this.renderInline(e.text, t, i)}</div>`;
4459
+ case "code": {
4460
+ const a = `${t.key}:${s}`;
4461
+ return r`<div class="code">
4462
+ <div class="code-head">
4463
+ <span class="label">${e.lang}</span>
4464
+ <button type="button" class="text-btn" @click=${() => this.copy(a, e.text)}>
4465
+ ${this.copiedKey === a ? this.msg.copied : this.msg.copy}
4466
+ </button>
4467
+ </div>
4468
+ <pre><code>${e.text}</code></pre>
4469
+ </div>`;
4470
+ }
4471
+ case "table":
4472
+ return r`<div class="table">
4473
+ <table>
4474
+ <thead>
4475
+ <tr>
4476
+ ${e.head.map((a) => r`<th>${this.renderInline(a, t, i)}</th>`)}
4477
+ </tr>
4478
+ </thead>
4479
+ <tbody>
4480
+ ${e.rows.map(
4481
+ (a) => r`<tr>
4482
+ ${a.map((o) => r`<td>${this.renderInline(o, t, i)}</td>`)}
4483
+ </tr>`
4484
+ )}
4485
+ </tbody>
4486
+ </table>
4487
+ </div>`;
4488
+ case "chart":
4489
+ return this.renderChart(e.spec);
4490
+ case "chartPending":
4491
+ return r`<div class="chart-pending"><span class="label">Rendering chart</span></div>`;
4492
+ case "img":
4493
+ return r`<div class="gallery ${e.images.length > 1 ? "many" : ""}">
4494
+ ${e.images.map(
4495
+ (a) => r`<figure>
4496
+ ${a.src && it(a.src, !0) ? r`<img
4497
+ src=${a.src}
4498
+ alt=${a.alt}
4499
+ loading="lazy"
4500
+ referrerpolicy="no-referrer"
4501
+ />` : r`<div class="img-missing"><span class="label">Image</span></div>`}
4502
+ ${a.alt ? r`<figcaption>${a.alt}</figcaption>` : m}
4503
+ </figure>`
4504
+ )}
4505
+ </div>`;
4506
+ default:
4507
+ return m;
4508
+ }
4509
+ }
4510
+ renderChart(e) {
4511
+ const t = e.series.length > 1 ? r`<span class="legend">
4512
+ ${e.series.map(
4513
+ (o, l) => r`<span
4514
+ ><span
4515
+ class="swatch"
4516
+ style="background:${_[l % _.length]}"
4517
+ ></span
4518
+ >${o.name}</span
4519
+ >`
4520
+ )}
4521
+ </span>` : m, i = r`<div class="chart-head">
4522
+ <span class="chart-title">${e.title}</span>${t}
4523
+ </div>`;
4524
+ if (e.type === "line") {
4525
+ const o = Math.max(0, ...e.series.flatMap((f) => f.values)), l = Math.pow(10, Math.floor(Math.log10(o || 1))), c = Math.ceil(o / l * 2) / 2 * l || 1, x = Math.max(e.labels.length, ...e.series.map((f) => f.values.length));
4526
+ return r`<figure class="chart" part="chart" aria-label=${e.title}>
4527
+ ${i}
4528
+ <div class="line-chart">
4529
+ <div class="plot">
4530
+ ${[1, 0.5, 0].map(
4531
+ (f) => r`<div class="tick ${f === 0 ? "base" : ""}" style="top:${(1 - f) * 100}%">
4532
+ <span>${Fe(Math.round(c * f), e.unit)}</span>
4533
+ </div>`
4534
+ )}
4535
+ <svg
4536
+ viewBox="0 0 600 170"
4537
+ preserveAspectRatio="none"
4538
+ role="img"
4539
+ aria-label=${e.title}
4540
+ >
4541
+ ${e.series.map(
4542
+ (f, O) => $`<polyline pathLength="1" stroke=${_[O % _.length]}
4543
+ points=${f.values.map(
4544
+ (S, b) => `${(x > 1 ? b / (x - 1) * 600 : 300).toFixed(1)},${(170 - S / c * 170).toFixed(1)}`
4545
+ ).join(
4546
+ " "
4547
+ )}><title>${f.name}: ${f.values.map((S) => Fe(S, e.unit)).join(", ")}</title></polyline>`
4548
+ )}
4549
+ </svg>
4550
+ </div>
4551
+ <div class="x-labels">${e.labels.map((f) => r`<span>${f}</span>`)}</div>
4552
+ </div>
4553
+ </figure>`;
4554
+ }
4555
+ const s = e.labels.map(
4556
+ (o, l) => e.series.reduce((c, x) => c + (x.values[l] || 0), 0)
4557
+ ), a = Math.max(0, ...s) || 1;
4558
+ return r`<figure class="chart" part="chart" aria-label=${e.title}>
4559
+ ${i}
4560
+ <div class="bars">
4561
+ ${e.labels.map(
4562
+ (o, l) => r`<div class="bar-row" title="${o}: ${Fe(s[l], e.unit)}">
4563
+ <span class="bar-label">${o}</span>
4564
+ <span class="bar-track"
4565
+ ><span class="bar-fill" style="width:${Math.max(0, s[l]) / a * 100}%">
4566
+ ${e.series.map(
4567
+ (c, x) => r`<span
4568
+ style="flex:${Math.max(0, c.values[l] || 0)};background:${e.series.length > 1 ? _[x % _.length] : "var(--c-ink)"}"
4569
+ ></span>`
4570
+ )}
4571
+ </span></span
4572
+ >
4573
+ <span class="bar-value">${Fe(s[l], e.unit)}</span>
4574
+ </div>`
4575
+ )}
4576
+ </div>
4577
+ </figure>`;
4578
+ }
4579
+ renderPanel() {
4580
+ if (!this.panel) return m;
4581
+ const e = this.msgs.find((f) => f.key === this.panel.key), t = e == null ? void 0 : e.sources[this.panel.n - 1];
4582
+ if (!e || !t) return m;
4583
+ const i = this.msg, s = Ke(t, this.panel.n), a = Ze(e.content), o = e.sources.map((f, O) => Ke(f, O + 1)).filter((f) => f.n !== s.n && (!a.size || a.has(f.n))), l = `ref:${e.key}:${s.n}`, c = `"${s.text}"
4584
+ — ${s.title} [${s.n}]${s.path ? `
4585
+ ${s.path}` : ""}${s.updated ? ` · Updated ${s.updated}` : ""}`, x = [
4586
+ s.updated ? `Updated ${s.updated}` : "",
4587
+ s.score !== null ? `Relevance ${s.score.toFixed(2)}` : ""
4588
+ ].filter(Boolean).join(" · ");
4589
+ return r`<aside
4590
+ class="panel ${this.panelDocked ? "docked" : "overlay"}"
4591
+ part="panel"
4592
+ role="region"
4593
+ aria-label=${z(i.sourceLabel, { n: s.n })}
4594
+ >
4595
+ <div class="panel-head">
4596
+ <span class="label"
4597
+ >${z(i.sourceLabel, { n: s.n })}${s.collection ? ` · ${s.collection}` : ""}</span
4598
+ >
4599
+ <button type="button" class="text-btn underline" @click=${() => this.panel = null}>
4600
+ ${i.close}
4601
+ </button>
4602
+ </div>
4603
+ <div class="panel-body">
4604
+ <div class="panel-meta">
4605
+ <h3>${s.title}</h3>
4606
+ ${s.path ? r`<span class="path">${s.path}</span>` : m}
4607
+ ${x ? r`<span class="meta">${x}</span>` : m}
4608
+ </div>
4609
+ <div class="passage-box">
4610
+ <span class="text">${s.text}</span>
4611
+ <div class="passage-foot">
4612
+ <span class="label">${i.citedPassage}</span>
4613
+ <button
4614
+ type="button"
4615
+ class="copy-ref"
4616
+ title=${i.copyReference}
4617
+ aria-label=${i.copyReference}
4618
+ @click=${() => this.copy(l, c)}
4619
+ >
4620
+ ${y.copy()}<span>${this.copiedKey === l ? i.copied : i.copy}</span>
4621
+ </button>
4622
+ </div>
4623
+ </div>
4624
+ </div>
4625
+ ${o.length ? r`<div class="panel-foot">
4626
+ <span class="label">${i.alsoCited}</span>
4627
+ <div class="chips">
4628
+ ${o.map(
4629
+ (f) => r`<button
4630
+ type="button"
4631
+ class="chip"
4632
+ @click=${() => this.panel = { key: e.key, n: f.n }}
4633
+ >
4634
+ ${f.n} · ${f.title}
4635
+ </button>`
4636
+ )}
4637
+ </div>
4638
+ </div>` : m}
4639
+ </aside>`;
4640
+ }
4641
+ renderComposer() {
4642
+ const e = this.msg, t = this.mode === "rag" ? e.placeholderRag : this.mode === "rich" ? e.placeholderRich : z(e.placeholderChat, { name: this.assistantName }), i = !this.draft.trim();
4643
+ return r`<div class="composer-wrap">
4644
+ <div class="composer-col">
4645
+ <input
4646
+ type="file"
4647
+ multiple
4648
+ hidden
4649
+ accept=".md,.markdown,.txt,.csv,.tsv,.json,.html,.htm,.yaml,.yml,.xml,.log,text/*"
4650
+ @change=${(s) => {
4651
+ const a = s.target;
4652
+ this.addFiles(a.files).then(() => a.value = "");
4653
+ }}
4654
+ />
4655
+ <div class="composer-box">
4656
+ ${this.busy ? r`<div class="composer-glow"></div>` : m}
4657
+ <div class="composer ${this.busy ? "busy" : ""}" part="composer">
4658
+ ${this.files.length ? r`<div class="pending-files">
4659
+ ${this.files.map(
4660
+ (s) => r`<div class="pending-file">
4661
+ <span class="ext">${ct(s.name)}</span>
4662
+ <span class="meta"
4663
+ ><span class="name">${s.name}</span
4664
+ ><span class="size">${Ve(s.size)}</span></span
4665
+ >
4666
+ <button
4667
+ type="button"
4668
+ aria-label=${e.removeFile}
4669
+ title=${e.removeFile}
4670
+ @click=${() => this.files = this.files.filter((a) => a !== s)}
4671
+ >
4672
+ ×
4673
+ </button>
4674
+ </div>`
4675
+ )}
4676
+ </div>` : m}
4677
+ <textarea
4678
+ class="input"
4679
+ rows="1"
4680
+ placeholder=${t}
4681
+ aria-label=${t}
4682
+ .value=${this.draft}
4683
+ @input=${this.onComposerInput}
4684
+ @keydown=${this.onComposerKey}
4685
+ ></textarea>
4686
+ <div class="composer-row">
4687
+ <div>
4688
+ ${this.allowUpload ? r`<button
4689
+ type="button"
4690
+ class="attach"
4691
+ title=${e.attach}
4692
+ aria-label=${e.attach}
4693
+ @click=${() => {
4694
+ var s;
4695
+ return (s = this.renderRoot.querySelector("input[type=file]")) == null ? void 0 : s.click();
4696
+ }}
4697
+ >
4698
+ ${y.clip()}
4699
+ </button>` : m}
4700
+ </div>
4701
+ ${this.busy ? r`<button
4702
+ type="button"
4703
+ class="send stop"
4704
+ title=${e.stop}
4705
+ aria-label=${e.stop}
4706
+ @click=${() => this.stop()}
4707
+ >
4708
+ ${y.stop()}
4709
+ </button>` : r`<button
4710
+ type="button"
4711
+ class="send"
4712
+ title=${e.send}
4713
+ aria-label=${e.send}
4714
+ ?disabled=${i}
4715
+ @click=${() => this.send()}
4716
+ >
4717
+ ${y.up()}
4718
+ </button>`}
4719
+ </div>
4720
+ </div>
4721
+ ${this.busy ? r`<div class="composer-ring"><div class="ring"></div></div>` : m}
4722
+ </div>
4723
+ <span class="footnote">${z(e.footnote, { name: this.assistantName })}</span>
4724
+ </div>
4725
+ </div>`;
4726
+ }
4727
+ }, j = new WeakMap(), A = new WeakMap(), E = new WeakMap(), N = new WeakMap(), B = new WeakMap(), D = new WeakMap(), R = new WeakMap(), U = new WeakMap(), F = new WeakMap(), K = new WeakMap(), P = new WeakMap(), H = new WeakMap(), J = new WeakMap(), W = new WeakMap(), q = new WeakMap(), G = new WeakMap(), V = new WeakMap(), X = new WeakMap(), Y = new WeakMap(), Q = new WeakMap(), Z = new WeakMap(), ee = new WeakMap(), te = new WeakMap(), ie = new WeakMap(), se = new WeakMap(), ae = new WeakMap(), re = new WeakMap(), ne = new WeakMap(), oe = new WeakMap(), le = new WeakMap(), ce = new WeakMap(), de = new WeakMap(), pe = new WeakMap(), he = new WeakMap(), ue = new WeakMap(), ge = new WeakMap(), me = new WeakMap(), be = new WeakMap(), fe = new WeakMap(), xe = new WeakMap(), ve = new WeakMap(), ye = new WeakMap(), ke = new WeakMap(), we = new WeakMap(), $e = new WeakMap(), Te = new WeakMap(), Ce = new WeakMap(), Se = new WeakMap(), ze = new WeakMap(), Oe = new WeakMap(), Me = new WeakMap(), _e = new WeakMap(), Ie = new WeakMap(), Le = new WeakMap(), je = new WeakMap(), Ae = new WeakMap(), Ee = new WeakMap(), Ne = new WeakMap(), Be = new WeakMap(), De = new WeakMap(), Re = new WeakMap(), dt);
4728
+ Nt(d, "styles", [kt, wt]);
4729
+ g([
4730
+ w({ attribute: !1 })
4731
+ ], d.prototype, "client", 1);
4732
+ g([
4733
+ w({ attribute: !1 })
4734
+ ], d.prototype, "messages", 1);
4735
+ g([
4736
+ w({ reflect: !0 })
4737
+ ], d.prototype, "theme", 1);
4738
+ g([
4739
+ w({ reflect: !0 })
4740
+ ], d.prototype, "mode", 1);
4741
+ g([
4742
+ w({ attribute: "render-as" })
4743
+ ], d.prototype, "renderAs", 1);
4744
+ g([
4745
+ w({ reflect: !0 })
4746
+ ], d.prototype, "glow", 1);
4747
+ g([
4748
+ w({ converter: I })
4749
+ ], d.prototype, "followups", 1);
4750
+ g([
4751
+ w({ converter: I, attribute: "auto-title" })
4752
+ ], d.prototype, "autoTitle", 1);
4753
+ g([
4754
+ w()
4755
+ ], d.prototype, "model", 1);
4756
+ g([
4757
+ w({ converter: We })
4758
+ ], d.prototype, "params", 1);
4759
+ g([
4760
+ w({ attribute: "system-message" })
4761
+ ], d.prototype, "systemMessage", 1);
4762
+ g([
4763
+ w({ converter: We })
4764
+ ], d.prototype, "retrieval", 1);
4765
+ g([
4766
+ w({ converter: We })
4767
+ ], d.prototype, "metadata", 1);
4768
+ g([
4769
+ w({ reflect: !0 })
4770
+ ], d.prototype, "embed", 1);
4771
+ g([
4772
+ w({ reflect: !0 })
4773
+ ], d.prototype, "position", 1);
4774
+ g([
4775
+ w({ converter: Bt })
4776
+ ], d.prototype, "sidebar", 1);
4777
+ g([
4778
+ w({ converter: I, attribute: "show-title" })
4779
+ ], d.prototype, "showTitle", 1);
4780
+ g([
4781
+ w({ attribute: "chat-id" })
4782
+ ], d.prototype, "chatIdAttr", 1);
4783
+ g([
4784
+ w({ attribute: "assistant-name" })
4785
+ ], d.prototype, "assistantName", 1);
4786
+ g([
4787
+ w({ attribute: "logo-url" })
4788
+ ], d.prototype, "logoUrl", 1);
4789
+ g([
4790
+ w()
4791
+ ], d.prototype, "heading", 1);
4792
+ g([
4793
+ w()
4794
+ ], d.prototype, "description", 1);
4795
+ g([
4796
+ w()
4797
+ ], d.prototype, "prompts", 1);
4798
+ g([
4799
+ w({ attribute: "bubble-text" })
4800
+ ], d.prototype, "bubbleText", 1);
4801
+ g([
4802
+ w({ type: Boolean, attribute: "greeting-bubble" })
4803
+ ], d.prototype, "greetingBubble", 1);
4804
+ g([
4805
+ w({ type: Boolean, attribute: "unread-badge" })
4806
+ ], d.prototype, "unreadBadge", 1);
4807
+ g([
4808
+ w({ converter: I, attribute: "allow-upload" })
4809
+ ], d.prototype, "allowUpload", 1);
4810
+ g([
4811
+ w({ converter: I, attribute: "allow-export" })
4812
+ ], d.prototype, "allowExport", 1);
4813
+ g([
4814
+ w({ converter: I })
4815
+ ], d.prototype, "branding", 1);
4816
+ g([
4817
+ v()
4818
+ ], d.prototype, "chatList", 1);
4819
+ g([
4820
+ v()
4821
+ ], d.prototype, "listState", 1);
4822
+ g([
4823
+ v()
4824
+ ], d.prototype, "activeId", 1);
4825
+ g([
4826
+ v()
4827
+ ], d.prototype, "chatTitle", 1);
4828
+ g([
4829
+ v()
4830
+ ], d.prototype, "bookmarked", 1);
4831
+ g([
4832
+ v()
4833
+ ], d.prototype, "msgs", 1);
4834
+ g([
4835
+ v()
4836
+ ], d.prototype, "loadingThread", 1);
4837
+ g([
4838
+ v()
4839
+ ], d.prototype, "threadError", 1);
4840
+ g([
4841
+ v()
4842
+ ], d.prototype, "busy", 1);
4843
+ g([
4844
+ v()
4845
+ ], d.prototype, "draft", 1);
4846
+ g([
4847
+ v()
4848
+ ], d.prototype, "files", 1);
4849
+ g([
4850
+ v()
4851
+ ], d.prototype, "search", 1);
4852
+ g([
4853
+ v()
4854
+ ], d.prototype, "sidebarOpen", 1);
4855
+ g([
4856
+ v()
4857
+ ], d.prototype, "width", 1);
4858
+ g([
4859
+ v()
4860
+ ], d.prototype, "panel", 1);
4861
+ g([
4862
+ v()
4863
+ ], d.prototype, "menuOpen", 1);
4864
+ g([
4865
+ v()
4866
+ ], d.prototype, "editingKey", 1);
4867
+ g([
4868
+ v()
4869
+ ], d.prototype, "editDraft", 1);
4870
+ g([
4871
+ v()
4872
+ ], d.prototype, "editingTitle", 1);
4873
+ g([
4874
+ v()
4875
+ ], d.prototype, "renamingId", 1);
4876
+ g([
4877
+ v()
4878
+ ], d.prototype, "toast", 1);
4879
+ g([
4880
+ v()
4881
+ ], d.prototype, "copiedKey", 1);
4882
+ g([
4883
+ v()
4884
+ ], d.prototype, "retrievalOpen", 1);
4885
+ g([
4886
+ v()
4887
+ ], d.prototype, "arrivedKey", 1);
4888
+ g([
4889
+ v()
4890
+ ], d.prototype, "dragging", 1);
4891
+ g([
4892
+ v()
4893
+ ], d.prototype, "showJump", 1);
4894
+ g([
4895
+ v()
4896
+ ], d.prototype, "offline", 1);
4897
+ g([
4898
+ v()
4899
+ ], d.prototype, "isOpen", 1);
4900
+ g([
4901
+ v()
4902
+ ], d.prototype, "expanded", 1);
4903
+ g([
4904
+ v()
4905
+ ], d.prototype, "bubble", 1);
4906
+ g([
4907
+ v()
4908
+ ], d.prototype, "seen", 1);
4909
+ g([
4910
+ v()
4911
+ ], d.prototype, "mobile", 1);
4912
+ d = g([
4913
+ xt("singlebase-chat")
4914
+ ], d);
4915
+ export {
4916
+ d as S,
4917
+ _t as a,
4918
+ Ke as b,
4919
+ Ze as c,
4920
+ $t as d,
4921
+ zt as e,
4922
+ Mt as p,
4923
+ Tt as r,
4924
+ tt as s
4925
+ };
4926
+ //# sourceMappingURL=chat-bXaRWel7.js.map