@burdenoff/website-sdk 2026.1102.2 → 2026.1104.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/README.md +63 -8
  2. package/dist/avatar-live-view/index.d.mts +29 -5
  3. package/dist/avatar-live-view/index.d.ts +29 -5
  4. package/dist/avatar-live-view/index.js +1319 -271
  5. package/dist/avatar-live-view/index.js.map +1 -1
  6. package/dist/avatar-live-view/index.mjs +1317 -269
  7. package/dist/avatar-live-view/index.mjs.map +1 -1
  8. package/dist/{chunk-R742FS5E.js → chunk-22OT6E26.js} +61 -27
  9. package/dist/chunk-22OT6E26.js.map +1 -0
  10. package/dist/{chunk-ETI2HQEC.mjs → chunk-5JQGE3XI.mjs} +46 -14
  11. package/dist/chunk-5JQGE3XI.mjs.map +1 -0
  12. package/dist/{chunk-FQH3AJN3.js → chunk-7O2I32ZN.js} +2 -2
  13. package/dist/chunk-7O2I32ZN.js.map +1 -0
  14. package/dist/{chunk-SFT3WHN5.mjs → chunk-K3QZGJEH.mjs} +2 -2
  15. package/dist/chunk-K3QZGJEH.mjs.map +1 -0
  16. package/dist/{chunk-SK5UGG6A.js → chunk-P5GMVPR6.js} +76 -20
  17. package/dist/chunk-P5GMVPR6.js.map +1 -0
  18. package/dist/{chunk-EUPFS6MZ.mjs → chunk-SMD7MEEA.mjs} +76 -20
  19. package/dist/chunk-SMD7MEEA.mjs.map +1 -0
  20. package/dist/components/explore.d.mts +2 -2
  21. package/dist/components/explore.d.ts +2 -2
  22. package/dist/components/explore.js +14 -14
  23. package/dist/components/explore.mjs +2 -2
  24. package/dist/{explore-DUTNYUOm.d.mts → explore-BV4dRwoC.d.ts} +8 -1
  25. package/dist/{explore-DjQE7Xia.d.ts → explore-BgEeGPvY.d.mts} +8 -1
  26. package/dist/{explore-avatar-live-config-Cetx8-Zu.d.ts → explore-avatar-live-config-CAfN5eAX.d.ts} +6 -3
  27. package/dist/{explore-avatar-live-config-Bp3kQbU2.d.mts → explore-avatar-live-config-N4WhJzgS.d.mts} +6 -3
  28. package/dist/{explore-types-Bb2Ih3d8.d.mts → explore-types-Ol1Mm3dW.d.mts} +12 -1
  29. package/dist/{explore-types-Bb2Ih3d8.d.ts → explore-types-Ol1Mm3dW.d.ts} +12 -1
  30. package/dist/hooks/index.d.mts +2 -2
  31. package/dist/hooks/index.d.ts +2 -2
  32. package/dist/hooks/index.js +9 -9
  33. package/dist/hooks/index.mjs +1 -1
  34. package/dist/index.d.mts +14 -8
  35. package/dist/index.d.ts +14 -8
  36. package/dist/index.js +100 -63
  37. package/dist/index.js.map +1 -1
  38. package/dist/index.mjs +43 -6
  39. package/dist/index.mjs.map +1 -1
  40. package/dist/{use-explore-chat-DunjG-3p.d.ts → use-explore-chat-B3dOOvJN.d.ts} +43 -3
  41. package/dist/{use-explore-chat-zRuoAin6.d.mts → use-explore-chat-CbfohA9O.d.mts} +43 -3
  42. package/package.json +1 -1
  43. package/dist/chunk-ETI2HQEC.mjs.map +0 -1
  44. package/dist/chunk-EUPFS6MZ.mjs.map +0 -1
  45. package/dist/chunk-FQH3AJN3.js.map +0 -1
  46. package/dist/chunk-R742FS5E.js.map +0 -1
  47. package/dist/chunk-SFT3WHN5.mjs.map +0 -1
  48. package/dist/chunk-SK5UGG6A.js.map +0 -1
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkFQH3AJN3_js = require('../chunk-FQH3AJN3.js');
3
+ var chunk7O2I32ZN_js = require('../chunk-7O2I32ZN.js');
4
4
  var chunkO4GS3XPZ_js = require('../chunk-O4GS3XPZ.js');
5
5
  var chunkC6OJIHNO_js = require('../chunk-C6OJIHNO.js');
6
6
  require('../chunk-ZSTFX7FV.js');
@@ -49,6 +49,15 @@ function readBotCheck(value) {
49
49
  }
50
50
  return mode === "off" ? "off" : "turnstile";
51
51
  }
