@pinecall/web 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,3510 @@
1
+ import { VoiceSession } from './chunk-LPRH4KOL.js';
2
+ import { usePinecallChat } from './chunk-LHZA26Z5.js';
3
+ import './chunk-MCAQMGBG.js';
4
+ import { createContext, useState, useSyncExternalStore, useCallback, useEffect, useContext, useMemo, useRef } from 'react';
5
+ import { jsxs, jsx } from 'react/jsx-runtime';
6
+
7
+ function useVoiceSession(opts) {
8
+ const [session] = useState(() => new VoiceSession(opts));
9
+ const state = useSyncExternalStore(
10
+ useCallback((cb) => session.subscribe(cb), [session]),
11
+ () => session.getState(),
12
+ () => session.getState()
13
+ );
14
+ useEffect(() => {
15
+ return () => {
16
+ session.destroy();
17
+ };
18
+ }, [session]);
19
+ const connect = useCallback(() => session.connect(), [session]);
20
+ const disconnect = useCallback(() => session.disconnect(), [session]);
21
+ const toggleMute = useCallback(() => session.toggleMute(), [session]);
22
+ const setMuted = useCallback(
23
+ (muted) => session.setMuted(muted),
24
+ [session]
25
+ );
26
+ const configure = useCallback(
27
+ (config) => session.configure(config),
28
+ [session]
29
+ );
30
+ const updateOptions = useCallback(
31
+ (patch) => session.updateOptions(patch),
32
+ [session]
33
+ );
34
+ const sendText = useCallback(
35
+ (text) => session.sendText(text),
36
+ [session]
37
+ );
38
+ const dismissTool = useCallback(
39
+ (toolCallId) => session.dismissTool(toolCallId),
40
+ [session]
41
+ );
42
+ const setContext = useCallback(
43
+ (key, value) => session.setContext(key, value),
44
+ [session]
45
+ );
46
+ return {
47
+ ...state,
48
+ connect,
49
+ disconnect,
50
+ toggleMute,
51
+ setMuted,
52
+ configure,
53
+ updateOptions,
54
+ sendText,
55
+ dismissTool,
56
+ setContext
57
+ };
58
+ }
59
+
60
+ // src/widget/styles.ts
61
+ var WIDGET_CSS = (
62
+ /* css */
63
+ `
64
+ /* \u2500\u2500 Container + CSS custom-property defaults \u2500\u2500 */
65
+ .vw-wrap {
66
+ /* \u2500\u2500 Orb idle gradient (RGB triplets) \u2500\u2500 */
67
+ --vw-orb-from: 255, 255, 255;
68
+ --vw-orb-mid: 240, 238, 231;
69
+ --vw-orb-to: 184, 181, 168;
70
+
71
+ /* \u2500\u2500 State colors (RGB triplets) \u2500\u2500 */
72
+ --vw-color-connecting: 245, 158, 11;
73
+ --vw-color-active: 76, 175, 80;
74
+ --vw-color-user-speaking: 52, 211, 153;
75
+ --vw-color-speaking: 248, 113, 113;
76
+ --vw-color-thinking: 139, 92, 246;
77
+ --vw-color-warning: 255, 160, 0;
78
+ --vw-color-accent: 124, 58, 237;
79
+ --vw-ring-color: 216, 65, 44;
80
+
81
+ /* \u2500\u2500 Panel / bubble (full CSS values) \u2500\u2500 */
82
+ --vw-panel-bg: rgba(16, 14, 20, .92);
83
+ --vw-panel-border: rgba(255, 255, 255, .08);
84
+ --vw-bubble-bot-bg: rgba(18, 16, 22, .9);
85
+ --vw-bubble-bot-color: #e8e4f0;
86
+ --vw-bubble-user-color: #e0d4f7;
87
+ --vw-label-bg: #181818;
88
+ --vw-label-color: #fff;
89
+
90
+ position: fixed;
91
+ right: 28px;
92
+ bottom: 28px;
93
+ z-index: 100;
94
+ overflow: visible;
95
+ }
96
+
97
+ /* \u2500\u2500 Orb \u2500\u2500 */
98
+ .vw-orb {
99
+ width: 64px;
100
+ height: 64px;
101
+ border-radius: 999px;
102
+ background:
103
+ radial-gradient(circle at 30% 30%,
104
+ rgb(var(--vw-orb-from)),
105
+ rgb(var(--vw-orb-mid)) 35%,
106
+ rgba(var(--vw-orb-to), .85) 70%,
107
+ rgb(var(--vw-orb-to)));
108
+ box-shadow:
109
+ 0 1px 0 rgba(255, 255, 255, .9) inset,
110
+ 0 -10px 24px rgba(var(--vw-ring-color), .15) inset,
111
+ 0 14px 40px -10px rgba(0, 0, 0, .25),
112
+ 0 0 0 1px rgba(0, 0, 0, .06);
113
+ cursor: pointer;
114
+ position: relative;
115
+ display: flex;
116
+ align-items: center;
117
+ justify-content: center;
118
+ transition: transform .2s ease;
119
+ }
120
+
121
+ .vw-orb:hover { transform: scale(1.04); }
122
+
123
+ .vw-orb::after {
124
+ content: "";
125
+ position: absolute;
126
+ inset: -8px;
127
+ border-radius: 999px;
128
+ border: 1px solid rgba(var(--vw-ring-color), .2);
129
+ animation: vw-breathe 3.2s ease-in-out infinite;
130
+ }
131
+
132
+ .vw-orb::before {
133
+ content: "";
134
+ position: absolute;
135
+ inset: -16px;
136
+ border-radius: 999px;
137
+ border: 1px solid rgba(var(--vw-ring-color), .08);
138
+ animation: vw-breathe 3.2s ease-in-out .5s infinite;
139
+ }
140
+
141
+ @keyframes vw-breathe {
142
+ 0%, 100% { transform: scale(1); opacity: .9; }
143
+ 50% { transform: scale(1.08); opacity: .3; }
144
+ }
145
+
146
+ /* \u2500\u2500 Label tooltip \u2500\u2500 */
147
+ .vw-label {
148
+ position: absolute;
149
+ right: 76px;
150
+ top: 50%;
151
+ transform: translateY(-50%);
152
+ background: var(--vw-label-bg);
153
+ color: var(--vw-label-color);
154
+ padding: 8px 12px;
155
+ border-radius: 999px;
156
+ font-size: 12px;
157
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
158
+ white-space: nowrap;
159
+ opacity: 0;
160
+ pointer-events: none;
161
+ transition: opacity .2s, transform .2s;
162
+ font-variant-numeric: tabular-nums;
163
+ }
164
+
165
+ .vw-wrap:hover .vw-label { opacity: 1; transform: translateY(-50%) translateX(-2px); }
166
+ .vw-wrap.is-live .vw-label { display: none; }
167
+
168
+ /* \u2500\u2500 State: connecting \u2500\u2500 */
169
+ .vw-orb.connecting {
170
+ background: radial-gradient(circle at 30% 30%, #fff,
171
+ rgba(var(--vw-color-connecting), .35) 35%,
172
+ rgba(var(--vw-color-connecting), .7) 70%,
173
+ rgba(var(--vw-color-connecting), 1));
174
+ animation: vw-breathe 1s ease-in-out infinite;
175
+ }
176
+ .vw-orb.connecting::after,
177
+ .vw-orb.connecting::before { border-color: rgba(var(--vw-color-connecting), .25); }
178
+
179
+ /* \u2500\u2500 State: active \u2500\u2500 */
180
+ .vw-orb.active {
181
+ background: radial-gradient(circle at 30% 30%, #fff,
182
+ rgba(var(--vw-color-active), .15) 35%,
183
+ rgba(var(--vw-color-active), .3) 70%,
184
+ rgba(var(--vw-color-active), .5));
185
+ box-shadow: 0 1px 0 rgba(255, 255, 255, .9) inset,
186
+ 0 14px 40px -10px rgba(0, 0, 0, .2),
187
+ 0 0 20px rgba(var(--vw-color-active), .15);
188
+ }
189
+ .vw-orb.active::after,
190
+ .vw-orb.active::before { border-color: rgba(var(--vw-color-active), .2); }
191
+
192
+ /* \u2500\u2500 State: user speaking \u2500\u2500 */
193
+ .vw-orb.user-speaking {
194
+ background: radial-gradient(circle at 30% 30%, #fff,
195
+ rgba(var(--vw-color-user-speaking), .35) 35%,
196
+ rgba(var(--vw-color-user-speaking), .7) 70%,
197
+ rgba(var(--vw-color-user-speaking), 1));
198
+ box-shadow: 0 1px 0 rgba(255, 255, 255, .9) inset,
199
+ 0 14px 40px -10px rgba(0, 0, 0, .2),
200
+ 0 0 30px rgba(var(--vw-color-user-speaking), .3);
201
+ }
202
+ .vw-orb.user-speaking::after,
203
+ .vw-orb.user-speaking::before { border-color: rgba(var(--vw-color-user-speaking), .3); }
204
+
205
+ /* \u2500\u2500 State: agent speaking \u2500\u2500 */
206
+ .vw-orb.speaking {
207
+ background: radial-gradient(circle at 30% 30%, #fff,
208
+ rgba(var(--vw-color-speaking), .35) 35%,
209
+ rgba(var(--vw-color-speaking), .7) 70%,
210
+ rgba(var(--vw-color-speaking), 1));
211
+ box-shadow: 0 1px 0 rgba(255, 255, 255, .9) inset,
212
+ 0 14px 40px -10px rgba(0, 0, 0, .2),
213
+ 0 0 30px rgba(var(--vw-color-speaking), .3);
214
+ animation: vw-speak-pulse .8s ease-in-out infinite;
215
+ }
216
+ .vw-orb.speaking::after,
217
+ .vw-orb.speaking::before { border-color: rgba(var(--vw-color-speaking), .3); }
218
+
219
+ @keyframes vw-speak-pulse {
220
+ 0%, 100% { transform: scale(1); }
221
+ 50% { transform: scale(1.06); }
222
+ }
223
+
224
+ /* \u2500\u2500 State: thinking \u2500\u2500 */
225
+ .vw-orb.thinking {
226
+ background: radial-gradient(circle at 30% 30%, #fff,
227
+ rgba(var(--vw-color-thinking), .35) 35%,
228
+ rgba(var(--vw-color-thinking), .7) 70%,
229
+ rgba(var(--vw-color-thinking), 1));
230
+ box-shadow: 0 1px 0 rgba(255, 255, 255, .9) inset,
231
+ 0 14px 40px -10px rgba(0, 0, 0, .2),
232
+ 0 0 24px rgba(var(--vw-color-thinking), .25);
233
+ animation: vw-think-pulse 1.6s ease-in-out infinite;
234
+ }
235
+ .vw-orb.thinking::after,
236
+ .vw-orb.thinking::before { border-color: rgba(var(--vw-color-thinking), .25); }
237
+
238
+ @keyframes vw-think-pulse {
239
+ 0%, 100% { transform: scale(1); opacity: 1; }
240
+ 50% { transform: scale(1.03); opacity: .85; }
241
+ }
242
+
243
+ /* \u2500\u2500 State: idle warning \u2500\u2500 */
244
+ .vw-orb.idle-warning {
245
+ background: radial-gradient(circle at 30% 30%, #fff,
246
+ rgba(var(--vw-color-warning), .35) 35%,
247
+ rgba(var(--vw-color-warning), .7) 70%,
248
+ rgba(var(--vw-color-warning), 1));
249
+ box-shadow: 0 1px 0 rgba(255, 255, 255, .9) inset,
250
+ 0 14px 40px -10px rgba(0, 0, 0, .2),
251
+ 0 0 30px rgba(var(--vw-color-warning), .35);
252
+ animation: vw-warning-blink .6s ease-in-out infinite;
253
+ }
254
+ .vw-orb.idle-warning::after,
255
+ .vw-orb.idle-warning::before { border-color: rgba(var(--vw-color-warning), .4); }
256
+
257
+ @keyframes vw-warning-blink {
258
+ 0%, 100% { opacity: 1; transform: scale(1); }
259
+ 50% { opacity: .55; transform: scale(.96); }
260
+ }
261
+
262
+ /* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
263
+ SPEECH BUBBLE \u2014 single bubble floating above orb
264
+ Like Apple notification banners \u2014 floats to the left
265
+ \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */
266
+
267
+ .vw-bubble {
268
+ position: absolute;
269
+ bottom: 12px;
270
+ right: 76px;
271
+ width: max-content;
272
+ max-width: 300px;
273
+ min-width: 120px;
274
+ padding: 10px 16px;
275
+ font-size: 13.5px;
276
+ line-height: 1.5;
277
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
278
+ word-break: break-word;
279
+ animation: vw-bubble-in .2s ease-out;
280
+ pointer-events: none;
281
+ z-index: 1;
282
+ }
283
+
284
+ /* Tail pointer \u2192 points right toward the orb */
285
+ .vw-bubble::after {
286
+ content: "";
287
+ position: absolute;
288
+ top: 50%;
289
+ right: -6px;
290
+ margin-top: -6px;
291
+ width: 12px;
292
+ height: 12px;
293
+ transform: rotate(45deg);
294
+ border-radius: 0 3px 0 0;
295
+ }
296
+
297
+ @keyframes vw-bubble-in {
298
+ from { opacity: 0; transform: translateY(8px); }
299
+ to { opacity: 1; transform: translateY(0); }
300
+ }
301
+
302
+ /* User bubble \u2014 accent glass */
303
+ .vw-bubble.vw-bubble--user {
304
+ background: rgba(var(--vw-color-accent), .15);
305
+ border: 1px solid rgba(var(--vw-color-accent), .25);
306
+ color: var(--vw-bubble-user-color);
307
+ border-radius: 14px 14px 4px 14px;
308
+ backdrop-filter: blur(12px);
309
+ -webkit-backdrop-filter: blur(12px);
310
+ box-shadow: 0 8px 32px -8px rgba(var(--vw-color-accent), .2);
311
+ }
312
+ .vw-bubble.vw-bubble--user::after {
313
+ background: rgba(var(--vw-color-accent), .15);
314
+ border-top: 1px solid rgba(var(--vw-color-accent), .25);
315
+ border-right: 1px solid rgba(var(--vw-color-accent), .25);
316
+ }
317
+
318
+ .vw-bubble.vw-bubble--user.vw-interim {
319
+ opacity: .5;
320
+ border-style: dashed;
321
+ }
322
+ .vw-bubble.vw-bubble--user.vw-interim::after {
323
+ border-style: dashed;
324
+ }
325
+
326
+ /* Bot bubble \u2014 dark frosted glass */
327
+ .vw-bubble.vw-bubble--bot {
328
+ background: var(--vw-bubble-bot-bg);
329
+ border: 1px solid rgba(255, 255, 255, .1);
330
+ color: var(--vw-bubble-bot-color);
331
+ border-radius: 14px 14px 14px 4px;
332
+ backdrop-filter: blur(16px);
333
+ -webkit-backdrop-filter: blur(16px);
334
+ box-shadow: 0 8px 32px -8px rgba(0, 0, 0, .4);
335
+ }
336
+ .vw-bubble.vw-bubble--bot::after {
337
+ background: var(--vw-bubble-bot-bg);
338
+ border-top: 1px solid rgba(255, 255, 255, .1);
339
+ border-right: 1px solid rgba(255, 255, 255, .1);
340
+ }
341
+
342
+ .vw-bubble.vw-bubble--bot.vw-speaking {
343
+ border-color: rgba(var(--vw-color-speaking), .25);
344
+ box-shadow: 0 8px 32px -8px rgba(var(--vw-color-speaking), .15);
345
+ }
346
+ .vw-bubble.vw-bubble--bot.vw-speaking::after {
347
+ border-color: rgba(var(--vw-color-speaking), .25);
348
+ }
349
+
350
+ .vw-bubble.vw-bubble--bot.vw-interrupted {
351
+ opacity: .45;
352
+ text-decoration: line-through;
353
+ text-decoration-color: rgba(255, 107, 178, .4);
354
+ }
355
+
356
+ /* Typing dots */
357
+ .vw-dots { display: inline-flex; gap: 4px; align-items: center; height: 18px; }
358
+ .vw-dots span {
359
+ width: 5px; height: 5px; border-radius: 999px;
360
+ background: rgba(255, 255, 255, .35);
361
+ animation: vw-dot-bounce .6s ease-in-out infinite;
362
+ }
363
+ .vw-dots span:nth-child(2) { animation-delay: .12s; }
364
+ .vw-dots span:nth-child(3) { animation-delay: .24s; }
365
+
366
+ @keyframes vw-dot-bounce {
367
+ 0%, 100% { transform: translateY(0); opacity: .3; }
368
+ 50% { transform: translateY(-4px); opacity: 1; }
369
+ }
370
+
371
+ /* Tool indicator \u2014 shown during tool execution */
372
+ .vw-tool-indicator {
373
+ display: inline-flex;
374
+ align-items: center;
375
+ gap: 6px;
376
+ font-size: 12px;
377
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
378
+ color: rgba(var(--vw-color-thinking), 1);
379
+ }
380
+ .vw-tool-indicator .vw-tool-icon { font-size: 14px; }
381
+ .vw-tool-indicator .vw-tool-name {
382
+ opacity: .85;
383
+ font-weight: 500;
384
+ letter-spacing: .01em;
385
+ }
386
+ .vw-tool-indicator .vw-dots { height: 14px; }
387
+ .vw-tool-indicator .vw-dots span {
388
+ width: 4px; height: 4px;
389
+ background: rgba(var(--vw-color-thinking), .6);
390
+ }
391
+
392
+ /* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
393
+ TRANSCRIPT PANEL \u2014 expandable conversation view
394
+ \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */
395
+
396
+ .vw-tp-btn {
397
+ position: absolute;
398
+ right: 72px;
399
+ bottom: 16px;
400
+ width: 32px;
401
+ height: 32px;
402
+ border-radius: 999px;
403
+ border: 1px solid rgba(255, 255, 255, .1);
404
+ background: rgba(24, 24, 24, .8);
405
+ backdrop-filter: blur(8px);
406
+ -webkit-backdrop-filter: blur(8px);
407
+ color: rgba(255, 255, 255, .6);
408
+ cursor: pointer;
409
+ display: flex;
410
+ align-items: center;
411
+ justify-content: center;
412
+ transition: all .15s;
413
+ font-size: 14px;
414
+ z-index: 2;
415
+ }
416
+
417
+ .vw-tp-btn:hover {
418
+ border-color: rgba(255, 255, 255, .25);
419
+ color: #fff;
420
+ transform: scale(1.08);
421
+ }
422
+
423
+ /* Panel */
424
+ .vw-tp {
425
+ position: absolute;
426
+ right: 0;
427
+ bottom: 80px;
428
+ width: 320px;
429
+ max-height: 400px;
430
+ background: var(--vw-panel-bg);
431
+ border: 1px solid var(--vw-panel-border);
432
+ border-radius: 16px;
433
+ backdrop-filter: blur(20px);
434
+ -webkit-backdrop-filter: blur(20px);
435
+ box-shadow: 0 20px 60px -15px rgba(0, 0, 0, .5);
436
+ display: flex;
437
+ flex-direction: column;
438
+ overflow: hidden;
439
+ animation: vw-panel-in .2s ease-out;
440
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
441
+ z-index: 3;
442
+ }
443
+
444
+ @keyframes vw-panel-in {
445
+ from { opacity: 0; transform: translateY(10px) scale(.97); }
446
+ to { opacity: 1; transform: translateY(0) scale(1); }
447
+ }
448
+
449
+ /* Panel header */
450
+ .vw-tp-head {
451
+ display: flex;
452
+ align-items: center;
453
+ justify-content: space-between;
454
+ padding: 12px 16px;
455
+ border-bottom: 1px solid rgba(255, 255, 255, .06);
456
+ }
457
+
458
+ .vw-tp-title {
459
+ font-size: 11px;
460
+ font-weight: 600;
461
+ letter-spacing: .06em;
462
+ text-transform: uppercase;
463
+ color: rgba(255, 255, 255, .5);
464
+ }
465
+
466
+ .vw-tp-close {
467
+ width: 22px; height: 22px;
468
+ border-radius: 999px;
469
+ border: 1px solid rgba(255, 255, 255, .1);
470
+ background: transparent;
471
+ color: rgba(255, 255, 255, .4);
472
+ cursor: pointer;
473
+ display: flex;
474
+ align-items: center;
475
+ justify-content: center;
476
+ font-size: 11px;
477
+ transition: all .15s;
478
+ }
479
+ .vw-tp-close:hover { border-color: rgba(255, 255, 255, .3); color: #fff; }
480
+
481
+ /* Panel body \u2014 scrollable */
482
+ .vw-tp-body {
483
+ flex: 1;
484
+ overflow-y: auto;
485
+ padding: 12px 14px;
486
+ display: flex;
487
+ flex-direction: column;
488
+ gap: 8px;
489
+ scrollbar-width: thin;
490
+ scrollbar-color: rgba(255,255,255,.08) transparent;
491
+ }
492
+ .vw-tp-body::-webkit-scrollbar { width: 4px; }
493
+ .vw-tp-body::-webkit-scrollbar-track { background: transparent; }
494
+ .vw-tp-body::-webkit-scrollbar-thumb { background: rgba(255,255,255,.1); border-radius: 4px; }
495
+
496
+ /* Message in panel */
497
+ .vw-tp-msg {
498
+ max-width: 85%;
499
+ padding: 8px 12px;
500
+ border-radius: 12px;
501
+ font-size: 13px;
502
+ line-height: 1.45;
503
+ animation: vw-bubble-in .15s ease-out;
504
+ }
505
+
506
+ .vw-tp-msg--user {
507
+ align-self: flex-end;
508
+ background: rgba(var(--vw-color-accent), .15);
509
+ border: 1px solid rgba(var(--vw-color-accent), .2);
510
+ color: var(--vw-bubble-user-color);
511
+ border-radius: 12px 12px 4px 12px;
512
+ }
513
+
514
+ .vw-tp-msg--user.vw-interim {
515
+ opacity: .5;
516
+ border-style: dashed;
517
+ }
518
+
519
+ .vw-tp-msg--bot {
520
+ align-self: flex-start;
521
+ background: rgba(255, 255, 255, .04);
522
+ border: 1px solid rgba(255, 255, 255, .06);
523
+ color: #d4d0e0;
524
+ border-radius: 12px 12px 12px 4px;
525
+ }
526
+
527
+ .vw-tp-msg--bot.vw-speaking {
528
+ border-color: rgba(var(--vw-color-speaking), .15);
529
+ }
530
+
531
+ .vw-tp-msg--bot.vw-interrupted {
532
+ opacity: .45;
533
+ }
534
+
535
+ .vw-tp-msg--system {
536
+ align-self: center;
537
+ max-width: 90%;
538
+ background: rgba(255, 255, 255, .03);
539
+ border: 1px solid rgba(255, 255, 255, .06);
540
+ color: rgba(255, 255, 255, .4);
541
+ border-radius: 8px;
542
+ font-size: 11.5px;
543
+ padding: 5px 12px;
544
+ text-align: center;
545
+ letter-spacing: .02em;
546
+ }
547
+
548
+ /* Empty state */
549
+ .vw-tp-empty {
550
+ text-align: center;
551
+ color: rgba(255, 255, 255, .25);
552
+ font-size: 12px;
553
+ padding: 40px 20px;
554
+ letter-spacing: .02em;
555
+ }
556
+
557
+ /* Tool UI \u2014 rendered inline in transcript */
558
+ .vw-tp-tool {
559
+ padding: 4px 0;
560
+ animation: vw-bubble-in .2s ease-out;
561
+ }
562
+
563
+ /* \u2500\u2500 Mobile \u2500\u2500 */
564
+ @media (max-width: 768px) {
565
+ .vw-wrap { right: 16px; bottom: 16px; }
566
+ .vw-orb { width: 52px; height: 52px; }
567
+ .vw-label { display: none; }
568
+ .vw-bubble { bottom: 68px; max-width: 220px; font-size: 12px; }
569
+ .vw-tp { width: 280px; max-height: 320px; bottom: 68px; }
570
+ .vw-tp-btn { right: 60px; }
571
+ .vw-lang-bar { bottom: 64px; }
572
+ }
573
+
574
+ /* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
575
+ LANGUAGE SELECTOR \u2014 pill bar above the orb
576
+ Hidden by default, shown on hover or during active call
577
+ \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */
578
+
579
+ .vw-lang-bar {
580
+ position: absolute;
581
+ bottom: 76px;
582
+ right: 0;
583
+ display: flex;
584
+ gap: 4px;
585
+ padding: 4px;
586
+ background: rgba(16, 14, 20, .75);
587
+ backdrop-filter: blur(12px);
588
+ -webkit-backdrop-filter: blur(12px);
589
+ border: 1px solid rgba(255, 255, 255, .08);
590
+ border-radius: 999px;
591
+ z-index: 2;
592
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
593
+
594
+ /* Hidden by default \u2014 revealed on hover */
595
+ opacity: 0;
596
+ pointer-events: none;
597
+ transform: translateY(4px);
598
+ transition: opacity .2s ease, transform .2s ease;
599
+ }
600
+
601
+ /* Show on hover (pre-call) */
602
+ .vw-wrap:hover .vw-lang-bar {
603
+ opacity: 1;
604
+ pointer-events: auto;
605
+ transform: translateY(0);
606
+ }
607
+
608
+ /* Always visible during active call */
609
+ .vw-wrap.is-live .vw-lang-bar {
610
+ opacity: 1;
611
+ pointer-events: auto;
612
+ transform: translateY(0);
613
+ }
614
+
615
+ .vw-lang-pill {
616
+ display: flex;
617
+ align-items: center;
618
+ gap: 4px;
619
+ padding: 5px 10px;
620
+ border-radius: 999px;
621
+ border: 1px solid transparent;
622
+ background: transparent;
623
+ color: rgba(255, 255, 255, .5);
624
+ font-size: 11px;
625
+ font-weight: 500;
626
+ cursor: pointer;
627
+ transition: all .15s ease;
628
+ white-space: nowrap;
629
+ letter-spacing: .02em;
630
+ }
631
+
632
+ .vw-lang-pill:hover {
633
+ color: rgba(255, 255, 255, .8);
634
+ background: rgba(255, 255, 255, .06);
635
+ }
636
+
637
+ .vw-lang-pill--active {
638
+ background: rgba(var(--vw-color-accent), .2);
639
+ border-color: rgba(var(--vw-color-accent), .3);
640
+ color: #fff;
641
+ font-weight: 600;
642
+ }
643
+
644
+ .vw-lang-pill--active:hover {
645
+ background: rgba(var(--vw-color-accent), .25);
646
+ }
647
+
648
+ .vw-lang-flag {
649
+ font-size: 14px;
650
+ line-height: 1;
651
+ }
652
+
653
+ .vw-lang-code {
654
+ line-height: 1;
655
+ }
656
+ `
657
+ );
658
+
659
+ // src/widget/presets.ts
660
+ var dark = {
661
+ orbFrom: "255, 255, 255",
662
+ orbMid: "240, 238, 231",
663
+ orbTo: "184, 181, 168",
664
+ colorConnecting: "245, 158, 11",
665
+ colorActive: "76, 175, 80",
666
+ colorUserSpeaking: "52, 211, 153",
667
+ colorSpeaking: "248, 113, 113",
668
+ colorThinking: "139, 92, 246",
669
+ colorWarning: "255, 160, 0",
670
+ colorAccent: "124, 58, 237",
671
+ ringColor: "216, 65, 44",
672
+ panelBg: "rgba(16, 14, 20, .92)",
673
+ panelBorder: "rgba(255, 255, 255, .08)",
674
+ bubbleBotBg: "rgba(18, 16, 22, .9)",
675
+ bubbleBotColor: "#e8e4f0",
676
+ bubbleUserColor: "#e0d4f7",
677
+ labelBg: "#181818",
678
+ labelColor: "#fff"
679
+ };
680
+ var midnight = {
681
+ orbFrom: "190, 210, 255",
682
+ orbMid: "90, 120, 200",
683
+ orbTo: "40, 55, 130",
684
+ colorConnecting: "100, 180, 255",
685
+ colorActive: "60, 200, 180",
686
+ colorUserSpeaking: "80, 220, 200",
687
+ colorSpeaking: "140, 160, 255",
688
+ colorThinking: "100, 120, 240",
689
+ colorWarning: "255, 180, 60",
690
+ colorAccent: "100, 140, 255",
691
+ ringColor: "70, 110, 210",
692
+ panelBg: "rgba(10, 15, 35, .94)",
693
+ panelBorder: "rgba(100, 140, 255, .12)",
694
+ bubbleBotBg: "rgba(15, 20, 45, .92)",
695
+ bubbleBotColor: "#c8d0f0",
696
+ bubbleUserColor: "#b8c8ff",
697
+ labelBg: "rgba(15, 20, 40, .92)",
698
+ labelColor: "#c8d4ff"
699
+ };
700
+ var aurora = {
701
+ orbFrom: "170, 255, 215",
702
+ orbMid: "60, 190, 150",
703
+ orbTo: "20, 130, 90",
704
+ colorConnecting: "255, 200, 60",
705
+ colorActive: "50, 220, 140",
706
+ colorUserSpeaking: "100, 240, 180",
707
+ colorSpeaking: "180, 100, 255",
708
+ colorThinking: "140, 80, 220",
709
+ colorWarning: "255, 200, 60",
710
+ colorAccent: "50, 200, 140",
711
+ ringColor: "40, 170, 110",
712
+ panelBg: "rgba(8, 20, 14, .94)",
713
+ panelBorder: "rgba(50, 200, 140, .1)",
714
+ bubbleBotBg: "rgba(10, 25, 18, .92)",
715
+ bubbleBotColor: "#c0ecd4",
716
+ bubbleUserColor: "#a8e8c4",
717
+ labelBg: "rgba(10, 24, 16, .92)",
718
+ labelColor: "#a8e8c4"
719
+ };
720
+ var sunset = {
721
+ orbFrom: "255, 215, 190",
722
+ orbMid: "235, 140, 90",
723
+ orbTo: "195, 70, 50",
724
+ colorConnecting: "255, 180, 60",
725
+ colorActive: "240, 160, 80",
726
+ colorUserSpeaking: "255, 200, 100",
727
+ colorSpeaking: "255, 100, 80",
728
+ colorThinking: "240, 140, 100",
729
+ colorWarning: "255, 180, 40",
730
+ colorAccent: "240, 120, 60",
731
+ ringColor: "215, 95, 45",
732
+ panelBg: "rgba(25, 12, 8, .94)",
733
+ panelBorder: "rgba(240, 120, 60, .1)",
734
+ bubbleBotBg: "rgba(30, 16, 10, .92)",
735
+ bubbleBotColor: "#f0d4c0",
736
+ bubbleUserColor: "#ffd8b4",
737
+ labelBg: "rgba(28, 14, 10, .92)",
738
+ labelColor: "#f0d0b0"
739
+ };
740
+ var light = {
741
+ orbFrom: "255, 255, 255",
742
+ orbMid: "225, 230, 245",
743
+ orbTo: "190, 200, 225",
744
+ colorConnecting: "230, 140, 10",
745
+ colorActive: "34, 150, 60",
746
+ colorUserSpeaking: "20, 170, 110",
747
+ colorSpeaking: "210, 50, 50",
748
+ colorThinking: "100, 60, 200",
749
+ colorWarning: "230, 140, 10",
750
+ colorAccent: "80, 40, 200",
751
+ ringColor: "100, 120, 200",
752
+ panelBg: "rgba(255, 255, 255, .95)",
753
+ panelBorder: "rgba(0, 0, 0, .08)",
754
+ bubbleBotBg: "rgba(245, 245, 250, .95)",
755
+ bubbleBotColor: "#2a2a3a",
756
+ bubbleUserColor: "#3a2a5a",
757
+ labelBg: "rgba(255, 255, 255, .92)",
758
+ labelColor: "#333"
759
+ };
760
+ var PRESETS = {
761
+ dark,
762
+ midnight,
763
+ aurora,
764
+ sunset,
765
+ light
766
+ };
767
+ var VoiceContext = createContext(null);
768
+ function useVoice() {
769
+ const ctx = useContext(VoiceContext);
770
+ if (!ctx) throw new Error("useVoice() must be used inside <VoiceWidget>");
771
+ return ctx;
772
+ }
773
+ var THEME_VAR_MAP = {
774
+ orbFrom: "--vw-orb-from",
775
+ orbMid: "--vw-orb-mid",
776
+ orbTo: "--vw-orb-to",
777
+ colorConnecting: "--vw-color-connecting",
778
+ colorActive: "--vw-color-active",
779
+ colorUserSpeaking: "--vw-color-user-speaking",
780
+ colorSpeaking: "--vw-color-speaking",
781
+ colorThinking: "--vw-color-thinking",
782
+ colorWarning: "--vw-color-warning",
783
+ colorAccent: "--vw-color-accent",
784
+ ringColor: "--vw-ring-color",
785
+ panelBg: "--vw-panel-bg",
786
+ panelBorder: "--vw-panel-border",
787
+ bubbleBotBg: "--vw-bubble-bot-bg",
788
+ bubbleBotColor: "--vw-bubble-bot-color",
789
+ bubbleUserColor: "--vw-bubble-user-color",
790
+ labelBg: "--vw-label-bg",
791
+ labelColor: "--vw-label-color"
792
+ };
793
+ function fmt(s) {
794
+ return `${Math.floor(s / 60)}:${(s % 60).toString().padStart(2, "0")}`;
795
+ }
796
+ function Dots() {
797
+ return /* @__PURE__ */ jsxs("span", { className: "vw-dots", children: [
798
+ /* @__PURE__ */ jsx("span", {}),
799
+ /* @__PURE__ */ jsx("span", {}),
800
+ /* @__PURE__ */ jsx("span", {})
801
+ ] });
802
+ }
803
+ function ThinkingIndicator({ toolCalls }) {
804
+ const pending = toolCalls.find((tc) => tc.result === void 0);
805
+ if (pending) {
806
+ return /* @__PURE__ */ jsxs("span", { className: "vw-tool-indicator", children: [
807
+ /* @__PURE__ */ jsx("span", { className: "vw-tool-icon", children: "\u{1F527}" }),
808
+ " ",
809
+ /* @__PURE__ */ jsx("span", { className: "vw-tool-name", children: pending.name }),
810
+ /* @__PURE__ */ jsx(Dots, {})
811
+ ] });
812
+ }
813
+ return /* @__PURE__ */ jsx(Dots, {});
814
+ }
815
+ function VoiceWidget({
816
+ agent,
817
+ server,
818
+ name = "Agent",
819
+ label,
820
+ config: userConfig,
821
+ metadata,
822
+ className,
823
+ preset = "dark",
824
+ theme,
825
+ onStatusChange,
826
+ tools,
827
+ trackedTools: trackedToolsProp,
828
+ languages,
829
+ defaultLanguage,
830
+ onLanguageChange,
831
+ tokenProvider,
832
+ children
833
+ }) {
834
+ const hasLanguages = languages && Object.keys(languages).length >= 2;
835
+ const langKeys = hasLanguages ? Object.keys(languages) : [];
836
+ const initialLang = defaultLanguage || (langKeys[0] ?? "");
837
+ const [selectedLang, setSelectedLang] = useState(initialLang);
838
+ const mergedConfig = useMemo(() => {
839
+ const langPreset = languages?.[selectedLang];
840
+ const langConfig = {};
841
+ if (langPreset?.voice) langConfig.voice = langPreset.voice;
842
+ if (langPreset?.stt) langConfig.stt = langPreset.stt;
843
+ if (langPreset?.language) langConfig.language = langPreset.language;
844
+ return { ...langConfig, ...userConfig };
845
+ }, [selectedLang, languages, userConfig]);
846
+ const trackedTools = useMemo(
847
+ () => trackedToolsProp ?? (tools ? Object.keys(tools) : void 0),
848
+ [tools, trackedToolsProp]
849
+ );
850
+ const session = useVoiceSession({
851
+ server,
852
+ agent,
853
+ config: Object.keys(mergedConfig).length > 0 ? mergedConfig : void 0,
854
+ metadata,
855
+ trackedTools,
856
+ tokenProvider
857
+ });
858
+ const [panelOpen, setPanelOpen] = useState(false);
859
+ const themeStyle = useMemo(() => {
860
+ const base = PRESETS[preset] ?? PRESETS.dark;
861
+ const merged = { ...base, ...theme };
862
+ const vars = {};
863
+ for (const [key, cssVar] of Object.entries(THEME_VAR_MAP)) {
864
+ const val = merged[key];
865
+ if (val !== void 0) vars[cssVar] = val;
866
+ }
867
+ return Object.keys(vars).length > 0 ? vars : void 0;
868
+ }, [preset, theme]);
869
+ const scrollRef = useRef(null);
870
+ useEffect(() => {
871
+ if (document.getElementById("vw-styles")) return;
872
+ const el = document.createElement("style");
873
+ el.id = "vw-styles";
874
+ el.textContent = WIDGET_CSS;
875
+ document.head.appendChild(el);
876
+ }, []);
877
+ useEffect(() => {
878
+ onStatusChange?.(session.status);
879
+ }, [session.status, onStatusChange]);
880
+ useEffect(() => {
881
+ if (scrollRef.current) {
882
+ scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
883
+ }
884
+ }, [session.messages, session.toolCalls]);
885
+ useEffect(() => {
886
+ if (!tools) return;
887
+ const hasRenderable = session.toolCalls.some(
888
+ (tc) => tc.result !== void 0 && tools[tc.name]
889
+ );
890
+ if (hasRenderable && !panelOpen) {
891
+ setPanelOpen(true);
892
+ }
893
+ }, [session.toolCalls, tools]);
894
+ const handleLanguageChange = useCallback(
895
+ (lang) => {
896
+ if (lang === selectedLang) return;
897
+ setSelectedLang(lang);
898
+ const preset2 = languages?.[lang];
899
+ if (!preset2) return;
900
+ const cfg = {};
901
+ if (preset2.voice) cfg.voice = preset2.voice;
902
+ if (preset2.stt) cfg.stt = preset2.stt;
903
+ if (preset2.language) cfg.language = preset2.language;
904
+ if (session.status === "connected" && Object.keys(cfg).length > 0) {
905
+ session.configure(cfg);
906
+ } else {
907
+ session.updateOptions({ config: { ...cfg, ...userConfig } });
908
+ }
909
+ onLanguageChange?.(lang, preset2);
910
+ },
911
+ [selectedLang, languages, session, userConfig, onLanguageChange]
912
+ );
913
+ const handleClick = useCallback(async () => {
914
+ if (session.status === "connected") {
915
+ session.disconnect();
916
+ setPanelOpen(false);
917
+ } else if (session.status === "idle" || session.status === "error") {
918
+ await session.connect();
919
+ }
920
+ }, [session]);
921
+ const isActive = session.status === "connected";
922
+ const idleLabel = label || `Talk to ${name}`;
923
+ const orbState = session.agentSpeaking ? "speaking" : session.userSpeaking ? "user-speaking" : session.phase === "thinking" ? "thinking" : session.idleWarning != null ? "idle-warning" : isActive ? "active" : session.status === "connecting" ? "connecting" : "";
924
+ const statusLabel = (() => {
925
+ if (session.status === "connecting") return "Connecting";
926
+ if (session.status === "error") return session.error || "Connection failed";
927
+ if (!isActive) return idleLabel;
928
+ return `${name} \xB7 ${fmt(session.duration)}`;
929
+ })();
930
+ const hasPendingTools = session.toolCalls.some((tc) => tc.result === void 0);
931
+ const activeBubble = [...session.messages].reverse().find(
932
+ (m2) => m2.role === "user" || m2.role === "bot" && (m2.text || hasPendingTools)
933
+ );
934
+ const showBubble = isActive && activeBubble && !panelOpen;
935
+ const showTranscriptBtn = isActive && session.messages.length > 0;
936
+ const widget = /* @__PURE__ */ jsxs(
937
+ "div",
938
+ {
939
+ className: `vw-wrap ${isActive ? "is-live" : ""} ${className || ""}`,
940
+ style: themeStyle,
941
+ children: [
942
+ hasLanguages && /* @__PURE__ */ jsx("div", { className: "vw-lang-bar", children: langKeys.map((key) => {
943
+ const lp = languages[key];
944
+ const isSelected = key === selectedLang;
945
+ return /* @__PURE__ */ jsxs(
946
+ "button",
947
+ {
948
+ className: `vw-lang-pill ${isSelected ? "vw-lang-pill--active" : ""}`,
949
+ onClick: () => handleLanguageChange(key),
950
+ "aria-label": lp.label || key,
951
+ "aria-pressed": isSelected,
952
+ children: [
953
+ lp.flag && /* @__PURE__ */ jsx("span", { className: "vw-lang-flag", children: lp.flag }),
954
+ /* @__PURE__ */ jsx("span", { className: "vw-lang-code", children: lp.label || key.toUpperCase() })
955
+ ]
956
+ },
957
+ key
958
+ );
959
+ }) }),
960
+ /* @__PURE__ */ jsx("div", { className: "vw-label", children: statusLabel }),
961
+ showBubble && /* @__PURE__ */ jsx(
962
+ "div",
963
+ {
964
+ className: `vw-bubble ${activeBubble.role === "user" ? "vw-bubble--user" : "vw-bubble--bot"} ${activeBubble.isInterim ? "vw-interim" : ""} ${activeBubble.speaking ? "vw-speaking" : ""} ${activeBubble.interrupted ? "vw-interrupted" : ""}`,
965
+ children: activeBubble.text || /* @__PURE__ */ jsx(ThinkingIndicator, { toolCalls: session.toolCalls })
966
+ },
967
+ activeBubble.id
968
+ ),
969
+ showTranscriptBtn && /* @__PURE__ */ jsx(
970
+ "button",
971
+ {
972
+ className: "vw-tp-btn",
973
+ onClick: () => setPanelOpen((p) => !p),
974
+ "aria-label": panelOpen ? "Close transcript" : "Open transcript",
975
+ children: panelOpen ? "\u2715" : "\u2630"
976
+ }
977
+ ),
978
+ panelOpen && /* @__PURE__ */ jsxs("div", { className: "vw-tp", children: [
979
+ /* @__PURE__ */ jsxs("div", { className: "vw-tp-head", children: [
980
+ /* @__PURE__ */ jsxs("div", { className: "vw-tp-title", children: [
981
+ "Transcript \xB7 ",
982
+ fmt(session.duration)
983
+ ] }),
984
+ /* @__PURE__ */ jsx(
985
+ "button",
986
+ {
987
+ className: "vw-tp-close",
988
+ onClick: () => setPanelOpen(false),
989
+ children: "\u2715"
990
+ }
991
+ )
992
+ ] }),
993
+ /* @__PURE__ */ jsxs("div", { className: "vw-tp-body", ref: scrollRef, children: [
994
+ session.messages.length === 0 ? /* @__PURE__ */ jsx("div", { className: "vw-tp-empty", children: "Waiting for conversation\u2026" }) : session.messages.map((msg) => /* @__PURE__ */ jsx(TranscriptMsg, { msg, toolCalls: session.toolCalls }, msg.id)),
995
+ tools && session.toolCalls.filter((tc) => tc.result !== void 0 && tools[tc.name]).map((tc) => /* @__PURE__ */ jsx("div", { className: "vw-tp-tool", children: tools[tc.name](
996
+ tc.result,
997
+ {
998
+ respond: (text) => {
999
+ session.sendText(text);
1000
+ session.dismissTool(tc.toolCallId);
1001
+ },
1002
+ dismiss: () => session.dismissTool(tc.toolCallId)
1003
+ },
1004
+ tc
1005
+ ) }, tc.toolCallId))
1006
+ ] })
1007
+ ] }),
1008
+ /* @__PURE__ */ jsx(
1009
+ "div",
1010
+ {
1011
+ className: `vw-orb ${orbState}`,
1012
+ role: "button",
1013
+ tabIndex: 0,
1014
+ "aria-label": isActive ? "End call" : idleLabel,
1015
+ onClick: handleClick,
1016
+ onKeyDown: (e) => e.key === "Enter" && handleClick()
1017
+ }
1018
+ )
1019
+ ]
1020
+ }
1021
+ );
1022
+ return /* @__PURE__ */ jsxs(VoiceContext.Provider, { value: session, children: [
1023
+ widget,
1024
+ children
1025
+ ] });
1026
+ }
1027
+ function TranscriptMsg({ msg, toolCalls = [] }) {
1028
+ if (msg.role === "system") {
1029
+ return /* @__PURE__ */ jsx("div", { className: "vw-tp-msg vw-tp-msg--system", children: msg.text });
1030
+ }
1031
+ const isUser = msg.role === "user";
1032
+ const hasPending = toolCalls.some((tc) => tc.result === void 0);
1033
+ if (!isUser && !msg.text && (!msg.speaking || hasPending)) return null;
1034
+ const cls = [
1035
+ "vw-tp-msg",
1036
+ isUser ? "vw-tp-msg--user" : "vw-tp-msg--bot",
1037
+ msg.isInterim ? "vw-interim" : "",
1038
+ msg.speaking ? "vw-speaking" : "",
1039
+ msg.interrupted ? "vw-interrupted" : ""
1040
+ ].filter(Boolean).join(" ");
1041
+ return /* @__PURE__ */ jsx("div", { className: cls, children: msg.text || /* @__PURE__ */ jsx(ThinkingIndicator, { toolCalls }) });
1042
+ }
1043
+
1044
+ // src/widget/locales.ts
1045
+ var en = {
1046
+ "hub.title": "How would you like to reach us?",
1047
+ "hub.subtitle": "Choose the option that suits you best",
1048
+ "hub.voice": "Talk to {name}",
1049
+ "hub.voiceDesc": "Live voice assistant",
1050
+ "hub.chat": "Chat with {name}",
1051
+ "hub.chatDesc": "Text chat \u2014 ask anything",
1052
+ "hub.whatsapp": "WhatsApp",
1053
+ "hub.whatsappDesc": "Chat with us instantly",
1054
+ "hub.callMe": "Call me",
1055
+ "hub.callMeDesc": "{name} calls you in seconds",
1056
+ "callMe.title": "We'll call you",
1057
+ "callMe.placeholder": "+1 (555) 123-4567",
1058
+ "callMe.submit": "Call me now",
1059
+ "callMe.formNote": "",
1060
+ "callMe.calling": "Calling...",
1061
+ "callMe.ended": "Call ended",
1062
+ "callMe.error": "Could not connect the call",
1063
+ "callMe.back": "Back"
1064
+ };
1065
+ var es = {
1066
+ "hub.title": "\xBFC\xF3mo prefieres contactarnos?",
1067
+ "hub.subtitle": "Elige la opci\xF3n que m\xE1s te convenga",
1068
+ "hub.voice": "Hablar con {name}",
1069
+ "hub.voiceDesc": "Asistente de voz en vivo",
1070
+ "hub.chat": "Chatear con {name}",
1071
+ "hub.chatDesc": "Chat de texto \u2014 pregunt\xE1 lo que quieras",
1072
+ "hub.whatsapp": "WhatsApp",
1073
+ "hub.whatsappDesc": "Chatea con nosotros al instante",
1074
+ "hub.callMe": "Te llamamos",
1075
+ "hub.callMeDesc": "{name} te llama en segundos",
1076
+ "callMe.title": "Te llamamos",
1077
+ "callMe.placeholder": "+51 987 654 321",
1078
+ "callMe.submit": "Llamarme ahora",
1079
+ "callMe.formNote": "",
1080
+ "callMe.calling": "Llamando...",
1081
+ "callMe.ended": "Llamada finalizada",
1082
+ "callMe.error": "No se pudo conectar la llamada",
1083
+ "callMe.back": "Volver"
1084
+ };
1085
+ var de = {
1086
+ "hub.title": "Wie m\xF6chten Sie uns erreichen?",
1087
+ "hub.subtitle": "W\xE4hlen Sie die passende Option",
1088
+ "hub.voice": "Mit {name} sprechen",
1089
+ "hub.voiceDesc": "Live-Sprachassistent",
1090
+ "hub.chat": "Mit {name} chatten",
1091
+ "hub.chatDesc": "Text-Chat \u2014 fragen Sie alles",
1092
+ "hub.whatsapp": "WhatsApp",
1093
+ "hub.whatsappDesc": "Chatten Sie sofort mit uns",
1094
+ "hub.callMe": "R\xFCckruf",
1095
+ "hub.callMeDesc": "{name} ruft Sie in Sekunden an",
1096
+ "callMe.title": "Wir rufen Sie an",
1097
+ "callMe.placeholder": "+49 170 1234567",
1098
+ "callMe.submit": "Jetzt anrufen",
1099
+ "callMe.formNote": "",
1100
+ "callMe.calling": "Anruf wird verbunden...",
1101
+ "callMe.ended": "Anruf beendet",
1102
+ "callMe.error": "Verbindung fehlgeschlagen",
1103
+ "callMe.back": "Zur\xFCck"
1104
+ };
1105
+ var pt = {
1106
+ "hub.title": "Como prefere nos contactar?",
1107
+ "hub.subtitle": "Escolha a op\xE7\xE3o mais conveniente",
1108
+ "hub.voice": "Falar com {name}",
1109
+ "hub.voiceDesc": "Assistente de voz ao vivo",
1110
+ "hub.chat": "Conversar com {name}",
1111
+ "hub.chatDesc": "Chat de texto \u2014 pergunte o que quiser",
1112
+ "hub.whatsapp": "WhatsApp",
1113
+ "hub.whatsappDesc": "Converse conosco instantaneamente",
1114
+ "hub.callMe": "Ligue-me",
1115
+ "hub.callMeDesc": "{name} liga para voc\xEA em segundos",
1116
+ "callMe.title": "Vamos ligar para voc\xEA",
1117
+ "callMe.placeholder": "+55 11 98765-4321",
1118
+ "callMe.submit": "Ligar agora",
1119
+ "callMe.formNote": "",
1120
+ "callMe.calling": "Ligando...",
1121
+ "callMe.ended": "Chamada encerrada",
1122
+ "callMe.error": "N\xE3o foi poss\xEDvel conectar a chamada",
1123
+ "callMe.back": "Voltar"
1124
+ };
1125
+ var locales = { en, es, de, pt };
1126
+ function t(locale, key, overrides, vars) {
1127
+ const base = locales[locale] ?? locales.en;
1128
+ let str = overrides?.[key] ?? base[key] ?? key;
1129
+ if (vars) {
1130
+ for (const [k, v2] of Object.entries(vars)) {
1131
+ str = str.replace(`{${k}}`, v2);
1132
+ }
1133
+ }
1134
+ return str;
1135
+ }
1136
+
1137
+ // src/widget/hub-styles.ts
1138
+ var HUB_CSS = (
1139
+ /* css */
1140
+ `
1141
+
1142
+ /* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
1143
+ ContactHub \u2014 above-orb contact menu
1144
+ \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */
1145
+
1146
+ /* \u2500\u2500 Backdrop \u2500\u2500 */
1147
+ .vw-hub-backdrop {
1148
+ position: fixed;
1149
+ inset: 0;
1150
+ z-index: 200;
1151
+ background: rgba(0, 0, 0, 0.45);
1152
+ backdrop-filter: blur(6px);
1153
+ -webkit-backdrop-filter: blur(6px);
1154
+ display: flex;
1155
+ align-items: flex-end;
1156
+ justify-content: flex-end;
1157
+ padding: 20px;
1158
+ animation: vwHubFade .2s ease;
1159
+ }
1160
+ @keyframes vwHubFade { from { opacity: 0; } to { opacity: 1; } }
1161
+
1162
+ /* \u2500\u2500 Panel \u2500\u2500 */
1163
+ .vw-hub-panel {
1164
+ position: relative;
1165
+ width: 100%;
1166
+ max-width: 320px;
1167
+ background: var(--vw-panel-bg, rgba(16, 14, 20, .92));
1168
+ border: 1px solid var(--vw-panel-border, rgba(255, 255, 255, .08));
1169
+ border-radius: 20px;
1170
+ padding: 26px 22px 22px;
1171
+ box-shadow: 0 24px 56px -12px rgba(0, 0, 0, 0.5);
1172
+ animation: vwHubUp .25s cubic-bezier(.2,.8,.2,1);
1173
+ margin-bottom: 70px;
1174
+ }
1175
+ .vw-hub-panel--chat {
1176
+ max-width: 400px;
1177
+ padding: 0;
1178
+ overflow: hidden;
1179
+ }
1180
+ @keyframes vwHubUp {
1181
+ from { opacity: 0; transform: translateY(16px) scale(0.96); }
1182
+ to { opacity: 1; transform: translateY(0) scale(1); }
1183
+ }
1184
+
1185
+ /* Close */
1186
+ .vw-hub-close {
1187
+ position: absolute;
1188
+ top: 10px; right: 10px;
1189
+ background: none;
1190
+ border: none;
1191
+ color: rgba(255, 255, 255, .4);
1192
+ cursor: pointer;
1193
+ padding: 6px;
1194
+ border-radius: 50%;
1195
+ transition: color .2s, background .2s;
1196
+ line-height: 1;
1197
+ }
1198
+ .vw-hub-close:hover { color: #fff; background: rgba(255, 255, 255, .06); }
1199
+
1200
+ /* \u2500\u2500 Header \u2500\u2500 */
1201
+ .vw-hub-header { text-align: center; margin-bottom: 16px; }
1202
+ .vw-hub-avatar { font-size: 28px; margin-bottom: 6px; }
1203
+ .vw-hub-header h3 {
1204
+ font-size: 17px;
1205
+ color: #fff;
1206
+ margin: 0 0 3px;
1207
+ font-weight: 500;
1208
+ font-family: inherit;
1209
+ }
1210
+ .vw-hub-header p { font-size: 12px; color: rgba(255, 255, 255, .5); margin: 0; }
1211
+
1212
+ /* \u2500\u2500 Option Cards \u2500\u2500 */
1213
+ .vw-hub-options { display: flex; flex-direction: column; gap: 8px; }
1214
+
1215
+ .vw-hub-opt {
1216
+ display: flex;
1217
+ align-items: center;
1218
+ gap: 12px;
1219
+ padding: 12px 14px;
1220
+ border-radius: 12px;
1221
+ background: rgba(255, 255, 255, .03);
1222
+ border: 1px solid rgba(255, 255, 255, .06);
1223
+ color: #fff;
1224
+ text-decoration: none;
1225
+ cursor: pointer;
1226
+ transition: background .2s, border-color .2s, transform .15s;
1227
+ font-family: inherit;
1228
+ text-align: left;
1229
+ width: 100%;
1230
+ font-size: 14px;
1231
+ }
1232
+ .vw-hub-opt:hover {
1233
+ background: rgba(255, 255, 255, .06);
1234
+ border-color: rgba(255, 255, 255, .1);
1235
+ transform: translateX(2px);
1236
+ }
1237
+
1238
+ .vw-hub-icon {
1239
+ width: 36px; height: 36px;
1240
+ border-radius: 10px;
1241
+ display: grid; place-items: center;
1242
+ flex-shrink: 0;
1243
+ }
1244
+ .vw-hub-icon--voice { background: rgba(124, 58, 237, .15); color: rgba(139, 92, 246, 1); }
1245
+ .vw-hub-icon--wa { background: rgba(34, 197, 94, .15); color: rgba(34, 197, 94, 1); }
1246
+ .vw-hub-icon--call {
1247
+ background: rgba(var(--vw-accent, 124, 58, 237), .12);
1248
+ color: rgba(var(--vw-accent, 124, 58, 237), 1);
1249
+ }
1250
+ .vw-hub-icon--chat { background: rgba(59, 130, 246, .15); color: rgba(96, 165, 250, 1); }
1251
+
1252
+ .vw-hub-body { display: flex; flex-direction: column; gap: 1px; flex: 1; min-width: 0; }
1253
+ .vw-hub-title { font-weight: 600; font-size: 13px; }
1254
+ .vw-hub-desc { font-size: 11px; color: rgba(255, 255, 255, .45); }
1255
+ .vw-hub-arrow { color: rgba(255, 255, 255, .3); font-size: 14px; flex-shrink: 0; }
1256
+
1257
+ /* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
1258
+ Call Me \u2014 form + transcript
1259
+ \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */
1260
+
1261
+ /* \u2500\u2500 Form View \u2500\u2500 */
1262
+ .vw-cm { text-align: center; padding: 4px 0; }
1263
+ .vw-cm-back {
1264
+ background: none; border: none; color: rgba(255, 255, 255, .4);
1265
+ cursor: pointer; font-size: 12px; margin-bottom: 16px;
1266
+ padding: 4px 8px; border-radius: 6px;
1267
+ transition: color .2s; font-family: inherit;
1268
+ }
1269
+ .vw-cm-back:hover { color: #fff; }
1270
+
1271
+ .vw-cm h3 {
1272
+ font-size: 19px;
1273
+ color: #fff; margin: 0 0 6px; font-weight: 500;
1274
+ font-family: inherit;
1275
+ }
1276
+ .vw-cm p {
1277
+ font-size: 12.5px; color: rgba(255, 255, 255, .5);
1278
+ line-height: 1.55; margin: 0 0 18px;
1279
+ }
1280
+
1281
+ .vw-cm-phone-icon {
1282
+ width: 54px; height: 54px; border-radius: 50%;
1283
+ background: linear-gradient(135deg, rgba(var(--vw-accent, 124, 58, 237), .15), rgba(var(--vw-accent, 124, 58, 237), .06));
1284
+ border: 1.5px solid rgba(var(--vw-accent, 124, 58, 237), .3);
1285
+ display: grid; place-items: center;
1286
+ margin: 0 auto 14px;
1287
+ color: rgba(var(--vw-accent, 124, 58, 237), 1);
1288
+ position: relative;
1289
+ }
1290
+ .vw-cm-phone-icon::after {
1291
+ content: '';
1292
+ position: absolute;
1293
+ inset: -6px;
1294
+ border-radius: 50%;
1295
+ border: 1.5px solid rgba(var(--vw-accent, 124, 58, 237), .15);
1296
+ animation: vwCmIconPulse 2.5s ease-in-out infinite;
1297
+ }
1298
+ @keyframes vwCmIconPulse {
1299
+ 0%, 100% { opacity: 0.6; transform: scale(1); }
1300
+ 50% { opacity: 0; transform: scale(1.25); }
1301
+ }
1302
+
1303
+ .vw-cm-form { display: flex; flex-direction: column; gap: 10px; }
1304
+ .vw-cm-form input {
1305
+ width: 100%; padding: 14px 16px; border-radius: 12px;
1306
+ background: rgba(255, 255, 255, .05);
1307
+ border: 1px solid rgba(255, 255, 255, .1);
1308
+ color: #fff; font-family: inherit; font-size: 16px;
1309
+ outline: none; transition: border-color .2s, box-shadow .2s; box-sizing: border-box;
1310
+ letter-spacing: 0.04em;
1311
+ }
1312
+ .vw-cm-form input:focus {
1313
+ border-color: rgba(var(--vw-accent, 124, 58, 237), .7);
1314
+ box-shadow: 0 0 0 3px rgba(var(--vw-accent, 124, 58, 237), .12);
1315
+ }
1316
+ .vw-cm-form input::placeholder { color: rgba(255, 255, 255, .25); letter-spacing: 0.02em; }
1317
+ .vw-cm-form button {
1318
+ display: flex; align-items: center; justify-content: center; gap: 8px;
1319
+ padding: 13px; border-radius: 12px;
1320
+ background: linear-gradient(135deg, rgba(var(--vw-accent, 124, 58, 237), 1), rgba(var(--vw-accent, 124, 58, 237), .8));
1321
+ color: #fff; font-family: inherit;
1322
+ font-weight: 600; font-size: 14px; border: none; cursor: pointer;
1323
+ transition: transform .2s, box-shadow .2s;
1324
+ letter-spacing: 0.01em;
1325
+ }
1326
+ .vw-cm-form button:hover:not(:disabled) {
1327
+ transform: translateY(-1px);
1328
+ box-shadow: 0 10px 28px -6px rgba(var(--vw-accent, 124, 58, 237), .5);
1329
+ }
1330
+ .vw-cm-form button:disabled { opacity: 0.4; cursor: not-allowed; }
1331
+ .vw-cm-error {
1332
+ font-size: 11px; color: rgba(248, 113, 113, 1);
1333
+ padding: 6px 0; line-height: 1.4;
1334
+ }
1335
+ .vw-cm-note {
1336
+ font-size: 10px; color: rgba(255, 255, 255, .3);
1337
+ line-height: 1.45; margin-top: 4px; opacity: 0.7;
1338
+ }
1339
+ .vw-cm-note a { color: rgba(var(--vw-accent, 124, 58, 237), 1); text-decoration: none; }
1340
+
1341
+ /* \u2500\u2500 Dialing Animation (used inside hub before call connects) \u2500\u2500 */
1342
+
1343
+ .vw-cm-dialing {
1344
+ display: flex; flex-direction: column; align-items: center;
1345
+ gap: 14px; padding: 28px 0;
1346
+ }
1347
+ .vw-cm-dialing-ring {
1348
+ width: 60px; height: 60px; border-radius: 50%;
1349
+ background: linear-gradient(135deg, rgba(var(--vw-accent, 124, 58, 237), .12), rgba(var(--vw-accent, 124, 58, 237), .04));
1350
+ border: 2px solid rgba(var(--vw-accent, 124, 58, 237), .3);
1351
+ display: grid; place-items: center;
1352
+ animation: vwCmRing 1.5s ease infinite;
1353
+ color: rgba(var(--vw-accent, 124, 58, 237), 1);
1354
+ position: relative;
1355
+ }
1356
+ .vw-cm-dialing-ring::after {
1357
+ content: '';
1358
+ position: absolute;
1359
+ inset: -8px;
1360
+ border-radius: 50%;
1361
+ border: 2px solid rgba(var(--vw-accent, 124, 58, 237), .2);
1362
+ animation: vwCmDialPulse 1.4s ease-out infinite;
1363
+ }
1364
+ .vw-cm-dialing-ring::before {
1365
+ content: '';
1366
+ position: absolute;
1367
+ inset: -16px;
1368
+ border-radius: 50%;
1369
+ border: 1.5px solid rgba(var(--vw-accent, 124, 58, 237), .1);
1370
+ animation: vwCmDialPulse 1.4s ease-out 0.3s infinite;
1371
+ }
1372
+ @keyframes vwCmRing {
1373
+ 0%, 100% { transform: scale(1); border-color: rgba(var(--vw-accent, 124, 58, 237), .3); }
1374
+ 50% { transform: scale(1.06); border-color: rgba(var(--vw-accent, 124, 58, 237), .6); }
1375
+ }
1376
+ @keyframes vwCmDialPulse {
1377
+ 0% { transform: scale(0.9); opacity: 1; }
1378
+ 100% { transform: scale(1.4); opacity: 0; }
1379
+ }
1380
+ .vw-cm-dialing-text { font-size: 13px; color: rgba(255, 255, 255, .55); font-weight: 500; }
1381
+ .vw-cm-dialing-phone { font-size: 12px; color: rgba(255, 255, 255, .35); letter-spacing: 0.06em; }
1382
+
1383
+ .vw-cm-error-view {
1384
+ display: flex; flex-direction: column; align-items: center;
1385
+ gap: 10px; padding: 24px 0;
1386
+ }
1387
+ .vw-cm-error-text { font-size: 13px; color: rgba(248, 113, 113, .9); text-align: center; line-height: 1.5; }
1388
+
1389
+ /* \u2500\u2500 Mobile \u2500\u2500 */
1390
+ @media (max-width: 640px) {
1391
+ .vw-hub-backdrop { padding: 14px; }
1392
+ .vw-hub-panel { max-width: 100%; margin-bottom: 56px; border-radius: 16px; padding: 22px 18px 18px; }
1393
+
1394
+ /* Chat: fullscreen takeover on mobile */
1395
+ .vw-hub-backdrop:has(.vw-hub-panel--chat) {
1396
+ padding: 0;
1397
+ background: var(--vw-panel-bg, rgba(16, 14, 20, .98));
1398
+ backdrop-filter: none;
1399
+ -webkit-backdrop-filter: none;
1400
+ }
1401
+ .vw-hub-panel--chat {
1402
+ max-width: 100%;
1403
+ height: 100%;
1404
+ margin-bottom: 0;
1405
+ border-radius: 0;
1406
+ border: none;
1407
+ box-shadow: none;
1408
+ }
1409
+ .vw-hub-panel--chat .vw-cv {
1410
+ height: 100%;
1411
+ max-height: 100%;
1412
+ }
1413
+ }
1414
+ `
1415
+ );
1416
+
1417
+ // src/widget/hub-chat-styles.ts
1418
+ var CHAT_VIEW_CSS = `
1419
+ /* \u2500\u2500 ChatView container \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
1420
+ .vw-cv {
1421
+ display: flex;
1422
+ flex-direction: column;
1423
+ height: 480px;
1424
+ max-height: 70vh;
1425
+ }
1426
+
1427
+ /* \u2500\u2500 Header \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
1428
+ .vw-cv-head {
1429
+ display: flex;
1430
+ align-items: center;
1431
+ gap: 10px;
1432
+ padding: 14px 16px;
1433
+ border-bottom: 1px solid rgba(255,255,255,.06);
1434
+ }
1435
+
1436
+ .vw-cv-back {
1437
+ background: none;
1438
+ border: none;
1439
+ color: rgba(255,255,255,.5);
1440
+ cursor: pointer;
1441
+ padding: 4px;
1442
+ border-radius: 6px;
1443
+ transition: color .2s, background .2s;
1444
+ }
1445
+ .vw-cv-back:hover {
1446
+ color: #fff;
1447
+ background: rgba(255,255,255,.08);
1448
+ }
1449
+
1450
+ .vw-cv-avatar {
1451
+ width: 32px;
1452
+ height: 32px;
1453
+ border-radius: 50%;
1454
+ background: linear-gradient(135deg, rgba(var(--vw-color-accent, 197,140,95), .3), rgba(var(--vw-color-accent, 197,140,95), .1));
1455
+ display: flex;
1456
+ align-items: center;
1457
+ justify-content: center;
1458
+ font-size: 14px;
1459
+ font-weight: 600;
1460
+ color: rgb(var(--vw-color-accent, 197,140,95));
1461
+ flex-shrink: 0;
1462
+ }
1463
+
1464
+ .vw-cv-who {
1465
+ flex: 1;
1466
+ min-width: 0;
1467
+ }
1468
+ .vw-cv-name {
1469
+ display: block;
1470
+ font-size: 14px;
1471
+ font-weight: 600;
1472
+ color: #fff;
1473
+ line-height: 1.2;
1474
+ }
1475
+ .vw-cv-status {
1476
+ display: flex;
1477
+ align-items: center;
1478
+ gap: 5px;
1479
+ font-size: 11px;
1480
+ color: rgba(255,255,255,.45);
1481
+ }
1482
+
1483
+ .vw-cv-dot {
1484
+ width: 6px;
1485
+ height: 6px;
1486
+ border-radius: 50%;
1487
+ background: #4ade80;
1488
+ box-shadow: 0 0 6px rgba(74,222,128,.5);
1489
+ flex-shrink: 0;
1490
+ }
1491
+ .vw-cv-dot--off {
1492
+ background: #f59e0b;
1493
+ box-shadow: 0 0 6px rgba(245,158,11,.5);
1494
+ }
1495
+
1496
+ .vw-cv-actions {
1497
+ display: flex;
1498
+ gap: 4px;
1499
+ }
1500
+
1501
+ .vw-cv-action {
1502
+ background: none;
1503
+ border: 1px solid rgba(255,255,255,.08);
1504
+ color: rgba(255,255,255,.45);
1505
+ cursor: pointer;
1506
+ padding: 6px;
1507
+ border-radius: 8px;
1508
+ transition: all .2s;
1509
+ display: flex;
1510
+ align-items: center;
1511
+ justify-content: center;
1512
+ }
1513
+ .vw-cv-action:hover {
1514
+ color: #fff;
1515
+ background: rgba(255,255,255,.08);
1516
+ border-color: rgba(255,255,255,.15);
1517
+ }
1518
+ .vw-cv-action--voice {
1519
+ color: rgb(var(--vw-color-accent, 197,140,95));
1520
+ border-color: rgba(var(--vw-color-accent, 197,140,95), .25);
1521
+ }
1522
+ .vw-cv-action--voice:hover {
1523
+ background: rgba(var(--vw-color-accent, 197,140,95), .12);
1524
+ color: rgb(var(--vw-color-accent, 197,140,95));
1525
+ border-color: rgba(var(--vw-color-accent, 197,140,95), .4);
1526
+ }
1527
+
1528
+ /* \u2500\u2500 Messages body \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
1529
+ .vw-cv-body {
1530
+ flex: 1;
1531
+ overflow-y: auto;
1532
+ padding: 16px;
1533
+ display: flex;
1534
+ flex-direction: column;
1535
+ gap: 10px;
1536
+ scrollbar-width: thin;
1537
+ scrollbar-color: rgba(255,255,255,.1) transparent;
1538
+ }
1539
+
1540
+ .vw-cv-msg {
1541
+ max-width: 85%;
1542
+ padding: 10px 14px;
1543
+ border-radius: 14px;
1544
+ font-size: 13.5px;
1545
+ line-height: 1.5;
1546
+ word-break: break-word;
1547
+ }
1548
+
1549
+ .vw-cv-msg--user {
1550
+ align-self: flex-end;
1551
+ background: rgba(var(--vw-color-accent, 197,140,95), .18);
1552
+ color: rgba(255,255,255,.92);
1553
+ border-bottom-right-radius: 4px;
1554
+ }
1555
+
1556
+ .vw-cv-msg--bot {
1557
+ align-self: flex-start;
1558
+ background: rgba(255,255,255,.05);
1559
+ color: rgba(255,255,255,.85);
1560
+ border-bottom-left-radius: 4px;
1561
+ border: 1px solid rgba(255,255,255,.06);
1562
+ }
1563
+
1564
+ /* Markdown inside bot messages */
1565
+ .vw-cv-md p { margin: 0 0 6px; }
1566
+ .vw-cv-md p:last-child { margin-bottom: 0; }
1567
+ .vw-cv-md strong { color: #fff; font-weight: 600; }
1568
+ .vw-cv-md em { font-style: italic; }
1569
+ .vw-cv-md code {
1570
+ background: rgba(255,255,255,.08);
1571
+ padding: 1px 5px;
1572
+ border-radius: 4px;
1573
+ font-size: 12px;
1574
+ font-family: monospace;
1575
+ }
1576
+ .vw-cv-md a {
1577
+ color: rgb(var(--vw-color-accent, 197,140,95));
1578
+ text-decoration: underline;
1579
+ text-underline-offset: 2px;
1580
+ }
1581
+ .vw-cv-md ul, .vw-cv-md ol {
1582
+ margin: 4px 0;
1583
+ padding-left: 18px;
1584
+ }
1585
+ .vw-cv-md li { margin-bottom: 2px; }
1586
+
1587
+ /* Streaming cursor */
1588
+ .vw-cv-cursor {
1589
+ display: inline-block;
1590
+ width: 2px;
1591
+ height: 14px;
1592
+ background: rgb(var(--vw-color-accent, 197,140,95));
1593
+ margin-left: 2px;
1594
+ vertical-align: text-bottom;
1595
+ animation: vw-cv-blink .8s infinite;
1596
+ }
1597
+
1598
+ @keyframes vw-cv-blink {
1599
+ 0%, 100% { opacity: 1; }
1600
+ 50% { opacity: 0; }
1601
+ }
1602
+
1603
+ /* Typing skeleton */
1604
+ .vw-cv-skeleton {
1605
+ display: flex;
1606
+ gap: 4px;
1607
+ padding: 14px 18px;
1608
+ }
1609
+ .vw-cv-sk-dot {
1610
+ width: 7px;
1611
+ height: 7px;
1612
+ border-radius: 50%;
1613
+ background: rgba(255,255,255,.25);
1614
+ animation: vw-cv-bounce 1.4s infinite ease-in-out;
1615
+ }
1616
+ .vw-cv-sk-dot:nth-child(2) { animation-delay: .16s; }
1617
+ .vw-cv-sk-dot:nth-child(3) { animation-delay: .32s; }
1618
+
1619
+ @keyframes vw-cv-bounce {
1620
+ 0%, 80%, 100% { transform: translateY(0); }
1621
+ 40% { transform: translateY(-5px); }
1622
+ }
1623
+
1624
+ /* Tool calls */
1625
+ .vw-cv-tool {
1626
+ display: flex;
1627
+ align-items: center;
1628
+ gap: 6px;
1629
+ padding: 6px 12px;
1630
+ margin: 2px 0;
1631
+ border-radius: 10px;
1632
+ font-size: 11px;
1633
+ font-family: monospace;
1634
+ background: rgba(167,139,250,.06);
1635
+ border: 1px solid rgba(167,139,250,.15);
1636
+ align-self: center;
1637
+ max-width: 90%;
1638
+ }
1639
+ .vw-cv-tool-icon { font-size: 12px; }
1640
+ .vw-cv-tool-name { color: rgb(167,139,250); font-weight: 600; }
1641
+ .vw-cv-tool-args { color: rgba(255,255,255,.4); font-size: 10px; word-break: break-all; }
1642
+
1643
+ /* \u2500\u2500 Quick options \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
1644
+ .vw-cv-quick {
1645
+ display: flex;
1646
+ flex-wrap: wrap;
1647
+ gap: 6px;
1648
+ padding: 8px 16px;
1649
+ border-top: 1px solid rgba(255,255,255,.04);
1650
+ }
1651
+ .vw-cv-quick button {
1652
+ background: rgba(255,255,255,.05);
1653
+ border: 1px solid rgba(255,255,255,.1);
1654
+ color: rgba(255,255,255,.7);
1655
+ padding: 6px 12px;
1656
+ border-radius: 20px;
1657
+ font-size: 12px;
1658
+ cursor: pointer;
1659
+ transition: all .2s;
1660
+ white-space: nowrap;
1661
+ }
1662
+ .vw-cv-quick button:hover:not(:disabled) {
1663
+ background: rgba(var(--vw-color-accent, 197,140,95), .12);
1664
+ border-color: rgba(var(--vw-color-accent, 197,140,95), .3);
1665
+ color: rgb(var(--vw-color-accent, 197,140,95));
1666
+ }
1667
+ .vw-cv-quick button:disabled {
1668
+ opacity: .4;
1669
+ cursor: default;
1670
+ }
1671
+
1672
+ /* \u2500\u2500 Input bar \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
1673
+ .vw-cv-input {
1674
+ display: flex;
1675
+ gap: 8px;
1676
+ padding: 12px 16px;
1677
+ border-top: 1px solid rgba(255,255,255,.06);
1678
+ }
1679
+ .vw-cv-input input {
1680
+ flex: 1;
1681
+ background: rgba(255,255,255,.05);
1682
+ border: 1px solid rgba(255,255,255,.1);
1683
+ color: #fff;
1684
+ padding: 10px 14px;
1685
+ border-radius: 12px;
1686
+ font-size: 16px; /* \u226516px prevents iOS Safari auto-zoom on focus */
1687
+ outline: none;
1688
+ transition: border-color .2s;
1689
+ }
1690
+ .vw-cv-input input::placeholder {
1691
+ color: rgba(255,255,255,.3);
1692
+ }
1693
+ .vw-cv-input input:focus {
1694
+ border-color: rgba(var(--vw-color-accent, 197,140,95), .4);
1695
+ }
1696
+
1697
+ .vw-cv-send {
1698
+ background: rgb(var(--vw-color-accent, 197,140,95));
1699
+ border: none;
1700
+ color: #fff;
1701
+ width: 38px;
1702
+ height: 38px;
1703
+ border-radius: 10px;
1704
+ cursor: pointer;
1705
+ display: flex;
1706
+ align-items: center;
1707
+ justify-content: center;
1708
+ transition: opacity .2s, transform .15s;
1709
+ flex-shrink: 0;
1710
+ }
1711
+ .vw-cv-send:hover:not(:disabled) {
1712
+ transform: scale(1.05);
1713
+ }
1714
+ .vw-cv-send:disabled {
1715
+ opacity: .3;
1716
+ cursor: default;
1717
+ }
1718
+ `;
1719
+
1720
+ // node_modules/.pnpm/marked@18.0.5/node_modules/marked/lib/marked.esm.js
1721
+ function M() {
1722
+ return { async: false, breaks: false, extensions: null, gfm: true, hooks: null, pedantic: false, renderer: null, silent: false, tokenizer: null, walkTokens: null };
1723
+ }
1724
+ var T = M();
1725
+ function N(l3) {
1726
+ T = l3;
1727
+ }
1728
+ var _ = { exec: () => null };
1729
+ function E(l3) {
1730
+ let e = [];
1731
+ return (t2) => {
1732
+ let n = Math.max(0, Math.min(3, t2 - 1)), s = e[n];
1733
+ return s || (s = l3(n), e[n] = s), s;
1734
+ };
1735
+ }
1736
+ function d(l3, e = "") {
1737
+ let t2 = typeof l3 == "string" ? l3 : l3.source, n = { replace: (s, r) => {
1738
+ let i = typeof r == "string" ? r : r.source;
1739
+ return i = i.replace(m.caret, "$1"), t2 = t2.replace(s, i), n;
1740
+ }, getRegex: () => new RegExp(t2, e) };
1741
+ return n;
1742
+ }
1743
+ var Te = ((l3 = "") => {
1744
+ try {
1745
+ return !!new RegExp("(?<=1)(?<!1)" + l3);
1746
+ } catch {
1747
+ return false;
1748
+ }
1749
+ })();
1750
+ var m = { codeRemoveIndent: /^(?: {1,4}| {0,3}\t)/gm, outputLinkReplace: /\\([\[\]])/g, indentCodeCompensation: /^(\s+)(?:```)/, beginningSpace: /^\s+/, endingHash: /#$/, startingSpaceChar: /^ /, endingSpaceChar: / $/, nonSpaceChar: /[^ ]/, newLineCharGlobal: /\n/g, tabCharGlobal: /\t/g, multipleSpaceGlobal: /\s+/g, blankLine: /^[ \t]*$/, doubleBlankLine: /\n[ \t]*\n[ \t]*$/, blockquoteStart: /^ {0,3}>/, blockquoteSetextReplace: /\n {0,3}((?:=+|-+) *)(?=\n|$)/g, blockquoteSetextReplace2: /^ {0,3}>[ \t]?/gm, listReplaceNesting: /^ {1,4}(?=( {4})*[^ ])/g, listIsTask: /^\[[ xX]\] +\S/, listReplaceTask: /^\[[ xX]\] +/, listTaskCheckbox: /\[[ xX]\]/, anyLine: /\n.*\n/, hrefBrackets: /^<(.*)>$/, tableDelimiter: /[:|]/, tableAlignChars: /^\||\| *$/g, tableRowBlankLine: /\n[ \t]*$/, tableAlignRight: /^ *-+: *$/, tableAlignCenter: /^ *:-+: *$/, tableAlignLeft: /^ *:-+ *$/, startATag: /^<a /i, endATag: /^<\/a>/i, startPreScriptTag: /^<(pre|code|kbd|script)(\s|>)/i, endPreScriptTag: /^<\/(pre|code|kbd|script)(\s|>)/i, startAngleBracket: /^</, endAngleBracket: />$/, pedanticHrefTitle: /^([^'"]*[^\s])\s+(['"])(.*)\2/, unicodeAlphaNumeric: /[\p{L}\p{N}]/u, escapeTest: /[&<>"']/, escapeReplace: /[&<>"']/g, escapeTestNoEncode: /[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/, escapeReplaceNoEncode: /[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/g, caret: /(^|[^\[])\^/g, percentDecode: /%25/g, findPipe: /\|/g, splitPipe: / \|/, slashPipe: /\\\|/g, carriageReturn: /\r\n|\r/g, spaceLine: /^ +$/gm, notSpaceStart: /^\S*/, endingNewline: /\n$/, listItemRegex: (l3) => new RegExp(`^( {0,3}${l3})((?:[ ][^\\n]*)?(?:\\n|$))`), nextBulletRegex: E((l3) => new RegExp(`^ {0,${l3}}(?:[*+-]|\\d{1,9}[.)])((?:[ ][^\\n]*)?(?:\\n|$))`)), hrRegex: E((l3) => new RegExp(`^ {0,${l3}}((?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$)`)), fencesBeginRegex: E((l3) => new RegExp(`^ {0,${l3}}(?:\`\`\`|~~~)`)), headingBeginRegex: E((l3) => new RegExp(`^ {0,${l3}}#`)), htmlBeginRegex: E((l3) => new RegExp(`^ {0,${l3}}<(?:[a-z].*>|!--)`, "i")), blockquoteBeginRegex: E((l3) => new RegExp(`^ {0,${l3}}>`)) };
1751
+ var Oe = /^(?:[ \t]*(?:\n|$))+/;
1752
+ var we = /^((?: {4}| {0,3}\t)[^\n]+(?:\n(?:[ \t]*(?:\n|$))*)?)+/;
1753
+ var ye = /^ {0,3}(`{3,}(?=[^`\n]*(?:\n|$))|~{3,})([^\n]*)(?:\n|$)(?:|([\s\S]*?)(?:\n|$))(?: {0,3}\1[~`]* *(?=\n|$)|$)/;
1754
+ var B = /^ {0,3}((?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/;
1755
+ var Pe = /^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/;
1756
+ var j = / {0,3}(?:[*+-]|\d{1,9}[.)])/;
1757
+ var oe = /^(?!bull |blockCode|fences|blockquote|heading|html|table)((?:.|\n(?!\s*?\n|bull |blockCode|fences|blockquote|heading|html|table))+?)\n {0,3}(=+|-+) *(?:\n+|$)/;
1758
+ var ae = d(oe).replace(/bull/g, j).replace(/blockCode/g, /(?: {4}| {0,3}\t)/).replace(/fences/g, / {0,3}(?:`{3,}|~{3,})/).replace(/blockquote/g, / {0,3}>/).replace(/heading/g, / {0,3}#{1,6}/).replace(/html/g, / {0,3}<[^\n>]+>\n/).replace(/\|table/g, "").getRegex();
1759
+ var Se = d(oe).replace(/bull/g, j).replace(/blockCode/g, /(?: {4}| {0,3}\t)/).replace(/fences/g, / {0,3}(?:`{3,}|~{3,})/).replace(/blockquote/g, / {0,3}>/).replace(/heading/g, / {0,3}#{1,6}/).replace(/html/g, / {0,3}<[^\n>]+>\n/).replace(/table/g, / {0,3}\|?(?:[:\- ]*\|)+[\:\- ]*\n/).getRegex();
1760
+ var F = /^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html|table| +\n)[^\n]+)*)/;
1761
+ var $e = /^[^\n]+/;
1762
+ var U = /(?!\s*\])(?:\\[\s\S]|[^\[\]\\])+/;
1763
+ var Le = d(/^ {0,3}\[(label)\]: *(?:\n[ \t]*)?([^<\s][^\s]*|<.*?>)(?:(?: +(?:\n[ \t]*)?| *\n[ \t]*)(title))? *(?:\n+|$)/).replace("label", U).replace("title", /(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/).getRegex();
1764
+ var _e = d(/^(bull)([ \t][^\n]*?)?(?:\n|$)/).replace(/bull/g, j).getRegex();
1765
+ var H = "address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|search|section|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul";
1766
+ var K = /<!--(?:-?>|[\s\S]*?(?:-->|$))/;
1767
+ var ze = d("^ {0,3}(?:<(script|pre|style|textarea)[\\s>][\\s\\S]*?(?:</\\1>[^\\n]*\\n+|$)|comment[^\\n]*(\\n+|$)|<\\?[\\s\\S]*?(?:\\?>\\n*|$)|<![A-Z][\\s\\S]*?(?:>\\n*|$)|<!\\[CDATA\\[[\\s\\S]*?(?:\\]\\]>\\n*|$)|</?(tag)(?: +|\\n|/?>)[\\s\\S]*?(?:(?:\\n[ ]*)+\\n|$)|<(?!script|pre|style|textarea)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n[ ]*)+\\n|$)|</(?!script|pre|style|textarea)[a-z][\\w-]*\\s*>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n[ ]*)+\\n|$))", "i").replace("comment", K).replace("tag", H).replace("attribute", / +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex();
1768
+ var le = d(F).replace("hr", B).replace("heading", " {0,3}#{1,6}(?:\\s|$)").replace("|lheading", "").replace("|table", "").replace("blockquote", " {0,3}>").replace("fences", " {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list", " {0,3}(?:[*+-]|1[.)])[ \\t]+[^ \\t\\n]").replace("html", "</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag", H).getRegex();
1769
+ var Me = d(/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/).replace("paragraph", le).getRegex();
1770
+ var W = { blockquote: Me, code: we, def: Le, fences: ye, heading: Pe, hr: B, html: ze, lheading: ae, list: _e, newline: Oe, paragraph: le, table: _, text: $e };
1771
+ var se = d("^ *([^\\n ].*)\\n {0,3}((?:\\| *)?:?-+:? *(?:\\| *:?-+:? *)*(?:\\| *)?)(?:\\n((?:(?! *\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)").replace("hr", B).replace("heading", " {0,3}#{1,6}(?:\\s|$)").replace("blockquote", " {0,3}>").replace("code", "(?: {4}| {0,3} )[^\\n]").replace("fences", " {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list", " {0,3}(?:[*+-]|1[.)])[ \\t]").replace("html", "</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag", H).getRegex();
1772
+ var Ee = { ...W, lheading: Se, table: se, paragraph: d(F).replace("hr", B).replace("heading", " {0,3}#{1,6}(?:\\s|$)").replace("|lheading", "").replace("table", se).replace("blockquote", " {0,3}>").replace("fences", " {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list", " {0,3}(?:[*+-]|1[.)])[ \\t]+[^ \\t\\n]").replace("html", "</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag", H).getRegex() };
1773
+ var Ie = { ...W, html: d(`^ *(?:comment *(?:\\n|\\s*$)|<(tag)[\\s\\S]+?</\\1> *(?:\\n{2,}|\\s*$)|<tag(?:"[^"]*"|'[^']*'|\\s[^'"/>\\s]*)*?/?> *(?:\\n{2,}|\\s*$))`).replace("comment", K).replace(/tag/g, "(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b").getRegex(), def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/, heading: /^(#{1,6})(.*)(?:\n+|$)/, fences: _, lheading: /^(.+?)\n {0,3}(=+|-+) *(?:\n+|$)/, paragraph: d(F).replace("hr", B).replace("heading", ` *#{1,6} *[^
1774
+ ]`).replace("lheading", ae).replace("|table", "").replace("blockquote", " {0,3}>").replace("|fences", "").replace("|list", "").replace("|html", "").replace("|tag", "").getRegex() };
1775
+ var Ae = /^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/;
1776
+ var Ce = /^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/;
1777
+ var ue = /^( {2,}|\\)\n(?!\s*$)/;
1778
+ var Be = /^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\<!\[`*_]|\b_|$)|[^ ](?= {2,}\n)))/;
1779
+ var I = /[\p{P}\p{S}]/u;
1780
+ var Z = /[\s\p{P}\p{S}]/u;
1781
+ var X = /[^\s\p{P}\p{S}]/u;
1782
+ var De = d(/^((?![*_])punctSpace)/, "u").replace(/punctSpace/g, Z).getRegex();
1783
+ var pe = /(?!~)[\p{P}\p{S}]/u;
1784
+ var qe = /(?!~)[\s\p{P}\p{S}]/u;
1785
+ var ve = /(?:[^\s\p{P}\p{S}]|~)/u;
1786
+ var He = d(/link|precode-code|html/, "g").replace("link", /\[(?:[^\[\]`]|(?<a>`+)[^`]+\k<a>(?!`))*?\]\((?:\\[\s\S]|[^\\\(\)]|\((?:\\[\s\S]|[^\\\(\)])*\))*\)/).replace("precode-", Te ? "(?<!`)()" : "(^^|[^`])").replace("code", /(?<b>`+)[^`]+\k<b>(?!`)/).replace("html", /<(?! )[^<>]*?>/).getRegex();
1787
+ var ce = /^(?:\*+(?:((?!\*)punct)|([^\s*]))?)|^_+(?:((?!_)punct)|([^\s_]))?/;
1788
+ var Ze = d(ce, "u").replace(/punct/g, I).getRegex();
1789
+ var Ge = d(ce, "u").replace(/punct/g, pe).getRegex();
1790
+ var he = "^[^_*]*?__[^_*]*?\\*[^_*]*?(?=__)|[^*]+(?=[^*])|(?!\\*)punct(\\*+)(?=[\\s]|$)|notPunctSpace(\\*+)(?!\\*)(?=punctSpace|$)|(?!\\*)punctSpace(\\*+)(?=notPunctSpace)|[\\s](\\*+)(?!\\*)(?=punct)|(?!\\*)punct(\\*+)(?!\\*)(?=punct)|notPunctSpace(\\*+)(?=notPunctSpace)";
1791
+ var Ne = d(he, "gu").replace(/notPunctSpace/g, X).replace(/punctSpace/g, Z).replace(/punct/g, I).getRegex();
1792
+ var Qe = d(he, "gu").replace(/notPunctSpace/g, ve).replace(/punctSpace/g, qe).replace(/punct/g, pe).getRegex();
1793
+ var je = d("^[^_*]*?\\*\\*[^_*]*?_[^_*]*?(?=\\*\\*)|[^_]+(?=[^_])|(?!_)punct(_+)(?=[\\s]|$)|notPunctSpace(_+)(?!_)(?=punctSpace|$)|(?!_)punctSpace(_+)(?=notPunctSpace)|[\\s](_+)(?!_)(?=punct)|(?!_)punct(_+)(?!_)(?=punct)", "gu").replace(/notPunctSpace/g, X).replace(/punctSpace/g, Z).replace(/punct/g, I).getRegex();
1794
+ var Fe = d(/^~~?(?:((?!~)punct)|[^\s~])/, "u").replace(/punct/g, I).getRegex();
1795
+ var Ue = "^[^~]+(?=[^~])|(?!~)punct(~~?)(?=[\\s]|$)|notPunctSpace(~~?)(?!~)(?=punctSpace|$)|(?!~)punctSpace(~~?)(?=notPunctSpace)|[\\s](~~?)(?!~)(?=punct)|(?!~)punct(~~?)(?!~)(?=punct)|notPunctSpace(~~?)(?=notPunctSpace)";
1796
+ var Ke = d(Ue, "gu").replace(/notPunctSpace/g, X).replace(/punctSpace/g, Z).replace(/punct/g, I).getRegex();
1797
+ var We = d(/\\(punct)/, "gu").replace(/punct/g, I).getRegex();
1798
+ var Xe = d(/^<(scheme:[^\s\x00-\x1f<>]*|email)>/).replace("scheme", /[a-zA-Z][a-zA-Z0-9+.-]{1,31}/).replace("email", /[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/).getRegex();
1799
+ var Je = d(K).replace("(?:-->|$)", "-->").getRegex();
1800
+ var Ve = d("^comment|^</[a-zA-Z][\\w:-]*\\s*>|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^<![a-zA-Z]+\\s[\\s\\S]*?>|^<!\\[CDATA\\[[\\s\\S]*?\\]\\]>").replace("comment", Je).replace("attribute", /\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/).getRegex();
1801
+ var v = /(?:\[(?:\\[\s\S]|[^\[\]\\])*\]|\\[\s\S]|`+(?!`)[^`]*?`+(?!`)|``+(?=\])|[^\[\]\\`])*?/;
1802
+ var Ye = d(/^!?\[(label)\]\(\s*(href)(?:(?:[ \t]+(?:\n[ \t]*)?|\n[ \t]*)(title))?\s*\)/).replace("label", v).replace("href", /<(?:\\.|[^\n<>\\])+>|[^ \t\n\x00-\x1f]*/).replace("title", /"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/).getRegex();
1803
+ var ke = d(/^!?\[(label)\]\[(ref)\]/).replace("label", v).replace("ref", U).getRegex();
1804
+ var de2 = d(/^!?\[(ref)\](?:\[\])?/).replace("ref", U).getRegex();
1805
+ var et = d("reflink|nolink(?!\\()", "g").replace("reflink", ke).replace("nolink", de2).getRegex();
1806
+ var ie = /[hH][tT][tT][pP][sS]?|[fF][tT][pP]/;
1807
+ var J = { _backpedal: _, anyPunctuation: We, autolink: Xe, blockSkip: He, br: ue, code: Ce, del: _, delLDelim: _, delRDelim: _, emStrongLDelim: Ze, emStrongRDelimAst: Ne, emStrongRDelimUnd: je, escape: Ae, link: Ye, nolink: de2, punctuation: De, reflink: ke, reflinkSearch: et, tag: Ve, text: Be, url: _ };
1808
+ var tt = { ...J, link: d(/^!?\[(label)\]\((.*?)\)/).replace("label", v).getRegex(), reflink: d(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace("label", v).getRegex() };
1809
+ var Q = { ...J, emStrongRDelimAst: Qe, emStrongLDelim: Ge, delLDelim: Fe, delRDelim: Ke, url: d(/^((?:protocol):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/).replace("protocol", ie).replace("email", /[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/).getRegex(), _backpedal: /(?:[^?!.,:;*_'"~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_'"~)]+(?!$))+/, del: /^(~~?)(?=[^\s~])((?:\\[\s\S]|[^\\])*?(?:\\[\s\S]|[^\s~\\]))\1(?=[^~]|$)/, text: d(/^([`~]+|[^`~])(?:(?= {2,}\n)|(?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)|[\s\S]*?(?:(?=[\\<!\[`*~_]|\b_|protocol:\/\/|www\.|$)|[^ ](?= {2,}\n)|[^a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-](?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)))/).replace("protocol", ie).getRegex() };
1810
+ var nt = { ...Q, br: d(ue).replace("{2,}", "*").getRegex(), text: d(Q.text).replace("\\b_", "\\b_| {2,}\\n").replace(/\{2,\}/g, "*").getRegex() };
1811
+ var D = { normal: W, gfm: Ee, pedantic: Ie };
1812
+ var A = { normal: J, gfm: Q, breaks: nt, pedantic: tt };
1813
+ var rt = { "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" };
1814
+ var ge = (l3) => rt[l3];
1815
+ function O(l3, e) {
1816
+ if (e) {
1817
+ if (m.escapeTest.test(l3)) return l3.replace(m.escapeReplace, ge);
1818
+ } else if (m.escapeTestNoEncode.test(l3)) return l3.replace(m.escapeReplaceNoEncode, ge);
1819
+ return l3;
1820
+ }
1821
+ function V(l3) {
1822
+ try {
1823
+ l3 = encodeURI(l3).replace(m.percentDecode, "%");
1824
+ } catch {
1825
+ return null;
1826
+ }
1827
+ return l3;
1828
+ }
1829
+ function Y(l3, e) {
1830
+ let t2 = l3.replace(m.findPipe, (r, i, o) => {
1831
+ let u = false, a = i;
1832
+ for (; --a >= 0 && o[a] === "\\"; ) u = !u;
1833
+ return u ? "|" : " |";
1834
+ }), n = t2.split(m.splitPipe), s = 0;
1835
+ if (n[0].trim() || n.shift(), n.length > 0 && !n.at(-1)?.trim() && n.pop(), e) if (n.length > e) n.splice(e);
1836
+ else for (; n.length < e; ) n.push("");
1837
+ for (; s < n.length; s++) n[s] = n[s].trim().replace(m.slashPipe, "|");
1838
+ return n;
1839
+ }
1840
+ function $(l3, e, t2) {
1841
+ let n = l3.length;
1842
+ if (n === 0) return "";
1843
+ let s = 0;
1844
+ for (; s < n; ) {
1845
+ let r = l3.charAt(n - s - 1);
1846
+ if (r === e && true) s++;
1847
+ else break;
1848
+ }
1849
+ return l3.slice(0, n - s);
1850
+ }
1851
+ function ee(l3) {
1852
+ let e = l3.split(`
1853
+ `), t2 = e.length - 1;
1854
+ for (; t2 >= 0 && m.blankLine.test(e[t2]); ) t2--;
1855
+ return e.length - t2 <= 2 ? l3 : e.slice(0, t2 + 1).join(`
1856
+ `);
1857
+ }
1858
+ function fe(l3, e) {
1859
+ if (l3.indexOf(e[1]) === -1) return -1;
1860
+ let t2 = 0;
1861
+ for (let n = 0; n < l3.length; n++) if (l3[n] === "\\") n++;
1862
+ else if (l3[n] === e[0]) t2++;
1863
+ else if (l3[n] === e[1] && (t2--, t2 < 0)) return n;
1864
+ return t2 > 0 ? -2 : -1;
1865
+ }
1866
+ function me(l3, e = 0) {
1867
+ let t2 = e, n = "";
1868
+ for (let s of l3) if (s === " ") {
1869
+ let r = 4 - t2 % 4;
1870
+ n += " ".repeat(r), t2 += r;
1871
+ } else n += s, t2++;
1872
+ return n;
1873
+ }
1874
+ function xe(l3, e, t2, n, s) {
1875
+ let r = e.href, i = e.title || null, o = l3[1].replace(s.other.outputLinkReplace, "$1");
1876
+ n.state.inLink = true;
1877
+ let u = { type: l3[0].charAt(0) === "!" ? "image" : "link", raw: t2, href: r, title: i, text: o, tokens: n.inlineTokens(o) };
1878
+ return n.state.inLink = false, u;
1879
+ }
1880
+ function st(l3, e, t2) {
1881
+ let n = l3.match(t2.other.indentCodeCompensation);
1882
+ if (n === null) return e;
1883
+ let s = n[1];
1884
+ return e.split(`
1885
+ `).map((r) => {
1886
+ let i = r.match(t2.other.beginningSpace);
1887
+ if (i === null) return r;
1888
+ let [o] = i;
1889
+ return o.length >= s.length ? r.slice(s.length) : r;
1890
+ }).join(`
1891
+ `);
1892
+ }
1893
+ var w = class {
1894
+ options;
1895
+ rules;
1896
+ lexer;
1897
+ constructor(e) {
1898
+ this.options = e || T;
1899
+ }
1900
+ space(e) {
1901
+ let t2 = this.rules.block.newline.exec(e);
1902
+ if (t2 && t2[0].length > 0) return { type: "space", raw: t2[0] };
1903
+ }
1904
+ code(e) {
1905
+ let t2 = this.rules.block.code.exec(e);
1906
+ if (t2) {
1907
+ let n = this.options.pedantic ? t2[0] : ee(t2[0]), s = n.replace(this.rules.other.codeRemoveIndent, "");
1908
+ return { type: "code", raw: n, codeBlockStyle: "indented", text: s };
1909
+ }
1910
+ }
1911
+ fences(e) {
1912
+ let t2 = this.rules.block.fences.exec(e);
1913
+ if (t2) {
1914
+ let n = t2[0], s = st(n, t2[3] || "", this.rules);
1915
+ return { type: "code", raw: n, lang: t2[2] ? t2[2].trim().replace(this.rules.inline.anyPunctuation, "$1") : t2[2], text: s };
1916
+ }
1917
+ }
1918
+ heading(e) {
1919
+ let t2 = this.rules.block.heading.exec(e);
1920
+ if (t2) {
1921
+ let n = t2[2].trim();
1922
+ if (this.rules.other.endingHash.test(n)) {
1923
+ let s = $(n, "#");
1924
+ (this.options.pedantic || !s || this.rules.other.endingSpaceChar.test(s)) && (n = s.trim());
1925
+ }
1926
+ return { type: "heading", raw: $(t2[0], `
1927
+ `), depth: t2[1].length, text: n, tokens: this.lexer.inline(n) };
1928
+ }
1929
+ }
1930
+ hr(e) {
1931
+ let t2 = this.rules.block.hr.exec(e);
1932
+ if (t2) return { type: "hr", raw: $(t2[0], `
1933
+ `) };
1934
+ }
1935
+ blockquote(e) {
1936
+ let t2 = this.rules.block.blockquote.exec(e);
1937
+ if (t2) {
1938
+ let n = $(t2[0], `
1939
+ `).split(`
1940
+ `), s = "", r = "", i = [];
1941
+ for (; n.length > 0; ) {
1942
+ let o = false, u = [], a;
1943
+ for (a = 0; a < n.length; a++) if (this.rules.other.blockquoteStart.test(n[a])) u.push(n[a]), o = true;
1944
+ else if (!o) u.push(n[a]);
1945
+ else break;
1946
+ n = n.slice(a);
1947
+ let c = u.join(`
1948
+ `), p = c.replace(this.rules.other.blockquoteSetextReplace, `
1949
+ $1`).replace(this.rules.other.blockquoteSetextReplace2, "");
1950
+ s = s ? `${s}
1951
+ ${c}` : c, r = r ? `${r}
1952
+ ${p}` : p;
1953
+ let k = this.lexer.state.top;
1954
+ if (this.lexer.state.top = true, this.lexer.blockTokens(p, i, true), this.lexer.state.top = k, n.length === 0) break;
1955
+ let h = i.at(-1);
1956
+ if (h?.type === "code") break;
1957
+ if (h?.type === "blockquote") {
1958
+ let R = h, f = R.raw + `
1959
+ ` + n.join(`
1960
+ `), S = this.blockquote(f);
1961
+ i[i.length - 1] = S, s = s.substring(0, s.length - R.raw.length) + S.raw, r = r.substring(0, r.length - R.text.length) + S.text;
1962
+ break;
1963
+ } else if (h?.type === "list") {
1964
+ let R = h, f = R.raw + `
1965
+ ` + n.join(`
1966
+ `), S = this.list(f);
1967
+ i[i.length - 1] = S, s = s.substring(0, s.length - h.raw.length) + S.raw, r = r.substring(0, r.length - R.raw.length) + S.raw, n = f.substring(i.at(-1).raw.length).split(`
1968
+ `);
1969
+ continue;
1970
+ }
1971
+ }
1972
+ return { type: "blockquote", raw: s, tokens: i, text: r };
1973
+ }
1974
+ }
1975
+ list(e) {
1976
+ let t2 = this.rules.block.list.exec(e);
1977
+ if (t2) {
1978
+ let n = t2[1].trim(), s = n.length > 1, r = { type: "list", raw: "", ordered: s, start: s ? +n.slice(0, -1) : "", loose: false, items: [] };
1979
+ n = s ? `\\d{1,9}\\${n.slice(-1)}` : `\\${n}`, this.options.pedantic && (n = s ? n : "[*+-]");
1980
+ let i = this.rules.other.listItemRegex(n), o = false;
1981
+ for (; e; ) {
1982
+ let a = false, c = "", p = "";
1983
+ if (!(t2 = i.exec(e)) || this.rules.block.hr.test(e)) break;
1984
+ c = t2[0], e = e.substring(c.length);
1985
+ let k = me(t2[2].split(`
1986
+ `, 1)[0], t2[1].length), h = e.split(`
1987
+ `, 1)[0], R = !k.trim(), f = 0;
1988
+ if (this.options.pedantic ? (f = 2, p = k.trimStart()) : R ? f = t2[1].length + 1 : (f = k.search(this.rules.other.nonSpaceChar), f = f > 4 ? 1 : f, p = k.slice(f), f += t2[1].length), R && this.rules.other.blankLine.test(h) && (c += h + `
1989
+ `, e = e.substring(h.length + 1), a = true), !a) {
1990
+ let S = this.rules.other.nextBulletRegex(f), te = this.rules.other.hrRegex(f), ne = this.rules.other.fencesBeginRegex(f), re = this.rules.other.headingBeginRegex(f), be = this.rules.other.htmlBeginRegex(f), Re = this.rules.other.blockquoteBeginRegex(f);
1991
+ for (; e; ) {
1992
+ let G = e.split(`
1993
+ `, 1)[0], C;
1994
+ if (h = G, this.options.pedantic ? (h = h.replace(this.rules.other.listReplaceNesting, " "), C = h) : C = h.replace(this.rules.other.tabCharGlobal, " "), ne.test(h) || re.test(h) || be.test(h) || Re.test(h) || S.test(h) || te.test(h)) break;
1995
+ if (C.search(this.rules.other.nonSpaceChar) >= f || !h.trim()) p += `
1996
+ ` + C.slice(f);
1997
+ else {
1998
+ if (R || k.replace(this.rules.other.tabCharGlobal, " ").search(this.rules.other.nonSpaceChar) >= 4 || ne.test(k) || re.test(k) || te.test(k)) break;
1999
+ p += `
2000
+ ` + h;
2001
+ }
2002
+ R = !h.trim(), c += G + `
2003
+ `, e = e.substring(G.length + 1), k = C.slice(f);
2004
+ }
2005
+ }
2006
+ r.loose || (o ? r.loose = true : this.rules.other.doubleBlankLine.test(c) && (o = true)), r.items.push({ type: "list_item", raw: c, task: !!this.options.gfm && this.rules.other.listIsTask.test(p), loose: false, text: p, tokens: [] }), r.raw += c;
2007
+ }
2008
+ let u = r.items.at(-1);
2009
+ if (u) u.raw = u.raw.trimEnd(), u.text = u.text.trimEnd();
2010
+ else return;
2011
+ r.raw = r.raw.trimEnd();
2012
+ for (let a of r.items) {
2013
+ this.lexer.state.top = false, a.tokens = this.lexer.blockTokens(a.text, []);
2014
+ let c = a.tokens[0];
2015
+ if (a.task && (c?.type === "text" || c?.type === "paragraph")) {
2016
+ a.text = a.text.replace(this.rules.other.listReplaceTask, ""), c.raw = c.raw.replace(this.rules.other.listReplaceTask, ""), c.text = c.text.replace(this.rules.other.listReplaceTask, "");
2017
+ for (let k = this.lexer.inlineQueue.length - 1; k >= 0; k--) if (this.rules.other.listIsTask.test(this.lexer.inlineQueue[k].src)) {
2018
+ this.lexer.inlineQueue[k].src = this.lexer.inlineQueue[k].src.replace(this.rules.other.listReplaceTask, "");
2019
+ break;
2020
+ }
2021
+ let p = this.rules.other.listTaskCheckbox.exec(a.raw);
2022
+ if (p) {
2023
+ let k = { type: "checkbox", raw: p[0] + " ", checked: p[0] !== "[ ]" };
2024
+ a.checked = k.checked, r.loose ? a.tokens[0] && ["paragraph", "text"].includes(a.tokens[0].type) && "tokens" in a.tokens[0] && a.tokens[0].tokens ? (a.tokens[0].raw = k.raw + a.tokens[0].raw, a.tokens[0].text = k.raw + a.tokens[0].text, a.tokens[0].tokens.unshift(k)) : a.tokens.unshift({ type: "paragraph", raw: k.raw, text: k.raw, tokens: [k] }) : a.tokens.unshift(k);
2025
+ }
2026
+ } else a.task && (a.task = false);
2027
+ if (!r.loose) {
2028
+ let p = a.tokens.filter((h) => h.type === "space"), k = p.length > 0 && p.some((h) => this.rules.other.anyLine.test(h.raw));
2029
+ r.loose = k;
2030
+ }
2031
+ }
2032
+ if (r.loose) for (let a of r.items) {
2033
+ a.loose = true;
2034
+ for (let c of a.tokens) c.type === "text" && (c.type = "paragraph");
2035
+ }
2036
+ return r;
2037
+ }
2038
+ }
2039
+ html(e) {
2040
+ let t2 = this.rules.block.html.exec(e);
2041
+ if (t2) {
2042
+ let n = ee(t2[0]);
2043
+ return { type: "html", block: true, raw: n, pre: t2[1] === "pre" || t2[1] === "script" || t2[1] === "style", text: n };
2044
+ }
2045
+ }
2046
+ def(e) {
2047
+ let t2 = this.rules.block.def.exec(e);
2048
+ if (t2) {
2049
+ let n = t2[1].toLowerCase().replace(this.rules.other.multipleSpaceGlobal, " "), s = t2[2] ? t2[2].replace(this.rules.other.hrefBrackets, "$1").replace(this.rules.inline.anyPunctuation, "$1") : "", r = t2[3] ? t2[3].substring(1, t2[3].length - 1).replace(this.rules.inline.anyPunctuation, "$1") : t2[3];
2050
+ return { type: "def", tag: n, raw: $(t2[0], `
2051
+ `), href: s, title: r };
2052
+ }
2053
+ }
2054
+ table(e) {
2055
+ let t2 = this.rules.block.table.exec(e);
2056
+ if (!t2 || !this.rules.other.tableDelimiter.test(t2[2])) return;
2057
+ let n = Y(t2[1]), s = t2[2].replace(this.rules.other.tableAlignChars, "").split("|"), r = t2[3]?.trim() ? t2[3].replace(this.rules.other.tableRowBlankLine, "").split(`
2058
+ `) : [], i = { type: "table", raw: $(t2[0], `
2059
+ `), header: [], align: [], rows: [] };
2060
+ if (n.length === s.length) {
2061
+ for (let o of s) this.rules.other.tableAlignRight.test(o) ? i.align.push("right") : this.rules.other.tableAlignCenter.test(o) ? i.align.push("center") : this.rules.other.tableAlignLeft.test(o) ? i.align.push("left") : i.align.push(null);
2062
+ for (let o = 0; o < n.length; o++) i.header.push({ text: n[o], tokens: this.lexer.inline(n[o]), header: true, align: i.align[o] });
2063
+ for (let o of r) i.rows.push(Y(o, i.header.length).map((u, a) => ({ text: u, tokens: this.lexer.inline(u), header: false, align: i.align[a] })));
2064
+ return i;
2065
+ }
2066
+ }
2067
+ lheading(e) {
2068
+ let t2 = this.rules.block.lheading.exec(e);
2069
+ if (t2) {
2070
+ let n = t2[1].trim();
2071
+ return { type: "heading", raw: $(t2[0], `
2072
+ `), depth: t2[2].charAt(0) === "=" ? 1 : 2, text: n, tokens: this.lexer.inline(n) };
2073
+ }
2074
+ }
2075
+ paragraph(e) {
2076
+ let t2 = this.rules.block.paragraph.exec(e);
2077
+ if (t2) {
2078
+ let n = t2[1].charAt(t2[1].length - 1) === `
2079
+ ` ? t2[1].slice(0, -1) : t2[1];
2080
+ return { type: "paragraph", raw: t2[0], text: n, tokens: this.lexer.inline(n) };
2081
+ }
2082
+ }
2083
+ text(e) {
2084
+ let t2 = this.rules.block.text.exec(e);
2085
+ if (t2) return { type: "text", raw: t2[0], text: t2[0], tokens: this.lexer.inline(t2[0]) };
2086
+ }
2087
+ escape(e) {
2088
+ let t2 = this.rules.inline.escape.exec(e);
2089
+ if (t2) return { type: "escape", raw: t2[0], text: t2[1] };
2090
+ }
2091
+ tag(e) {
2092
+ let t2 = this.rules.inline.tag.exec(e);
2093
+ if (t2) return !this.lexer.state.inLink && this.rules.other.startATag.test(t2[0]) ? this.lexer.state.inLink = true : this.lexer.state.inLink && this.rules.other.endATag.test(t2[0]) && (this.lexer.state.inLink = false), !this.lexer.state.inRawBlock && this.rules.other.startPreScriptTag.test(t2[0]) ? this.lexer.state.inRawBlock = true : this.lexer.state.inRawBlock && this.rules.other.endPreScriptTag.test(t2[0]) && (this.lexer.state.inRawBlock = false), { type: "html", raw: t2[0], inLink: this.lexer.state.inLink, inRawBlock: this.lexer.state.inRawBlock, block: false, text: t2[0] };
2094
+ }
2095
+ link(e) {
2096
+ let t2 = this.rules.inline.link.exec(e);
2097
+ if (t2) {
2098
+ let n = t2[2].trim();
2099
+ if (!this.options.pedantic && this.rules.other.startAngleBracket.test(n)) {
2100
+ if (!this.rules.other.endAngleBracket.test(n)) return;
2101
+ let i = $(n.slice(0, -1), "\\");
2102
+ if ((n.length - i.length) % 2 === 0) return;
2103
+ } else {
2104
+ let i = fe(t2[2], "()");
2105
+ if (i === -2) return;
2106
+ if (i > -1) {
2107
+ let u = (t2[0].indexOf("!") === 0 ? 5 : 4) + t2[1].length + i;
2108
+ t2[2] = t2[2].substring(0, i), t2[0] = t2[0].substring(0, u).trim(), t2[3] = "";
2109
+ }
2110
+ }
2111
+ let s = t2[2], r = "";
2112
+ if (this.options.pedantic) {
2113
+ let i = this.rules.other.pedanticHrefTitle.exec(s);
2114
+ i && (s = i[1], r = i[3]);
2115
+ } else r = t2[3] ? t2[3].slice(1, -1) : "";
2116
+ return s = s.trim(), this.rules.other.startAngleBracket.test(s) && (this.options.pedantic && !this.rules.other.endAngleBracket.test(n) ? s = s.slice(1) : s = s.slice(1, -1)), xe(t2, { href: s && s.replace(this.rules.inline.anyPunctuation, "$1"), title: r && r.replace(this.rules.inline.anyPunctuation, "$1") }, t2[0], this.lexer, this.rules);
2117
+ }
2118
+ }
2119
+ reflink(e, t2) {
2120
+ let n;
2121
+ if ((n = this.rules.inline.reflink.exec(e)) || (n = this.rules.inline.nolink.exec(e))) {
2122
+ let s = (n[2] || n[1]).replace(this.rules.other.multipleSpaceGlobal, " "), r = t2[s.toLowerCase()];
2123
+ if (!r) {
2124
+ let i = n[0].charAt(0);
2125
+ return { type: "text", raw: i, text: i };
2126
+ }
2127
+ return xe(n, r, n[0], this.lexer, this.rules);
2128
+ }
2129
+ }
2130
+ emStrong(e, t2, n = "") {
2131
+ let s = this.rules.inline.emStrongLDelim.exec(e);
2132
+ if (!s || !s[1] && !s[2] && !s[3] && !s[4] || s[4] && n.match(this.rules.other.unicodeAlphaNumeric)) return;
2133
+ if (!(s[1] || s[3] || "") || !n || this.rules.inline.punctuation.exec(n)) {
2134
+ let i = [...s[0]].length - 1, o, u, a = i, c = 0, p = s[0][0] === "*" ? this.rules.inline.emStrongRDelimAst : this.rules.inline.emStrongRDelimUnd;
2135
+ for (p.lastIndex = 0, t2 = t2.slice(-1 * e.length + i); (s = p.exec(t2)) !== null; ) {
2136
+ if (o = s[1] || s[2] || s[3] || s[4] || s[5] || s[6], !o) continue;
2137
+ if (u = [...o].length, s[3] || s[4]) {
2138
+ a += u;
2139
+ continue;
2140
+ } else if ((s[5] || s[6]) && i % 3 && !((i + u) % 3)) {
2141
+ c += u;
2142
+ continue;
2143
+ }
2144
+ if (a -= u, a > 0) continue;
2145
+ u = Math.min(u, u + a + c);
2146
+ let k = [...s[0]][0].length, h = e.slice(0, i + s.index + k + u);
2147
+ if (Math.min(i, u) % 2) {
2148
+ let f = h.slice(1, -1);
2149
+ return { type: "em", raw: h, text: f, tokens: this.lexer.inlineTokens(f) };
2150
+ }
2151
+ let R = h.slice(2, -2);
2152
+ return { type: "strong", raw: h, text: R, tokens: this.lexer.inlineTokens(R) };
2153
+ }
2154
+ }
2155
+ }
2156
+ codespan(e) {
2157
+ let t2 = this.rules.inline.code.exec(e);
2158
+ if (t2) {
2159
+ let n = t2[2].replace(this.rules.other.newLineCharGlobal, " "), s = this.rules.other.nonSpaceChar.test(n), r = this.rules.other.startingSpaceChar.test(n) && this.rules.other.endingSpaceChar.test(n);
2160
+ return s && r && (n = n.substring(1, n.length - 1)), { type: "codespan", raw: t2[0], text: n };
2161
+ }
2162
+ }
2163
+ br(e) {
2164
+ let t2 = this.rules.inline.br.exec(e);
2165
+ if (t2) return { type: "br", raw: t2[0] };
2166
+ }
2167
+ del(e, t2, n = "") {
2168
+ let s = this.rules.inline.delLDelim.exec(e);
2169
+ if (!s) return;
2170
+ if (!(s[1] || "") || !n || this.rules.inline.punctuation.exec(n)) {
2171
+ let i = [...s[0]].length - 1, o, u, a = i, c = this.rules.inline.delRDelim;
2172
+ for (c.lastIndex = 0, t2 = t2.slice(-1 * e.length + i); (s = c.exec(t2)) !== null; ) {
2173
+ if (o = s[1] || s[2] || s[3] || s[4] || s[5] || s[6], !o || (u = [...o].length, u !== i)) continue;
2174
+ if (s[3] || s[4]) {
2175
+ a += u;
2176
+ continue;
2177
+ }
2178
+ if (a -= u, a > 0) continue;
2179
+ u = Math.min(u, u + a);
2180
+ let p = [...s[0]][0].length, k = e.slice(0, i + s.index + p + u), h = k.slice(i, -i);
2181
+ return { type: "del", raw: k, text: h, tokens: this.lexer.inlineTokens(h) };
2182
+ }
2183
+ }
2184
+ }
2185
+ autolink(e) {
2186
+ let t2 = this.rules.inline.autolink.exec(e);
2187
+ if (t2) {
2188
+ let n, s;
2189
+ return t2[2] === "@" ? (n = t2[1], s = "mailto:" + n) : (n = t2[1], s = n), { type: "link", raw: t2[0], text: n, href: s, tokens: [{ type: "text", raw: n, text: n }] };
2190
+ }
2191
+ }
2192
+ url(e) {
2193
+ let t2;
2194
+ if (t2 = this.rules.inline.url.exec(e)) {
2195
+ let n, s;
2196
+ if (t2[2] === "@") n = t2[0], s = "mailto:" + n;
2197
+ else {
2198
+ let r;
2199
+ do
2200
+ r = t2[0], t2[0] = this.rules.inline._backpedal.exec(t2[0])?.[0] ?? "";
2201
+ while (r !== t2[0]);
2202
+ n = t2[0], t2[1] === "www." ? s = "http://" + t2[0] : s = t2[0];
2203
+ }
2204
+ return { type: "link", raw: t2[0], text: n, href: s, tokens: [{ type: "text", raw: n, text: n }] };
2205
+ }
2206
+ }
2207
+ inlineText(e) {
2208
+ let t2 = this.rules.inline.text.exec(e);
2209
+ if (t2) {
2210
+ let n = this.lexer.state.inRawBlock;
2211
+ return { type: "text", raw: t2[0], text: t2[0], escaped: n };
2212
+ }
2213
+ }
2214
+ };
2215
+ var x = class l {
2216
+ tokens;
2217
+ options;
2218
+ state;
2219
+ inlineQueue;
2220
+ tokenizer;
2221
+ constructor(e) {
2222
+ this.tokens = [], this.tokens.links = /* @__PURE__ */ Object.create(null), this.options = e || T, this.options.tokenizer = this.options.tokenizer || new w(), this.tokenizer = this.options.tokenizer, this.tokenizer.options = this.options, this.tokenizer.lexer = this, this.inlineQueue = [], this.state = { inLink: false, inRawBlock: false, top: true };
2223
+ let t2 = { other: m, block: D.normal, inline: A.normal };
2224
+ this.options.pedantic ? (t2.block = D.pedantic, t2.inline = A.pedantic) : this.options.gfm && (t2.block = D.gfm, this.options.breaks ? t2.inline = A.breaks : t2.inline = A.gfm), this.tokenizer.rules = t2;
2225
+ }
2226
+ static get rules() {
2227
+ return { block: D, inline: A };
2228
+ }
2229
+ static lex(e, t2) {
2230
+ return new l(t2).lex(e);
2231
+ }
2232
+ static lexInline(e, t2) {
2233
+ return new l(t2).inlineTokens(e);
2234
+ }
2235
+ lex(e) {
2236
+ e = e.replace(m.carriageReturn, `
2237
+ `), this.blockTokens(e, this.tokens);
2238
+ for (let t2 = 0; t2 < this.inlineQueue.length; t2++) {
2239
+ let n = this.inlineQueue[t2];
2240
+ this.inlineTokens(n.src, n.tokens);
2241
+ }
2242
+ return this.inlineQueue = [], this.tokens;
2243
+ }
2244
+ blockTokens(e, t2 = [], n = false) {
2245
+ this.tokenizer.lexer = this, this.options.pedantic && (e = e.replace(m.tabCharGlobal, " ").replace(m.spaceLine, ""));
2246
+ let s = 1 / 0;
2247
+ for (; e; ) {
2248
+ if (e.length < s) s = e.length;
2249
+ else {
2250
+ this.infiniteLoopError(e.charCodeAt(0));
2251
+ break;
2252
+ }
2253
+ let r;
2254
+ if (this.options.extensions?.block?.some((o) => (r = o.call({ lexer: this }, e, t2)) ? (e = e.substring(r.raw.length), t2.push(r), true) : false)) continue;
2255
+ if (r = this.tokenizer.space(e)) {
2256
+ e = e.substring(r.raw.length);
2257
+ let o = t2.at(-1);
2258
+ r.raw.length === 1 && o !== void 0 ? o.raw += `
2259
+ ` : t2.push(r);
2260
+ continue;
2261
+ }
2262
+ if (r = this.tokenizer.code(e)) {
2263
+ e = e.substring(r.raw.length);
2264
+ let o = t2.at(-1);
2265
+ o?.type === "paragraph" || o?.type === "text" ? (o.raw += (o.raw.endsWith(`
2266
+ `) ? "" : `
2267
+ `) + r.raw, o.text += `
2268
+ ` + r.text, this.inlineQueue.at(-1).src = o.text) : t2.push(r);
2269
+ continue;
2270
+ }
2271
+ if (r = this.tokenizer.fences(e)) {
2272
+ e = e.substring(r.raw.length), t2.push(r);
2273
+ continue;
2274
+ }
2275
+ if (r = this.tokenizer.heading(e)) {
2276
+ e = e.substring(r.raw.length), t2.push(r);
2277
+ continue;
2278
+ }
2279
+ if (r = this.tokenizer.hr(e)) {
2280
+ e = e.substring(r.raw.length), t2.push(r);
2281
+ continue;
2282
+ }
2283
+ if (r = this.tokenizer.blockquote(e)) {
2284
+ e = e.substring(r.raw.length), t2.push(r);
2285
+ continue;
2286
+ }
2287
+ if (r = this.tokenizer.list(e)) {
2288
+ e = e.substring(r.raw.length), t2.push(r);
2289
+ continue;
2290
+ }
2291
+ if (r = this.tokenizer.html(e)) {
2292
+ e = e.substring(r.raw.length), t2.push(r);
2293
+ continue;
2294
+ }
2295
+ if (r = this.tokenizer.def(e)) {
2296
+ e = e.substring(r.raw.length);
2297
+ let o = t2.at(-1);
2298
+ o?.type === "paragraph" || o?.type === "text" ? (o.raw += (o.raw.endsWith(`
2299
+ `) ? "" : `
2300
+ `) + r.raw, o.text += `
2301
+ ` + r.raw, this.inlineQueue.at(-1).src = o.text) : this.tokens.links[r.tag] || (this.tokens.links[r.tag] = { href: r.href, title: r.title }, t2.push(r));
2302
+ continue;
2303
+ }
2304
+ if (r = this.tokenizer.table(e)) {
2305
+ e = e.substring(r.raw.length), t2.push(r);
2306
+ continue;
2307
+ }
2308
+ if (r = this.tokenizer.lheading(e)) {
2309
+ e = e.substring(r.raw.length), t2.push(r);
2310
+ continue;
2311
+ }
2312
+ let i = e;
2313
+ if (this.options.extensions?.startBlock) {
2314
+ let o = 1 / 0, u = e.slice(1), a;
2315
+ this.options.extensions.startBlock.forEach((c) => {
2316
+ a = c.call({ lexer: this }, u), typeof a == "number" && a >= 0 && (o = Math.min(o, a));
2317
+ }), o < 1 / 0 && o >= 0 && (i = e.substring(0, o + 1));
2318
+ }
2319
+ if (this.state.top && (r = this.tokenizer.paragraph(i))) {
2320
+ let o = t2.at(-1);
2321
+ n && o?.type === "paragraph" ? (o.raw += (o.raw.endsWith(`
2322
+ `) ? "" : `
2323
+ `) + r.raw, o.text += `
2324
+ ` + r.text, this.inlineQueue.pop(), this.inlineQueue.at(-1).src = o.text) : t2.push(r), n = i.length !== e.length, e = e.substring(r.raw.length);
2325
+ continue;
2326
+ }
2327
+ if (r = this.tokenizer.text(e)) {
2328
+ e = e.substring(r.raw.length);
2329
+ let o = t2.at(-1);
2330
+ o?.type === "text" ? (o.raw += (o.raw.endsWith(`
2331
+ `) ? "" : `
2332
+ `) + r.raw, o.text += `
2333
+ ` + r.text, this.inlineQueue.pop(), this.inlineQueue.at(-1).src = o.text) : t2.push(r);
2334
+ continue;
2335
+ }
2336
+ if (e) {
2337
+ this.infiniteLoopError(e.charCodeAt(0));
2338
+ break;
2339
+ }
2340
+ }
2341
+ return this.state.top = true, t2;
2342
+ }
2343
+ inline(e, t2 = []) {
2344
+ return this.inlineQueue.push({ src: e, tokens: t2 }), t2;
2345
+ }
2346
+ inlineTokens(e, t2 = []) {
2347
+ this.tokenizer.lexer = this;
2348
+ let n = e, s = null;
2349
+ if (this.tokens.links) {
2350
+ let a = Object.keys(this.tokens.links);
2351
+ if (a.length > 0) for (; (s = this.tokenizer.rules.inline.reflinkSearch.exec(n)) !== null; ) a.includes(s[0].slice(s[0].lastIndexOf("[") + 1, -1)) && (n = n.slice(0, s.index) + "[" + "a".repeat(s[0].length - 2) + "]" + n.slice(this.tokenizer.rules.inline.reflinkSearch.lastIndex));
2352
+ }
2353
+ for (; (s = this.tokenizer.rules.inline.anyPunctuation.exec(n)) !== null; ) n = n.slice(0, s.index) + "++" + n.slice(this.tokenizer.rules.inline.anyPunctuation.lastIndex);
2354
+ let r;
2355
+ for (; (s = this.tokenizer.rules.inline.blockSkip.exec(n)) !== null; ) r = s[2] ? s[2].length : 0, n = n.slice(0, s.index + r) + "[" + "a".repeat(s[0].length - r - 2) + "]" + n.slice(this.tokenizer.rules.inline.blockSkip.lastIndex);
2356
+ n = this.options.hooks?.emStrongMask?.call({ lexer: this }, n) ?? n;
2357
+ let i = false, o = "", u = 1 / 0;
2358
+ for (; e; ) {
2359
+ if (e.length < u) u = e.length;
2360
+ else {
2361
+ this.infiniteLoopError(e.charCodeAt(0));
2362
+ break;
2363
+ }
2364
+ i || (o = ""), i = false;
2365
+ let a;
2366
+ if (this.options.extensions?.inline?.some((p) => (a = p.call({ lexer: this }, e, t2)) ? (e = e.substring(a.raw.length), t2.push(a), true) : false)) continue;
2367
+ if (a = this.tokenizer.escape(e)) {
2368
+ e = e.substring(a.raw.length), t2.push(a);
2369
+ continue;
2370
+ }
2371
+ if (a = this.tokenizer.tag(e)) {
2372
+ e = e.substring(a.raw.length), t2.push(a);
2373
+ continue;
2374
+ }
2375
+ if (a = this.tokenizer.link(e)) {
2376
+ e = e.substring(a.raw.length), t2.push(a);
2377
+ continue;
2378
+ }
2379
+ if (a = this.tokenizer.reflink(e, this.tokens.links)) {
2380
+ e = e.substring(a.raw.length);
2381
+ let p = t2.at(-1);
2382
+ a.type === "text" && p?.type === "text" ? (p.raw += a.raw, p.text += a.text) : t2.push(a);
2383
+ continue;
2384
+ }
2385
+ if (a = this.tokenizer.emStrong(e, n, o)) {
2386
+ e = e.substring(a.raw.length), t2.push(a);
2387
+ continue;
2388
+ }
2389
+ if (a = this.tokenizer.codespan(e)) {
2390
+ e = e.substring(a.raw.length), t2.push(a);
2391
+ continue;
2392
+ }
2393
+ if (a = this.tokenizer.br(e)) {
2394
+ e = e.substring(a.raw.length), t2.push(a);
2395
+ continue;
2396
+ }
2397
+ if (a = this.tokenizer.del(e, n, o)) {
2398
+ e = e.substring(a.raw.length), t2.push(a);
2399
+ continue;
2400
+ }
2401
+ if (a = this.tokenizer.autolink(e)) {
2402
+ e = e.substring(a.raw.length), t2.push(a);
2403
+ continue;
2404
+ }
2405
+ if (!this.state.inLink && (a = this.tokenizer.url(e))) {
2406
+ e = e.substring(a.raw.length), t2.push(a);
2407
+ continue;
2408
+ }
2409
+ let c = e;
2410
+ if (this.options.extensions?.startInline) {
2411
+ let p = 1 / 0, k = e.slice(1), h;
2412
+ this.options.extensions.startInline.forEach((R) => {
2413
+ h = R.call({ lexer: this }, k), typeof h == "number" && h >= 0 && (p = Math.min(p, h));
2414
+ }), p < 1 / 0 && p >= 0 && (c = e.substring(0, p + 1));
2415
+ }
2416
+ if (a = this.tokenizer.inlineText(c)) {
2417
+ e = e.substring(a.raw.length), a.raw.slice(-1) !== "_" && (o = a.raw.slice(-1)), i = true;
2418
+ let p = t2.at(-1);
2419
+ p?.type === "text" ? (p.raw += a.raw, p.text += a.text) : t2.push(a);
2420
+ continue;
2421
+ }
2422
+ if (e) {
2423
+ this.infiniteLoopError(e.charCodeAt(0));
2424
+ break;
2425
+ }
2426
+ }
2427
+ return t2;
2428
+ }
2429
+ infiniteLoopError(e) {
2430
+ let t2 = "Infinite loop on byte: " + e;
2431
+ if (this.options.silent) console.error(t2);
2432
+ else throw new Error(t2);
2433
+ }
2434
+ };
2435
+ var y = class {
2436
+ options;
2437
+ parser;
2438
+ constructor(e) {
2439
+ this.options = e || T;
2440
+ }
2441
+ space(e) {
2442
+ return "";
2443
+ }
2444
+ code({ text: e, lang: t2, escaped: n }) {
2445
+ let s = (t2 || "").match(m.notSpaceStart)?.[0], r = e.replace(m.endingNewline, "") + `
2446
+ `;
2447
+ return s ? '<pre><code class="language-' + O(s) + '">' + (n ? r : O(r, true)) + `</code></pre>
2448
+ ` : "<pre><code>" + (n ? r : O(r, true)) + `</code></pre>
2449
+ `;
2450
+ }
2451
+ blockquote({ tokens: e }) {
2452
+ return `<blockquote>
2453
+ ${this.parser.parse(e)}</blockquote>
2454
+ `;
2455
+ }
2456
+ html({ text: e }) {
2457
+ return e;
2458
+ }
2459
+ def(e) {
2460
+ return "";
2461
+ }
2462
+ heading({ tokens: e, depth: t2 }) {
2463
+ return `<h${t2}>${this.parser.parseInline(e)}</h${t2}>
2464
+ `;
2465
+ }
2466
+ hr(e) {
2467
+ return `<hr>
2468
+ `;
2469
+ }
2470
+ list(e) {
2471
+ let t2 = e.ordered, n = e.start, s = "";
2472
+ for (let o = 0; o < e.items.length; o++) {
2473
+ let u = e.items[o];
2474
+ s += this.listitem(u);
2475
+ }
2476
+ let r = t2 ? "ol" : "ul", i = t2 && n !== 1 ? ' start="' + n + '"' : "";
2477
+ return "<" + r + i + `>
2478
+ ` + s + "</" + r + `>
2479
+ `;
2480
+ }
2481
+ listitem(e) {
2482
+ return `<li>${this.parser.parse(e.tokens)}</li>
2483
+ `;
2484
+ }
2485
+ checkbox({ checked: e }) {
2486
+ return "<input " + (e ? 'checked="" ' : "") + 'disabled="" type="checkbox"> ';
2487
+ }
2488
+ paragraph({ tokens: e }) {
2489
+ return `<p>${this.parser.parseInline(e)}</p>
2490
+ `;
2491
+ }
2492
+ table(e) {
2493
+ let t2 = "", n = "";
2494
+ for (let r = 0; r < e.header.length; r++) n += this.tablecell(e.header[r]);
2495
+ t2 += this.tablerow({ text: n });
2496
+ let s = "";
2497
+ for (let r = 0; r < e.rows.length; r++) {
2498
+ let i = e.rows[r];
2499
+ n = "";
2500
+ for (let o = 0; o < i.length; o++) n += this.tablecell(i[o]);
2501
+ s += this.tablerow({ text: n });
2502
+ }
2503
+ return s && (s = `<tbody>${s}</tbody>`), `<table>
2504
+ <thead>
2505
+ ` + t2 + `</thead>
2506
+ ` + s + `</table>
2507
+ `;
2508
+ }
2509
+ tablerow({ text: e }) {
2510
+ return `<tr>
2511
+ ${e}</tr>
2512
+ `;
2513
+ }
2514
+ tablecell(e) {
2515
+ let t2 = this.parser.parseInline(e.tokens), n = e.header ? "th" : "td";
2516
+ return (e.align ? `<${n} align="${e.align}">` : `<${n}>`) + t2 + `</${n}>
2517
+ `;
2518
+ }
2519
+ strong({ tokens: e }) {
2520
+ return `<strong>${this.parser.parseInline(e)}</strong>`;
2521
+ }
2522
+ em({ tokens: e }) {
2523
+ return `<em>${this.parser.parseInline(e)}</em>`;
2524
+ }
2525
+ codespan({ text: e }) {
2526
+ return `<code>${O(e, true)}</code>`;
2527
+ }
2528
+ br(e) {
2529
+ return "<br>";
2530
+ }
2531
+ del({ tokens: e }) {
2532
+ return `<del>${this.parser.parseInline(e)}</del>`;
2533
+ }
2534
+ link({ href: e, title: t2, tokens: n }) {
2535
+ let s = this.parser.parseInline(n), r = V(e);
2536
+ if (r === null) return s;
2537
+ e = r;
2538
+ let i = '<a href="' + e + '"';
2539
+ return t2 && (i += ' title="' + O(t2) + '"'), i += ">" + s + "</a>", i;
2540
+ }
2541
+ image({ href: e, title: t2, text: n, tokens: s }) {
2542
+ s && (n = this.parser.parseInline(s, this.parser.textRenderer));
2543
+ let r = V(e);
2544
+ if (r === null) return O(n);
2545
+ e = r;
2546
+ let i = `<img src="${e}" alt="${O(n)}"`;
2547
+ return t2 && (i += ` title="${O(t2)}"`), i += ">", i;
2548
+ }
2549
+ text(e) {
2550
+ return "tokens" in e && e.tokens ? this.parser.parseInline(e.tokens) : "escaped" in e && e.escaped ? e.text : O(e.text);
2551
+ }
2552
+ };
2553
+ var L = class {
2554
+ strong({ text: e }) {
2555
+ return e;
2556
+ }
2557
+ em({ text: e }) {
2558
+ return e;
2559
+ }
2560
+ codespan({ text: e }) {
2561
+ return e;
2562
+ }
2563
+ del({ text: e }) {
2564
+ return e;
2565
+ }
2566
+ html({ text: e }) {
2567
+ return e;
2568
+ }
2569
+ text({ text: e }) {
2570
+ return e;
2571
+ }
2572
+ link({ text: e }) {
2573
+ return "" + e;
2574
+ }
2575
+ image({ text: e }) {
2576
+ return "" + e;
2577
+ }
2578
+ br() {
2579
+ return "";
2580
+ }
2581
+ checkbox({ raw: e }) {
2582
+ return e;
2583
+ }
2584
+ };
2585
+ var b = class l2 {
2586
+ options;
2587
+ renderer;
2588
+ textRenderer;
2589
+ constructor(e) {
2590
+ this.options = e || T, this.options.renderer = this.options.renderer || new y(), this.renderer = this.options.renderer, this.renderer.options = this.options, this.renderer.parser = this, this.textRenderer = new L();
2591
+ }
2592
+ static parse(e, t2) {
2593
+ return new l2(t2).parse(e);
2594
+ }
2595
+ static parseInline(e, t2) {
2596
+ return new l2(t2).parseInline(e);
2597
+ }
2598
+ parse(e) {
2599
+ this.renderer.parser = this;
2600
+ let t2 = "";
2601
+ for (let n = 0; n < e.length; n++) {
2602
+ let s = e[n];
2603
+ if (this.options.extensions?.renderers?.[s.type]) {
2604
+ let i = s, o = this.options.extensions.renderers[i.type].call({ parser: this }, i);
2605
+ if (o !== false || !["space", "hr", "heading", "code", "table", "blockquote", "list", "html", "def", "paragraph", "text"].includes(i.type)) {
2606
+ t2 += o || "";
2607
+ continue;
2608
+ }
2609
+ }
2610
+ let r = s;
2611
+ switch (r.type) {
2612
+ case "space": {
2613
+ t2 += this.renderer.space(r);
2614
+ break;
2615
+ }
2616
+ case "hr": {
2617
+ t2 += this.renderer.hr(r);
2618
+ break;
2619
+ }
2620
+ case "heading": {
2621
+ t2 += this.renderer.heading(r);
2622
+ break;
2623
+ }
2624
+ case "code": {
2625
+ t2 += this.renderer.code(r);
2626
+ break;
2627
+ }
2628
+ case "table": {
2629
+ t2 += this.renderer.table(r);
2630
+ break;
2631
+ }
2632
+ case "blockquote": {
2633
+ t2 += this.renderer.blockquote(r);
2634
+ break;
2635
+ }
2636
+ case "list": {
2637
+ t2 += this.renderer.list(r);
2638
+ break;
2639
+ }
2640
+ case "checkbox": {
2641
+ t2 += this.renderer.checkbox(r);
2642
+ break;
2643
+ }
2644
+ case "html": {
2645
+ t2 += this.renderer.html(r);
2646
+ break;
2647
+ }
2648
+ case "def": {
2649
+ t2 += this.renderer.def(r);
2650
+ break;
2651
+ }
2652
+ case "paragraph": {
2653
+ t2 += this.renderer.paragraph(r);
2654
+ break;
2655
+ }
2656
+ case "text": {
2657
+ t2 += this.renderer.text(r);
2658
+ break;
2659
+ }
2660
+ default: {
2661
+ let i = 'Token with "' + r.type + '" type was not found.';
2662
+ if (this.options.silent) return console.error(i), "";
2663
+ throw new Error(i);
2664
+ }
2665
+ }
2666
+ }
2667
+ return t2;
2668
+ }
2669
+ parseInline(e, t2 = this.renderer) {
2670
+ this.renderer.parser = this;
2671
+ let n = "";
2672
+ for (let s = 0; s < e.length; s++) {
2673
+ let r = e[s];
2674
+ if (this.options.extensions?.renderers?.[r.type]) {
2675
+ let o = this.options.extensions.renderers[r.type].call({ parser: this }, r);
2676
+ if (o !== false || !["escape", "html", "link", "image", "strong", "em", "codespan", "br", "del", "text"].includes(r.type)) {
2677
+ n += o || "";
2678
+ continue;
2679
+ }
2680
+ }
2681
+ let i = r;
2682
+ switch (i.type) {
2683
+ case "escape": {
2684
+ n += t2.text(i);
2685
+ break;
2686
+ }
2687
+ case "html": {
2688
+ n += t2.html(i);
2689
+ break;
2690
+ }
2691
+ case "link": {
2692
+ n += t2.link(i);
2693
+ break;
2694
+ }
2695
+ case "image": {
2696
+ n += t2.image(i);
2697
+ break;
2698
+ }
2699
+ case "checkbox": {
2700
+ n += t2.checkbox(i);
2701
+ break;
2702
+ }
2703
+ case "strong": {
2704
+ n += t2.strong(i);
2705
+ break;
2706
+ }
2707
+ case "em": {
2708
+ n += t2.em(i);
2709
+ break;
2710
+ }
2711
+ case "codespan": {
2712
+ n += t2.codespan(i);
2713
+ break;
2714
+ }
2715
+ case "br": {
2716
+ n += t2.br(i);
2717
+ break;
2718
+ }
2719
+ case "del": {
2720
+ n += t2.del(i);
2721
+ break;
2722
+ }
2723
+ case "text": {
2724
+ n += t2.text(i);
2725
+ break;
2726
+ }
2727
+ default: {
2728
+ let o = 'Token with "' + i.type + '" type was not found.';
2729
+ if (this.options.silent) return console.error(o), "";
2730
+ throw new Error(o);
2731
+ }
2732
+ }
2733
+ }
2734
+ return n;
2735
+ }
2736
+ };
2737
+ var P = class {
2738
+ options;
2739
+ block;
2740
+ constructor(e) {
2741
+ this.options = e || T;
2742
+ }
2743
+ static passThroughHooks = /* @__PURE__ */ new Set(["preprocess", "postprocess", "processAllTokens", "emStrongMask"]);
2744
+ static passThroughHooksRespectAsync = /* @__PURE__ */ new Set(["preprocess", "postprocess", "processAllTokens"]);
2745
+ preprocess(e) {
2746
+ return e;
2747
+ }
2748
+ postprocess(e) {
2749
+ return e;
2750
+ }
2751
+ processAllTokens(e) {
2752
+ return e;
2753
+ }
2754
+ emStrongMask(e) {
2755
+ return e;
2756
+ }
2757
+ provideLexer(e = this.block) {
2758
+ return e ? x.lex : x.lexInline;
2759
+ }
2760
+ provideParser(e = this.block) {
2761
+ return e ? b.parse : b.parseInline;
2762
+ }
2763
+ };
2764
+ var q = class {
2765
+ defaults = M();
2766
+ options = this.setOptions;
2767
+ parse = this.parseMarkdown(true);
2768
+ parseInline = this.parseMarkdown(false);
2769
+ Parser = b;
2770
+ Renderer = y;
2771
+ TextRenderer = L;
2772
+ Lexer = x;
2773
+ Tokenizer = w;
2774
+ Hooks = P;
2775
+ constructor(...e) {
2776
+ this.use(...e);
2777
+ }
2778
+ walkTokens(e, t2) {
2779
+ let n = [];
2780
+ for (let s of e) switch (n = n.concat(t2.call(this, s)), s.type) {
2781
+ case "table": {
2782
+ let r = s;
2783
+ for (let i of r.header) n = n.concat(this.walkTokens(i.tokens, t2));
2784
+ for (let i of r.rows) for (let o of i) n = n.concat(this.walkTokens(o.tokens, t2));
2785
+ break;
2786
+ }
2787
+ case "list": {
2788
+ let r = s;
2789
+ n = n.concat(this.walkTokens(r.items, t2));
2790
+ break;
2791
+ }
2792
+ default: {
2793
+ let r = s;
2794
+ this.defaults.extensions?.childTokens?.[r.type] ? this.defaults.extensions.childTokens[r.type].forEach((i) => {
2795
+ let o = r[i].flat(1 / 0);
2796
+ n = n.concat(this.walkTokens(o, t2));
2797
+ }) : r.tokens && (n = n.concat(this.walkTokens(r.tokens, t2)));
2798
+ }
2799
+ }
2800
+ return n;
2801
+ }
2802
+ use(...e) {
2803
+ let t2 = this.defaults.extensions || { renderers: {}, childTokens: {} };
2804
+ return e.forEach((n) => {
2805
+ let s = { ...n };
2806
+ if (s.async = this.defaults.async || s.async || false, n.extensions && (n.extensions.forEach((r) => {
2807
+ if (!r.name) throw new Error("extension name required");
2808
+ if ("renderer" in r) {
2809
+ let i = t2.renderers[r.name];
2810
+ i ? t2.renderers[r.name] = function(...o) {
2811
+ let u = r.renderer.apply(this, o);
2812
+ return u === false && (u = i.apply(this, o)), u;
2813
+ } : t2.renderers[r.name] = r.renderer;
2814
+ }
2815
+ if ("tokenizer" in r) {
2816
+ if (!r.level || r.level !== "block" && r.level !== "inline") throw new Error("extension level must be 'block' or 'inline'");
2817
+ let i = t2[r.level];
2818
+ i ? i.unshift(r.tokenizer) : t2[r.level] = [r.tokenizer], r.start && (r.level === "block" ? t2.startBlock ? t2.startBlock.push(r.start) : t2.startBlock = [r.start] : r.level === "inline" && (t2.startInline ? t2.startInline.push(r.start) : t2.startInline = [r.start]));
2819
+ }
2820
+ "childTokens" in r && r.childTokens && (t2.childTokens[r.name] = r.childTokens);
2821
+ }), s.extensions = t2), n.renderer) {
2822
+ let r = this.defaults.renderer || new y(this.defaults);
2823
+ for (let i in n.renderer) {
2824
+ if (!(i in r)) throw new Error(`renderer '${i}' does not exist`);
2825
+ if (["options", "parser"].includes(i)) continue;
2826
+ let o = i, u = n.renderer[o], a = r[o];
2827
+ r[o] = (...c) => {
2828
+ let p = u.apply(r, c);
2829
+ return p === false && (p = a.apply(r, c)), p || "";
2830
+ };
2831
+ }
2832
+ s.renderer = r;
2833
+ }
2834
+ if (n.tokenizer) {
2835
+ let r = this.defaults.tokenizer || new w(this.defaults);
2836
+ for (let i in n.tokenizer) {
2837
+ if (!(i in r)) throw new Error(`tokenizer '${i}' does not exist`);
2838
+ if (["options", "rules", "lexer"].includes(i)) continue;
2839
+ let o = i, u = n.tokenizer[o], a = r[o];
2840
+ r[o] = (...c) => {
2841
+ let p = u.apply(r, c);
2842
+ return p === false && (p = a.apply(r, c)), p;
2843
+ };
2844
+ }
2845
+ s.tokenizer = r;
2846
+ }
2847
+ if (n.hooks) {
2848
+ let r = this.defaults.hooks || new P();
2849
+ for (let i in n.hooks) {
2850
+ if (!(i in r)) throw new Error(`hook '${i}' does not exist`);
2851
+ if (["options", "block"].includes(i)) continue;
2852
+ let o = i, u = n.hooks[o], a = r[o];
2853
+ P.passThroughHooks.has(i) ? r[o] = (c) => {
2854
+ if (this.defaults.async && P.passThroughHooksRespectAsync.has(i)) return (async () => {
2855
+ let k = await u.call(r, c);
2856
+ return a.call(r, k);
2857
+ })();
2858
+ let p = u.call(r, c);
2859
+ return a.call(r, p);
2860
+ } : r[o] = (...c) => {
2861
+ if (this.defaults.async) return (async () => {
2862
+ let k = await u.apply(r, c);
2863
+ return k === false && (k = await a.apply(r, c)), k;
2864
+ })();
2865
+ let p = u.apply(r, c);
2866
+ return p === false && (p = a.apply(r, c)), p;
2867
+ };
2868
+ }
2869
+ s.hooks = r;
2870
+ }
2871
+ if (n.walkTokens) {
2872
+ let r = this.defaults.walkTokens, i = n.walkTokens;
2873
+ s.walkTokens = function(o) {
2874
+ let u = [];
2875
+ return u.push(i.call(this, o)), r && (u = u.concat(r.call(this, o))), u;
2876
+ };
2877
+ }
2878
+ this.defaults = { ...this.defaults, ...s };
2879
+ }), this;
2880
+ }
2881
+ setOptions(e) {
2882
+ return this.defaults = { ...this.defaults, ...e }, this;
2883
+ }
2884
+ lexer(e, t2) {
2885
+ return x.lex(e, t2 ?? this.defaults);
2886
+ }
2887
+ parser(e, t2) {
2888
+ return b.parse(e, t2 ?? this.defaults);
2889
+ }
2890
+ parseMarkdown(e) {
2891
+ return (n, s) => {
2892
+ let r = { ...s }, i = { ...this.defaults, ...r }, o = this.onError(!!i.silent, !!i.async);
2893
+ if (this.defaults.async === true && r.async === false) return o(new Error("marked(): The async option was set to true by an extension. Remove async: false from the parse options object to return a Promise."));
2894
+ if (typeof n > "u" || n === null) return o(new Error("marked(): input parameter is undefined or null"));
2895
+ if (typeof n != "string") return o(new Error("marked(): input parameter is of type " + Object.prototype.toString.call(n) + ", string expected"));
2896
+ if (i.hooks && (i.hooks.options = i, i.hooks.block = e), i.async) return (async () => {
2897
+ let u = i.hooks ? await i.hooks.preprocess(n) : n, c = await (i.hooks ? await i.hooks.provideLexer(e) : e ? x.lex : x.lexInline)(u, i), p = i.hooks ? await i.hooks.processAllTokens(c) : c;
2898
+ i.walkTokens && await Promise.all(this.walkTokens(p, i.walkTokens));
2899
+ let h = await (i.hooks ? await i.hooks.provideParser(e) : e ? b.parse : b.parseInline)(p, i);
2900
+ return i.hooks ? await i.hooks.postprocess(h) : h;
2901
+ })().catch(o);
2902
+ try {
2903
+ i.hooks && (n = i.hooks.preprocess(n));
2904
+ let a = (i.hooks ? i.hooks.provideLexer(e) : e ? x.lex : x.lexInline)(n, i);
2905
+ i.hooks && (a = i.hooks.processAllTokens(a)), i.walkTokens && this.walkTokens(a, i.walkTokens);
2906
+ let p = (i.hooks ? i.hooks.provideParser(e) : e ? b.parse : b.parseInline)(a, i);
2907
+ return i.hooks && (p = i.hooks.postprocess(p)), p;
2908
+ } catch (u) {
2909
+ return o(u);
2910
+ }
2911
+ };
2912
+ }
2913
+ onError(e, t2) {
2914
+ return (n) => {
2915
+ if (n.message += `
2916
+ Please report this to https://github.com/markedjs/marked.`, e) {
2917
+ let s = "<p>An error occurred:</p><pre>" + O(n.message + "", true) + "</pre>";
2918
+ return t2 ? Promise.resolve(s) : s;
2919
+ }
2920
+ if (t2) return Promise.reject(n);
2921
+ throw n;
2922
+ };
2923
+ }
2924
+ };
2925
+ var z = new q();
2926
+ function g(l3, e) {
2927
+ return z.parse(l3, e);
2928
+ }
2929
+ g.options = g.setOptions = function(l3) {
2930
+ return z.setOptions(l3), g.defaults = z.defaults, N(g.defaults), g;
2931
+ };
2932
+ g.getDefaults = M;
2933
+ g.defaults = T;
2934
+ g.use = function(...l3) {
2935
+ return z.use(...l3), g.defaults = z.defaults, N(g.defaults), g;
2936
+ };
2937
+ g.walkTokens = function(l3, e) {
2938
+ return z.walkTokens(l3, e);
2939
+ };
2940
+ g.parseInline = z.parseInline;
2941
+ g.Parser = b;
2942
+ g.parser = b.parse;
2943
+ g.Renderer = y;
2944
+ g.TextRenderer = L;
2945
+ g.Lexer = x;
2946
+ g.lexer = x.lex;
2947
+ g.Tokenizer = w;
2948
+ g.Hooks = P;
2949
+ g.parse = g;
2950
+ g.options;
2951
+ g.setOptions;
2952
+ g.use;
2953
+ g.walkTokens;
2954
+ g.parseInline;
2955
+ b.parse;
2956
+ x.lex;
2957
+ g.setOptions({ breaks: true, gfm: true });
2958
+ function sanitize(html) {
2959
+ return html.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, "");
2960
+ }
2961
+ function renderMarkdown(text) {
2962
+ if (!text) return "";
2963
+ return sanitize(g.parse(text));
2964
+ }
2965
+ var IconMic = () => /* @__PURE__ */ jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.2", strokeLinecap: "round", strokeLinejoin: "round", children: [
2966
+ /* @__PURE__ */ jsx("rect", { x: "9", y: "1", width: "6", height: "11", rx: "3" }),
2967
+ /* @__PURE__ */ jsx("path", { d: "M19 10v1a7 7 0 0 1-14 0v-1" }),
2968
+ /* @__PURE__ */ jsx("line", { x1: "12", y1: "19", x2: "12", y2: "23" }),
2969
+ /* @__PURE__ */ jsx("line", { x1: "8", y1: "23", x2: "16", y2: "23" })
2970
+ ] });
2971
+ var IconSend = () => /* @__PURE__ */ jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "M2 8l12-6-4 14-3-6-5-2z" }) });
2972
+ var IconTrash = () => /* @__PURE__ */ jsx("svg", { width: "13", height: "13", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", children: /* @__PURE__ */ jsx("path", { d: "M2 4h12M5 4V3a1 1 0 011-1h4a1 1 0 011 1v1M6 7v5M10 7v5M3 4l1 9a2 2 0 002 2h4a2 2 0 002-2l1-9" }) });
2973
+ var IconBack = () => /* @__PURE__ */ jsx("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("polyline", { points: "15 18 9 12 15 6" }) });
2974
+ function StreamingText({ targetText, streaming }) {
2975
+ const CHARS_PER_FRAME = 2;
2976
+ const displayedRef = useRef(0);
2977
+ const rafRef = useRef(null);
2978
+ const nodeRef = useRef(null);
2979
+ const prevTargetRef = useRef("");
2980
+ if (targetText.length < prevTargetRef.current.length) {
2981
+ displayedRef.current = 0;
2982
+ }
2983
+ prevTargetRef.current = targetText;
2984
+ useEffect(() => {
2985
+ if (!streaming) {
2986
+ displayedRef.current = targetText.length;
2987
+ if (nodeRef.current) {
2988
+ nodeRef.current.innerHTML = renderMarkdown(targetText);
2989
+ }
2990
+ return;
2991
+ }
2992
+ function tick() {
2993
+ const target = targetText.length;
2994
+ const current = displayedRef.current;
2995
+ if (current < target) {
2996
+ displayedRef.current = Math.min(current + CHARS_PER_FRAME, target);
2997
+ const visible = targetText.slice(0, displayedRef.current);
2998
+ if (nodeRef.current) {
2999
+ nodeRef.current.innerHTML = renderMarkdown(visible);
3000
+ }
3001
+ rafRef.current = requestAnimationFrame(tick);
3002
+ }
3003
+ }
3004
+ rafRef.current = requestAnimationFrame(tick);
3005
+ return () => {
3006
+ if (rafRef.current) cancelAnimationFrame(rafRef.current);
3007
+ };
3008
+ }, [targetText, streaming]);
3009
+ const initialHtml = useMemo(() => {
3010
+ if (!streaming) return renderMarkdown(targetText);
3011
+ const visible = targetText.slice(0, displayedRef.current);
3012
+ return renderMarkdown(visible);
3013
+ }, [targetText, streaming]);
3014
+ return /* @__PURE__ */ jsx("div", { className: "vw-cv-md", ref: nodeRef, dangerouslySetInnerHTML: { __html: initialHtml } });
3015
+ }
3016
+ function ChatView({
3017
+ agent,
3018
+ server,
3019
+ name,
3020
+ locale,
3021
+ labels,
3022
+ chat,
3023
+ tokenProvider,
3024
+ onBack,
3025
+ onVoiceCall
3026
+ }) {
3027
+ const [input, setInput] = useState("");
3028
+ const bodyRef = useRef(null);
3029
+ const inputRef = useRef(null);
3030
+ const chatTokenProvider = chat.tokenProvider || tokenProvider;
3031
+ const { messages, send, connected, typing, error } = usePinecallChat({
3032
+ agent,
3033
+ server,
3034
+ tokenProvider: chatTokenProvider
3035
+ });
3036
+ useEffect(() => {
3037
+ requestAnimationFrame(() => {
3038
+ if (bodyRef.current) {
3039
+ bodyRef.current.scrollTo({ top: bodyRef.current.scrollHeight, behavior: "smooth" });
3040
+ }
3041
+ });
3042
+ }, [messages, typing]);
3043
+ const allMessages = useMemo(() => {
3044
+ if (!chat.greeting) return messages;
3045
+ const greetingMsg = {
3046
+ id: 0,
3047
+ role: "bot",
3048
+ text: chat.greeting,
3049
+ isStreaming: false
3050
+ };
3051
+ return [greetingMsg, ...messages];
3052
+ }, [messages, chat.greeting]);
3053
+ const hasUserMessages = messages.some((m2) => m2.role === "user");
3054
+ const handleSubmit = (e) => {
3055
+ e.preventDefault();
3056
+ if (!input.trim() || typing) return;
3057
+ send(input.trim());
3058
+ setInput("");
3059
+ requestAnimationFrame(() => inputRef.current?.focus({ preventScroll: true }));
3060
+ };
3061
+ const handleQuick = useCallback((query) => {
3062
+ send(query);
3063
+ }, [send]);
3064
+ const handleClear = useCallback(() => {
3065
+ window.location.reload();
3066
+ }, []);
3067
+ return /* @__PURE__ */ jsxs("div", { className: "vw-cv", children: [
3068
+ /* @__PURE__ */ jsxs("div", { className: "vw-cv-head", children: [
3069
+ /* @__PURE__ */ jsx("button", { className: "vw-cv-back", onClick: onBack, children: /* @__PURE__ */ jsx(IconBack, {}) }),
3070
+ /* @__PURE__ */ jsx("div", { className: "vw-cv-avatar", children: name.charAt(0) }),
3071
+ /* @__PURE__ */ jsxs("div", { className: "vw-cv-who", children: [
3072
+ /* @__PURE__ */ jsx("span", { className: "vw-cv-name", children: name }),
3073
+ /* @__PURE__ */ jsxs("span", { className: "vw-cv-status", children: [
3074
+ /* @__PURE__ */ jsx("span", { className: `vw-cv-dot ${connected ? "" : "vw-cv-dot--off"}` }),
3075
+ connected ? "en l\xEDnea" : "conectando\u2026"
3076
+ ] })
3077
+ ] }),
3078
+ /* @__PURE__ */ jsxs("div", { className: "vw-cv-actions", children: [
3079
+ hasUserMessages && /* @__PURE__ */ jsx("button", { className: "vw-cv-action", onClick: handleClear, title: "Nueva conversaci\xF3n", children: /* @__PURE__ */ jsx(IconTrash, {}) }),
3080
+ /* @__PURE__ */ jsx("button", { className: "vw-cv-action vw-cv-action--voice", onClick: onVoiceCall, title: "Llamada de voz", children: /* @__PURE__ */ jsx(IconMic, {}) })
3081
+ ] })
3082
+ ] }),
3083
+ /* @__PURE__ */ jsxs("div", { className: "vw-cv-body", ref: bodyRef, children: [
3084
+ allMessages.map((msg) => {
3085
+ if (msg.role === "user") {
3086
+ return /* @__PURE__ */ jsx("div", { className: "vw-cv-msg vw-cv-msg--user", children: msg.text }, msg.id);
3087
+ }
3088
+ return /* @__PURE__ */ jsxs("div", { className: `vw-cv-msg vw-cv-msg--bot ${msg.isStreaming ? "vw-cv-streaming" : ""}`, children: [
3089
+ /* @__PURE__ */ jsx(StreamingText, { targetText: msg.text || "", streaming: !!msg.isStreaming }),
3090
+ msg.isStreaming && /* @__PURE__ */ jsx("span", { className: "vw-cv-cursor" })
3091
+ ] }, msg.id);
3092
+ }),
3093
+ typing && !messages.some((m2) => m2.isStreaming) && /* @__PURE__ */ jsxs("div", { className: "vw-cv-msg vw-cv-msg--bot vw-cv-skeleton", children: [
3094
+ /* @__PURE__ */ jsx("span", { className: "vw-cv-sk-dot" }),
3095
+ /* @__PURE__ */ jsx("span", { className: "vw-cv-sk-dot" }),
3096
+ /* @__PURE__ */ jsx("span", { className: "vw-cv-sk-dot" })
3097
+ ] }),
3098
+ error && /* @__PURE__ */ jsxs("div", { className: "vw-cv-msg vw-cv-msg--bot", style: { color: "rgba(248,113,113,.9)", borderColor: "rgba(248,113,113,.2)" }, children: [
3099
+ "\u26A0\uFE0F ",
3100
+ error
3101
+ ] })
3102
+ ] }),
3103
+ !hasUserMessages && chat.quickOptions && chat.quickOptions.length > 0 && /* @__PURE__ */ jsx("div", { className: "vw-cv-quick", children: chat.quickOptions.map((opt, i) => /* @__PURE__ */ jsx("button", { onClick: () => handleQuick(opt.query), disabled: typing, children: opt.label }, i)) }),
3104
+ /* @__PURE__ */ jsxs("form", { className: "vw-cv-input", onSubmit: handleSubmit, autoComplete: "off", children: [
3105
+ /* @__PURE__ */ jsx(
3106
+ "input",
3107
+ {
3108
+ ref: inputRef,
3109
+ type: "text",
3110
+ placeholder: "Escrib\xED tu mensaje...",
3111
+ value: input,
3112
+ onChange: (e) => setInput(e.target.value),
3113
+ disabled: typing
3114
+ }
3115
+ ),
3116
+ /* @__PURE__ */ jsx("button", { type: "submit", className: "vw-cv-send", disabled: typing || !input.trim(), children: /* @__PURE__ */ jsx(IconSend, {}) })
3117
+ ] })
3118
+ ] });
3119
+ }
3120
+ var IconMic2 = () => /* @__PURE__ */ jsxs("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.2", strokeLinecap: "round", strokeLinejoin: "round", children: [
3121
+ /* @__PURE__ */ jsx("rect", { x: "9", y: "1", width: "6", height: "11", rx: "3" }),
3122
+ /* @__PURE__ */ jsx("path", { d: "M19 10v1a7 7 0 0 1-14 0v-1" }),
3123
+ /* @__PURE__ */ jsx("line", { x1: "12", y1: "19", x2: "12", y2: "23" }),
3124
+ /* @__PURE__ */ jsx("line", { x1: "8", y1: "23", x2: "16", y2: "23" })
3125
+ ] });
3126
+ var IconWhatsApp = () => /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ jsx("path", { d: "M17.5 14.4c-.3-.1-1.7-.8-2-.9-.3-.1-.5-.2-.7.1-.2.3-.8.9-1 1.1-.2.2-.4.2-.7.1-.3-.1-1.3-.5-2.4-1.5-.9-.8-1.5-1.8-1.7-2.1-.2-.3 0-.5.1-.6.1-.1.3-.4.4-.5.1-.2.2-.3.3-.5.1-.2 0-.4 0-.5-.1-.1-.7-1.7-.9-2.3-.2-.6-.5-.5-.7-.5h-.6c-.2 0-.5.1-.8.4-.3.3-1 1-1 2.4 0 1.4 1 2.8 1.2 3 .1.2 2 3 4.8 4.2.7.3 1.2.5 1.6.6.7.2 1.3.2 1.8.1.6-.1 1.7-.7 1.9-1.3.2-.7.2-1.2.2-1.3-.1-.1-.3-.2-.6-.3zM12 2C6.5 2 2 6.5 2 12c0 1.8.5 3.5 1.3 5L2 22l5.2-1.3c1.4.8 3 1.2 4.7 1.2h.1c5.5 0 10-4.5 10-10S17.5 2 12 2z" }) });
3127
+ var IconPhone = ({ size = 20 }) => /* @__PURE__ */ jsx("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z" }) });
3128
+ var IconX = ({ size = 16 }) => /* @__PURE__ */ jsxs("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
3129
+ /* @__PURE__ */ jsx("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
3130
+ /* @__PURE__ */ jsx("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
3131
+ ] });
3132
+ function findLastIndex(arr, fn) {
3133
+ for (let i = arr.length - 1; i >= 0; i--) {
3134
+ if (fn(arr[i])) return i;
3135
+ }
3136
+ return -1;
3137
+ }
3138
+ function whatsappUrl(phone) {
3139
+ const clean = phone.replace(/\D/g, "");
3140
+ return `https://wa.me/${clean}`;
3141
+ }
3142
+ function ContactHub({
3143
+ open,
3144
+ onClose,
3145
+ channels,
3146
+ name,
3147
+ locale,
3148
+ labels,
3149
+ avatar,
3150
+ callMeEndpoint,
3151
+ agent,
3152
+ server,
3153
+ chat,
3154
+ tokenProvider,
3155
+ onCallMeState,
3156
+ connect
3157
+ }) {
3158
+ const [view, setView] = useState("menu");
3159
+ const [phone, setPhone] = useState("");
3160
+ const [status, setStatus] = useState("idle");
3161
+ const [errorMsg, setErrorMsg] = useState("");
3162
+ useEffect(() => {
3163
+ if (document.getElementById("vw-hub-styles")) return;
3164
+ const el = document.createElement("style");
3165
+ el.id = "vw-hub-styles";
3166
+ el.textContent = HUB_CSS + CHAT_VIEW_CSS;
3167
+ document.head.appendChild(el);
3168
+ }, []);
3169
+ const sseAbortRef = useRef(null);
3170
+ const sseMessagesRef = useRef([]);
3171
+ const sseIdCounter = useRef(0);
3172
+ const sseDurationRef = useRef(0);
3173
+ const sseTimerRef = useRef(null);
3174
+ const sseStartTimeRef = useRef(null);
3175
+ const ssePhoneRef = useRef("");
3176
+ useEffect(() => {
3177
+ if (!open) {
3178
+ const timer = setTimeout(() => {
3179
+ setView("menu");
3180
+ setStatus("idle");
3181
+ setPhone("");
3182
+ setErrorMsg("");
3183
+ }, 300);
3184
+ return () => clearTimeout(timer);
3185
+ }
3186
+ }, [open]);
3187
+ useEffect(() => {
3188
+ return () => {
3189
+ sseAbortRef.current?.abort();
3190
+ if (sseTimerRef.current) clearInterval(sseTimerRef.current);
3191
+ };
3192
+ }, []);
3193
+ const hasWebrtc = channels.some((c) => c.type === "webrtc");
3194
+ const hasChat = channels.some((c) => c.type === "chat") && !!chat;
3195
+ const waChannel = channels.find((c) => c.type === "whatsapp" && c.phone);
3196
+ const phoneChannel = channels.find((c) => c.type === "phone");
3197
+ const showCallMe = !!callMeEndpoint && !!phoneChannel;
3198
+ const handleVoice = async () => {
3199
+ onClose();
3200
+ await connect();
3201
+ };
3202
+ const l3 = (key) => t(locale, key, labels, { name });
3203
+ const handleVoiceFromChat = async () => {
3204
+ onClose();
3205
+ await connect();
3206
+ };
3207
+ const emitSSEState = (status2) => {
3208
+ onCallMeState?.({
3209
+ status: status2,
3210
+ messages: [...sseMessagesRef.current],
3211
+ duration: sseDurationRef.current,
3212
+ phone: ssePhoneRef.current
3213
+ });
3214
+ };
3215
+ const handleSSEEvent = (event, data) => {
3216
+ switch (event) {
3217
+ case "call.started": {
3218
+ sseStartTimeRef.current = Date.now();
3219
+ sseTimerRef.current = setInterval(() => {
3220
+ sseDurationRef.current = Math.floor((Date.now() - sseStartTimeRef.current) / 1e3);
3221
+ emitSSEState("connected");
3222
+ }, 1e3);
3223
+ emitSSEState("connected");
3224
+ break;
3225
+ }
3226
+ case "bot.word": {
3227
+ const mid = data.messageId;
3228
+ const msgs = sseMessagesRef.current;
3229
+ const idx = msgs.findIndex((m2) => m2.role === "bot" && m2.messageId === mid);
3230
+ if (idx >= 0) {
3231
+ msgs[idx] = { ...msgs[idx], text: data.text, speaking: true };
3232
+ } else {
3233
+ msgs.push({ id: ++sseIdCounter.current, role: "bot", messageId: mid, text: data.text, speaking: true });
3234
+ }
3235
+ sseMessagesRef.current = [...msgs];
3236
+ emitSSEState("connected");
3237
+ break;
3238
+ }
3239
+ case "bot.confirmed": {
3240
+ const mid = data.messageId;
3241
+ const msgs = sseMessagesRef.current;
3242
+ const idx = msgs.findIndex((m2) => m2.role === "bot" && m2.messageId === mid);
3243
+ if (idx >= 0) {
3244
+ msgs[idx] = { ...msgs[idx], text: data.text, speaking: false };
3245
+ } else {
3246
+ msgs.push({ id: ++sseIdCounter.current, role: "bot", messageId: mid, text: data.text, speaking: false });
3247
+ }
3248
+ sseMessagesRef.current = [...msgs];
3249
+ emitSSEState("connected");
3250
+ break;
3251
+ }
3252
+ case "user.speaking": {
3253
+ if (!data.text) break;
3254
+ const msgs = sseMessagesRef.current;
3255
+ const lastUserIdx = findLastIndex(msgs, (m2) => m2.role === "user");
3256
+ const hasBotAfter = lastUserIdx >= 0 && msgs.slice(lastUserIdx + 1).some((m2) => m2.role === "bot");
3257
+ if (lastUserIdx >= 0 && !hasBotAfter) {
3258
+ msgs[lastUserIdx] = { ...msgs[lastUserIdx], text: data.text, isInterim: true };
3259
+ } else {
3260
+ msgs.push({ id: ++sseIdCounter.current, role: "user", text: data.text, isInterim: true });
3261
+ }
3262
+ sseMessagesRef.current = [...msgs];
3263
+ emitSSEState("connected");
3264
+ break;
3265
+ }
3266
+ case "user.message": {
3267
+ if (!data.text) break;
3268
+ const msgs = sseMessagesRef.current;
3269
+ const idx = findLastIndex(msgs, (m2) => m2.role === "user" && !!m2.isInterim);
3270
+ if (idx >= 0) {
3271
+ msgs[idx] = { ...msgs[idx], text: data.text, isInterim: false };
3272
+ } else {
3273
+ msgs.push({ id: ++sseIdCounter.current, role: "user", text: data.text, isInterim: false });
3274
+ }
3275
+ sseMessagesRef.current = [...msgs];
3276
+ emitSSEState("connected");
3277
+ break;
3278
+ }
3279
+ case "call.ended": {
3280
+ sseDurationRef.current = data.duration || sseDurationRef.current;
3281
+ if (sseTimerRef.current) clearInterval(sseTimerRef.current);
3282
+ onCallMeState?.({
3283
+ status: "ended",
3284
+ messages: [...sseMessagesRef.current],
3285
+ duration: sseDurationRef.current,
3286
+ phone: ssePhoneRef.current
3287
+ });
3288
+ break;
3289
+ }
3290
+ case "error": {
3291
+ if (sseTimerRef.current) clearInterval(sseTimerRef.current);
3292
+ onCallMeState?.({
3293
+ status: "error",
3294
+ messages: [],
3295
+ duration: 0,
3296
+ phone: ssePhoneRef.current,
3297
+ error: data.message
3298
+ });
3299
+ break;
3300
+ }
3301
+ }
3302
+ };
3303
+ const startCallMe = async (phoneNum) => {
3304
+ sseMessagesRef.current = [];
3305
+ sseIdCounter.current = 0;
3306
+ sseDurationRef.current = 0;
3307
+ sseStartTimeRef.current = null;
3308
+ ssePhoneRef.current = phoneNum;
3309
+ const controller = new AbortController();
3310
+ sseAbortRef.current = controller;
3311
+ onCallMeState?.({ status: "dialing", messages: [], duration: 0, phone: phoneNum });
3312
+ let res;
3313
+ try {
3314
+ res = await fetch(callMeEndpoint, {
3315
+ method: "POST",
3316
+ headers: { "Content-Type": "application/json" },
3317
+ body: JSON.stringify({ phone: phoneNum }),
3318
+ signal: controller.signal
3319
+ });
3320
+ } catch (err) {
3321
+ if (err.name === "AbortError") return;
3322
+ onCallMeState?.({ status: "error", messages: [], duration: 0, phone: phoneNum, error: l3("callMe.error") });
3323
+ return;
3324
+ }
3325
+ const ct = res.headers.get("content-type") || "";
3326
+ if (ct.includes("application/json")) {
3327
+ const data = await res.json().catch(() => ({}));
3328
+ onCallMeState?.({ status: "error", messages: [], duration: 0, phone: phoneNum, error: data.error || l3("callMe.error") });
3329
+ return;
3330
+ }
3331
+ const reader = res.body.getReader();
3332
+ const decoder = new TextDecoder();
3333
+ let buffer = "";
3334
+ try {
3335
+ while (true) {
3336
+ const { done, value } = await reader.read();
3337
+ if (done) break;
3338
+ buffer += decoder.decode(value, { stream: true });
3339
+ const lines = buffer.split("\n");
3340
+ buffer = lines.pop();
3341
+ let currentEvent = "";
3342
+ for (const line of lines) {
3343
+ if (line.startsWith("event: ")) {
3344
+ currentEvent = line.slice(7).trim();
3345
+ } else if (line.startsWith("data: ") && currentEvent) {
3346
+ try {
3347
+ const data = JSON.parse(line.slice(6));
3348
+ handleSSEEvent(currentEvent, data);
3349
+ } catch {
3350
+ }
3351
+ currentEvent = "";
3352
+ }
3353
+ }
3354
+ }
3355
+ } catch (err) {
3356
+ if (err.name !== "AbortError") {
3357
+ console.error("[ContactHub] Stream error:", err);
3358
+ }
3359
+ }
3360
+ };
3361
+ const handleStartCall = (e) => {
3362
+ e.preventDefault();
3363
+ if (!phone.trim()) return;
3364
+ onClose();
3365
+ startCallMe(phone.trim());
3366
+ };
3367
+ if (!open) return null;
3368
+ return /* @__PURE__ */ jsx("div", { className: "vw-hub-backdrop", onClick: (e) => {
3369
+ if (e.target === e.currentTarget) onClose();
3370
+ }, children: /* @__PURE__ */ jsxs("div", { className: `vw-hub-panel${view === "chat" ? " vw-hub-panel--chat" : ""}`, children: [
3371
+ view !== "chat" && /* @__PURE__ */ jsx("button", { className: "vw-hub-close", onClick: onClose, children: /* @__PURE__ */ jsx(IconX, {}) }),
3372
+ view === "menu" ? /* @__PURE__ */ jsxs("div", { className: "vw-hub-menu", children: [
3373
+ /* @__PURE__ */ jsxs("div", { className: "vw-hub-header", children: [
3374
+ avatar && /* @__PURE__ */ jsx("div", { className: "vw-hub-avatar", children: avatar }),
3375
+ /* @__PURE__ */ jsx("h3", { children: l3("hub.title") }),
3376
+ /* @__PURE__ */ jsx("p", { children: l3("hub.subtitle") })
3377
+ ] }),
3378
+ /* @__PURE__ */ jsxs("div", { className: "vw-hub-options", children: [
3379
+ hasWebrtc && /* @__PURE__ */ jsxs("button", { className: "vw-hub-opt", onClick: handleVoice, children: [
3380
+ /* @__PURE__ */ jsx("span", { className: "vw-hub-icon vw-hub-icon--voice", children: /* @__PURE__ */ jsx(IconMic2, {}) }),
3381
+ /* @__PURE__ */ jsxs("span", { className: "vw-hub-body", children: [
3382
+ /* @__PURE__ */ jsx("span", { className: "vw-hub-title", children: l3("hub.voice") }),
3383
+ /* @__PURE__ */ jsx("span", { className: "vw-hub-desc", children: l3("hub.voiceDesc") })
3384
+ ] }),
3385
+ /* @__PURE__ */ jsx("span", { className: "vw-hub-arrow", children: "\u2192" })
3386
+ ] }),
3387
+ hasChat && /* @__PURE__ */ jsxs("button", { className: "vw-hub-opt", onClick: () => setView("chat"), children: [
3388
+ /* @__PURE__ */ jsx("span", { className: "vw-hub-icon vw-hub-icon--chat", children: /* @__PURE__ */ jsx("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" }) }) }),
3389
+ /* @__PURE__ */ jsxs("span", { className: "vw-hub-body", children: [
3390
+ /* @__PURE__ */ jsx("span", { className: "vw-hub-title", children: l3("hub.chat") }),
3391
+ /* @__PURE__ */ jsx("span", { className: "vw-hub-desc", children: l3("hub.chatDesc") })
3392
+ ] }),
3393
+ /* @__PURE__ */ jsx("span", { className: "vw-hub-arrow", children: "\u2192" })
3394
+ ] }),
3395
+ waChannel && /* @__PURE__ */ jsxs(
3396
+ "a",
3397
+ {
3398
+ className: "vw-hub-opt",
3399
+ href: whatsappUrl(waChannel.phone),
3400
+ target: "_blank",
3401
+ rel: "noopener noreferrer",
3402
+ onClick: onClose,
3403
+ children: [
3404
+ /* @__PURE__ */ jsx("span", { className: "vw-hub-icon vw-hub-icon--wa", children: /* @__PURE__ */ jsx(IconWhatsApp, {}) }),
3405
+ /* @__PURE__ */ jsxs("span", { className: "vw-hub-body", children: [
3406
+ /* @__PURE__ */ jsx("span", { className: "vw-hub-title", children: l3("hub.whatsapp") }),
3407
+ /* @__PURE__ */ jsx("span", { className: "vw-hub-desc", children: l3("hub.whatsappDesc") })
3408
+ ] }),
3409
+ /* @__PURE__ */ jsx("span", { className: "vw-hub-arrow", children: "\u2192" })
3410
+ ]
3411
+ }
3412
+ ),
3413
+ showCallMe && /* @__PURE__ */ jsxs("button", { className: "vw-hub-opt", onClick: () => setView("call"), children: [
3414
+ /* @__PURE__ */ jsx("span", { className: "vw-hub-icon vw-hub-icon--call", children: /* @__PURE__ */ jsx(IconPhone, {}) }),
3415
+ /* @__PURE__ */ jsxs("span", { className: "vw-hub-body", children: [
3416
+ /* @__PURE__ */ jsx("span", { className: "vw-hub-title", children: l3("hub.callMe") }),
3417
+ /* @__PURE__ */ jsx("span", { className: "vw-hub-desc", children: l3("hub.callMeDesc") })
3418
+ ] }),
3419
+ /* @__PURE__ */ jsx("span", { className: "vw-hub-arrow", children: "\u2192" })
3420
+ ] })
3421
+ ] })
3422
+ ] }) : view === "call" ? /* @__PURE__ */ jsxs("div", { className: "vw-cm", children: [
3423
+ /* @__PURE__ */ jsxs("button", { className: "vw-cm-back", onClick: () => setView("menu"), children: [
3424
+ "\u2190 ",
3425
+ l3("callMe.back")
3426
+ ] }),
3427
+ /* @__PURE__ */ jsx("div", { className: "vw-cm-phone-icon", children: /* @__PURE__ */ jsx(IconPhone, { size: 24 }) }),
3428
+ /* @__PURE__ */ jsx("h3", { children: l3("callMe.title") }),
3429
+ /* @__PURE__ */ jsxs("form", { className: "vw-cm-form", onSubmit: handleStartCall, children: [
3430
+ /* @__PURE__ */ jsx(
3431
+ "input",
3432
+ {
3433
+ type: "tel",
3434
+ placeholder: l3("callMe.placeholder"),
3435
+ value: phone,
3436
+ onChange: (e) => {
3437
+ setPhone(e.target.value);
3438
+ if (status === "error") setStatus("idle");
3439
+ },
3440
+ autoFocus: true
3441
+ }
3442
+ ),
3443
+ /* @__PURE__ */ jsxs("button", { type: "submit", disabled: !phone.trim(), children: [
3444
+ /* @__PURE__ */ jsx(IconPhone, { size: 16 }),
3445
+ l3("callMe.submit")
3446
+ ] }),
3447
+ status === "error" && /* @__PURE__ */ jsx("span", { className: "vw-cm-error", children: errorMsg }),
3448
+ l3("callMe.formNote") && /* @__PURE__ */ jsx("span", { className: "vw-cm-note", dangerouslySetInnerHTML: { __html: l3("callMe.formNote") } })
3449
+ ] })
3450
+ ] }) : view === "chat" ? /* @__PURE__ */ jsx(
3451
+ ChatView,
3452
+ {
3453
+ agent,
3454
+ server,
3455
+ name,
3456
+ locale,
3457
+ labels,
3458
+ chat,
3459
+ tokenProvider,
3460
+ onBack: () => setView("menu"),
3461
+ onVoiceCall: handleVoiceFromChat
3462
+ }
3463
+ ) : null
3464
+ ] }) });
3465
+ }
3466
+ var cache = /* @__PURE__ */ new Map();
3467
+ function useAgentInfo(agentId, server = "https://voice.pinecall.io") {
3468
+ const key = `${server}|${agentId}`;
3469
+ const [info, setInfo] = useState(cache.get(key) ?? null);
3470
+ const [loading, setLoading] = useState(!cache.has(key));
3471
+ const mountedRef = useRef(true);
3472
+ useEffect(() => {
3473
+ mountedRef.current = true;
3474
+ return () => {
3475
+ mountedRef.current = false;
3476
+ };
3477
+ }, []);
3478
+ useEffect(() => {
3479
+ if (cache.has(key)) {
3480
+ setInfo(cache.get(key));
3481
+ setLoading(false);
3482
+ return;
3483
+ }
3484
+ let cancelled = false;
3485
+ setLoading(true);
3486
+ const baseUrl = server.replace(/\/$/, "");
3487
+ fetch(`${baseUrl}/api/sdk/agent-info/${encodeURIComponent(agentId)}`).then((res) => {
3488
+ if (!res.ok) throw new Error(`${res.status}`);
3489
+ return res.json();
3490
+ }).then((data) => {
3491
+ if (!cancelled && mountedRef.current) {
3492
+ cache.set(key, data);
3493
+ setInfo(data);
3494
+ setLoading(false);
3495
+ }
3496
+ }).catch(() => {
3497
+ if (!cancelled && mountedRef.current) {
3498
+ setLoading(false);
3499
+ }
3500
+ });
3501
+ return () => {
3502
+ cancelled = true;
3503
+ };
3504
+ }, [key]);
3505
+ return { info, loading };
3506
+ }
3507
+
3508
+ export { ChatView, ContactHub, PRESETS, VoiceWidget, t, useAgentInfo, useVoice, useVoiceSession };
3509
+ //# sourceMappingURL=index.js.map
3510
+ //# sourceMappingURL=index.js.map