52
+ var QUESTION_MODES = /* @__PURE__ */ new Set([
53
+ "any",
54
+ "suggested"
55
+ ]);
56
+ function readQuestions(value) {
57
+ if (value === void 0) return "suggested";
58
+ if (typeof value !== "string" || !QUESTION_MODES.has(value)) return null;
59
+ return value === "any" ? "any" : "suggested";
60
+ }
52
61
  function readAvailability(status, body) {
53
62
  if (status !== 200 || !isRecord(body)) return INERT;
54
63
  const { available, reason } = body;
@@ -58,16 +67,21 @@ function readAvailability(status, body) {
58
67
  if (reason === "ok") {
59
68
  const { consentVersion, maxSessionSeconds } = body;
60
69
  const botCheck = readBotCheck(body.botCheck);
61
- if (available !== true || typeof consentVersion !== "string" || !chunkFQH3AJN3_js.isAvatarVersion(consentVersion) || typeof maxSessionSeconds !== "number" || !Number.isInteger(maxSessionSeconds) || maxSessionSeconds < 1 || botCheck === null) {
70
+ const questions = readQuestions(body.questions);
71
+ if (available !== true || typeof consentVersion !== "string" || !chunk7O2I32ZN_js.isAvatarVersion(consentVersion) || typeof maxSessionSeconds !== "number" || !Number.isInteger(maxSessionSeconds) || maxSessionSeconds < 1 || botCheck === null || questions === null) {
62
72
  return INERT;
63
73
  }
64
74
  return {
65
75
  kind: "available",
66
- offer: { consentVersion, maxSessionSeconds, botCheck }
76
+ offer: { consentVersion, maxSessionSeconds, botCheck, questions }
67
77
  };
68
78
  }
69
79
  const meaning = available ? void 0 : AVAILABILITY_REASONS.get(reason);
70
- return meaning === void 0 || meaning === "inert" ? INERT : { kind: "refused", reason: meaning };
80
+ return meaning === void 0 || meaning === "inert" ? INERT : {
81
+ kind: "refused",
82
+ reason: meaning,
83
+ questions: body.questions === "any" ? "any" : "suggested"
84
+ };
71
85
  }
72
86
  var CREATE_REFUSALS = /* @__PURE__ */ new Map([
73
87
  ["busy", "busy"],
@@ -146,7 +160,7 @@ function deadline(timeoutMs, outer) {
146
160
  };
147
161
  }
148
162
  async function requestAvailability(target) {
149
- if (!chunkFQH3AJN3_js.isAvatarSite(target.site) || !LOCALE.test(target.locale)) return INERT;
163
+ if (!chunk7O2I32ZN_js.isAvatarSite(target.site) || !LOCALE.test(target.locale)) return INERT;
150
164
  const query = new URLSearchParams({
151
165
  site: target.site,
152
166
  locale: target.locale
@@ -287,7 +301,31 @@ var EN = {
287
301
  locale: "The live avatar isn't offered in this language yet.",
288
302
  paused: "The live avatar is paused right now.",
289
303
  notEligible: "The avatar reads the first answer to a suggested question, within fifteen minutes. Start a new chat and choose a suggested question.",
290
- answerClaimed: "The avatar has already read this answer."
304
+ answerClaimed: "The avatar has already read this answer.",
305
+ askHeadline: "Ask a question, and the avatar reads the answer aloud.",
306
+ askLabel: "Question for the avatar",
307
+ askPlaceholder: "Ask the avatar\u2026",
308
+ askFooter: "Answers are AI-generated and can be wrong. Don't include personal details.",
309
+ askNoFiles: "To attach files, use Chat.",
310
+ askBusy: "You can ask when the current answer is ready.",
311
+ askUnavailable: "Chat isn't available right now.",
312
+ gettingAnswer: "Getting the answer\u2026",
313
+ startWhenReady: "Start when ready",
314
+ armed: "The avatar will start when the answer is ready.",
315
+ cancel: "Cancel",
316
+ armedCancelled: "The avatar didn't start. Press Start when ready to try again.",
317
+ notSpoken: "This answer stays in Chat as text. The avatar reads only answers that pass its speech checks.",
318
+ answerFailed: "The assistant couldn't answer. Try asking again.",
319
+ declined: "No problem. The answer is in Chat.",
320
+ askHere: "To hear an answer, ask it here.",
321
+ newChatForAvatar: "New chat for the avatar",
322
+ newChatNote: "Your current chat stays in History.",
323
+ newChatStarted: "Started a new chat for the avatar.",
324
+ readInChat: "Read the answer and sources in Chat",
325
+ usedToday: "You've had today's avatar session. Answers will show here as text.",
326
+ needsAnswerAny: "Ask a question here, and the avatar reads the answer aloud.",
327
+ startNewChatDetailAny: "The avatar reads aloud only the first answer in a new chat started in the Avatar tab, provided it passes the speech checks.",
328
+ notEligibleAny: "The avatar can't read this answer aloud. The answer and sources are in Chat."
291
329
  };
292
330
  var ZH = {
293
331
  checking: "\u6B63\u5728\u68C0\u67E5\u5B9E\u65F6\u865A\u62DF\u5F62\u8C61\u662F\u5426\u53EF\u7528\u2026",
@@ -321,7 +359,32 @@ var ZH = {
321
359
  paused: "\u5B9E\u65F6\u865A\u62DF\u5F62\u8C61\u76EE\u524D\u5DF2\u6682\u505C\u3002",
322
360
  // TRANSLATION REVIEW PENDING (BOFF-9797): draft.
323
361
  notEligible: "\u865A\u62DF\u5F62\u8C61\u53EA\u6717\u8BFB\u63A8\u8350\u95EE\u9898\u7684\u7B2C\u4E00\u4E2A\u56DE\u7B54\uFF0C\u4E14\u987B\u5728\u5341\u4E94\u5206\u949F\u5185\u3002\u8BF7\u5F00\u59CB\u65B0\u7684\u804A\u5929\uFF0C\u5E76\u9009\u62E9\u4E00\u4E2A\u63A8\u8350\u95EE\u9898\u3002",
324
- answerClaimed: "\u865A\u62DF\u5F62\u8C61\u5DF2\u7ECF\u6717\u8BFB\u8FC7\u8FD9\u4E2A\u56DE\u7B54\u3002"
362
+ answerClaimed: "\u865A\u62DF\u5F62\u8C61\u5DF2\u7ECF\u6717\u8BFB\u8FC7\u8FD9\u4E2A\u56DE\u7B54\u3002",
363
+ // TRANSLATION REVIEW PENDING (BOFF-9797): draft, the Avatar tab's question box.
364
+ askHeadline: "\u63D0\u51FA\u95EE\u9898\uFF0C\u865A\u62DF\u5F62\u8C61\u4F1A\u6717\u8BFB\u56DE\u7B54\u3002",
365
+ askLabel: "\u5411\u865A\u62DF\u5F62\u8C61\u63D0\u7684\u95EE\u9898",
366
+ askPlaceholder: "\u5411\u865A\u62DF\u5F62\u8C61\u63D0\u95EE\u2026",
367
+ askFooter: "\u56DE\u7B54\u7531 AI \u751F\u6210\uFF0C\u53EF\u80FD\u6709\u8BEF\u3002\u8BF7\u52FF\u5305\u542B\u4E2A\u4EBA\u4FE1\u606F\u3002",
368
+ askNoFiles: "\u5982\u9700\u9644\u52A0\u6587\u4EF6\uFF0C\u8BF7\u4F7F\u7528\u804A\u5929\u3002",
369
+ askBusy: "\u5F53\u524D\u56DE\u7B54\u51C6\u5907\u597D\u540E\u5373\u53EF\u63D0\u95EE\u3002",
370
+ askUnavailable: "\u804A\u5929\u76EE\u524D\u4E0D\u53EF\u7528\u3002",
371
+ gettingAnswer: "\u6B63\u5728\u83B7\u53D6\u56DE\u7B54\u2026",
372
+ startWhenReady: "\u51C6\u5907\u597D\u540E\u5F00\u59CB",
373
+ armed: "\u56DE\u7B54\u51C6\u5907\u597D\u540E\uFF0C\u865A\u62DF\u5F62\u8C61\u5C06\u5F00\u59CB\u3002",
374
+ cancel: "\u53D6\u6D88",
375
+ armedCancelled: "\u865A\u62DF\u5F62\u8C61\u672A\u542F\u52A8\u3002\u53EF\u518D\u6B21\u6309\u201C\u51C6\u5907\u597D\u540E\u5F00\u59CB\u201D\u3002",
376
+ notSpoken: "\u6B64\u56DE\u7B54\u4EE5\u6587\u5B57\u5F62\u5F0F\u4FDD\u7559\u5728\u804A\u5929\u4E2D\u3002\u865A\u62DF\u5F62\u8C61\u53EA\u6717\u8BFB\u901A\u8FC7\u5176\u8BED\u97F3\u68C0\u67E5\u7684\u56DE\u7B54\u3002",
377
+ answerFailed: "\u52A9\u624B\u65E0\u6CD5\u56DE\u7B54\u3002\u8BF7\u91CD\u65B0\u63D0\u95EE\u3002",
378
+ declined: "\u6CA1\u5173\u7CFB\u3002\u56DE\u7B54\u5728\u804A\u5929\u4E2D\u3002",
379
+ askHere: "\u5982\u9700\u542C\u53D6\u56DE\u7B54\uFF0C\u8BF7\u5728\u8FD9\u91CC\u63D0\u95EE\u3002",
380
+ newChatForAvatar: "\u4E3A\u865A\u62DF\u5F62\u8C61\u5F00\u59CB\u65B0\u804A\u5929",
381
+ newChatNote: "\u5F53\u524D\u804A\u5929\u4F1A\u4FDD\u7559\u5728\u5386\u53F2\u8BB0\u5F55\u4E2D\u3002",
382
+ newChatStarted: "\u5DF2\u4E3A\u865A\u62DF\u5F62\u8C61\u5F00\u59CB\u65B0\u7684\u804A\u5929\u3002",
383
+ readInChat: "\u5728\u804A\u5929\u4E2D\u67E5\u770B\u56DE\u7B54\u548C\u6765\u6E90",
384
+ usedToday: "\u60A8\u4ECA\u5929\u5DF2\u4F7F\u7528\u8FC7\u865A\u62DF\u5F62\u8C61\u3002\u56DE\u7B54\u5C06\u4EE5\u6587\u5B57\u663E\u793A\u5728\u8FD9\u91CC\u3002",
385
+ needsAnswerAny: "\u5728\u8FD9\u91CC\u63D0\u95EE\uFF0C\u865A\u62DF\u5F62\u8C61\u4F1A\u6717\u8BFB\u56DE\u7B54\u3002",
386
+ startNewChatDetailAny: "\u865A\u62DF\u5F62\u8C61\u53EA\u6717\u8BFB\u5728\u201C\u865A\u62DF\u5F62\u8C61\u201D\u6807\u7B7E\u9875\u4E2D\u5F00\u59CB\u7684\u65B0\u804A\u5929\u7684\u7B2C\u4E00\u4E2A\u56DE\u7B54\uFF0C\u4E14\u8BE5\u56DE\u7B54\u987B\u901A\u8FC7\u8BED\u97F3\u68C0\u67E5\u3002",
387
+ notEligibleAny: "\u865A\u62DF\u5F62\u8C61\u65E0\u6CD5\u6717\u8BFB\u6B64\u56DE\u7B54\u3002\u56DE\u7B54\u548C\u6765\u6E90\u5728\u804A\u5929\u4E2D\u3002"
325
388
  };
326
389
  var HI = {
327
390
  checking: "\u091C\u093E\u0901\u091A \u0939\u094B \u0930\u0939\u0940 \u0939\u0948 \u0915\u093F \u0932\u093E\u0907\u0935 \u0905\u0935\u0924\u093E\u0930 \u0909\u092A\u0932\u092C\u094D\u0927 \u0939\u0948 \u092F\u093E \u0928\u0939\u0940\u0902\u2026",
@@ -355,7 +418,32 @@ var HI = {
355
418
  paused: "\u0932\u093E\u0907\u0935 \u0905\u0935\u0924\u093E\u0930 \u0905\u092D\u0940 \u0930\u0941\u0915\u093E \u0939\u0941\u0906 \u0939\u0948\u0964",
356
419
  // TRANSLATION REVIEW PENDING (BOFF-9797): draft.
357
420
  notEligible: "\u0905\u0935\u0924\u093E\u0930 \u0938\u0941\u091D\u093E\u090F \u0917\u090F \u092A\u094D\u0930\u0936\u094D\u0928 \u0915\u093E \u092A\u0939\u0932\u093E \u0909\u0924\u094D\u0924\u0930 \u0939\u0940 \u092A\u0922\u093C\u0924\u093E \u0939\u0948, \u092A\u0902\u0926\u094D\u0930\u0939 \u092E\u093F\u0928\u091F \u0915\u0947 \u092D\u0940\u0924\u0930\u0964 \u0928\u0908 \u091A\u0948\u091F \u0936\u0941\u0930\u0942 \u0915\u0930\u0947\u0902 \u0914\u0930 \u0915\u094B\u0908 \u0938\u0941\u091D\u093E\u092F\u093E \u0917\u092F\u093E \u092A\u094D\u0930\u0936\u094D\u0928 \u091A\u0941\u0928\u0947\u0902\u0964",
358
- answerClaimed: "\u0905\u0935\u0924\u093E\u0930 \u092F\u0939 \u0909\u0924\u094D\u0924\u0930 \u092A\u0939\u0932\u0947 \u0939\u0940 \u092A\u0922\u093C \u091A\u0941\u0915\u093E \u0939\u0948\u0964"
421
+ answerClaimed: "\u0905\u0935\u0924\u093E\u0930 \u092F\u0939 \u0909\u0924\u094D\u0924\u0930 \u092A\u0939\u0932\u0947 \u0939\u0940 \u092A\u0922\u093C \u091A\u0941\u0915\u093E \u0939\u0948\u0964",
422
+ // TRANSLATION REVIEW PENDING (BOFF-9797): draft, the Avatar tab's question box.
423
+ askHeadline: "\u0915\u094B\u0908 \u092A\u094D\u0930\u0936\u094D\u0928 \u092A\u0942\u091B\u0947\u0902, \u0914\u0930 \u0905\u0935\u0924\u093E\u0930 \u0909\u0938\u0915\u093E \u0909\u0924\u094D\u0924\u0930 \u091C\u093C\u094B\u0930 \u0938\u0947 \u092A\u0922\u093C\u0947\u0917\u093E\u0964",
424
+ askLabel: "\u0905\u0935\u0924\u093E\u0930 \u0915\u0947 \u0932\u093F\u090F \u092A\u094D\u0930\u0936\u094D\u0928",
425
+ askPlaceholder: "\u0905\u0935\u0924\u093E\u0930 \u0938\u0947 \u092A\u0942\u091B\u0947\u0902\u2026",
426
+ askFooter: "\u0909\u0924\u094D\u0924\u0930 AI \u0926\u094D\u0935\u093E\u0930\u093E \u092C\u0928\u093E\u090F \u091C\u093E\u0924\u0947 \u0939\u0948\u0902 \u0914\u0930 \u0917\u0932\u0924 \u0939\u094B \u0938\u0915\u0924\u0947 \u0939\u0948\u0902\u0964 \u0928\u093F\u091C\u0940 \u091C\u093E\u0928\u0915\u093E\u0930\u0940 \u0936\u093E\u092E\u093F\u0932 \u0928 \u0915\u0930\u0947\u0902\u0964",
427
+ askNoFiles: "\u092B\u093C\u093E\u0907\u0932\u0947\u0902 \u091C\u094B\u0921\u093C\u0928\u0947 \u0915\u0947 \u0932\u093F\u090F \u091A\u0948\u091F \u0915\u093E \u0909\u092A\u092F\u094B\u0917 \u0915\u0930\u0947\u0902\u0964",
428
+ askBusy: "\u092E\u094C\u091C\u0942\u0926\u093E \u0909\u0924\u094D\u0924\u0930 \u0924\u0948\u092F\u093E\u0930 \u0939\u094B\u0928\u0947 \u092A\u0930 \u0906\u092A \u092A\u0942\u091B \u0938\u0915\u0924\u0947 \u0939\u0948\u0902\u0964",
429
+ askUnavailable: "\u091A\u0948\u091F \u0905\u092D\u0940 \u0909\u092A\u0932\u092C\u094D\u0927 \u0928\u0939\u0940\u0902 \u0939\u0948\u0964",
430
+ gettingAnswer: "\u0909\u0924\u094D\u0924\u0930 \u0932\u093E\u092F\u093E \u091C\u093E \u0930\u0939\u093E \u0939\u0948\u2026",
431
+ startWhenReady: "\u0924\u0948\u092F\u093E\u0930 \u0939\u094B\u0928\u0947 \u092A\u0930 \u0936\u0941\u0930\u0942 \u0915\u0930\u0947\u0902",
432
+ armed: "\u0909\u0924\u094D\u0924\u0930 \u0924\u0948\u092F\u093E\u0930 \u0939\u094B\u0924\u0947 \u0939\u0940 \u0905\u0935\u0924\u093E\u0930 \u0936\u0941\u0930\u0942 \u0939\u094B\u0917\u093E\u0964",
433
+ cancel: "\u0930\u0926\u094D\u0926 \u0915\u0930\u0947\u0902",
434
+ armedCancelled: "\u0905\u0935\u0924\u093E\u0930 \u0936\u0941\u0930\u0942 \u0928\u0939\u0940\u0902 \u0939\u0941\u0906\u0964 \u092B\u093F\u0930 \u0938\u0947 \u0915\u094B\u0936\u093F\u0936 \u0915\u0930\u0928\u0947 \u0915\u0947 \u0932\u093F\u090F \u201C\u0924\u0948\u092F\u093E\u0930 \u0939\u094B\u0928\u0947 \u092A\u0930 \u0936\u0941\u0930\u0942 \u0915\u0930\u0947\u0902\u201D \u0926\u092C\u093E\u090F\u0901\u0964",
435
+ notSpoken: "\u092F\u0939 \u0909\u0924\u094D\u0924\u0930 \u091A\u0948\u091F \u092E\u0947\u0902 \u091F\u0947\u0915\u094D\u0938\u094D\u091F \u0915\u0947 \u0930\u0942\u092A \u092E\u0947\u0902 \u0930\u0939\u0947\u0917\u093E\u0964 \u0905\u0935\u0924\u093E\u0930 \u0915\u0947\u0935\u0932 \u0935\u0939\u0940 \u0909\u0924\u094D\u0924\u0930 \u092A\u0922\u093C\u0924\u093E \u0939\u0948 \u091C\u094B \u0909\u0938\u0915\u0940 \u0935\u093E\u0923\u0940 \u091C\u093E\u0901\u091A \u092E\u0947\u0902 \u092A\u093E\u0938 \u0939\u094B\u0924\u0947 \u0939\u0948\u0902\u0964",
436
+ answerFailed: "\u0938\u0939\u093E\u092F\u0915 \u0909\u0924\u094D\u0924\u0930 \u0928\u0939\u0940\u0902 \u0926\u0947 \u0938\u0915\u093E\u0964 \u092B\u093F\u0930 \u0938\u0947 \u092A\u0942\u091B\u0915\u0930 \u0926\u0947\u0916\u0947\u0902\u0964",
437
+ declined: "\u0915\u094B\u0908 \u092C\u093E\u0924 \u0928\u0939\u0940\u0902\u0964 \u0909\u0924\u094D\u0924\u0930 \u091A\u0948\u091F \u092E\u0947\u0902 \u0939\u0948\u0964",
438
+ askHere: "\u0909\u0924\u094D\u0924\u0930 \u0938\u0941\u0928\u0928\u0947 \u0915\u0947 \u0932\u093F\u090F, \u092F\u0939\u093E\u0901 \u092A\u0942\u091B\u0947\u0902\u0964",
439
+ newChatForAvatar: "\u0905\u0935\u0924\u093E\u0930 \u0915\u0947 \u0932\u093F\u090F \u0928\u0908 \u091A\u0948\u091F",
440
+ newChatNote: "\u0906\u092A\u0915\u0940 \u092E\u094C\u091C\u0942\u0926\u093E \u091A\u0948\u091F \u0907\u0924\u093F\u0939\u093E\u0938 \u092E\u0947\u0902 \u0930\u0939\u0947\u0917\u0940\u0964",
441
+ newChatStarted: "\u0905\u0935\u0924\u093E\u0930 \u0915\u0947 \u0932\u093F\u090F \u0928\u0908 \u091A\u0948\u091F \u0936\u0941\u0930\u0942 \u0915\u0940 \u0917\u0908\u0964",
442
+ readInChat: "\u0909\u0924\u094D\u0924\u0930 \u0914\u0930 \u0938\u094D\u0930\u094B\u0924 \u091A\u0948\u091F \u092E\u0947\u0902 \u092A\u0922\u093C\u0947\u0902",
443
+ usedToday: "\u0906\u091C \u0915\u093E \u0905\u0935\u0924\u093E\u0930 \u0938\u0924\u094D\u0930 \u0906\u092A \u0932\u0947 \u091A\u0941\u0915\u0947 \u0939\u0948\u0902\u0964 \u0909\u0924\u094D\u0924\u0930 \u092F\u0939\u093E\u0901 \u091F\u0947\u0915\u094D\u0938\u094D\u091F \u0915\u0947 \u0930\u0942\u092A \u092E\u0947\u0902 \u0926\u093F\u0916\u0947\u0902\u0917\u0947\u0964",
444
+ needsAnswerAny: "\u092F\u0939\u093E\u0901 \u092A\u094D\u0930\u0936\u094D\u0928 \u092A\u0942\u091B\u0947\u0902, \u0914\u0930 \u0905\u0935\u0924\u093E\u0930 \u0909\u0924\u094D\u0924\u0930 \u091C\u093C\u094B\u0930 \u0938\u0947 \u092A\u0922\u093C\u0947\u0917\u093E\u0964",
445
+ startNewChatDetailAny: "\u0905\u0935\u0924\u093E\u0930 \u0915\u0947\u0935\u0932 \u0905\u0935\u0924\u093E\u0930 \u091F\u0948\u092C \u092E\u0947\u0902 \u0936\u0941\u0930\u0942 \u0915\u0940 \u0917\u0908 \u0928\u0908 \u091A\u0948\u091F \u0915\u093E \u092A\u0939\u0932\u093E \u0909\u0924\u094D\u0924\u0930 \u091C\u093C\u094B\u0930 \u0938\u0947 \u092A\u0922\u093C\u0924\u093E \u0939\u0948, \u092C\u0936\u0930\u094D\u0924\u0947 \u0935\u0939 \u0935\u093E\u0923\u0940 \u091C\u093E\u0901\u091A \u092E\u0947\u0902 \u092A\u093E\u0938 \u0939\u094B\u0964",
446
+ notEligibleAny: "\u0905\u0935\u0924\u093E\u0930 \u092F\u0939 \u0909\u0924\u094D\u0924\u0930 \u091C\u093C\u094B\u0930 \u0938\u0947 \u0928\u0939\u0940\u0902 \u092A\u0922\u093C \u0938\u0915\u0924\u093E\u0964 \u0909\u0924\u094D\u0924\u0930 \u0914\u0930 \u0938\u094D\u0930\u094B\u0924 \u091A\u0948\u091F \u092E\u0947\u0902 \u0939\u0948\u0902\u0964"
359
447
  };
360
448
  var ES = {
361
449
  checking: "Comprobando si el avatar en vivo est\xE1 disponible\u2026",
@@ -389,7 +477,32 @@ var ES = {
389
477
  paused: "El avatar en vivo est\xE1 en pausa en este momento.",
390
478
  // TRANSLATION REVIEW PENDING (BOFF-9797): draft.
391
479
  notEligible: "El avatar lee la primera respuesta a una pregunta sugerida, en un plazo de quince minutos. Inicia un chat nuevo y elige una pregunta sugerida.",
392
- answerClaimed: "El avatar ya ha le\xEDdo esta respuesta."
480
+ answerClaimed: "El avatar ya ha le\xEDdo esta respuesta.",
481
+ // TRANSLATION REVIEW PENDING (BOFF-9797): draft, the Avatar tab's question box.
482
+ askHeadline: "Haz una pregunta y el avatar leer\xE1 la respuesta en voz alta.",
483
+ askLabel: "Pregunta para el avatar",
484
+ askPlaceholder: "Pregunta al avatar\u2026",
485
+ askFooter: "Las respuestas las genera la IA y pueden contener errores. No incluyas datos personales.",
486
+ askNoFiles: "Para adjuntar archivos, usa el chat.",
487
+ askBusy: "Podr\xE1s preguntar cuando la respuesta actual est\xE9 lista.",
488
+ askUnavailable: "El chat no est\xE1 disponible en este momento.",
489
+ gettingAnswer: "Obteniendo la respuesta\u2026",
490
+ startWhenReady: "Iniciar cuando est\xE9 lista",
491
+ armed: "El avatar empezar\xE1 cuando la respuesta est\xE9 lista.",
492
+ cancel: "Cancelar",
493
+ armedCancelled: "El avatar no se ha iniciado. Pulsa Iniciar cuando est\xE9 lista para volver a intentarlo.",
494
+ notSpoken: "Esta respuesta se queda en el chat como texto. El avatar solo lee respuestas que superan sus comprobaciones de voz.",
495
+ answerFailed: "El asistente no pudo responder. Vuelve a preguntar.",
496
+ declined: "De acuerdo. La respuesta est\xE1 en el chat.",
497
+ askHere: "Para escuchar una respuesta, pregunta aqu\xED.",
498
+ newChatForAvatar: "Chat nuevo para el avatar",
499
+ newChatNote: "Tu chat actual se queda en el historial.",
500
+ newChatStarted: "Se ha iniciado un chat nuevo para el avatar.",
501
+ readInChat: "Leer la respuesta y las fuentes en el chat",
502
+ usedToday: "Ya has usado la sesi\xF3n de avatar de hoy. Las respuestas se mostrar\xE1n aqu\xED como texto.",
503
+ needsAnswerAny: "Haz una pregunta aqu\xED y el avatar leer\xE1 la respuesta en voz alta.",
504
+ startNewChatDetailAny: "El avatar solo lee en voz alta la primera respuesta de un chat nuevo iniciado en la pesta\xF1a Avatar, si supera las comprobaciones de voz.",
505
+ notEligibleAny: "El avatar no puede leer esta respuesta en voz alta. La respuesta y las fuentes est\xE1n en el chat."
393
506
  };
394
507
  var AR = {
395
508
  checking: "\u062C\u0627\u0631\u064D \u0627\u0644\u062A\u062D\u0642\u0642 \u0645\u0646 \u062A\u0648\u0641\u0631 \u0627\u0644\u0623\u0641\u0627\u062A\u0627\u0631 \u0627\u0644\u0645\u0628\u0627\u0634\u0631\u2026",
@@ -423,7 +536,32 @@ var AR = {
423
536
  paused: "\u0627\u0644\u0623\u0641\u0627\u062A\u0627\u0631 \u0627\u0644\u0645\u0628\u0627\u0634\u0631 \u0645\u062A\u0648\u0642\u0641 \u0645\u0624\u0642\u062A\u064B\u0627 \u0627\u0644\u0622\u0646.",
424
537
  // TRANSLATION REVIEW PENDING (BOFF-9797): draft.
425
538
  notEligible: "\u064A\u0642\u0631\u0623 \u0627\u0644\u0623\u0641\u0627\u062A\u0627\u0631 \u0627\u0644\u0625\u062C\u0627\u0628\u0629 \u0627\u0644\u0623\u0648\u0644\u0649 \u0639\u0646 \u0633\u0624\u0627\u0644 \u0645\u0642\u062A\u0631\u062D\u060C \u062E\u0644\u0627\u0644 \u062E\u0645\u0633 \u0639\u0634\u0631\u0629 \u062F\u0642\u064A\u0642\u0629. \u0627\u0628\u062F\u0623 \u062F\u0631\u062F\u0634\u0629 \u062C\u062F\u064A\u062F\u0629 \u0648\u0627\u062E\u062A\u0631 \u0633\u0624\u0627\u0644\u064B\u0627 \u0645\u0642\u062A\u0631\u062D\u064B\u0627.",
426
- answerClaimed: "\u0642\u0631\u0623 \u0627\u0644\u0623\u0641\u0627\u062A\u0627\u0631 \u0647\u0630\u0647 \u0627\u0644\u0625\u062C\u0627\u0628\u0629 \u0645\u0646 \u0642\u0628\u0644."
539
+ answerClaimed: "\u0642\u0631\u0623 \u0627\u0644\u0623\u0641\u0627\u062A\u0627\u0631 \u0647\u0630\u0647 \u0627\u0644\u0625\u062C\u0627\u0628\u0629 \u0645\u0646 \u0642\u0628\u0644.",
540
+ // TRANSLATION REVIEW PENDING (BOFF-9797): draft, the Avatar tab's question box.
541
+ askHeadline: "\u0627\u0637\u0631\u062D \u0633\u0624\u0627\u0644\u064B\u0627\u060C \u0648\u0633\u064A\u0642\u0631\u0623 \u0627\u0644\u0623\u0641\u0627\u062A\u0627\u0631 \u0627\u0644\u0625\u062C\u0627\u0628\u0629 \u0628\u0635\u0648\u062A \u0639\u0627\u0644\u064D.",
542
+ askLabel: "\u0633\u0624\u0627\u0644 \u0644\u0644\u0623\u0641\u0627\u062A\u0627\u0631",
543
+ askPlaceholder: "\u0627\u0633\u0623\u0644 \u0627\u0644\u0623\u0641\u0627\u062A\u0627\u0631\u2026",
544
+ askFooter: "\u0627\u0644\u0625\u062C\u0627\u0628\u0627\u062A \u0645\u064F\u0648\u0644\u064E\u0651\u062F\u0629 \u0628\u0627\u0644\u0630\u0643\u0627\u0621 \u0627\u0644\u0627\u0635\u0637\u0646\u0627\u0639\u064A \u0648\u0642\u062F \u062A\u0643\u0648\u0646 \u062E\u0627\u0637\u0626\u0629. \u0644\u0627 \u062A\u0636\u0645\u0651\u0646 \u0628\u064A\u0627\u0646\u0627\u062A \u0634\u062E\u0635\u064A\u0629.",
545
+ askNoFiles: "\u0644\u0625\u0631\u0641\u0627\u0642 \u0645\u0644\u0641\u0627\u062A\u060C \u0627\u0633\u062A\u062E\u062F\u0645 \u0627\u0644\u062F\u0631\u062F\u0634\u0629.",
546
+ askBusy: "\u064A\u0645\u0643\u0646\u0643 \u0627\u0644\u0633\u0624\u0627\u0644 \u0639\u0646\u062F\u0645\u0627 \u062A\u0635\u0628\u062D \u0627\u0644\u0625\u062C\u0627\u0628\u0629 \u0627\u0644\u062D\u0627\u0644\u064A\u0629 \u062C\u0627\u0647\u0632\u0629.",
547
+ askUnavailable: "\u0627\u0644\u062F\u0631\u062F\u0634\u0629 \u063A\u064A\u0631 \u0645\u062A\u0627\u062D\u0629 \u0627\u0644\u0622\u0646.",
548
+ gettingAnswer: "\u062C\u0627\u0631\u064D \u0627\u0644\u062D\u0635\u0648\u0644 \u0639\u0644\u0649 \u0627\u0644\u0625\u062C\u0627\u0628\u0629\u2026",
549
+ startWhenReady: "\u0627\u0644\u0628\u062F\u0621 \u0639\u0646\u062F \u0627\u0644\u062C\u0627\u0647\u0632\u064A\u0629",
550
+ armed: "\u0633\u064A\u0628\u062F\u0623 \u0627\u0644\u0623\u0641\u0627\u062A\u0627\u0631 \u0639\u0646\u062F\u0645\u0627 \u062A\u0635\u0628\u062D \u0627\u0644\u0625\u062C\u0627\u0628\u0629 \u062C\u0627\u0647\u0632\u0629.",
551
+ cancel: "\u0625\u0644\u063A\u0627\u0621",
552
+ armedCancelled: "\u0644\u0645 \u064A\u0628\u062F\u0623 \u0627\u0644\u0623\u0641\u0627\u062A\u0627\u0631. \u0627\u0636\u063A\u0637 \u0639\u0644\u0649 \u0627\u0644\u0628\u062F\u0621 \u0639\u0646\u062F \u0627\u0644\u062C\u0627\u0647\u0632\u064A\u0629 \u0644\u0644\u0645\u062D\u0627\u0648\u0644\u0629 \u0645\u0631\u0629 \u0623\u062E\u0631\u0649.",
553
+ notSpoken: "\u062A\u0628\u0642\u0649 \u0647\u0630\u0647 \u0627\u0644\u0625\u062C\u0627\u0628\u0629 \u0641\u064A \u0627\u0644\u062F\u0631\u062F\u0634\u0629 \u0646\u0635\u064B\u0627. \u064A\u0642\u0631\u0623 \u0627\u0644\u0623\u0641\u0627\u062A\u0627\u0631 \u0641\u0642\u0637 \u0627\u0644\u0625\u062C\u0627\u0628\u0627\u062A \u0627\u0644\u062A\u064A \u062A\u062C\u062A\u0627\u0632 \u0641\u062D\u0648\u0635 \u0627\u0644\u0646\u0637\u0642.",
554
+ answerFailed: "\u062A\u0639\u0630\u0651\u0631 \u0639\u0644\u0649 \u0627\u0644\u0645\u0633\u0627\u0639\u062F \u0627\u0644\u0625\u062C\u0627\u0628\u0629. \u062D\u0627\u0648\u0644 \u0627\u0644\u0633\u0624\u0627\u0644 \u0645\u0631\u0629 \u0623\u062E\u0631\u0649.",
555
+ declined: "\u0644\u0627 \u0628\u0623\u0633. \u0627\u0644\u0625\u062C\u0627\u0628\u0629 \u0645\u0648\u062C\u0648\u062F\u0629 \u0641\u064A \u0627\u0644\u062F\u0631\u062F\u0634\u0629.",
556
+ askHere: "\u0644\u0633\u0645\u0627\u0639 \u0625\u062C\u0627\u0628\u0629\u060C \u0627\u0633\u0623\u0644 \u0647\u0646\u0627.",
557
+ newChatForAvatar: "\u062F\u0631\u062F\u0634\u0629 \u062C\u062F\u064A\u062F\u0629 \u0644\u0644\u0623\u0641\u0627\u062A\u0627\u0631",
558
+ newChatNote: "\u062A\u0628\u0642\u0649 \u062F\u0631\u062F\u0634\u062A\u0643 \u0627\u0644\u062D\u0627\u0644\u064A\u0629 \u0641\u064A \u0627\u0644\u0633\u062C\u0644.",
559
+ newChatStarted: "\u0628\u062F\u0623\u062A \u062F\u0631\u062F\u0634\u0629 \u062C\u062F\u064A\u062F\u0629 \u0644\u0644\u0623\u0641\u0627\u062A\u0627\u0631.",
560
+ readInChat: "\u0627\u0642\u0631\u0623 \u0627\u0644\u0625\u062C\u0627\u0628\u0629 \u0648\u0627\u0644\u0645\u0635\u0627\u062F\u0631 \u0641\u064A \u0627\u0644\u062F\u0631\u062F\u0634\u0629",
561
+ usedToday: "\u0644\u0642\u062F \u0627\u0633\u062A\u062E\u062F\u0645\u062A \u062C\u0644\u0633\u0629 \u0627\u0644\u0623\u0641\u0627\u062A\u0627\u0631 \u0644\u0647\u0630\u0627 \u0627\u0644\u064A\u0648\u0645. \u0633\u062A\u0638\u0647\u0631 \u0627\u0644\u0625\u062C\u0627\u0628\u0627\u062A \u0647\u0646\u0627 \u0646\u0635\u064B\u0627.",
562
+ needsAnswerAny: "\u0627\u0637\u0631\u062D \u0633\u0624\u0627\u0644\u064B\u0627 \u0647\u0646\u0627\u060C \u0648\u0633\u064A\u0642\u0631\u0623 \u0627\u0644\u0623\u0641\u0627\u062A\u0627\u0631 \u0627\u0644\u0625\u062C\u0627\u0628\u0629 \u0628\u0635\u0648\u062A \u0639\u0627\u0644\u064D.",
563
+ startNewChatDetailAny: "\u064A\u0642\u0631\u0623 \u0627\u0644\u0623\u0641\u0627\u062A\u0627\u0631 \u0628\u0635\u0648\u062A \u0639\u0627\u0644\u064D \u0627\u0644\u0625\u062C\u0627\u0628\u0629 \u0627\u0644\u0623\u0648\u0644\u0649 \u0641\u0642\u0637 \u0641\u064A \u062F\u0631\u062F\u0634\u0629 \u062C\u062F\u064A\u062F\u0629 \u0628\u062F\u0623\u062A \u0641\u064A \u0639\u0644\u0627\u0645\u0629 \u062A\u0628\u0648\u064A\u0628 \u0627\u0644\u0623\u0641\u0627\u062A\u0627\u0631\u060C \u0628\u0634\u0631\u0637 \u0623\u0646 \u062A\u062C\u062A\u0627\u0632 \u0641\u062D\u0648\u0635 \u0627\u0644\u0646\u0637\u0642.",
564
+ notEligibleAny: "\u0644\u0627 \u064A\u0645\u0643\u0646 \u0644\u0644\u0623\u0641\u0627\u062A\u0627\u0631 \u0642\u0631\u0627\u0621\u0629 \u0647\u0630\u0647 \u0627\u0644\u0625\u062C\u0627\u0628\u0629 \u0628\u0635\u0648\u062A \u0639\u0627\u0644\u064D. \u0627\u0644\u0625\u062C\u0627\u0628\u0629 \u0648\u0627\u0644\u0645\u0635\u0627\u062F\u0631 \u0645\u0648\u062C\u0648\u062F\u0629 \u0641\u064A \u0627\u0644\u062F\u0631\u062F\u0634\u0629."
427
565
  };
428
566
  var TA = {
429
567
  checking: "\u0BA8\u0BC7\u0BB0\u0BB2\u0BC8 \u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BCD \u0B95\u0BBF\u0B9F\u0BC8\u0B95\u0BCD\u0B95\u0BBF\u0BB1\u0BA4\u0BBE \u0B8E\u0BA9\u0B9A\u0BCD \u0B9A\u0BB0\u0BBF\u0BAA\u0BBE\u0BB0\u0BCD\u0B95\u0BCD\u0B95\u0BBF\u0BB1\u0BA4\u0BC1\u2026",
@@ -457,7 +595,32 @@ var TA = {
457
595
  paused: "\u0BA8\u0BC7\u0BB0\u0BB2\u0BC8 \u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BCD \u0B87\u0BAA\u0BCD\u0BAA\u0BCB\u0BA4\u0BC1 \u0B87\u0B9F\u0BC8\u0BA8\u0BBF\u0BB1\u0BC1\u0BA4\u0BCD\u0BA4\u0BAA\u0BCD\u0BAA\u0B9F\u0BCD\u0B9F\u0BC1\u0BB3\u0BCD\u0BB3\u0BA4\u0BC1.",
458
596
  // TRANSLATION REVIEW PENDING (BOFF-9797): draft.
459
597
  notEligible: "\u0BAA\u0BB0\u0BBF\u0BA8\u0BCD\u0BA4\u0BC1\u0BB0\u0BC8\u0B95\u0BCD\u0B95\u0BAA\u0BCD\u0BAA\u0B9F\u0BCD\u0B9F \u0B95\u0BC7\u0BB3\u0BCD\u0BB5\u0BBF\u0B95\u0BCD\u0B95\u0BBE\u0BA9 \u0BAE\u0BC1\u0BA4\u0BB2\u0BCD \u0BAA\u0BA4\u0BBF\u0BB2\u0BC8 \u0BAE\u0B9F\u0BCD\u0B9F\u0BC1\u0BAE\u0BC7, \u0BAA\u0BA4\u0BBF\u0BA9\u0BC8\u0BA8\u0BCD\u0BA4\u0BC1 \u0BA8\u0BBF\u0BAE\u0BBF\u0B9F\u0B99\u0BCD\u0B95\u0BB3\u0BC1\u0B95\u0BCD\u0B95\u0BC1\u0BB3\u0BCD, \u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BCD \u0BAA\u0B9F\u0BBF\u0B95\u0BCD\u0B95\u0BC1\u0BAE\u0BCD. \u0BAA\u0BC1\u0BA4\u0BBF\u0BAF \u0B85\u0BB0\u0B9F\u0BCD\u0B9F\u0BC8\u0BAF\u0BC8\u0BA4\u0BCD \u0BA4\u0BCA\u0B9F\u0B99\u0BCD\u0B95\u0BBF, \u0BAA\u0BB0\u0BBF\u0BA8\u0BCD\u0BA4\u0BC1\u0BB0\u0BC8\u0B95\u0BCD\u0B95\u0BAA\u0BCD\u0BAA\u0B9F\u0BCD\u0B9F \u0B92\u0BB0\u0BC1 \u0B95\u0BC7\u0BB3\u0BCD\u0BB5\u0BBF\u0BAF\u0BC8\u0BA4\u0BCD \u0BA4\u0BC7\u0BB0\u0BCD\u0BA8\u0BCD\u0BA4\u0BC6\u0B9F\u0BC1\u0B95\u0BCD\u0B95\u0BB5\u0BC1\u0BAE\u0BCD.",
460
- answerClaimed: "\u0B87\u0BA8\u0BCD\u0BA4\u0BAA\u0BCD \u0BAA\u0BA4\u0BBF\u0BB2\u0BC8 \u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BCD \u0B8F\u0BB1\u0BCD\u0B95\u0BC6\u0BA9\u0BB5\u0BC7 \u0BAA\u0B9F\u0BBF\u0BA4\u0BCD\u0BA4\u0BC1\u0BB5\u0BBF\u0B9F\u0BCD\u0B9F\u0BA4\u0BC1."
598
+ answerClaimed: "\u0B87\u0BA8\u0BCD\u0BA4\u0BAA\u0BCD \u0BAA\u0BA4\u0BBF\u0BB2\u0BC8 \u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BCD \u0B8F\u0BB1\u0BCD\u0B95\u0BC6\u0BA9\u0BB5\u0BC7 \u0BAA\u0B9F\u0BBF\u0BA4\u0BCD\u0BA4\u0BC1\u0BB5\u0BBF\u0B9F\u0BCD\u0B9F\u0BA4\u0BC1.",
599
+ // TRANSLATION REVIEW PENDING (BOFF-9797): draft, the Avatar tab's question box.
600
+ askHeadline: "\u0B92\u0BB0\u0BC1 \u0B95\u0BC7\u0BB3\u0BCD\u0BB5\u0BBF\u0BAF\u0BC8\u0B95\u0BCD \u0B95\u0BC7\u0BB3\u0BC1\u0B99\u0BCD\u0B95\u0BB3\u0BCD, \u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BCD \u0BAA\u0BA4\u0BBF\u0BB2\u0BC8 \u0B89\u0BB0\u0B95\u0BCD\u0B95\u0BAA\u0BCD \u0BAA\u0B9F\u0BBF\u0B95\u0BCD\u0B95\u0BC1\u0BAE\u0BCD.",
601
+ askLabel: "\u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BC1\u0B95\u0BCD\u0B95\u0BBE\u0BA9 \u0B95\u0BC7\u0BB3\u0BCD\u0BB5\u0BBF",
602
+ askPlaceholder: "\u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BBF\u0B9F\u0BAE\u0BCD \u0B95\u0BC7\u0BB3\u0BC1\u0B99\u0BCD\u0B95\u0BB3\u0BCD\u2026",
603
+ askFooter: "\u0BAA\u0BA4\u0BBF\u0BB2\u0BCD\u0B95\u0BB3\u0BCD AI \u0B89\u0BB0\u0BC1\u0BB5\u0BBE\u0B95\u0BCD\u0B95\u0BBF\u0BAF\u0BB5\u0BC8, \u0BA4\u0BB5\u0BB1\u0BBE\u0B95 \u0B87\u0BB0\u0BC1\u0B95\u0BCD\u0B95\u0BB2\u0BBE\u0BAE\u0BCD. \u0BA4\u0BA9\u0BBF\u0BAA\u0BCD\u0BAA\u0B9F\u0BCD\u0B9F \u0BB5\u0BBF\u0BB5\u0BB0\u0B99\u0BCD\u0B95\u0BB3\u0BC8\u0B9A\u0BCD \u0B9A\u0BC7\u0BB0\u0BCD\u0B95\u0BCD\u0B95 \u0BB5\u0BC7\u0BA3\u0BCD\u0B9F\u0BBE\u0BAE\u0BCD.",
604
+ askNoFiles: "\u0B95\u0BCB\u0BAA\u0BCD\u0BAA\u0BC1\u0B95\u0BB3\u0BC8 \u0B87\u0BA3\u0BC8\u0B95\u0BCD\u0B95, \u0B85\u0BB0\u0B9F\u0BCD\u0B9F\u0BC8\u0BAF\u0BC8\u0BAA\u0BCD \u0BAA\u0BAF\u0BA9\u0BCD\u0BAA\u0B9F\u0BC1\u0BA4\u0BCD\u0BA4\u0BB5\u0BC1\u0BAE\u0BCD.",
605
+ askBusy: "\u0BA4\u0BB1\u0BCD\u0BAA\u0BCB\u0BA4\u0BC8\u0BAF \u0BAA\u0BA4\u0BBF\u0BB2\u0BCD \u0BA4\u0BAF\u0BBE\u0BB0\u0BBE\u0BA9\u0BA4\u0BC1\u0BAE\u0BCD \u0BA8\u0BC0\u0B99\u0BCD\u0B95\u0BB3\u0BCD \u0B95\u0BC7\u0B9F\u0BCD\u0B95\u0BB2\u0BBE\u0BAE\u0BCD.",
606
+ askUnavailable: "\u0B85\u0BB0\u0B9F\u0BCD\u0B9F\u0BC8 \u0B87\u0BAA\u0BCD\u0BAA\u0BCB\u0BA4\u0BC1 \u0B95\u0BBF\u0B9F\u0BC8\u0B95\u0BCD\u0B95\u0BB5\u0BBF\u0BB2\u0BCD\u0BB2\u0BC8.",
607
+ gettingAnswer: "\u0BAA\u0BA4\u0BBF\u0BB2\u0BC8\u0BAA\u0BCD \u0BAA\u0BC6\u0BB1\u0BC1\u0B95\u0BBF\u0BB1\u0BA4\u0BC1\u2026",
608
+ startWhenReady: "\u0BA4\u0BAF\u0BBE\u0BB0\u0BBE\u0BA9\u0BA4\u0BC1\u0BAE\u0BCD \u0BA4\u0BCA\u0B9F\u0B99\u0BCD\u0B95\u0BC1",
609
+ armed: "\u0BAA\u0BA4\u0BBF\u0BB2\u0BCD \u0BA4\u0BAF\u0BBE\u0BB0\u0BBE\u0BA9\u0BA4\u0BC1\u0BAE\u0BCD \u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BCD \u0BA4\u0BCA\u0B9F\u0B99\u0BCD\u0B95\u0BC1\u0BAE\u0BCD.",
610
+ cancel: "\u0BB0\u0BA4\u0BCD\u0BA4\u0BC1\u0B9A\u0BC6\u0BAF\u0BCD",
611
+ armedCancelled: "\u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BCD \u0BA4\u0BCA\u0B9F\u0B99\u0BCD\u0B95\u0BB5\u0BBF\u0BB2\u0BCD\u0BB2\u0BC8. \u0BAE\u0BC0\u0BA3\u0BCD\u0B9F\u0BC1\u0BAE\u0BCD \u0BAE\u0BC1\u0BAF\u0BB2, \u0BA4\u0BAF\u0BBE\u0BB0\u0BBE\u0BA9\u0BA4\u0BC1\u0BAE\u0BCD \u0BA4\u0BCA\u0B9F\u0B99\u0BCD\u0B95\u0BC1 \u0B8E\u0BA9\u0BCD\u0BAA\u0BA4\u0BC8 \u0B85\u0BB4\u0BC1\u0BA4\u0BCD\u0BA4\u0BB5\u0BC1\u0BAE\u0BCD.",
612
+ notSpoken: "\u0B87\u0BA8\u0BCD\u0BA4\u0BAA\u0BCD \u0BAA\u0BA4\u0BBF\u0BB2\u0BCD \u0B85\u0BB0\u0B9F\u0BCD\u0B9F\u0BC8\u0BAF\u0BBF\u0BB2\u0BCD \u0B89\u0BB0\u0BC8\u0BAF\u0BBE\u0B95\u0BB5\u0BC7 \u0B87\u0BB0\u0BC1\u0B95\u0BCD\u0B95\u0BC1\u0BAE\u0BCD. \u0BAA\u0BC7\u0B9A\u0BCD\u0B9A\u0BC1\u0B9A\u0BCD \u0B9A\u0BB0\u0BBF\u0BAA\u0BBE\u0BB0\u0BCD\u0BAA\u0BCD\u0BAA\u0BC1\u0B95\u0BB3\u0BBF\u0BB2\u0BCD \u0BA4\u0BC7\u0BB1\u0BC1\u0BAE\u0BCD \u0BAA\u0BA4\u0BBF\u0BB2\u0BCD\u0B95\u0BB3\u0BC8 \u0BAE\u0B9F\u0BCD\u0B9F\u0BC1\u0BAE\u0BC7 \u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BCD \u0BAA\u0B9F\u0BBF\u0B95\u0BCD\u0B95\u0BC1\u0BAE\u0BCD.",
613
+ answerFailed: "\u0B89\u0BA4\u0BB5\u0BBF\u0BAF\u0BBE\u0BB3\u0BB0\u0BBE\u0BB2\u0BCD \u0BAA\u0BA4\u0BBF\u0BB2\u0BB3\u0BBF\u0B95\u0BCD\u0B95 \u0BAE\u0BC1\u0B9F\u0BBF\u0BAF\u0BB5\u0BBF\u0BB2\u0BCD\u0BB2\u0BC8. \u0BAE\u0BC0\u0BA3\u0BCD\u0B9F\u0BC1\u0BAE\u0BCD \u0B95\u0BC7\u0B9F\u0BCD\u0B9F\u0BC1\u0BAA\u0BCD \u0BAA\u0BBE\u0BB0\u0BC1\u0B99\u0BCD\u0B95\u0BB3\u0BCD.",
614
+ declined: "\u0BAA\u0BB0\u0BB5\u0BBE\u0BAF\u0BBF\u0BB2\u0BCD\u0BB2\u0BC8. \u0BAA\u0BA4\u0BBF\u0BB2\u0BCD \u0B85\u0BB0\u0B9F\u0BCD\u0B9F\u0BC8\u0BAF\u0BBF\u0BB2\u0BCD \u0B89\u0BB3\u0BCD\u0BB3\u0BA4\u0BC1.",
615
+ askHere: "\u0BAA\u0BA4\u0BBF\u0BB2\u0BC8\u0B95\u0BCD \u0B95\u0BC7\u0B9F\u0BCD\u0B95, \u0B87\u0B99\u0BCD\u0B95\u0BC7 \u0B95\u0BC7\u0BB3\u0BC1\u0B99\u0BCD\u0B95\u0BB3\u0BCD.",
616
+ newChatForAvatar: "\u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BC1\u0B95\u0BCD\u0B95\u0BBE\u0BA9 \u0BAA\u0BC1\u0BA4\u0BBF\u0BAF \u0B85\u0BB0\u0B9F\u0BCD\u0B9F\u0BC8",
617
+ newChatNote: "\u0B89\u0B99\u0BCD\u0B95\u0BB3\u0BCD \u0BA4\u0BB1\u0BCD\u0BAA\u0BCB\u0BA4\u0BC8\u0BAF \u0B85\u0BB0\u0B9F\u0BCD\u0B9F\u0BC8 \u0BB5\u0BB0\u0BB2\u0BBE\u0BB1\u0BCD\u0BB1\u0BBF\u0BB2\u0BCD \u0B87\u0BB0\u0BC1\u0B95\u0BCD\u0B95\u0BC1\u0BAE\u0BCD.",
618
+ newChatStarted: "\u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BC1\u0B95\u0BCD\u0B95\u0BBE\u0B95\u0BAA\u0BCD \u0BAA\u0BC1\u0BA4\u0BBF\u0BAF \u0B85\u0BB0\u0B9F\u0BCD\u0B9F\u0BC8 \u0BA4\u0BCA\u0B9F\u0B99\u0BCD\u0B95\u0BAA\u0BCD\u0BAA\u0B9F\u0BCD\u0B9F\u0BA4\u0BC1.",
619
+ readInChat: "\u0BAA\u0BA4\u0BBF\u0BB2\u0BC8\u0BAF\u0BC1\u0BAE\u0BCD \u0B86\u0BA4\u0BBE\u0BB0\u0B99\u0BCD\u0B95\u0BB3\u0BC8\u0BAF\u0BC1\u0BAE\u0BCD \u0B85\u0BB0\u0B9F\u0BCD\u0B9F\u0BC8\u0BAF\u0BBF\u0BB2\u0BCD \u0BAA\u0B9F\u0BBF\u0B95\u0BCD\u0B95\u0BB5\u0BC1\u0BAE\u0BCD",
620
+ usedToday: "\u0B87\u0BA9\u0BCD\u0BB1\u0BC8\u0BAF \u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BCD \u0B85\u0BAE\u0BB0\u0BCD\u0BB5\u0BC8 \u0BA8\u0BC0\u0B99\u0BCD\u0B95\u0BB3\u0BCD \u0BAA\u0BAF\u0BA9\u0BCD\u0BAA\u0B9F\u0BC1\u0BA4\u0BCD\u0BA4\u0BBF\u0BB5\u0BBF\u0B9F\u0BCD\u0B9F\u0BC0\u0BB0\u0BCD\u0B95\u0BB3\u0BCD. \u0BAA\u0BA4\u0BBF\u0BB2\u0BCD\u0B95\u0BB3\u0BCD \u0B87\u0B99\u0BCD\u0B95\u0BC7 \u0B89\u0BB0\u0BC8\u0BAF\u0BBE\u0B95\u0B95\u0BCD \u0B95\u0BBE\u0B9F\u0BCD\u0B9F\u0BAA\u0BCD\u0BAA\u0B9F\u0BC1\u0BAE\u0BCD.",
621
+ needsAnswerAny: "\u0B87\u0B99\u0BCD\u0B95\u0BC7 \u0B92\u0BB0\u0BC1 \u0B95\u0BC7\u0BB3\u0BCD\u0BB5\u0BBF\u0BAF\u0BC8\u0B95\u0BCD \u0B95\u0BC7\u0BB3\u0BC1\u0B99\u0BCD\u0B95\u0BB3\u0BCD, \u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BCD \u0BAA\u0BA4\u0BBF\u0BB2\u0BC8 \u0B89\u0BB0\u0B95\u0BCD\u0B95\u0BAA\u0BCD \u0BAA\u0B9F\u0BBF\u0B95\u0BCD\u0B95\u0BC1\u0BAE\u0BCD.",
622
+ startNewChatDetailAny: "\u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BCD \u0BA4\u0BBE\u0BB5\u0BB2\u0BBF\u0BB2\u0BCD \u0BA4\u0BCA\u0B9F\u0B99\u0BCD\u0B95\u0BBF\u0BAF \u0BAA\u0BC1\u0BA4\u0BBF\u0BAF \u0B85\u0BB0\u0B9F\u0BCD\u0B9F\u0BC8\u0BAF\u0BBF\u0BA9\u0BCD \u0BAE\u0BC1\u0BA4\u0BB2\u0BCD \u0BAA\u0BA4\u0BBF\u0BB2\u0BC8 \u0BAE\u0B9F\u0BCD\u0B9F\u0BC1\u0BAE\u0BC7, \u0B85\u0BA4\u0BC1 \u0BAA\u0BC7\u0B9A\u0BCD\u0B9A\u0BC1\u0B9A\u0BCD \u0B9A\u0BB0\u0BBF\u0BAA\u0BBE\u0BB0\u0BCD\u0BAA\u0BCD\u0BAA\u0BC1\u0B95\u0BB3\u0BBF\u0BB2\u0BCD \u0BA4\u0BC7\u0BB1\u0BBF\u0BA9\u0BBE\u0BB2\u0BCD, \u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BCD \u0B89\u0BB0\u0B95\u0BCD\u0B95\u0BAA\u0BCD \u0BAA\u0B9F\u0BBF\u0B95\u0BCD\u0B95\u0BC1\u0BAE\u0BCD.",
623
+ notEligibleAny: "\u0B87\u0BA8\u0BCD\u0BA4\u0BAA\u0BCD \u0BAA\u0BA4\u0BBF\u0BB2\u0BC8 \u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BBE\u0BB2\u0BCD \u0B89\u0BB0\u0B95\u0BCD\u0B95\u0BAA\u0BCD \u0BAA\u0B9F\u0BBF\u0B95\u0BCD\u0B95 \u0BAE\u0BC1\u0B9F\u0BBF\u0BAF\u0BBE\u0BA4\u0BC1. \u0BAA\u0BA4\u0BBF\u0BB2\u0BC1\u0BAE\u0BCD \u0B86\u0BA4\u0BBE\u0BB0\u0B99\u0BCD\u0B95\u0BB3\u0BC1\u0BAE\u0BCD \u0B85\u0BB0\u0B9F\u0BCD\u0B9F\u0BC8\u0BAF\u0BBF\u0BB2\u0BCD \u0B89\u0BB3\u0BCD\u0BB3\u0BA9."
461
624
  };
462
625
  var STRINGS = {
463
626
  en: EN,
@@ -481,7 +644,8 @@ var CONSENT = /* @__PURE__ */ new Map([
481
644
  processing: "When you start, Cloudflare checks for bots. The answer text goes to Google to create the voice. Your browser connects to LiveKit, which sees your IP address. LiveKit fetches our temporary audio file and passes the voice to Protoface, which makes the avatar video streamed through LiveKit.",
482
645
  storage: "Your microphone and camera are not used. We do not record the live session. We temporarily store the generated voice file and keep a record of this consent. The privacy notice explains our safeguards, storage periods and the providers' processing. For people aged eighteen and over.",
483
646
  privacyLink: "How we handle this",
484
- botCheck: "turnstile"
647
+ botCheck: "turnstile",
648
+ questions: "suggested"
485
649
  }
486
650
  }
487
651
  ],
@@ -496,7 +660,8 @@ var CONSENT = /* @__PURE__ */ new Map([
496
660
  processing: "When you start, Cloudflare checks for bots. The answer text goes to Google to create the voice. Our server sends that voice through LiveKit to Protoface, which makes the avatar video streamed through LiveKit. Your browser connects to LiveKit, which sees your IP address.",
497
661
  storage: "Your microphone and camera are not used. We do not record the live session or store the generated voice. We keep a record of this consent. The privacy notice explains our safeguards, storage periods and the providers' processing. For people aged eighteen and over.",
498
662
  privacyLink: "How we handle this",
499
- botCheck: "turnstile"
663
+ botCheck: "turnstile",
664
+ questions: "suggested"
500
665
  }
501
666
  }
502
667
  ],
@@ -512,7 +677,8 @@ var CONSENT = /* @__PURE__ */ new Map([
512
677
  processing: "When you start, Cloudflare checks for bots. The answer text goes to Google to create the voice. Our server sends that voice through LiveKit to Protoface, which makes the avatar video streamed through LiveKit. Your browser connects to LiveKit, which sees your IP address.",
513
678
  storage: "Your microphone and camera are not used. We do not record the live session or store the generated voice. We keep a record of this consent. The privacy notice explains our safeguards, storage periods and the providers' processing. For people aged eighteen and over.",
514
679
  privacyLink: "How we handle this",
515
- botCheck: "turnstile"
680
+ botCheck: "turnstile",
681
+ questions: "suggested"
516
682
  }
517
683
  }
518
684
  ],
@@ -528,13 +694,50 @@ var CONSENT = /* @__PURE__ */ new Map([
528
694
  processing: "The answer text goes to Google to create the voice. Our server sends that voice through LiveKit to Protoface, which makes the avatar video streamed through LiveKit. Your browser connects to LiveKit, which sees your IP address.",
529
695
  storage: "Your microphone and camera are not used. We do not record the live session or store the generated voice. We keep a record of this consent. The privacy notice explains our safeguards, storage periods and the providers' processing. For people aged eighteen and over.",
530
696
  privacyLink: "How we handle this",
531
- botCheck: "off"
697
+ botCheck: "off",
698
+ questions: "suggested"
699
+ }
700
+ }
701
+ ],
702
+ [
703
+ // The Avatar tab's own question box (contract v1.3, `questions: "any"`): the first answer in a new chat started in
704
+ // the Avatar tab is read whether the visitor chose a suggested question or typed their own, so the intro says so and
705
+ // warns against personal details in a typed one. Product-neutral, with the bot check: one notice and one digest for
706
+ // every site (gitops docs/avatar-web/en-web-consent-2026-11-05.txt).
707
+ "web-consent-2026-11-05",
708
+ {
709
+ en: {
710
+ title: "Live AI avatar (beta)",
711
+ introProduct: null,
712
+ intro: "This is an AI avatar, not a real person. It reads aloud, for up to a minute, the first answer in a new chat started in the Avatar tab, provided it passes the speech checks, whether you chose a suggested question or typed your own. The answer is AI-generated and can be wrong. Don't put personal details in a question you type.",
713
+ processing: "When you start, Cloudflare checks for bots. The answer text goes to Google to create the voice. Our server sends that voice through LiveKit to Protoface, which makes the avatar video streamed through LiveKit. Your browser connects to LiveKit, which sees your IP address.",
714
+ storage: "Your microphone and camera are not used. We do not record the live session or store the generated voice. We keep a record of this consent. The privacy notice explains our safeguards, storage periods and the providers' processing. For people aged eighteen and over.",
715
+ privacyLink: "How we handle this",
716
+ botCheck: "turnstile",
717
+ questions: "any"
718
+ }
719
+ }
720
+ ],
721
+ [
722
+ // The words of web-consent-2026-11-05 without "When you start, Cloudflare checks for bots.", for a server that runs
723
+ // no bot check (gitops docs/avatar-web/en-web-consent-2026-11-06.txt).
724
+ "web-consent-2026-11-06",
725
+ {
726
+ en: {
727
+ title: "Live AI avatar (beta)",
728
+ introProduct: null,
729
+ intro: "This is an AI avatar, not a real person. It reads aloud, for up to a minute, the first answer in a new chat started in the Avatar tab, provided it passes the speech checks, whether you chose a suggested question or typed your own. The answer is AI-generated and can be wrong. Don't put personal details in a question you type.",
730
+ processing: "The answer text goes to Google to create the voice. Our server sends that voice through LiveKit to Protoface, which makes the avatar video streamed through LiveKit. Your browser connects to LiveKit, which sees your IP address.",
731
+ storage: "Your microphone and camera are not used. We do not record the live session or store the generated voice. We keep a record of this consent. The privacy notice explains our safeguards, storage periods and the providers' processing. For people aged eighteen and over.",
732
+ privacyLink: "How we handle this",
733
+ botCheck: "off",
734
+ questions: "any"
532
735
  }
533
736
  }
534
737
  ]
535
738
  ]);
536
739
  function avatarConsentCopy(version, locale) {
537
- if (!chunkFQH3AJN3_js.isAvatarLiveLocaleReviewed(locale)) return null;
740
+ if (!chunk7O2I32ZN_js.isAvatarLiveLocaleReviewed(locale)) return null;
538
741
  return CONSENT.get(version)?.[locale] ?? null;
539
742
  }
540
743
 
@@ -659,6 +862,9 @@ var CLOCK_TOLERANCE_MS = 5e3;
659
862
  var SERVICE_MAX_AGE_MS = 15 * 6e4;
660
863
  var ANSWER_OFFER_MS = SERVICE_MAX_AGE_MS - 6e4;
661
864
  var MAX_TIMER_MS = 2147483647;
865
+ var ASK_MAX_LENGTH = 300;
866
+ var MAX_REFERENCES = 64;
867
+ var USED_ON_KEY = "boff.explore.avatarUsedOn";
662
868
  var PRIMARY = '[data-avatar-primary], [data-boff-explore="panel-continue-chat"]';
663
869
  var IDLE = { name: "idle" };
664
870
  var INERT2 = { name: "inert" };
@@ -671,12 +877,26 @@ var REFUSAL_TEXT = {
671
877
  not_eligible: "notEligible",
672
878
  answer_claimed: "answerClaimed"
673
879
  };
674
- var WAITING = { answerId: null, startOver: false, offerUntil: NaN };
675
- var START_OVER = {
880
+ var EMPTY = {
881
+ kind: "empty",
676
882
  answerId: null,
677
- startOver: true,
678
- offerUntil: NaN
883
+ startOver: false,
884
+ offerUntil: NaN,
885
+ question: null,
886
+ pendingAnswerId: null,
887
+ askedHere: false
888
+ };
889
+ var START_OVER = { ...EMPTY, kind: "start-over", startOver: true };
890
+ var SUGGESTED_RULES = {
891
+ any: false,
892
+ askedHere: null,
893
+ token: null,
894
+ inFlight: false
679
895
  };
896
+ function isAskedHere(question, rules) {
897
+ const asked = rules.askedHere;
898
+ return rules.any && asked !== null && question.id === asked.messageId && asked.token === rules.token;
899
+ }
680
900
  function createdAtOf(message) {
681
901
  const raw = message.createdAt;
682
902
  return typeof raw === "string" && raw !== "" ? Date.parse(raw) : NaN;
@@ -684,25 +904,110 @@ function createdAtOf(message) {
684
904
  function offeredAt(exchange, now) {
685
905
  return exchange.answerId !== null && !(now < exchange.offerUntil) ? START_OVER : exchange;
686
906
  }
687
- function firstExchange(messages) {
688
- if (!messages || messages.length === 0) return WAITING;
907
+ function readable(question, answer) {
908
+ const references = answer.references?.length ?? 0;
909
+ return answer.answered === true && references >= 1 && references <= MAX_REFERENCES && (question.attachments?.length ?? 0) === 0;
910
+ }
911
+ function firstExchange(messages, rules = SUGGESTED_RULES) {
912
+ if (!messages || messages.length === 0) return EMPTY;
689
913
  if (messages.length > 2) return START_OVER;
690
914
  const [question, answer] = messages;
691
915
  if (question?.role !== "USER") return START_OVER;
692
- if (answer === void 0) return WAITING;
916
+ const first = { question, askedHere: isAskedHere(question, rules) };
917
+ if (answer === void 0) {
918
+ if (rules.inFlight) return { ...EMPTY, ...first, kind: "asking" };
919
+ return rules.any ? { ...START_OVER, ...first, kind: "failed" } : EMPTY;
920
+ }
693
921
  if (answer.role !== "ASSISTANT") return START_OVER;
694
922
  if (answer.status === "PENDING" || answer.status === "RUNNING") {
695
- return WAITING;
923
+ return {
924
+ ...EMPTY,
925
+ ...first,
926
+ kind: "asking",
927
+ pendingAnswerId: isAvatarMessageId(answer.id) ? answer.id : null
928
+ };
929
+ }
930
+ if (rules.any && answer.status === "FAILED") {
931
+ return { ...START_OVER, ...first, kind: "failed" };
696
932
  }
697
933
  if (answer.status !== "COMPLETED" || answer.content.trim() === "" || !isAvatarMessageId(answer.id)) {
698
934
  return START_OVER;
699
935
  }
936
+ if (rules.any && !first.askedHere) {
937
+ return { ...START_OVER, ...first, kind: "ask-here" };
938
+ }
939
+ if (rules.any && !readable(question, answer)) {
940
+ return { ...START_OVER, ...first, kind: "text-only" };
941
+ }
700
942
  return {
943
+ ...EMPTY,
944
+ ...first,
945
+ kind: "answer",
701
946
  answerId: answer.id,
702
- startOver: false,
703
947
  offerUntil: createdAtOf(answer) + ANSWER_OFFER_MS
704
948
  };
705
949
  }
950
+ function inFlight(conversation) {
951
+ return conversation?.phase === "sending" || conversation?.phase === "streaming";
952
+ }
953
+ function utcToday() {
954
+ return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
955
+ }
956
+ function usedTodayHere() {
957
+ try {
958
+ return window.localStorage.getItem(USED_ON_KEY) === utcToday();
959
+ } catch {
960
+ return false;
961
+ }
962
+ }
963
+ function noteUsedToday() {
964
+ try {
965
+ window.localStorage.setItem(USED_ON_KEY, utcToday());
966
+ } catch {
967
+ }
968
+ }
969
+ var silence = null;
970
+ function silentWav() {
971
+ if (silence !== null) return silence;
972
+ const rate = 8e3;
973
+ const samples = rate / 10;
974
+ const bytes = new Uint8Array(44 + samples);
975
+ const view = new DataView(bytes.buffer);
976
+ const text = (at, value) => {
977
+ for (let i = 0; i < value.length; i += 1) {
978
+ bytes[at + i] = value.charCodeAt(i);
979
+ }
980
+ };
981
+ text(0, "RIFF");
982
+ view.setUint32(4, 36 + samples, true);
983
+ text(8, "WAVE");
984
+ text(12, "fmt ");
985
+ view.setUint32(16, 16, true);
986
+ view.setUint16(20, 1, true);
987
+ view.setUint16(22, 1, true);
988
+ view.setUint32(24, rate, true);
989
+ view.setUint32(28, rate, true);
990
+ view.setUint16(32, 1, true);
991
+ view.setUint16(34, 8, true);
992
+ text(36, "data");
993
+ view.setUint32(40, samples, true);
994
+ bytes.fill(128, 44);
995
+ let binary = "";
996
+ for (const byte of bytes) binary += String.fromCharCode(byte);
997
+ silence = `data:audio/wav;base64,${btoa(binary)}`;
998
+ return silence;
999
+ }
1000
+ function unlockSound(audio) {
1001
+ if (audio === null || audio.srcObject) return;
1002
+ try {
1003
+ audio.src = silentWav();
1004
+ void Promise.resolve(audio.play()).then(
1005
+ () => audio.pause(),
1006
+ () => void 0
1007
+ );
1008
+ } catch {
1009
+ }
1010
+ }
706
1011
  function offering(offer, messageId, claimed) {
707
1012
  return claimed.has(messageId) ? { name: "refused", reason: "answer_claimed" } : { name: "consent", offer, messageId };
708
1013
  }
@@ -721,13 +1026,20 @@ function clock(seconds) {
721
1026
  function AvatarLiveView({
722
1027
  live,
723
1028
  active,
1029
+ open,
724
1030
  locale,
725
1031
  productName,
726
1032
  still,
727
1033
  fallback,
728
1034
  onContinueInChat,
1035
+ onVoiceHold,
729
1036
  continueInChat,
730
1037
  newChat,
1038
+ send,
1039
+ tryAsking,
1040
+ prompts,
1041
+ touchFirst,
1042
+ currentPath,
731
1043
  off,
732
1044
  base,
733
1045
  headers,
@@ -736,18 +1048,56 @@ function AvatarLiveView({
736
1048
  const S = avatarLiveStrings(locale);
737
1049
  const uid = react.useId();
738
1050
  const consentTitleId = `${uid}-consent`;
739
- const exchange = firstExchange(conversation?.messages);
1051
+ const [questions, setQuestions] = react.useState("suggested");
1052
+ const questionsRef = react.useRef("suggested");
1053
+ const askedHereRef = react.useRef(null);
1054
+ const askSeqRef = react.useRef(0);
1055
+ const [, setAskedHereTick] = react.useState(0);
1056
+ const setAskedHere = react.useCallback((next) => {
1057
+ if (next === null) {
1058
+ askSeqRef.current += 1;
1059
+ if (askedHereRef.current === null) return;
1060
+ }
1061
+ askedHereRef.current = next;
1062
+ setAskedHereTick((tick) => tick + 1);
1063
+ }, []);
1064
+ const token = conversation?.getConversationToken() ?? null;
1065
+ const exchange = firstExchange(conversation?.messages, {
1066
+ any: questions === "any",
1067
+ askedHere: askedHereRef.current,
1068
+ token,
1069
+ inFlight: inFlight(conversation)
1070
+ });
740
1071
  const [ageTick, setAgeTick] = react.useState(0);
741
- const { answerId, startOver } = offeredAt(exchange, Date.now());
1072
+ const shown = offeredAt(exchange, Date.now());
1073
+ const { answerId, startOver } = shown;
742
1074
  const offerUntil = answerId === null ? null : exchange.offerUntil;
743
1075
  const [phase, setPhase] = react.useState(IDLE);
744
1076
  const [blocked, setBlocked] = react.useState(false);
745
1077
  const [now, setNow] = react.useState(() => Date.now());
1078
+ const [draft, setDraft] = react.useState("");
1079
+ const chatMaxLength = conversation?.catalog.limits.maxMessageLength;
1080
+ const askMaxLength = chatMaxLength !== void 0 && Number.isFinite(chatMaxLength) && chatMaxLength >= 1 ? Math.min(ASK_MAX_LENGTH, Math.floor(chatMaxLength)) : ASK_MAX_LENGTH;
1081
+ const [note, setNote] = react.useState(null);
1082
+ const [usedToday, setUsedToday] = react.useState(false);
1083
+ const showing = active && !off;
1084
+ const behindChat = open && !active && !off;
746
1085
  const phaseRef = react.useRef(IDLE);
747
- const latest = react.useRef({ live, locale, base, headers, exchange, off });
748
- latest.current = { live, locale, base, headers, exchange, off };
1086
+ const latest = react.useRef({
1087
+ live,
1088
+ locale,
1089
+ base,
1090
+ headers,
1091
+ off,
1092
+ currentPath,
1093
+ showing
1094
+ });
1095
+ latest.current = { live, locale, base, headers, off, currentPath, showing };
749
1096
  const conversationRef = react.useRef(conversation);
750
1097
  conversationRef.current = conversation;
1098
+ const waitRef = react.useRef(null);
1099
+ const sendingRef = react.useRef(false);
1100
+ const textBoxRef = react.useRef(false);
751
1101
  const checkRef = react.useRef(null);
752
1102
  const askedLocale = react.useRef(locale);
753
1103
  const startRef = react.useRef(null);
@@ -761,8 +1111,32 @@ function AvatarLiveView({
761
1111
  phaseRef.current = next;
762
1112
  setPhase(next);
763
1113
  }, []);
1114
+ const inSight = react.useCallback(
1115
+ () => latest.current.showing && (typeof document === "undefined" || document.visibilityState !== "hidden"),
1116
+ []
1117
+ );
1118
+ const setMode = react.useCallback((next) => {
1119
+ questionsRef.current = next;
1120
+ setQuestions(next);
1121
+ }, []);
1122
+ const exchangeNow = react.useCallback(
1123
+ () => offeredAt(
1124
+ firstExchange(conversationRef.current?.messages, {
1125
+ any: questionsRef.current === "any",
1126
+ askedHere: askedHereRef.current,
1127
+ token: conversationRef.current?.getConversationToken() ?? null,
1128
+ inFlight: inFlight(conversationRef.current)
1129
+ }),
1130
+ Date.now()
1131
+ ),
1132
+ []
1133
+ );
764
1134
  const offeredNow = react.useCallback(
765
- () => offeredAt(latest.current.exchange, Date.now()).answerId,
1135
+ () => exchangeNow().answerId,
1136
+ [exchangeNow]
1137
+ );
1138
+ const pathNow = react.useCallback(
1139
+ () => latest.current.currentPath ?? (typeof window === "undefined" ? "" : window.location.pathname),
766
1140
  []
767
1141
  );
768
1142
  const reoffer = react.useCallback(
@@ -795,6 +1169,17 @@ function AvatarLiveView({
795
1169
  },
796
1170
  [go]
797
1171
  );
1172
+ const goLive = react.useCallback(() => {
1173
+ const current = phaseRef.current;
1174
+ const handle = sessionRef.current;
1175
+ if (current.name !== "pending" || !handle) return;
1176
+ handle.speakerArrived = true;
1177
+ if (questionsRef.current === "any") {
1178
+ noteUsedToday();
1179
+ setUsedToday(true);
1180
+ }
1181
+ go({ name: "live", session: current.session });
1182
+ }, [go]);
798
1183
  const cancelStart = react.useCallback((reason) => {
799
1184
  const run = startRef.current;
800
1185
  if (!run) return;
@@ -802,6 +1187,36 @@ function AvatarLiveView({
802
1187
  run.cancelled = reason;
803
1188
  run.turnstile?.cancel();
804
1189
  }, []);
1190
+ const applyAvailability = react.useCallback(
1191
+ (result, locale2) => {
1192
+ const { live: live2 } = latest.current;
1193
+ if (result.kind === "inert") {
1194
+ setMode("suggested");
1195
+ go(INERT2);
1196
+ return;
1197
+ }
1198
+ if (result.kind === "refused") {
1199
+ setMode(result.questions);
1200
+ go({ name: "refused", reason: result.reason });
1201
+ return;
1202
+ }
1203
+ setUsedToday(usedTodayHere());
1204
+ const copy = avatarConsentCopy(result.offer.consentVersion, locale2);
1205
+ if (copy === null || copy.botCheck !== result.offer.botCheck || copy.questions !== result.offer.questions) {
1206
+ setMode("suggested");
1207
+ go(INERT2);
1208
+ return;
1209
+ }
1210
+ if (result.offer.botCheck === "turnstile" && chunk7O2I32ZN_js.turnstileSiteKeyOf(live2) === null) {
1211
+ setMode("suggested");
1212
+ go(INERT2);
1213
+ return;
1214
+ }
1215
+ setMode(result.offer.questions);
1216
+ go(reoffer({ ...result.offer, locale: locale2, copy }));
1217
+ },
1218
+ [go, reoffer, setMode]
1219
+ );
805
1220
  const check = react.useCallback(() => {
806
1221
  const { live: live2, locale: locale2, base: base2, headers: headers2, off: off2 } = latest.current;
807
1222
  checkRef.current?.abort();
@@ -823,26 +1238,9 @@ function AvatarLiveView({
823
1238
  }).then((result) => {
824
1239
  if (checkRef.current !== controller) return;
825
1240
  checkRef.current = null;
826
- if (result.kind === "inert") {
827
- go(INERT2);
828
- return;
829
- }
830
- if (result.kind === "refused") {
831
- go({ name: "refused", reason: result.reason });
832
- return;
833
- }
834
- const copy = avatarConsentCopy(result.offer.consentVersion, locale2);
835
- if (copy === null || copy.botCheck !== result.offer.botCheck) {
836
- go(INERT2);
837
- return;
838
- }
839
- if (result.offer.botCheck === "turnstile" && chunkFQH3AJN3_js.turnstileSiteKeyOf(live2) === null) {
840
- go(INERT2);
841
- return;
842
- }
843
- go(reoffer({ ...result.offer, locale: locale2, copy }));
1241
+ applyAvailability(result, locale2);
844
1242
  });
845
- }, [go, reoffer]);
1243
+ }, [applyAvailability, go]);
846
1244
  const begin = react.useCallback(
847
1245
  (session, module, offer, target) => {
848
1246
  const received = Date.now();
@@ -887,8 +1285,8 @@ function AvatarLiveView({
887
1285
  reason: run.cancelled
888
1286
  });
889
1287
  }
890
- const shown = phaseRef.current;
891
- if (claimed && shown.name === "consent" && shown.messageId === context.messageId) {
1288
+ const shown2 = phaseRef.current;
1289
+ if (claimed && shown2.name === "consent" && shown2.messageId === context.messageId) {
892
1290
  go({ name: "refused", reason: "answer_claimed" });
893
1291
  }
894
1292
  return;
@@ -923,86 +1321,186 @@ function AvatarLiveView({
923
1321
  },
924
1322
  [begin, check, go]
925
1323
  );
1324
+ const launch = react.useCallback(
1325
+ (offer, messageId, preloaded) => {
1326
+ const { live: live2, base: base2, headers: headers2 } = latest.current;
1327
+ if (base2 === null) return;
1328
+ const exchangeAtStart = exchangeNow();
1329
+ if (exchangeAtStart.answerId !== messageId) {
1330
+ go(reoffer(offer));
1331
+ return;
1332
+ }
1333
+ if (claimedRef.current.has(messageId)) {
1334
+ go({ name: "refused", reason: "answer_claimed" });
1335
+ return;
1336
+ }
1337
+ const refusedFrom = exchangeAtStart.offerUntil - ANSWER_OFFER_MS + SERVICE_MAX_AGE_MS;
1338
+ const siteKey = offer.botCheck === "turnstile" ? chunk7O2I32ZN_js.turnstileSiteKeyOf(live2) : null;
1339
+ if (offer.botCheck === "turnstile" && (siteKey === null || !canBindBotCheck())) {
1340
+ go(INERT2);
1341
+ return;
1342
+ }
1343
+ const conversationToken = conversationRef.current?.getConversationToken() ?? null;
1344
+ const idempotencyKey = newIdempotencyKey();
1345
+ if (conversationToken === null || !isAvatarConversationToken(conversationToken) || idempotencyKey === null) {
1346
+ go({ name: "ended", how: "failed" });
1347
+ return;
1348
+ }
1349
+ const body2 = {
1350
+ site: live2.site,
1351
+ locale: offer.locale,
1352
+ conversationToken,
1353
+ messageId,
1354
+ consentVersion: offer.consentVersion,
1355
+ manifestVersion: live2.manifestVersion
1356
+ };
1357
+ const run = { cancelled: null, turnstile: null };
1358
+ startRef.current = run;
1359
+ const module = preloaded ?? loadModule(live2.load);
1360
+ let turnstile = null;
1361
+ if (siteKey === null) {
1362
+ go({ name: "creating" });
1363
+ } else {
1364
+ go({ name: "bot-check", offer, messageId });
1365
+ turnstile = runTurnstile(
1366
+ botBoxRef.current,
1367
+ siteKey,
1368
+ "avatar_start",
1369
+ avatarBotBinding(body2)
1370
+ );
1371
+ run.turnstile = turnstile;
1372
+ }
1373
+ void (async () => {
1374
+ let loaded;
1375
+ let botToken;
1376
+ try {
1377
+ [loaded, botToken] = await Promise.all([module, turnstile?.token]);
1378
+ } catch {
1379
+ turnstile?.cancel();
1380
+ if (run.cancelled === null) {
1381
+ startRef.current = null;
1382
+ go(INERT2);
1383
+ }
1384
+ return;
1385
+ }
1386
+ turnstile?.cancel();
1387
+ if (run.cancelled !== null) return;
1388
+ if (!(Date.now() < refusedFrom)) {
1389
+ startRef.current = null;
1390
+ go({ name: "needs-answer", offer });
1391
+ return;
1392
+ }
1393
+ if (turnstile !== null) go({ name: "creating" });
1394
+ const result = await requestCreate({
1395
+ base: base2,
1396
+ headers: headers2,
1397
+ idempotencyKey,
1398
+ botToken,
1399
+ body: body2
1400
+ });
1401
+ if (startRef.current === run) startRef.current = null;
1402
+ settle(result, run, {
1403
+ module: loaded,
1404
+ offer,
1405
+ messageId,
1406
+ base: base2,
1407
+ headers: headers2
1408
+ });
1409
+ })();
1410
+ },
1411
+ [exchangeNow, go, reoffer, settle]
1412
+ );
926
1413
  const start = react.useCallback(() => {
927
1414
  const current = phaseRef.current;
928
1415
  if (current.name !== "consent") return;
929
- const { live: live2, base: base2, headers: headers2 } = latest.current;
930
- if (base2 === null) return;
931
- const { offer, messageId } = current;
932
- if (offeredNow() !== messageId) {
933
- go(reoffer(offer));
934
- return;
935
- }
936
- const refusedFrom = latest.current.exchange.offerUntil - ANSWER_OFFER_MS + SERVICE_MAX_AGE_MS;
937
- const siteKey = offer.botCheck === "turnstile" ? chunkFQH3AJN3_js.turnstileSiteKeyOf(live2) : null;
938
- if (offer.botCheck === "turnstile" && (siteKey === null || !canBindBotCheck())) {
939
- go(INERT2);
940
- return;
941
- }
942
- const conversationToken = conversationRef.current?.getConversationToken() ?? null;
943
- const idempotencyKey = newIdempotencyKey();
944
- if (conversationToken === null || !isAvatarConversationToken(conversationToken) || idempotencyKey === null) {
945
- go({ name: "ended", how: "failed" });
1416
+ if (current.offer.questions === "any") unlockSound(audioRef.current);
1417
+ launch(current.offer, current.messageId, null);
1418
+ }, [launch]);
1419
+ const cancelWaiting = react.useCallback(
1420
+ (told) => {
1421
+ const wait = waitRef.current;
1422
+ waitRef.current = null;
1423
+ wait?.check?.abort();
1424
+ const current = phaseRef.current;
1425
+ if (current.name !== "waiting") return;
1426
+ if (told) setNote("cancelled");
1427
+ go({ name: "needs-answer", offer: current.offer });
1428
+ },
1429
+ [go]
1430
+ );
1431
+ const bindingHolds = react.useCallback(
1432
+ (bound, exchange2) => {
1433
+ const { live: live2, locale: locale2 } = latest.current;
1434
+ return conversationRef.current?.getConversationToken() === bound.token && exchange2.question?.id === bound.questionId && live2.site === bound.site && locale2 === bound.locale && pathNow() === bound.path;
1435
+ },
1436
+ [pathNow]
1437
+ );
1438
+ const startWhenReady = react.useCallback(() => {
1439
+ const current = phaseRef.current;
1440
+ if (current.name !== "needs-answer") return;
1441
+ const { live: live2, locale: locale2 } = latest.current;
1442
+ const exchange2 = exchangeNow();
1443
+ const token2 = conversationRef.current?.getConversationToken() ?? null;
1444
+ if (exchange2.kind !== "asking" || !exchange2.askedHere || exchange2.question === null || exchange2.pendingAnswerId === null || token2 === null || !isAvatarConversationToken(token2)) {
946
1445
  return;
947
1446
  }
948
- const body2 = {
949
- site: live2.site,
950
- locale: offer.locale,
951
- conversationToken,
952
- messageId,
953
- consentVersion: offer.consentVersion,
954
- manifestVersion: live2.manifestVersion
955
- };
956
- const run = { cancelled: null, turnstile: null };
957
- startRef.current = run;
1447
+ unlockSound(audioRef.current);
958
1448
  const module = loadModule(live2.load);
959
- let turnstile = null;
960
- if (siteKey === null) {
961
- go({ name: "creating" });
962
- } else {
963
- go({ name: "bot-check", offer, messageId });
964
- turnstile = runTurnstile(
965
- botBoxRef.current,
966
- siteKey,
967
- "avatar_start",
968
- avatarBotBinding(body2)
969
- );
970
- run.turnstile = turnstile;
971
- }
972
- void (async () => {
973
- let loaded;
974
- let botToken;
975
- try {
976
- [loaded, botToken] = await Promise.all([module, turnstile?.token]);
977
- } catch {
978
- turnstile?.cancel();
979
- if (run.cancelled === null) {
980
- startRef.current = null;
981
- go(INERT2);
982
- }
983
- return;
984
- }
985
- turnstile?.cancel();
986
- if (run.cancelled !== null) return;
987
- if (!(Date.now() < refusedFrom)) {
988
- startRef.current = null;
989
- go({ name: "needs-answer", offer });
1449
+ module.catch(() => void 0);
1450
+ waitRef.current = {
1451
+ bound: {
1452
+ token: token2,
1453
+ questionId: exchange2.question.id,
1454
+ answerId: exchange2.pendingAnswerId,
1455
+ site: live2.site,
1456
+ locale: locale2,
1457
+ path: pathNow(),
1458
+ consentVersion: current.offer.consentVersion,
1459
+ botCheck: current.offer.botCheck
1460
+ },
1461
+ module,
1462
+ check: null
1463
+ };
1464
+ setNote(null);
1465
+ go({ name: "waiting", offer: current.offer });
1466
+ }, [exchangeNow, go, pathNow]);
1467
+ const confirm = react.useCallback(
1468
+ (offer, wait) => {
1469
+ const { live: live2, locale: locale2, base: base2, headers: headers2 } = latest.current;
1470
+ if (base2 === null) {
1471
+ cancelWaiting(true);
990
1472
  return;
991
1473
  }
992
- if (turnstile !== null) go({ name: "creating" });
993
- const result = await requestCreate({
1474
+ const controller = new AbortController();
1475
+ wait.check = controller;
1476
+ void requestAvailability({
994
1477
  base: base2,
995
1478
  headers: headers2,
996
- idempotencyKey,
997
- botToken,
998
- body: body2
1479
+ site: live2.site,
1480
+ locale: locale2,
1481
+ signal: controller.signal
1482
+ }).then((result) => {
1483
+ if (waitRef.current !== wait || phaseRef.current.name !== "waiting") {
1484
+ return;
1485
+ }
1486
+ waitRef.current = null;
1487
+ const exchange2 = exchangeNow();
1488
+ const same = result.kind === "available" && result.offer.consentVersion === wait.bound.consentVersion && result.offer.botCheck === wait.bound.botCheck && result.offer.questions === "any" && exchange2.kind === "answer" && exchange2.answerId === wait.bound.answerId && bindingHolds(wait.bound, exchange2);
1489
+ if (!same || result.kind !== "available") {
1490
+ applyAvailability(result, locale2);
1491
+ return;
1492
+ }
1493
+ launch({ ...offer, ...result.offer }, wait.bound.answerId, wait.module);
999
1494
  });
1000
- if (startRef.current === run) startRef.current = null;
1001
- settle(result, run, { module: loaded, offer, messageId, base: base2, headers: headers2 });
1002
- })();
1003
- }, [go, offeredNow, reoffer, settle]);
1495
+ },
1496
+ [applyAvailability, bindingHolds, cancelWaiting, exchangeNow, launch]
1497
+ );
1004
1498
  const stop = react.useCallback(() => {
1005
1499
  const current = phaseRef.current;
1500
+ if (current.name === "waiting") {
1501
+ cancelWaiting(false);
1502
+ return;
1503
+ }
1006
1504
  if (current.name === "bot-check") {
1007
1505
  cancelStart("user");
1008
1506
  go(reoffer(current.offer));
@@ -1016,11 +1514,13 @@ function AvatarLiveView({
1016
1514
  if (current.name === "pending" || current.name === "live") {
1017
1515
  finish("stopped", "user");
1018
1516
  }
1019
- }, [cancelStart, finish, go, reoffer]);
1517
+ }, [cancelStart, cancelWaiting, finish, go, reoffer]);
1020
1518
  const leave = react.useCallback(
1021
- (reason) => {
1519
+ (event) => {
1022
1520
  const current = phaseRef.current;
1521
+ const reason = event === "user" || event === "chat" ? "user" : "page_hide";
1023
1522
  const how = reason === "user" ? "stopped" : "interrupted";
1523
+ const keepsSession = event === "chat" || event === "hidden";
1024
1524
  switch (current.name) {
1025
1525
  case "checking": {
1026
1526
  if (reason !== "user") return;
@@ -1030,49 +1530,63 @@ function AvatarLiveView({
1030
1530
  go(IDLE);
1031
1531
  return;
1032
1532
  }
1533
+ case "waiting":
1534
+ cancelWaiting(true);
1535
+ return;
1033
1536
  case "bot-check":
1034
1537
  cancelStart(reason);
1035
1538
  go(reason === "user" ? IDLE : reoffer(current.offer));
1036
1539
  return;
1037
1540
  case "creating":
1541
+ if (keepsSession) return;
1038
1542
  cancelStart(reason);
1039
1543
  go({ name: "ended", how });
1040
1544
  return;
1041
1545
  case "pending":
1042
1546
  case "live":
1547
+ if (keepsSession) {
1548
+ if (current.name === "pending" && sessionRef.current?.speakerArrived) {
1549
+ goLive();
1550
+ }
1551
+ return;
1552
+ }
1043
1553
  finish(how, reason);
1044
1554
  return;
1045
1555
  default:
1046
1556
  return;
1047
1557
  }
1048
1558
  },
1049
- [cancelStart, finish, go, reoffer]
1559
+ [cancelStart, cancelWaiting, finish, go, goLive, reoffer]
1050
1560
  );
1051
- const showing = active && !off;
1052
1561
  react.useEffect(() => {
1053
1562
  if (!showing) {
1054
- leave("user");
1563
+ leave(behindChat ? "chat" : "user");
1055
1564
  return;
1056
1565
  }
1057
1566
  const current = phaseRef.current;
1567
+ if (current.name === "creating" || current.name === "pending" || current.name === "live") {
1568
+ setNow(Date.now());
1569
+ return;
1570
+ }
1058
1571
  const offered = offeredNow();
1059
1572
  const used = offered !== null && claimedRef.current.has(offered);
1060
1573
  if (current.name === "ended" && used) return;
1061
1574
  if (current.name === "refused" && current.reason === "answer_claimed" && used) {
1062
1575
  return;
1063
1576
  }
1064
- if (current.name === "idle" || current.name === "inert" || current.name === "refused" || current.name === "needs-answer" || current.name === "consent" || current.name === "ended" || // Asking, with nothing actually asking: React's strict mode unmounts and mounts a component again with the state it
1577
+ if (current.name === "idle" || current.name === "inert" || current.name === "refused" || current.name === "needs-answer" || current.name === "consent" || current.name === "declined" || current.name === "ended" || // Asking, with nothing actually asking: React's strict mode unmounts and mounts a component again with the state it
1065
1578
  // left, and the unmount in between dropped the question. (This view mounts already showing, the first time the
1066
1579
  // Avatar view opens.)
1067
1580
  current.name === "checking" && checkRef.current === null) {
1068
1581
  check();
1069
1582
  }
1070
- }, [showing, check, leave, offeredNow]);
1583
+ }, [showing, behindChat, check, leave, offeredNow]);
1071
1584
  react.useEffect(() => {
1072
1585
  if (askedLocale.current === locale) return;
1073
1586
  askedLocale.current = locale;
1587
+ if (phaseRef.current.name === "waiting") cancelWaiting(true);
1074
1588
  const current = phaseRef.current.name;
1075
- if (current !== "checking" && current !== "needs-answer" && current !== "consent" && current !== "refused" && current !== "inert") {
1589
+ if (current !== "checking" && current !== "needs-answer" && current !== "consent" && current !== "declined" && current !== "refused" && current !== "inert") {
1076
1590
  return;
1077
1591
  }
1078
1592
  if (active) {
@@ -1082,7 +1596,8 @@ function AvatarLiveView({
1082
1596
  checkRef.current = null;
1083
1597
  go(IDLE);
1084
1598
  }
1085
- }, [active, check, go, locale]);
1599
+ }, [active, cancelWaiting, check, go, locale]);
1600
+ const kind = shown.kind;
1086
1601
  react.useEffect(() => {
1087
1602
  const current = phaseRef.current;
1088
1603
  if (current.name === "needs-answer" && answerId !== null) {
@@ -1091,8 +1606,49 @@ function AvatarLiveView({
1091
1606
  go(
1092
1607
  answerId === null ? { name: "needs-answer", offer: current.offer } : { ...current, messageId: answerId }
1093
1608
  );
1609
+ } else if (current.name === "declined" && answerId === null) {
1610
+ if (kind !== "asking") go({ name: "needs-answer", offer: current.offer });
1094
1611
  }
1095
- }, [answerId, go]);
1612
+ }, [answerId, kind, go]);
1613
+ react.useEffect(() => {
1614
+ const current = phaseRef.current;
1615
+ const wait = waitRef.current;
1616
+ if (current.name !== "waiting" || wait === null || wait.check !== null) {
1617
+ return;
1618
+ }
1619
+ const now2 = exchangeNow();
1620
+ const holds = bindingHolds(wait.bound, now2);
1621
+ if (holds && now2.kind === "asking" && now2.pendingAnswerId === wait.bound.answerId) {
1622
+ return;
1623
+ }
1624
+ if (!holds || now2.kind !== "answer" || now2.answerId !== wait.bound.answerId) {
1625
+ cancelWaiting(now2.kind !== "failed" && now2.kind !== "text-only");
1626
+ return;
1627
+ }
1628
+ confirm(current.offer, wait);
1629
+ });
1630
+ const resent = conversation?.resent ?? null;
1631
+ react.useEffect(() => {
1632
+ const asked = askedHereRef.current;
1633
+ if (resent === null || asked === null || !resent.replacedMessageIds.includes(asked.messageId)) {
1634
+ return;
1635
+ }
1636
+ setAskedHere({
1637
+ messageId: resent.sent.userMessageId,
1638
+ token: resent.sent.conversationToken
1639
+ });
1640
+ }, [resent, setAskedHere]);
1641
+ const empty = (conversation?.messages.length ?? 0) === 0;
1642
+ react.useEffect(() => {
1643
+ if (empty) setAskedHere(null);
1644
+ }, [empty, setAskedHere]);
1645
+ react.useEffect(() => {
1646
+ const asked = askedHereRef.current;
1647
+ if (asked !== null && asked.token !== token) setAskedHere(null);
1648
+ }, [token, setAskedHere]);
1649
+ react.useEffect(() => {
1650
+ if (showing) setUsedToday(usedTodayHere());
1651
+ }, [showing]);
1096
1652
  react.useEffect(() => {
1097
1653
  if (offerUntil === null) return;
1098
1654
  const timer = setTimeout(
@@ -1111,7 +1667,9 @@ function AvatarLiveView({
1111
1667
  const wasLive = phaseRef.current.name === "live";
1112
1668
  switch (event.type) {
1113
1669
  case "speaker-track":
1114
- if (event.kind === "video") handle.speakerArrived = true;
1670
+ if (event.kind !== "video") return;
1671
+ handle.speakerArrived = true;
1672
+ if (!inSight()) goLive();
1115
1673
  return;
1116
1674
  case "playback-blocked":
1117
1675
  setBlocked(event.blocked);
@@ -1128,7 +1686,7 @@ function AvatarLiveView({
1128
1686
  return;
1129
1687
  }
1130
1688
  },
1131
- [finish]
1689
+ [finish, goLive, inSight]
1132
1690
  );
1133
1691
  react.useEffect(() => {
1134
1692
  if (phase.name !== "pending") return;
@@ -1202,11 +1760,23 @@ function AvatarLiveView({
1202
1760
  const timer = setInterval(() => setNow(Date.now()), 1e3);
1203
1761
  return () => clearInterval(timer);
1204
1762
  }, [ticking]);
1763
+ const voiceLine = phase.name === "live" ? S.speaking : phase.name === "creating" || phase.name === "pending" ? S.connecting : null;
1764
+ const onVoiceHoldRef = react.useRef(onVoiceHold);
1765
+ onVoiceHoldRef.current = onVoiceHold;
1766
+ react.useEffect(() => {
1767
+ onVoiceHoldRef.current?.(voiceLine);
1768
+ }, [voiceLine]);
1769
+ react.useEffect(() => () => onVoiceHoldRef.current?.(null), []);
1205
1770
  react.useEffect(() => {
1206
1771
  if (typeof window === "undefined") return;
1207
1772
  const onPageHide = () => leave("page_hide");
1208
1773
  const onVisibility = () => {
1209
- if (document.visibilityState === "hidden") leave("page_hide");
1774
+ if (document.visibilityState === "hidden") {
1775
+ leave("hidden");
1776
+ return;
1777
+ }
1778
+ const current = phaseRef.current.name;
1779
+ if (current === "pending" || current === "live") setNow(Date.now());
1210
1780
  };
1211
1781
  window.addEventListener("pagehide", onPageHide);
1212
1782
  document.addEventListener("visibilitychange", onVisibility);
@@ -1226,6 +1796,9 @@ function AvatarLiveView({
1226
1796
  run.cancelled = "user";
1227
1797
  run.turnstile?.cancel();
1228
1798
  }
1799
+ const wait = waitRef.current;
1800
+ waitRef.current = null;
1801
+ wait?.check?.abort();
1229
1802
  const handle = sessionRef.current;
1230
1803
  sessionRef.current = null;
1231
1804
  if (handle && !handle.done) {
@@ -1242,19 +1815,74 @@ function AvatarLiveView({
1242
1815
  },
1243
1816
  []
1244
1817
  );
1818
+ const any = questions === "any";
1819
+ const textMode = any && (usedToday && (phase.name === "needs-answer" || phase.name === "consent" || phase.name === "declined" || phase.name === "ended") || phase.name === "refused" && phase.reason === "limits");
1820
+ textBoxRef.current = textMode;
1821
+ const askState = !any ? void 0 : textMode ? "text" : phase.name === "needs-answer" ? kind === "empty" ? "ready" : kind : phase.name;
1822
+ const notNow = react.useCallback(() => {
1823
+ const current = phaseRef.current;
1824
+ if ((current.name === "consent" || current.name === "needs-answer") && current.offer.questions === "any") {
1825
+ go({ name: "declined", offer: current.offer });
1826
+ return;
1827
+ }
1828
+ onContinueInChat();
1829
+ }, [go, onContinueInChat]);
1830
+ const ask = react.useCallback(
1831
+ (text) => {
1832
+ const conversation2 = conversationRef.current;
1833
+ const question = text.trim();
1834
+ if (conversation2 === null || question === "" || sendingRef.current) {
1835
+ return;
1836
+ }
1837
+ const spoken = !textBoxRef.current;
1838
+ if (spoken && conversation2.messages.length > 0) return;
1839
+ sendingRef.current = true;
1840
+ setAskedHere(null);
1841
+ const seq = askSeqRef.current;
1842
+ setNote(null);
1843
+ setDraft("");
1844
+ void conversation2.send(question, [], spoken ? { surface: "AVATAR" } : {}).then((added) => {
1845
+ if (added === null) {
1846
+ setDraft((current) => current === "" ? question : current);
1847
+ }
1848
+ if (!spoken || added === null || askSeqRef.current !== seq || added.conversationToken !== (conversationRef.current?.getConversationToken() ?? null)) {
1849
+ return;
1850
+ }
1851
+ setAskedHere({
1852
+ messageId: added.userMessageId,
1853
+ token: added.conversationToken
1854
+ });
1855
+ }).finally(() => {
1856
+ sendingRef.current = false;
1857
+ });
1858
+ },
1859
+ [setAskedHere]
1860
+ );
1861
+ const newChatForAvatar = react.useCallback(() => {
1862
+ const conversation2 = conversationRef.current;
1863
+ if (conversation2 === null) return;
1864
+ const now2 = exchangeNow();
1865
+ const failedQuestion = now2.kind === "failed" ? now2.question?.content ?? null : null;
1866
+ conversation2.reset();
1867
+ setAskedHere(null);
1868
+ setNote("new-chat");
1869
+ if (failedQuestion !== null) {
1870
+ setDraft((current2) => current2 === "" ? failedQuestion : current2);
1871
+ }
1872
+ const current = phaseRef.current;
1873
+ if (current.name === "needs-answer" || current.name === "consent" || current.name === "declined") {
1874
+ go({ name: "needs-answer", offer: current.offer });
1875
+ } else {
1876
+ check();
1877
+ }
1878
+ }, [check, exchangeNow, go, setAskedHere]);
1245
1879
  react.useEffect(() => {
1246
1880
  if (!active) return;
1247
1881
  const focused = document.activeElement;
1248
1882
  if (focused && focused !== document.body && focused.isConnected) return;
1249
1883
  rootRef.current?.querySelector(PRIMARY)?.focus();
1250
- }, [active, phase.name, blocked]);
1251
- const onPlaying = react.useCallback(() => {
1252
- const current = phaseRef.current;
1253
- const handle = sessionRef.current;
1254
- if (current.name !== "pending" || !handle) return;
1255
- handle.speakerArrived = true;
1256
- go({ name: "live", session: current.session });
1257
- }, [go]);
1884
+ }, [active, phase.name, askState, shown.pendingAnswerId, blocked]);
1885
+ const onPlaying = goLive;
1258
1886
  const enablePlayback = react.useCallback(() => {
1259
1887
  void sessionRef.current?.joined?.enablePlayback().catch(() => void 0);
1260
1888
  }, []);
@@ -1285,7 +1913,7 @@ function AvatarLiveView({
1285
1913
  height: small ? 64 : 128,
1286
1914
  className: chunkC6OJIHNO_js.cn(
1287
1915
  "shrink-0 rounded-full border border-border object-cover shadow-sm",
1288
- small ? "h-16 w-16" : "h-32 w-32"
1916
+ small ? "h-16 w-16" : any ? "h-[min(12rem,32dvh)] w-[min(12rem,32dvh)]" : "h-32 w-32"
1289
1917
  )
1290
1918
  }
1291
1919
  );
@@ -1334,12 +1962,440 @@ function AvatarLiveView({
1334
1962
  children: S.stop
1335
1963
  }
1336
1964
  );
1965
+ const readInChatButton = (primary) => /* @__PURE__ */ jsxRuntime.jsx(
1966
+ "button",
1967
+ {
1968
+ type: "button",
1969
+ "data-avatar-primary": primary ? "" : void 0,
1970
+ "data-boff-explore": "avatar-live-read-in-chat",
1971
+ className: primary ? primaryButton : secondaryButton,
1972
+ onClick: onContinueInChat,
1973
+ children: S.readInChat
1974
+ }
1975
+ );
1976
+ const consentCard = (copy) => /* @__PURE__ */ jsxRuntime.jsxs(
1977
+ "section",
1978
+ {
1979
+ "aria-labelledby": consentTitleId,
1980
+ "data-boff-explore": "avatar-live-consent",
1981
+ className: "w-full max-w-sm rounded-lg border border-border p-4 text-start",
1982
+ children: [
1983
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { id: consentTitleId, className: "text-base font-semibold", children: copy.title }),
1984
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 text-sm", children: productName === null || copy.introProduct === null ? copy.intro : chunkO4GS3XPZ_js.fill(copy.introProduct, { product: productName }) }),
1985
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 text-sm text-muted-foreground", children: copy.processing }),
1986
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 text-sm text-muted-foreground", children: copy.storage }),
1987
+ /* @__PURE__ */ jsxRuntime.jsxs(
1988
+ "a",
1989
+ {
1990
+ href: PRIVACY_HREF,
1991
+ target: "_blank",
1992
+ rel: "noopener noreferrer",
1993
+ "data-boff-explore": "avatar-live-privacy",
1994
+ className: "mt-2 inline-block text-sm font-medium text-primary underline underline-offset-2 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
1995
+ children: [
1996
+ copy.privacyLink,
1997
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "sr-only", children: [
1998
+ " ",
1999
+ S.opensInNewTab
2000
+ ] })
2001
+ ]
2002
+ }
2003
+ )
2004
+ ]
2005
+ }
2006
+ );
2007
+ const consentActions = (whenReady) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center justify-center gap-2", children: [
2008
+ /* @__PURE__ */ jsxRuntime.jsx(
2009
+ "button",
2010
+ {
2011
+ type: "button",
2012
+ "data-avatar-primary": "",
2013
+ "data-boff-explore": whenReady ? "avatar-live-start-when-ready" : "avatar-live-start",
2014
+ className: primaryButton,
2015
+ onClick: whenReady ? startWhenReady : start,
2016
+ children: whenReady ? S.startWhenReady : S.start
2017
+ }
2018
+ ),
2019
+ /* @__PURE__ */ jsxRuntime.jsx(
2020
+ "button",
2021
+ {
2022
+ type: "button",
2023
+ "data-boff-explore": "avatar-live-not-now",
2024
+ className: secondaryButton,
2025
+ onClick: notNow,
2026
+ children: S.notNow
2027
+ }
2028
+ )
2029
+ ] });
2030
+ const liveMedia = (playing) => /* @__PURE__ */ jsxRuntime.jsxs(
2031
+ "div",
2032
+ {
2033
+ className: chunkC6OJIHNO_js.cn(
2034
+ "relative shrink-0 overflow-hidden rounded-xl border border-border bg-muted",
2035
+ any ? "h-[min(12rem,32dvh)] w-[min(12rem,32dvh)]" : "h-48 w-48"
2036
+ ),
2037
+ children: [
2038
+ /* @__PURE__ */ jsxRuntime.jsx(
2039
+ "video",
2040
+ {
2041
+ ref: videoRef,
2042
+ "aria-label": S.video,
2043
+ "data-boff-explore": "avatar-live-video",
2044
+ playsInline: true,
2045
+ autoPlay: true,
2046
+ muted: true,
2047
+ onPlaying,
2048
+ className: chunkC6OJIHNO_js.cn("h-full w-full object-cover", !playing && "opacity-0")
2049
+ }
2050
+ ),
2051
+ playing ? null : /* @__PURE__ */ jsxRuntime.jsx(
2052
+ "img",
2053
+ {
2054
+ src: still.src,
2055
+ alt: "",
2056
+ decoding: "async",
2057
+ className: "absolute inset-0 h-full w-full object-cover"
2058
+ }
2059
+ ),
2060
+ any ? null : /* @__PURE__ */ jsxRuntime.jsx("audio", { ref: audioRef, "data-boff-explore": "avatar-live-audio" })
2061
+ ]
2062
+ }
2063
+ );
2064
+ const liveBody = (session) => /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2065
+ /* @__PURE__ */ jsxRuntime.jsx(
2066
+ "section",
2067
+ {
2068
+ "aria-label": S.captions,
2069
+ "data-boff-explore": "avatar-live-captions",
2070
+ lang: session.captions.locale || void 0,
2071
+ dir: "auto",
2072
+ tabIndex: 0,
2073
+ className: "max-h-32 w-full max-w-sm overflow-y-auto rounded-lg bg-muted p-3 text-start text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
2074
+ children: session.captions.text
2075
+ }
2076
+ ),
2077
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: S.answerInChat }),
2078
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-sm tabular-nums text-muted-foreground", children: [
2079
+ S.timeLeft,
2080
+ " ",
2081
+ /* @__PURE__ */ jsxRuntime.jsx("span", { role: "timer", "data-boff-explore": "avatar-live-countdown", children: clock(Math.max(0, (session.endsAt - now) / 1e3)) })
2082
+ ] })
2083
+ ] });
2084
+ const liveActions = (back) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center justify-center gap-2", children: [
2085
+ blocked ? /* @__PURE__ */ jsxRuntime.jsx(
2086
+ "button",
2087
+ {
2088
+ type: "button",
2089
+ "data-boff-explore": "avatar-live-sound",
2090
+ className: primaryButton,
2091
+ onClick: enablePlayback,
2092
+ children: S.tapForSound
2093
+ }
2094
+ ) : null,
2095
+ stopButton,
2096
+ back
2097
+ ] });
2098
+ const badge = /* @__PURE__ */ jsxRuntime.jsx(
2099
+ "p",
2100
+ {
2101
+ "data-boff-explore": "avatar-live-badge",
2102
+ className: "rounded-full bg-muted px-3 py-1 text-xs font-medium text-foreground",
2103
+ children: S.badge
2104
+ }
2105
+ );
2106
+ if (any) {
2107
+ let status = "";
2108
+ let outcome2 = false;
2109
+ let lead = null;
2110
+ let top2 = null;
2111
+ let media2 = stillPicture(false);
2112
+ let body2 = null;
2113
+ let actions2 = null;
2114
+ let newChatOffer = false;
2115
+ let box = null;
2116
+ const first = exchange.question;
2117
+ const questionLine = first === null ? null : /* @__PURE__ */ jsxRuntime.jsx(
2118
+ "p",
2119
+ {
2120
+ "data-boff-explore": "avatar-live-question",
2121
+ dir: "auto",
2122
+ className: "line-clamp-2 w-full max-w-sm break-words text-sm font-medium",
2123
+ children: first.content
2124
+ }
2125
+ );
2126
+ const activity = conversation?.activity ?? null;
2127
+ const activityLine = activity === null ? null : /* @__PURE__ */ jsxRuntime.jsx(
2128
+ "p",
2129
+ {
2130
+ "data-boff-explore": "avatar-live-activity",
2131
+ className: "text-xs text-muted-foreground",
2132
+ children: activity
2133
+ }
2134
+ );
2135
+ if (textMode) {
2136
+ const messages = conversation?.messages ?? [];
2137
+ let questionAt = messages.length - 1;
2138
+ while (questionAt >= 0 && messages[questionAt]?.role !== "USER") {
2139
+ questionAt -= 1;
2140
+ }
2141
+ const lastQuestion = questionAt === -1 ? void 0 : messages[questionAt];
2142
+ const after = questionAt === -1 ? void 0 : messages[questionAt + 1];
2143
+ const lastAnswer = after?.role === "ASSISTANT" ? after : void 0;
2144
+ const chatPhase = conversation?.phase;
2145
+ const unanswered = lastQuestion === void 0 || lastAnswer !== void 0 ? null : chatPhase === "sending" || chatPhase === "streaming" ? "waiting" : chatPhase === "error" || chatPhase === "limited" ? "failed" : null;
2146
+ if (phase.name === "refused") {
2147
+ status = S[REFUSAL_TEXT[phase.reason]];
2148
+ outcome2 = true;
2149
+ } else if (phase.name === "ended") {
2150
+ status = S[phase.how];
2151
+ outcome2 = true;
2152
+ }
2153
+ body2 = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2154
+ lastQuestion === void 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(
2155
+ "p",
2156
+ {
2157
+ "data-boff-explore": "avatar-live-question",
2158
+ dir: "auto",
2159
+ className: "line-clamp-2 w-full max-w-sm break-words text-sm font-medium",
2160
+ children: lastQuestion.content
2161
+ }
2162
+ ),
2163
+ lastAnswer === void 0 ? unanswered === "waiting" ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: activity ?? S.gettingAnswer }) : unanswered === "failed" ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: S.answerFailed }) : null : lastAnswer.status === "PENDING" || lastAnswer.status === "RUNNING" ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: activity ?? S.gettingAnswer }) : lastAnswer.status === "FAILED" ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: S.answerFailed }) : /* @__PURE__ */ jsxRuntime.jsx(
2164
+ "p",
2165
+ {
2166
+ "data-boff-explore": "avatar-live-text-answer",
2167
+ dir: "auto",
2168
+ className: "line-clamp-6 w-full max-w-sm whitespace-pre-wrap break-words text-start text-sm",
2169
+ children: lastAnswer.content
2170
+ }
2171
+ )
2172
+ ] });
2173
+ const ended = phase.name === "ended";
2174
+ actions2 = lastAnswer === void 0 && unanswered !== "failed" && !ended ? null : readInChatButton(ended);
2175
+ box = "text";
2176
+ } else {
2177
+ switch (phase.name) {
2178
+ case "checking":
2179
+ status = S.checking;
2180
+ break;
2181
+ case "needs-answer":
2182
+ switch (shown.kind) {
2183
+ case "empty":
2184
+ status = note === "new-chat" ? S.newChatStarted : "";
2185
+ lead = /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-base font-semibold", children: S.askHeadline });
2186
+ box = "spoken";
2187
+ break;
2188
+ case "asking":
2189
+ case "answer": {
2190
+ const card = shown.askedHere && shown.pendingAnswerId !== null;
2191
+ status = note === "cancelled" ? S.armedCancelled : S.gettingAnswer;
2192
+ if (card) media2 = stillPicture(true);
2193
+ body2 = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2194
+ questionLine,
2195
+ activityLine,
2196
+ card ? consentCard(phase.offer.copy) : null
2197
+ ] });
2198
+ actions2 = card ? consentActions(true) : null;
2199
+ break;
2200
+ }
2201
+ case "text-only":
2202
+ status = S.notSpoken;
2203
+ outcome2 = true;
2204
+ body2 = questionLine;
2205
+ actions2 = readInChatButton(false);
2206
+ newChatOffer = true;
2207
+ break;
2208
+ case "failed":
2209
+ status = S.answerFailed;
2210
+ outcome2 = true;
2211
+ body2 = questionLine;
2212
+ newChatOffer = true;
2213
+ break;
2214
+ case "ask-here":
2215
+ status = S.askHere;
2216
+ outcome2 = true;
2217
+ actions2 = readInChatButton(false);
2218
+ newChatOffer = true;
2219
+ break;
2220
+ default:
2221
+ status = S.startNewChat;
2222
+ outcome2 = true;
2223
+ body2 = /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: S.startNewChatDetailAny });
2224
+ actions2 = readInChatButton(false);
2225
+ newChatOffer = true;
2226
+ break;
2227
+ }
2228
+ break;
2229
+ case "consent":
2230
+ media2 = stillPicture(true);
2231
+ body2 = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2232
+ questionLine,
2233
+ consentCard(phase.offer.copy)
2234
+ ] });
2235
+ actions2 = consentActions(false);
2236
+ break;
2237
+ case "declined":
2238
+ status = S.declined;
2239
+ actions2 = readInChatButton(true);
2240
+ break;
2241
+ case "waiting":
2242
+ status = S.armed;
2243
+ body2 = questionLine;
2244
+ actions2 = /* @__PURE__ */ jsxRuntime.jsx(
2245
+ "button",
2246
+ {
2247
+ type: "button",
2248
+ "data-avatar-primary": "",
2249
+ "data-boff-explore": "avatar-live-cancel",
2250
+ className: secondaryButton,
2251
+ onClick: stop,
2252
+ children: S.cancel
2253
+ }
2254
+ );
2255
+ break;
2256
+ case "refused":
2257
+ outcome2 = true;
2258
+ if (phase.reason === "not_eligible" || phase.reason === "answer_claimed") {
2259
+ status = phase.reason === "not_eligible" ? S.notEligibleAny : S.answerClaimed;
2260
+ actions2 = readInChatButton(false);
2261
+ newChatOffer = true;
2262
+ } else {
2263
+ status = S[REFUSAL_TEXT[phase.reason]];
2264
+ actions2 = continueButton;
2265
+ }
2266
+ break;
2267
+ case "bot-check":
2268
+ status = S.botCheck;
2269
+ actions2 = stopButton;
2270
+ break;
2271
+ case "creating":
2272
+ status = S.connecting;
2273
+ actions2 = stopButton;
2274
+ break;
2275
+ case "pending":
2276
+ case "live":
2277
+ status = phase.name === "live" ? S.speaking : S.connecting;
2278
+ top2 = badge;
2279
+ media2 = liveMedia(phase.name === "live");
2280
+ body2 = liveBody(phase.session);
2281
+ actions2 = liveActions(readInChatButton(false));
2282
+ break;
2283
+ case "ended":
2284
+ status = S[phase.how];
2285
+ outcome2 = true;
2286
+ actions2 = readInChatButton(true);
2287
+ newChatOffer = true;
2288
+ break;
2289
+ }
2290
+ }
2291
+ const reason = inFlight(conversation) ? S.askBusy : conversation?.canSend ? null : S.askUnavailable;
2292
+ const chips = box !== null && shown.kind === "empty" && prompts.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1", children: [
2293
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs font-medium text-muted-foreground", children: tryAsking }),
2294
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex max-h-28 flex-wrap gap-2 overflow-y-auto", children: prompts.map((prompt) => /* @__PURE__ */ jsxRuntime.jsx(
2295
+ "button",
2296
+ {
2297
+ type: "button",
2298
+ "data-boff-explore": "avatar-live-chip",
2299
+ "aria-disabled": reason !== null ? "true" : void 0,
2300
+ className: "min-h-11 rounded-full border border-border bg-background px-3 py-2 text-start text-sm text-foreground transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring aria-disabled:cursor-not-allowed aria-disabled:opacity-50 motion-reduce:transition-none",
2301
+ onClick: () => {
2302
+ if (reason === null) ask(prompt);
2303
+ },
2304
+ children: prompt
2305
+ },
2306
+ prompt
2307
+ )) })
2308
+ ] }) : null;
2309
+ const foot = box === null && !newChatOffer ? null : /* @__PURE__ */ jsxRuntime.jsxs(
2310
+ "div",
2311
+ {
2312
+ "data-boff-explore": "avatar-live-foot",
2313
+ className: "flex shrink-0 flex-col gap-2 border-t border-border bg-background p-3 pb-[max(0.75rem,env(safe-area-inset-bottom))]",
2314
+ children: [
2315
+ newChatOffer ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-1 text-center", children: [
2316
+ /* @__PURE__ */ jsxRuntime.jsx(
2317
+ "button",
2318
+ {
2319
+ type: "button",
2320
+ "data-avatar-primary": "",
2321
+ "data-boff-explore": "avatar-live-new-chat-avatar",
2322
+ className: chunkC6OJIHNO_js.cn(primaryButton, "min-h-11"),
2323
+ onClick: newChatForAvatar,
2324
+ children: S.newChatForAvatar
2325
+ }
2326
+ ),
2327
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: S.newChatNote })
2328
+ ] }) : null,
2329
+ chips,
2330
+ box !== null && usedToday ? /* @__PURE__ */ jsxRuntime.jsx(
2331
+ "p",
2332
+ {
2333
+ "data-boff-explore": "avatar-live-used-today",
2334
+ className: "text-xs text-muted-foreground",
2335
+ children: S.usedToday
2336
+ }
2337
+ ) : null,
2338
+ box === null ? null : /* @__PURE__ */ jsxRuntime.jsx(
2339
+ AskBox,
2340
+ {
2341
+ value: draft,
2342
+ maxLength: askMaxLength,
2343
+ onChange: setDraft,
2344
+ onAsk: ask,
2345
+ reason,
2346
+ label: S.askLabel,
2347
+ placeholder: S.askPlaceholder,
2348
+ send,
2349
+ footer: S.askFooter,
2350
+ noFiles: S.askNoFiles,
2351
+ hint: box === "spoken" ? S.needsAnswerAny : null,
2352
+ touchFirst
2353
+ }
2354
+ )
2355
+ ]
2356
+ }
2357
+ );
2358
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2359
+ "div",
2360
+ {
2361
+ ref: rootRef,
2362
+ "data-boff-explore": "avatar-live",
2363
+ "data-phase": phase.name,
2364
+ "data-ask": askState,
2365
+ className: "absolute inset-0 flex flex-col bg-background",
2366
+ children: [
2367
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-h-0 flex-1 flex-col items-center gap-4 overflow-y-auto p-6 text-center", children: [
2368
+ top2,
2369
+ media2,
2370
+ lead,
2371
+ /* @__PURE__ */ jsxRuntime.jsx(
2372
+ "p",
2373
+ {
2374
+ role: "status",
2375
+ "data-boff-explore": "avatar-live-status",
2376
+ className: outcome2 ? "text-base font-semibold" : "text-sm text-muted-foreground",
2377
+ children: status
2378
+ }
2379
+ ),
2380
+ body2,
2381
+ /* @__PURE__ */ jsxRuntime.jsx("div", { ref: botBoxRef, "data-boff-explore": "avatar-live-bot-check" }),
2382
+ actions2
2383
+ ] }),
2384
+ foot,
2385
+ /* @__PURE__ */ jsxRuntime.jsx("audio", { ref: audioRef, "data-boff-explore": "avatar-live-audio" })
2386
+ ]
2387
+ }
2388
+ );
2389
+ }
1337
2390
  const headline = {
1338
2391
  idle: "",
1339
2392
  checking: S.checking,
1340
2393
  inert: "",
1341
- "needs-answer": startOver ? S.startNewChat : S.needsAnswer,
2394
+ // A question asked and its answer on its way: the answer is coming (the avatar is offered once it completes).
2395
+ "needs-answer": startOver ? S.startNewChat : shown.kind === "asking" ? S.gettingAnswer : S.needsAnswer,
1342
2396
  consent: "",
2397
+ declined: S.declined,
2398
+ waiting: S.armed,
1343
2399
  refused: phase.name === "refused" ? S[REFUSAL_TEXT[phase.reason]] : "",
1344
2400
  "bot-check": S.botCheck,
1345
2401
  creating: S.connecting,
@@ -1357,65 +2413,11 @@ function AvatarLiveView({
1357
2413
  body = /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: startOver ? S.startNewChatDetail : S.needsAnswerDetail });
1358
2414
  actions = startOver ? startOverActions : continueButton;
1359
2415
  break;
1360
- case "consent": {
1361
- const { copy } = phase.offer;
2416
+ case "consent":
1362
2417
  media = stillPicture(true);
1363
- body = /* @__PURE__ */ jsxRuntime.jsxs(
1364
- "section",
1365
- {
1366
- "aria-labelledby": consentTitleId,
1367
- "data-boff-explore": "avatar-live-consent",
1368
- className: "w-full max-w-sm rounded-lg border border-border p-4 text-start",
1369
- children: [
1370
- /* @__PURE__ */ jsxRuntime.jsx("h2", { id: consentTitleId, className: "text-base font-semibold", children: copy.title }),
1371
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 text-sm", children: productName === null || copy.introProduct === null ? copy.intro : chunkO4GS3XPZ_js.fill(copy.introProduct, { product: productName }) }),
1372
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 text-sm text-muted-foreground", children: copy.processing }),
1373
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 text-sm text-muted-foreground", children: copy.storage }),
1374
- /* @__PURE__ */ jsxRuntime.jsxs(
1375
- "a",
1376
- {
1377
- href: PRIVACY_HREF,
1378
- target: "_blank",
1379
- rel: "noopener noreferrer",
1380
- "data-boff-explore": "avatar-live-privacy",
1381
- className: "mt-2 inline-block text-sm font-medium text-primary underline underline-offset-2 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
1382
- children: [
1383
- copy.privacyLink,
1384
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "sr-only", children: [
1385
- " ",
1386
- S.opensInNewTab
1387
- ] })
1388
- ]
1389
- }
1390
- )
1391
- ]
1392
- }
1393
- );
1394
- actions = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center justify-center gap-2", children: [
1395
- /* @__PURE__ */ jsxRuntime.jsx(
1396
- "button",
1397
- {
1398
- type: "button",
1399
- "data-avatar-primary": "",
1400
- "data-boff-explore": "avatar-live-start",
1401
- className: primaryButton,
1402
- onClick: start,
1403
- children: S.start
1404
- }
1405
- ),
1406
- /* @__PURE__ */ jsxRuntime.jsx(
1407
- "button",
1408
- {
1409
- type: "button",
1410
- "data-boff-explore": "avatar-live-not-now",
1411
- className: secondaryButton,
1412
- onClick: onContinueInChat,
1413
- children: S.notNow
1414
- }
1415
- )
1416
- ] });
2418
+ body = consentCard(phase.offer.copy);
2419
+ actions = consentActions(false);
1417
2420
  break;
1418
- }
1419
2421
  case "refused":
1420
2422
  actions = phase.reason === "not_eligible" ? startOverActions : continueButton;
1421
2423
  break;
@@ -1424,77 +2426,11 @@ function AvatarLiveView({
1424
2426
  actions = stopButton;
1425
2427
  break;
1426
2428
  case "pending":
1427
- case "live": {
1428
- const playing = phase.name === "live";
1429
- const left = Math.max(0, (phase.session.endsAt - now) / 1e3);
1430
- top = /* @__PURE__ */ jsxRuntime.jsx(
1431
- "p",
1432
- {
1433
- "data-boff-explore": "avatar-live-badge",
1434
- className: "rounded-full bg-muted px-3 py-1 text-xs font-medium text-foreground",
1435
- children: S.badge
1436
- }
1437
- );
1438
- media = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative h-48 w-48 shrink-0 overflow-hidden rounded-xl border border-border bg-muted", children: [
1439
- /* @__PURE__ */ jsxRuntime.jsx(
1440
- "video",
1441
- {
1442
- ref: videoRef,
1443
- "aria-label": S.video,
1444
- "data-boff-explore": "avatar-live-video",
1445
- playsInline: true,
1446
- autoPlay: true,
1447
- muted: true,
1448
- onPlaying,
1449
- className: chunkC6OJIHNO_js.cn(
1450
- "h-full w-full object-cover",
1451
- !playing && "opacity-0"
1452
- )
1453
- }
1454
- ),
1455
- playing ? null : /* @__PURE__ */ jsxRuntime.jsx(
1456
- "img",
1457
- {
1458
- src: still.src,
1459
- alt: "",
1460
- decoding: "async",
1461
- className: "absolute inset-0 h-full w-full object-cover"
1462
- }
1463
- ),
1464
- /* @__PURE__ */ jsxRuntime.jsx("audio", { ref: audioRef, "data-boff-explore": "avatar-live-audio" })
1465
- ] });
1466
- body = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1467
- /* @__PURE__ */ jsxRuntime.jsx(
1468
- "section",
1469
- {
1470
- "aria-label": S.captions,
1471
- "data-boff-explore": "avatar-live-captions",
1472
- lang: phase.session.captions.locale || void 0,
1473
- dir: "auto",
1474
- tabIndex: 0,
1475
- className: "max-h-32 w-full max-w-sm overflow-y-auto rounded-lg bg-muted p-3 text-start text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
1476
- children: phase.session.captions.text
1477
- }
1478
- ),
1479
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: S.answerInChat }),
1480
- /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-sm tabular-nums text-muted-foreground", children: [
1481
- S.timeLeft,
1482
- " ",
1483
- /* @__PURE__ */ jsxRuntime.jsx("span", { role: "timer", "data-boff-explore": "avatar-live-countdown", children: clock(left) })
1484
- ] })
1485
- ] });
1486
- actions = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center justify-center gap-2", children: [
1487
- blocked ? /* @__PURE__ */ jsxRuntime.jsx(
1488
- "button",
1489
- {
1490
- type: "button",
1491
- "data-boff-explore": "avatar-live-sound",
1492
- className: primaryButton,
1493
- onClick: enablePlayback,
1494
- children: S.tapForSound
1495
- }
1496
- ) : null,
1497
- stopButton,
2429
+ case "live":
2430
+ top = badge;
2431
+ media = liveMedia(phase.name === "live");
2432
+ body = liveBody(phase.session);
2433
+ actions = liveActions(
1498
2434
  /* @__PURE__ */ jsxRuntime.jsx(
1499
2435
  "button",
1500
2436
  {
@@ -1505,9 +2441,8 @@ function AvatarLiveView({
1505
2441
  children: continueInChat
1506
2442
  }
1507
2443
  )
1508
- ] });
2444
+ );
1509
2445
  break;
1510
- }
1511
2446
  case "ended":
1512
2447
  body = /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: S.answerInChat });
1513
2448
  actions = /* @__PURE__ */ jsxRuntime.jsx(
@@ -1549,6 +2484,119 @@ function AvatarLiveView({
1549
2484
  }
1550
2485
  );
1551
2486
  }
2487
+ function AskBox({
2488
+ value,
2489
+ maxLength,
2490
+ onChange,
2491
+ onAsk,
2492
+ reason,
2493
+ label,
2494
+ placeholder,
2495
+ send,
2496
+ footer,
2497
+ noFiles,
2498
+ hint,
2499
+ touchFirst
2500
+ }) {
2501
+ const uid = react.useId();
2502
+ const reasonId = `${uid}-reason`;
2503
+ const hintId = `${uid}-hint`;
2504
+ const footerId = `${uid}-footer`;
2505
+ const [refusedFiles, setRefusedFiles] = react.useState(false);
2506
+ const empty = value.trim() === "";
2507
+ const submit = () => {
2508
+ if (reason !== null || empty) return;
2509
+ onAsk(value);
2510
+ };
2511
+ const onKeyDown = (event) => {
2512
+ if (event.nativeEvent.isComposing || event.keyCode === 229) {
2513
+ if (event.key === "Escape") event.stopPropagation();
2514
+ return;
2515
+ }
2516
+ if (event.key === "Enter" && !event.shiftKey) {
2517
+ event.preventDefault();
2518
+ submit();
2519
+ }
2520
+ };
2521
+ const onPaste = (event) => {
2522
+ if (event.clipboardData.files.length === 0) return;
2523
+ event.preventDefault();
2524
+ setRefusedFiles(true);
2525
+ };
2526
+ const onDrop = (event) => {
2527
+ if (!Array.from(event.dataTransfer.types).includes("Files")) return;
2528
+ event.preventDefault();
2529
+ setRefusedFiles(true);
2530
+ };
2531
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2532
+ "form",
2533
+ {
2534
+ "data-boff-explore": "avatar-live-ask",
2535
+ className: "flex w-full flex-col gap-1",
2536
+ onSubmit: (event) => {
2537
+ event.preventDefault();
2538
+ submit();
2539
+ },
2540
+ children: [
2541
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-end gap-2", children: [
2542
+ /* @__PURE__ */ jsxRuntime.jsx(
2543
+ "textarea",
2544
+ {
2545
+ value,
2546
+ rows: 1,
2547
+ maxLength,
2548
+ "aria-label": label,
2549
+ "aria-describedby": hint === null ? footerId : `${hintId} ${footerId}`,
2550
+ placeholder,
2551
+ dir: "auto",
2552
+ "data-avatar-primary": touchFirst ? void 0 : "",
2553
+ "data-boff-explore": "avatar-live-ask-input",
2554
+ className: "max-h-32 min-h-11 flex-1 resize-none rounded-md border border-border bg-background px-3 py-2.5 text-base text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring sm:text-sm",
2555
+ onChange: (event) => {
2556
+ setRefusedFiles(false);
2557
+ onChange(event.target.value);
2558
+ },
2559
+ onKeyDown,
2560
+ onPaste,
2561
+ onDrop
2562
+ }
2563
+ ),
2564
+ /* @__PURE__ */ jsxRuntime.jsx(
2565
+ "button",
2566
+ {
2567
+ type: "submit",
2568
+ "aria-disabled": reason !== null || empty ? "true" : void 0,
2569
+ "aria-describedby": reason !== null ? reasonId : void 0,
2570
+ "data-avatar-primary": touchFirst ? "" : void 0,
2571
+ "data-boff-explore": "avatar-live-ask-send",
2572
+ className: "inline-flex h-11 min-w-11 shrink-0 items-center justify-center rounded-md bg-primary px-4 text-sm font-medium text-primary-foreground transition-opacity hover:opacity-90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background aria-disabled:cursor-not-allowed aria-disabled:opacity-50 motion-reduce:transition-none",
2573
+ children: send
2574
+ }
2575
+ )
2576
+ ] }),
2577
+ reason === null ? null : /* @__PURE__ */ jsxRuntime.jsx(
2578
+ "p",
2579
+ {
2580
+ id: reasonId,
2581
+ "data-boff-explore": "avatar-live-ask-reason",
2582
+ className: "text-xs text-muted-foreground",
2583
+ children: reason
2584
+ }
2585
+ ),
2586
+ refusedFiles ? /* @__PURE__ */ jsxRuntime.jsx(
2587
+ "p",
2588
+ {
2589
+ "data-boff-explore": "avatar-live-ask-files",
2590
+ className: "text-xs text-muted-foreground",
2591
+ children: noFiles
2592
+ }
2593
+ ) : null,
2594
+ hint === null ? null : /* @__PURE__ */ jsxRuntime.jsx("p", { id: hintId, className: "sr-only", children: hint }),
2595
+ /* @__PURE__ */ jsxRuntime.jsx("p", { id: footerId, className: "text-xs text-muted-foreground", children: footer })
2596
+ ]
2597
+ }
2598
+ );
2599
+ }
1552
2600
 
1553
2601
  exports.AvatarLiveView = AvatarLiveView;
1554
2602
  //# sourceMappingURL=index.js.map