@burdenoff/website-sdk 2026.922.4 → 2026.923.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -2438,16 +2438,16 @@ function useRateLimit(maxAttempts, windowMinutes) {
2438
2438
  }
2439
2439
  }, [maxAttempts]);
2440
2440
  function recordAttempt() {
2441
- const now = Date.now();
2441
+ const now2 = Date.now();
2442
2442
  const state = rateLimitRef.current;
2443
- if (state && now > state.resetTime) {
2443
+ if (state && now2 > state.resetTime) {
2444
2444
  rateLimitRef.current = null;
2445
2445
  }
2446
2446
  const current = rateLimitRef.current;
2447
2447
  if (!current) {
2448
2448
  rateLimitRef.current = {
2449
2449
  attempts: 1,
2450
- resetTime: now + windowMinutes * 60 * 1e3
2450
+ resetTime: now2 + windowMinutes * 60 * 1e3
2451
2451
  };
2452
2452
  return false;
2453
2453
  }
@@ -3542,16 +3542,16 @@ function useRateLimit2(maxAttempts, windowMinutes) {
3542
3542
  const [isLimited, setIsLimited] = React.useState(false);
3543
3543
  const [resetTime, setResetTime] = React.useState(null);
3544
3544
  function recordAttempt() {
3545
- const now = Date.now();
3545
+ const now2 = Date.now();
3546
3546
  const state = rateLimitRef.current;
3547
- if (state && now > state.resetTime) {
3547
+ if (state && now2 > state.resetTime) {
3548
3548
  rateLimitRef.current = null;
3549
3549
  }
3550
3550
  const current = rateLimitRef.current;
3551
3551
  if (!current) {
3552
3552
  rateLimitRef.current = {
3553
3553
  attempts: 1,
3554
- resetTime: now + windowMinutes * 60 * 1e3
3554
+ resetTime: now2 + windowMinutes * 60 * 1e3
3555
3555
  };
3556
3556
  return false;
3557
3557
  }
@@ -4585,8 +4585,8 @@ function LaunchCountdown({
4585
4585
  launchedMessage = "We have launched!",
4586
4586
  className
4587
4587
  }) {
4588
- const [now, setNow] = React.useState(() => Date.now());
4589
- const remainingMs = launchDate - now;
4588
+ const [now2, setNow] = React.useState(() => Date.now());
4589
+ const remainingMs = launchDate - now2;
4590
4590
  const hasLaunched = remainingMs <= 0;
4591
4591
  React.useEffect(() => {
4592
4592
  if (hasLaunched) return;
@@ -5959,7 +5959,7 @@ var EN = {
5959
5959
  showLess: "Show less",
5960
5960
  sources: "Sources",
5961
5961
  nextYouCouldAsk: "Next you could ask",
5962
- placeholder: "Describe the problem you're facing\u2026",
5962
+ placeholder: "Describe the problem\u2026",
5963
5963
  placeholderProduct: "Describe a problem, or ask about {product}\u2026",
5964
5964
  send: "Send",
5965
5965
  stop: "Stop",
@@ -6000,6 +6000,20 @@ var EN = {
6000
6000
  feedbackDismiss: "Dismiss",
6001
6001
  feedbackThanks: "Thanks \u2014 that helps.",
6002
6002
  feedbackNotSent: "That didn't send.",
6003
+ escalateOpen: "Talk to a person",
6004
+ escalateTitle: "Send this conversation to a person",
6005
+ escalateBody: "We'll pass the whole conversation on, so you don't have to type any of it again.",
6006
+ escalateEmailLabel: "Your email address",
6007
+ escalateEmailPlaceholder: "you@example.com",
6008
+ escalateNoteLabel: "Anything else a person should know? (optional)",
6009
+ escalateSubmit: "Send to a person",
6010
+ escalateSending: "Sending\u2026",
6011
+ escalateCancel: "Cancel",
6012
+ escalateInvalidEmail: "That doesn't look like an address we can reply to. Please check it.",
6013
+ escalateSent: "A person now has this conversation. We'll reply to {email}.",
6014
+ escalateRateLimited: "That's a lot of requests in a short time. Please try again in a few minutes.",
6015
+ escalateCaptcha: "We couldn't verify that you're human. Please try that again.",
6016
+ escalateFailed: "We couldn't pass that on just now. Please try again.",
6003
6017
  prevSuggestion: "Previous suggestion",
6004
6018
  nextSuggestion: "Next suggestion",
6005
6019
  conceptIllustration: "Concept illustration",
@@ -6010,6 +6024,9 @@ var EN = {
6010
6024
  conceptAskQuestion: "How does {title} work in {product}?",
6011
6025
  copyAnswer: "Copy answer",
6012
6026
  copyFailed: "Couldn't copy",
6027
+ readAloud: "Read aloud",
6028
+ stopReading: "Stop reading",
6029
+ answerTable: "Table",
6013
6030
  groundedIn: "What this answer is based on",
6014
6031
  sourceCountOne: "1 source",
6015
6032
  sourceCountMany: "{count} sources",
@@ -6044,7 +6061,7 @@ var ZH = {
6044
6061
  showLess: "\u6536\u8D77",
6045
6062
  sources: "\u6765\u6E90",
6046
6063
  nextYouCouldAsk: "\u4F60\u8FD8\u53EF\u4EE5\u95EE",
6047
- placeholder: "\u63CF\u8FF0\u4F60\u9047\u5230\u7684\u95EE\u9898\u2026",
6064
+ placeholder: "\u63CF\u8FF0\u4F60\u7684\u95EE\u9898\u2026",
6048
6065
  placeholderProduct: "\u63CF\u8FF0\u95EE\u9898\uFF0C\u6216\u8BE2\u95EE {product}\u2026",
6049
6066
  send: "\u53D1\u9001",
6050
6067
  stop: "\u505C\u6B62",
@@ -6082,6 +6099,20 @@ var ZH = {
6082
6099
  feedbackDismiss: "\u5173\u95ED",
6083
6100
  feedbackThanks: "\u8C22\u8C22\uFF0C\u8FD9\u5BF9\u6211\u4EEC\u5F88\u6709\u5E2E\u52A9\u3002",
6084
6101
  feedbackNotSent: "\u6CA1\u6709\u63D0\u4EA4\u6210\u529F\u3002",
6102
+ escalateOpen: "\u8054\u7CFB\u771F\u4EBA",
6103
+ escalateTitle: "\u628A\u8FD9\u6BB5\u5BF9\u8BDD\u8F6C\u7ED9\u771F\u4EBA",
6104
+ escalateBody: "\u6211\u4EEC\u4F1A\u628A\u6574\u6BB5\u5BF9\u8BDD\u4E00\u8D77\u8F6C\u8FC7\u53BB\uFF0C\u60A8\u4E0D\u7528\u518D\u91CD\u65B0\u6253\u4E00\u904D\u3002",
6105
+ escalateEmailLabel: "\u60A8\u7684\u90AE\u7BB1\u5730\u5740",
6106
+ escalateEmailPlaceholder: "you@example.com",
6107
+ escalateNoteLabel: "\u8FD8\u6709\u4EC0\u4E48\u9700\u8981\u544A\u8BC9\u6211\u4EEC\u7684\u5417\uFF1F\uFF08\u9009\u586B\uFF09",
6108
+ escalateSubmit: "\u8F6C\u7ED9\u771F\u4EBA",
6109
+ escalateSending: "\u6B63\u5728\u53D1\u9001\u2026",
6110
+ escalateCancel: "\u53D6\u6D88",
6111
+ escalateInvalidEmail: "\u8FD9\u4F3C\u4E4E\u4E0D\u662F\u4E00\u4E2A\u6211\u4EEC\u53EF\u4EE5\u56DE\u590D\u7684\u90AE\u7BB1\u5730\u5740\uFF0C\u8BF7\u68C0\u67E5\u4E00\u4E0B\u3002",
6112
+ escalateSent: "\u5DF2\u6709\u540C\u4E8B\u63A5\u624B\u8FD9\u6BB5\u5BF9\u8BDD\uFF0C\u6211\u4EEC\u4F1A\u56DE\u590D\u5230 {email}\u3002",
6113
+ escalateRateLimited: "\u77ED\u65F6\u95F4\u5185\u8BF7\u6C42\u8FC7\u591A\uFF0C\u8BF7\u51E0\u5206\u949F\u540E\u518D\u8BD5\u3002",
6114
+ escalateCaptcha: "\u6211\u4EEC\u65E0\u6CD5\u9A8C\u8BC1\u60A8\u662F\u771F\u4EBA\uFF0C\u8BF7\u518D\u8BD5\u4E00\u6B21\u3002",
6115
+ escalateFailed: "\u6682\u65F6\u65E0\u6CD5\u8F6C\u4EA4\uFF0C\u8BF7\u518D\u8BD5\u4E00\u6B21\u3002",
6085
6116
  prevSuggestion: "\u4E0A\u4E00\u4E2A\u5EFA\u8BAE",
6086
6117
  nextSuggestion: "\u4E0B\u4E00\u4E2A\u5EFA\u8BAE",
6087
6118
  conceptIllustration: "\u6982\u5FF5\u793A\u610F\u56FE",
@@ -6092,6 +6123,9 @@ var ZH = {
6092
6123
  conceptAskQuestion: "{product} \u7684 {title} \u662F\u600E\u4E48\u8FD0\u4F5C\u7684\uFF1F",
6093
6124
  copyAnswer: "\u590D\u5236\u56DE\u7B54",
6094
6125
  copyFailed: "\u590D\u5236\u5931\u8D25",
6126
+ readAloud: "\u6717\u8BFB",
6127
+ stopReading: "\u505C\u6B62\u6717\u8BFB",
6128
+ answerTable: "\u8868\u683C",
6095
6129
  groundedIn: "\u8FD9\u4E2A\u56DE\u7B54\u7684\u4F9D\u636E",
6096
6130
  sourceCountOne: "1 \u4E2A\u6765\u6E90",
6097
6131
  sourceCountMany: "{count} \u4E2A\u6765\u6E90",
@@ -6122,7 +6156,7 @@ var HI = {
6122
6156
  showLess: "\u0915\u092E \u0926\u093F\u0916\u093E\u090F\u0901",
6123
6157
  sources: "\u0938\u094D\u0930\u094B\u0924",
6124
6158
  nextYouCouldAsk: "\u0906\u0917\u0947 \u0906\u092A \u092A\u0942\u091B \u0938\u0915\u0924\u0947 \u0939\u0948\u0902",
6125
- placeholder: "\u0905\u092A\u0928\u0940 \u0938\u092E\u0938\u094D\u092F\u093E \u092F\u0939\u093E\u0901 \u092C\u0924\u093E\u090F\u0902\u2026",
6159
+ placeholder: "\u0905\u092A\u0928\u0940 \u0938\u092E\u0938\u094D\u092F\u093E \u092C\u0924\u093E\u090F\u0902\u2026",
6126
6160
  placeholderProduct: "\u0938\u092E\u0938\u094D\u092F\u093E \u092C\u0924\u093E\u090F\u0902, \u092F\u093E {product} \u0915\u0947 \u092C\u093E\u0930\u0947 \u092E\u0947\u0902 \u092A\u0942\u091B\u0947\u0902\u2026",
6127
6161
  send: "\u092D\u0947\u091C\u0947\u0902",
6128
6162
  stop: "\u0930\u094B\u0915\u0947\u0902",
@@ -6160,6 +6194,20 @@ var HI = {
6160
6194
  feedbackDismiss: "\u092C\u0902\u0926 \u0915\u0930\u0947\u0902",
6161
6195
  feedbackThanks: "\u0927\u0928\u094D\u092F\u0935\u093E\u0926, \u0907\u0938\u0938\u0947 \u092E\u0926\u0926 \u092E\u093F\u0932\u0924\u0940 \u0939\u0948\u0964",
6162
6196
  feedbackNotSent: "\u092F\u0939 \u092D\u0947\u091C\u093E \u0928\u0939\u0940\u0902 \u091C\u093E \u0938\u0915\u093E\u0964",
6197
+ escalateOpen: "\u0915\u093F\u0938\u0940 \u0935\u094D\u092F\u0915\u094D\u0924\u093F \u0938\u0947 \u092C\u093E\u0924 \u0915\u0930\u0947\u0902",
6198
+ escalateTitle: "\u092F\u0939 \u092C\u093E\u0924\u091A\u0940\u0924 \u0915\u093F\u0938\u0940 \u0935\u094D\u092F\u0915\u094D\u0924\u093F \u0915\u094B \u092D\u0947\u091C\u0947\u0902",
6199
+ escalateBody: "\u0939\u092E \u092A\u0942\u0930\u0940 \u092C\u093E\u0924\u091A\u0940\u0924 \u0906\u0917\u0947 \u092D\u0947\u091C \u0926\u0947\u0902\u0917\u0947, \u0924\u093E\u0915\u093F \u0906\u092A\u0915\u094B \u0926\u094B\u092C\u093E\u0930\u093E \u0915\u0941\u091B \u0932\u093F\u0916\u0928\u093E \u0928 \u092A\u0921\u093C\u0947\u0964",
6200
+ escalateEmailLabel: "\u0906\u092A\u0915\u093E \u0908\u092E\u0947\u0932 \u092A\u0924\u093E",
6201
+ escalateEmailPlaceholder: "you@example.com",
6202
+ escalateNoteLabel: "\u0915\u094D\u092F\u093E \u0915\u0941\u091B \u0914\u0930 \u092C\u0924\u093E\u0928\u093E \u091A\u093E\u0939\u0947\u0902\u0917\u0947? (\u0935\u0948\u0915\u0932\u094D\u092A\u093F\u0915)",
6203
+ escalateSubmit: "\u0915\u093F\u0938\u0940 \u0935\u094D\u092F\u0915\u094D\u0924\u093F \u0915\u094B \u092D\u0947\u091C\u0947\u0902",
6204
+ escalateSending: "\u092D\u0947\u091C\u093E \u091C\u093E \u0930\u0939\u093E \u0939\u0948\u2026",
6205
+ escalateCancel: "\u0930\u0926\u094D\u0926 \u0915\u0930\u0947\u0902",
6206
+ escalateInvalidEmail: "\u092F\u0939 \u0910\u0938\u093E \u0908\u092E\u0947\u0932 \u092A\u0924\u093E \u0928\u0939\u0940\u0902 \u0932\u0917\u0924\u093E \u091C\u093F\u0938 \u092A\u0930 \u0939\u092E \u091C\u0935\u093E\u092C \u092D\u0947\u091C \u0938\u0915\u0947\u0902\u0964 \u0915\u0943\u092A\u092F\u093E \u091C\u093E\u0901\u091A \u0932\u0947\u0902\u0964",
6207
+ escalateSent: "\u0905\u092C \u092F\u0939 \u092C\u093E\u0924\u091A\u0940\u0924 \u090F\u0915 \u0935\u094D\u092F\u0915\u094D\u0924\u093F \u0915\u0947 \u092A\u093E\u0938 \u0939\u0948\u0964 \u0939\u092E {email} \u092A\u0930 \u091C\u0935\u093E\u092C \u0926\u0947\u0902\u0917\u0947\u0964",
6208
+ escalateRateLimited: "\u0925\u094B\u0921\u093C\u0947 \u0938\u092E\u092F \u092E\u0947\u0902 \u092C\u0939\u0941\u0924 \u0938\u093E\u0930\u0947 \u0905\u0928\u0941\u0930\u094B\u0927 \u0939\u094B \u0917\u090F\u0964 \u0915\u0943\u092A\u092F\u093E \u0915\u0941\u091B \u092E\u093F\u0928\u091F \u092C\u093E\u0926 \u0915\u094B\u0936\u093F\u0936 \u0915\u0930\u0947\u0902\u0964",
6209
+ escalateCaptcha: "\u0939\u092E \u092F\u0939 \u0938\u0924\u094D\u092F\u093E\u092A\u093F\u0924 \u0928\u0939\u0940\u0902 \u0915\u0930 \u0938\u0915\u0947 \u0915\u093F \u0906\u092A \u090F\u0915 \u0935\u094D\u092F\u0915\u094D\u0924\u093F \u0939\u0948\u0902\u0964 \u0915\u0943\u092A\u092F\u093E \u092B\u093F\u0930 \u0915\u094B\u0936\u093F\u0936 \u0915\u0930\u0947\u0902\u0964",
6210
+ escalateFailed: "\u0905\u092D\u0940 \u0907\u0938\u0947 \u0906\u0917\u0947 \u0928\u0939\u0940\u0902 \u092D\u0947\u091C\u093E \u091C\u093E \u0938\u0915\u093E\u0964 \u0915\u0943\u092A\u092F\u093E \u092B\u093F\u0930 \u0915\u094B\u0936\u093F\u0936 \u0915\u0930\u0947\u0902\u0964",
6163
6211
  prevSuggestion: "\u092A\u093F\u091B\u0932\u093E \u0938\u0941\u091D\u093E\u0935",
6164
6212
  nextSuggestion: "\u0905\u0917\u0932\u093E \u0938\u0941\u091D\u093E\u0935",
6165
6213
  conceptIllustration: "\u0905\u0935\u0927\u093E\u0930\u0923\u093E \u091A\u093F\u0924\u094D\u0930\u0923",
@@ -6170,6 +6218,9 @@ var HI = {
6170
6218
  conceptAskQuestion: "{product} \u092E\u0947\u0902 {title} \u0915\u0948\u0938\u0947 \u0915\u093E\u092E \u0915\u0930\u0924\u093E \u0939\u0948?",
6171
6219
  copyAnswer: "\u0909\u0924\u094D\u0924\u0930 \u0915\u0949\u092A\u0940 \u0915\u0930\u0947\u0902",
6172
6220
  copyFailed: "\u0915\u0949\u092A\u0940 \u0928\u0939\u0940\u0902 \u0939\u094B \u0938\u0915\u093E",
6221
+ readAloud: "\u091C\u093C\u094B\u0930 \u0938\u0947 \u092A\u0922\u093C\u0947\u0902",
6222
+ stopReading: "\u092A\u0922\u093C\u0928\u093E \u092C\u0902\u0926 \u0915\u0930\u0947\u0902",
6223
+ answerTable: "\u0924\u093E\u0932\u093F\u0915\u093E",
6173
6224
  groundedIn: "\u092F\u0939 \u0909\u0924\u094D\u0924\u0930 \u0915\u093F\u0938 \u092A\u0930 \u0906\u0927\u093E\u0930\u093F\u0924 \u0939\u0948",
6174
6225
  sourceCountOne: "1 \u0938\u094D\u0930\u094B\u0924",
6175
6226
  sourceCountMany: "{count} \u0938\u094D\u0930\u094B\u0924",
@@ -6204,7 +6255,7 @@ var ES = {
6204
6255
  showLess: "Ver menos",
6205
6256
  sources: "Fuentes",
6206
6257
  nextYouCouldAsk: "Tambi\xE9n puedes preguntar",
6207
- placeholder: "Describe el problema que tienes\u2026",
6258
+ placeholder: "Describe el problema\u2026",
6208
6259
  placeholderProduct: "Describe un problema o pregunta por {product}\u2026",
6209
6260
  send: "Enviar",
6210
6261
  stop: "Detener",
@@ -6242,6 +6293,20 @@ var ES = {
6242
6293
  feedbackDismiss: "Cerrar",
6243
6294
  feedbackThanks: "Gracias, nos sirve.",
6244
6295
  feedbackNotSent: "No se ha podido enviar.",
6296
+ escalateOpen: "Hablar con una persona",
6297
+ escalateTitle: "Env\xEDa esta conversaci\xF3n a una persona",
6298
+ escalateBody: "Le pasaremos la conversaci\xF3n entera, as\xED no tienes que volver a escribirla.",
6299
+ escalateEmailLabel: "Tu direcci\xF3n de correo",
6300
+ escalateEmailPlaceholder: "tu@ejemplo.com",
6301
+ escalateNoteLabel: "\xBFAlgo m\xE1s que deber\xEDamos saber? (opcional)",
6302
+ escalateSubmit: "Enviar a una persona",
6303
+ escalateSending: "Enviando\u2026",
6304
+ escalateCancel: "Cancelar",
6305
+ escalateInvalidEmail: "No parece una direcci\xF3n a la que podamos responder. Rev\xEDsala, por favor.",
6306
+ escalateSent: "Una persona ya tiene esta conversaci\xF3n. Te responderemos a {email}.",
6307
+ escalateRateLimited: "Han sido muchas peticiones en poco tiempo. Int\xE9ntalo de nuevo en unos minutos.",
6308
+ escalateCaptcha: "No hemos podido verificar que eres una persona. Int\xE9ntalo de nuevo.",
6309
+ escalateFailed: "No hemos podido pasarlo ahora mismo. Int\xE9ntalo de nuevo.",
6245
6310
  prevSuggestion: "Sugerencia anterior",
6246
6311
  nextSuggestion: "Sugerencia siguiente",
6247
6312
  conceptIllustration: "Ilustraci\xF3n del concepto",
@@ -6252,6 +6317,9 @@ var ES = {
6252
6317
  conceptAskQuestion: "\xBFC\xF3mo funciona {title} en {product}?",
6253
6318
  copyAnswer: "Copiar respuesta",
6254
6319
  copyFailed: "No se pudo copiar",
6320
+ readAloud: "Leer en voz alta",
6321
+ stopReading: "Dejar de leer",
6322
+ answerTable: "Tabla",
6255
6323
  groundedIn: "En qu\xE9 se basa esta respuesta",
6256
6324
  sourceCountOne: "1 fuente",
6257
6325
  sourceCountMany: "{count} fuentes",
@@ -6286,7 +6354,7 @@ var AR = {
6286
6354
  showLess: "\u0639\u0631\u0636 \u0623\u0642\u0644",
6287
6355
  sources: "\u0627\u0644\u0645\u0635\u0627\u062F\u0631",
6288
6356
  nextYouCouldAsk: "\u064A\u0645\u0643\u0646\u0643 \u0623\u0646 \u062A\u0633\u0623\u0644 \u0628\u0639\u062F \u0630\u0644\u0643",
6289
- placeholder: "\u0635\u0641 \u0627\u0644\u0645\u0634\u0643\u0644\u0629 \u0627\u0644\u062A\u064A \u062A\u0648\u0627\u062C\u0647\u0647\u0627\u2026",
6357
+ placeholder: "\u0635\u0641 \u0627\u0644\u0645\u0634\u0643\u0644\u0629\u2026",
6290
6358
  placeholderProduct: "\u0635\u0641 \u0645\u0634\u0643\u0644\u062A\u0643 \u0623\u0648 \u0627\u0633\u0623\u0644 \u0639\u0646 {product}\u2026",
6291
6359
  send: "\u0625\u0631\u0633\u0627\u0644",
6292
6360
  stop: "\u0625\u064A\u0642\u0627\u0641",
@@ -6324,6 +6392,20 @@ var AR = {
6324
6392
  feedbackDismiss: "\u0625\u063A\u0644\u0627\u0642",
6325
6393
  feedbackThanks: "\u0634\u0643\u0631\u064B\u0627\u060C \u0647\u0630\u0627 \u064A\u0633\u0627\u0639\u062F\u0646\u0627.",
6326
6394
  feedbackNotSent: "\u0644\u0645 \u064A\u062A\u0645 \u0627\u0644\u0625\u0631\u0633\u0627\u0644.",
6395
+ escalateOpen: "\u062A\u0648\u0627\u0635\u0644 \u0645\u0639 \u0634\u062E\u0635",
6396
+ escalateTitle: "\u0623\u0631\u0633\u0644 \u0647\u0630\u0647 \u0627\u0644\u0645\u062D\u0627\u062F\u062B\u0629 \u0625\u0644\u0649 \u0634\u062E\u0635",
6397
+ escalateBody: "\u0633\u0646\u0645\u0631\u0651\u0631 \u0627\u0644\u0645\u062D\u0627\u062F\u062B\u0629 \u0643\u0627\u0645\u0644\u0629\u060C \u062D\u062A\u0649 \u0644\u0627 \u062A\u0636\u0637\u0631 \u0625\u0644\u0649 \u0643\u062A\u0627\u0628\u062A\u0647\u0627 \u0645\u0646 \u062C\u062F\u064A\u062F.",
6398
+ escalateEmailLabel: "\u0628\u0631\u064A\u062F\u0643 \u0627\u0644\u0625\u0644\u0643\u062A\u0631\u0648\u0646\u064A",
6399
+ escalateEmailPlaceholder: "you@example.com",
6400
+ escalateNoteLabel: "\u0647\u0644 \u0645\u0646 \u0634\u064A\u0621 \u0622\u062E\u0631 \u064A\u0646\u0628\u063A\u064A \u0623\u0646 \u0646\u0639\u0631\u0641\u0647\u061F (\u0627\u062E\u062A\u064A\u0627\u0631\u064A)",
6401
+ escalateSubmit: "\u0625\u0631\u0633\u0627\u0644 \u0625\u0644\u0649 \u0634\u062E\u0635",
6402
+ escalateSending: "\u062C\u0627\u0631\u064D \u0627\u0644\u0625\u0631\u0633\u0627\u0644\u2026",
6403
+ escalateCancel: "\u0625\u0644\u063A\u0627\u0621",
6404
+ escalateInvalidEmail: "\u0644\u0627 \u064A\u0628\u062F\u0648 \u0647\u0630\u0627 \u0639\u0646\u0648\u0627\u0646\u064B\u0627 \u064A\u0645\u0643\u0646\u0646\u0627 \u0627\u0644\u0631\u062F \u0639\u0644\u064A\u0647. \u064A\u0631\u062C\u0649 \u0627\u0644\u062A\u062D\u0642\u0642 \u0645\u0646\u0647.",
6405
+ escalateSent: "\u0623\u0635\u0628\u062D\u062A \u0647\u0630\u0647 \u0627\u0644\u0645\u062D\u0627\u062F\u062B\u0629 \u0644\u062F\u0649 \u0623\u062D\u062F \u0627\u0644\u0632\u0645\u0644\u0627\u0621. \u0633\u0646\u0631\u062F \u0639\u0644\u0649 {email}.",
6406
+ escalateRateLimited: "\u0637\u0644\u0628\u0627\u062A \u0643\u062B\u064A\u0631\u0629 \u062E\u0644\u0627\u0644 \u0648\u0642\u062A \u0642\u0635\u064A\u0631. \u064A\u0631\u062C\u0649 \u0627\u0644\u0645\u062D\u0627\u0648\u0644\u0629 \u0628\u0639\u062F \u0628\u0636\u0639 \u062F\u0642\u0627\u0626\u0642.",
6407
+ escalateCaptcha: "\u062A\u0639\u0630\u0651\u0631 \u0627\u0644\u062A\u062D\u0642\u0642 \u0645\u0646 \u0623\u0646\u0643 \u0644\u0633\u062A \u0631\u0648\u0628\u0648\u062A\u064B\u0627. \u064A\u0631\u062C\u0649 \u0627\u0644\u0645\u062D\u0627\u0648\u0644\u0629 \u0645\u0631\u0629 \u0623\u062E\u0631\u0649.",
6408
+ escalateFailed: "\u062A\u0639\u0630\u0651\u0631 \u062A\u0645\u0631\u064A\u0631 \u0627\u0644\u0645\u062D\u0627\u062F\u062B\u0629 \u0627\u0644\u0622\u0646. \u064A\u0631\u062C\u0649 \u0627\u0644\u0645\u062D\u0627\u0648\u0644\u0629 \u0645\u0631\u0629 \u0623\u062E\u0631\u0649.",
6327
6409
  prevSuggestion: "\u0627\u0644\u0627\u0642\u062A\u0631\u0627\u062D \u0627\u0644\u0633\u0627\u0628\u0642",
6328
6410
  nextSuggestion: "\u0627\u0644\u0627\u0642\u062A\u0631\u0627\u062D \u0627\u0644\u062A\u0627\u0644\u064A",
6329
6411
  conceptIllustration: "\u0631\u0633\u0645 \u062A\u0648\u0636\u064A\u062D\u064A \u0644\u0644\u0645\u0641\u0647\u0648\u0645",
@@ -6334,6 +6416,9 @@ var AR = {
6334
6416
  conceptAskQuestion: "\u0643\u064A\u0641 \u064A\u0639\u0645\u0644 {title} \u0641\u064A {product}\u061F",
6335
6417
  copyAnswer: "\u0646\u0633\u062E \u0627\u0644\u0625\u062C\u0627\u0628\u0629",
6336
6418
  copyFailed: "\u062A\u0639\u0630\u0651\u0631 \u0627\u0644\u0646\u0633\u062E",
6419
+ readAloud: "\u0627\u0642\u0631\u0623 \u0628\u0635\u0648\u062A \u0639\u0627\u0644\u064D",
6420
+ stopReading: "\u0625\u064A\u0642\u0627\u0641 \u0627\u0644\u0642\u0631\u0627\u0621\u0629",
6421
+ answerTable: "\u062C\u062F\u0648\u0644",
6337
6422
  groundedIn: "\u0639\u0644\u0649 \u0645\u0627\u0630\u0627 \u062A\u0633\u062A\u0646\u062F \u0647\u0630\u0647 \u0627\u0644\u0625\u062C\u0627\u0628\u0629",
6338
6423
  sourceCountOne: "\u0645\u0635\u062F\u0631 \u0648\u0627\u062D\u062F",
6339
6424
  sourceCountMany: "{count} \u0645\u0635\u0627\u062F\u0631",
@@ -6368,7 +6453,7 @@ var TA = {
6368
6453
  showLess: "\u0B95\u0BC1\u0BB1\u0BC8\u0BB5\u0BBE\u0B95\u0B95\u0BCD \u0B95\u0BBE\u0B9F\u0BCD\u0B9F\u0BC1",
6369
6454
  sources: "\u0BAE\u0BC2\u0BB2\u0B99\u0BCD\u0B95\u0BB3\u0BCD",
6370
6455
  nextYouCouldAsk: "\u0B85\u0B9F\u0BC1\u0BA4\u0BCD\u0BA4\u0BC1 \u0BA8\u0BC0\u0B99\u0BCD\u0B95\u0BB3\u0BCD \u0B95\u0BC7\u0B9F\u0BCD\u0B95\u0BB2\u0BBE\u0BAE\u0BCD",
6371
- placeholder: "\u0BA8\u0BC0\u0B99\u0BCD\u0B95\u0BB3\u0BCD \u0B8E\u0BA4\u0BBF\u0BB0\u0BCD\u0B95\u0BCA\u0BB3\u0BCD\u0BB3\u0BC1\u0BAE\u0BCD \u0B9A\u0BBF\u0B95\u0BCD\u0B95\u0BB2\u0BC8 \u0BB5\u0BBF\u0BB5\u0BB0\u0BBF\u0BAF\u0BC1\u0B99\u0BCD\u0B95\u0BB3\u0BCD\u2026",
6456
+ placeholder: "\u0B9A\u0BBF\u0B95\u0BCD\u0B95\u0BB2\u0BC8 \u0BB5\u0BBF\u0BB5\u0BB0\u0BBF\u0BAF\u0BC1\u0B99\u0BCD\u0B95\u0BB3\u0BCD\u2026",
6372
6457
  placeholderProduct: "\u0B9A\u0BBF\u0B95\u0BCD\u0B95\u0BB2\u0BC8 \u0BB5\u0BBF\u0BB5\u0BB0\u0BBF\u0BAF\u0BC1\u0B99\u0BCD\u0B95\u0BB3\u0BCD, \u0B85\u0BB2\u0BCD\u0BB2\u0BA4\u0BC1 {product} \u0BAA\u0BB1\u0BCD\u0BB1\u0BBF\u0B95\u0BCD \u0B95\u0BC7\u0BB3\u0BC1\u0B99\u0BCD\u0B95\u0BB3\u0BCD\u2026",
6373
6458
  send: "\u0B85\u0BA9\u0BC1\u0BAA\u0BCD\u0BAA\u0BC1",
6374
6459
  stop: "\u0BA8\u0BBF\u0BB1\u0BC1\u0BA4\u0BCD\u0BA4\u0BC1",
@@ -6406,6 +6491,20 @@ var TA = {
6406
6491
  feedbackDismiss: "\u0BAE\u0BC2\u0B9F\u0BC1",
6407
6492
  feedbackThanks: "\u0BA8\u0BA9\u0BCD\u0BB1\u0BBF, \u0B87\u0BA4\u0BC1 \u0B8E\u0B99\u0BCD\u0B95\u0BB3\u0BC1\u0B95\u0BCD\u0B95\u0BC1 \u0B89\u0BA4\u0BB5\u0BC1\u0B95\u0BBF\u0BB1\u0BA4\u0BC1.",
6408
6493
  feedbackNotSent: "\u0B85\u0BA9\u0BC1\u0BAA\u0BCD\u0BAA \u0BAE\u0BC1\u0B9F\u0BBF\u0BAF\u0BB5\u0BBF\u0BB2\u0BCD\u0BB2\u0BC8.",
6494
+ escalateOpen: "\u0B92\u0BB0\u0BC1\u0BB5\u0BB0\u0BBF\u0B9F\u0BAE\u0BCD \u0BAA\u0BC7\u0B9A\u0BC1\u0B99\u0BCD\u0B95\u0BB3\u0BCD",
6495
+ escalateTitle: "\u0B87\u0BA8\u0BCD\u0BA4 \u0B89\u0BB0\u0BC8\u0BAF\u0BBE\u0B9F\u0BB2\u0BC8 \u0B92\u0BB0\u0BC1\u0BB5\u0BB0\u0BC1\u0B95\u0BCD\u0B95\u0BC1 \u0B85\u0BA9\u0BC1\u0BAA\u0BCD\u0BAA\u0BC1\u0B99\u0BCD\u0B95\u0BB3\u0BCD",
6496
+ escalateBody: "\u0BAE\u0BC1\u0BB4\u0BC1 \u0B89\u0BB0\u0BC8\u0BAF\u0BBE\u0B9F\u0BB2\u0BC8\u0BAF\u0BC1\u0BAE\u0BCD \u0BA8\u0BBE\u0B99\u0BCD\u0B95\u0BB3\u0BCD \u0B85\u0BA9\u0BC1\u0BAA\u0BCD\u0BAA\u0BBF\u0BB5\u0BBF\u0B9F\u0BC1\u0BB5\u0BCB\u0BAE\u0BCD; \u0BA8\u0BC0\u0B99\u0BCD\u0B95\u0BB3\u0BCD \u0BAE\u0BC0\u0BA3\u0BCD\u0B9F\u0BC1\u0BAE\u0BCD \u0BA4\u0B9F\u0BCD\u0B9F\u0B9A\u0BCD\u0B9A\u0BC1 \u0B9A\u0BC6\u0BAF\u0BCD\u0BAF \u0BB5\u0BC7\u0BA3\u0BCD\u0B9F\u0BBF\u0BAF\u0BA4\u0BBF\u0BB2\u0BCD\u0BB2\u0BC8.",
6497
+ escalateEmailLabel: "\u0B89\u0B99\u0BCD\u0B95\u0BB3\u0BCD \u0BAE\u0BBF\u0BA9\u0BCD\u0BA9\u0B9E\u0BCD\u0B9A\u0BB2\u0BCD \u0BAE\u0BC1\u0B95\u0BB5\u0BB0\u0BBF",
6498
+ escalateEmailPlaceholder: "you@example.com",
6499
+ escalateNoteLabel: "\u0BB5\u0BC7\u0BB1\u0BC1 \u0B8F\u0BA4\u0BC7\u0BA9\u0BC1\u0BAE\u0BCD \u0B9A\u0BCA\u0BB2\u0BCD\u0BB2 \u0BB5\u0BBF\u0BB0\u0BC1\u0BAE\u0BCD\u0BAA\u0BC1\u0B95\u0BBF\u0BB1\u0BC0\u0BB0\u0BCD\u0B95\u0BB3\u0BBE? (\u0BB5\u0BBF\u0BB0\u0BC1\u0BAA\u0BCD\u0BAA\u0BAE\u0BCD)",
6500
+ escalateSubmit: "\u0B92\u0BB0\u0BC1\u0BB5\u0BB0\u0BC1\u0B95\u0BCD\u0B95\u0BC1 \u0B85\u0BA9\u0BC1\u0BAA\u0BCD\u0BAA\u0BC1",
6501
+ escalateSending: "\u0B85\u0BA9\u0BC1\u0BAA\u0BCD\u0BAA\u0BAA\u0BCD\u0BAA\u0B9F\u0BC1\u0B95\u0BBF\u0BB1\u0BA4\u0BC1\u2026",
6502
+ escalateCancel: "\u0BB0\u0BA4\u0BCD\u0BA4\u0BC1 \u0B9A\u0BC6\u0BAF\u0BCD",
6503
+ escalateInvalidEmail: "\u0B87\u0BA4\u0BC1 \u0BA8\u0BBE\u0B99\u0BCD\u0B95\u0BB3\u0BCD \u0BAA\u0BA4\u0BBF\u0BB2\u0BB3\u0BBF\u0B95\u0BCD\u0B95\u0B95\u0BCD\u0B95\u0BC2\u0B9F\u0BBF\u0BAF \u0BAE\u0BBF\u0BA9\u0BCD\u0BA9\u0B9E\u0BCD\u0B9A\u0BB2\u0BCD \u0BAE\u0BC1\u0B95\u0BB5\u0BB0\u0BBF \u0BAA\u0BCB\u0BB2\u0BCD \u0BA4\u0BC6\u0BB0\u0BBF\u0BAF\u0BB5\u0BBF\u0BB2\u0BCD\u0BB2\u0BC8. \u0B9A\u0BB0\u0BBF\u0BAA\u0BBE\u0BB0\u0BCD\u0B95\u0BCD\u0B95\u0BB5\u0BC1\u0BAE\u0BCD.",
6504
+ escalateSent: "\u0B87\u0BA8\u0BCD\u0BA4 \u0B89\u0BB0\u0BC8\u0BAF\u0BBE\u0B9F\u0BB2\u0BCD \u0B87\u0BAA\u0BCD\u0BAA\u0BCB\u0BA4\u0BC1 \u0B92\u0BB0\u0BC1\u0BB5\u0BB0\u0BBF\u0B9F\u0BAE\u0BCD \u0B89\u0BB3\u0BCD\u0BB3\u0BA4\u0BC1. {email} \u0BAE\u0BC1\u0B95\u0BB5\u0BB0\u0BBF\u0B95\u0BCD\u0B95\u0BC1\u0BAA\u0BCD \u0BAA\u0BA4\u0BBF\u0BB2\u0BB3\u0BBF\u0BAA\u0BCD\u0BAA\u0BCB\u0BAE\u0BCD.",
6505
+ escalateRateLimited: "\u0B95\u0BC1\u0BB1\u0BC1\u0B95\u0BBF\u0BAF \u0BA8\u0BC7\u0BB0\u0BA4\u0BCD\u0BA4\u0BBF\u0BB2\u0BCD \u0B85\u0BA4\u0BBF\u0B95 \u0B95\u0BCB\u0BB0\u0BBF\u0B95\u0BCD\u0B95\u0BC8\u0B95\u0BB3\u0BCD. \u0B9A\u0BBF\u0BB2 \u0BA8\u0BBF\u0BAE\u0BBF\u0B9F\u0B99\u0BCD\u0B95\u0BB3\u0BCD \u0B95\u0BB4\u0BBF\u0BA4\u0BCD\u0BA4\u0BC1 \u0BAE\u0BC1\u0BAF\u0BB1\u0BCD\u0B9A\u0BBF\u0B95\u0BCD\u0B95\u0BB5\u0BC1\u0BAE\u0BCD.",
6506
+ escalateCaptcha: "\u0BA8\u0BC0\u0B99\u0BCD\u0B95\u0BB3\u0BCD \u0BAE\u0BA9\u0BBF\u0BA4\u0BB0\u0BCD \u0B8E\u0BA9\u0BCD\u0BAA\u0BA4\u0BC8 \u0B89\u0BB1\u0BC1\u0BA4\u0BBF\u0B9A\u0BC6\u0BAF\u0BCD\u0BAF \u0BAE\u0BC1\u0B9F\u0BBF\u0BAF\u0BB5\u0BBF\u0BB2\u0BCD\u0BB2\u0BC8. \u0BAE\u0BC0\u0BA3\u0BCD\u0B9F\u0BC1\u0BAE\u0BCD \u0BAE\u0BC1\u0BAF\u0BB1\u0BCD\u0B9A\u0BBF\u0B95\u0BCD\u0B95\u0BB5\u0BC1\u0BAE\u0BCD.",
6507
+ escalateFailed: "\u0B87\u0BAA\u0BCD\u0BAA\u0BCB\u0BA4\u0BC1 \u0B85\u0BA9\u0BC1\u0BAA\u0BCD\u0BAA \u0BAE\u0BC1\u0B9F\u0BBF\u0BAF\u0BB5\u0BBF\u0BB2\u0BCD\u0BB2\u0BC8. \u0BAE\u0BC0\u0BA3\u0BCD\u0B9F\u0BC1\u0BAE\u0BCD \u0BAE\u0BC1\u0BAF\u0BB1\u0BCD\u0B9A\u0BBF\u0B95\u0BCD\u0B95\u0BB5\u0BC1\u0BAE\u0BCD.",
6409
6508
  prevSuggestion: "\u0BAE\u0BC1\u0BA8\u0BCD\u0BA4\u0BC8\u0BAF \u0BAA\u0BB0\u0BBF\u0BA8\u0BCD\u0BA4\u0BC1\u0BB0\u0BC8",
6410
6509
  nextSuggestion: "\u0B85\u0B9F\u0BC1\u0BA4\u0BCD\u0BA4 \u0BAA\u0BB0\u0BBF\u0BA8\u0BCD\u0BA4\u0BC1\u0BB0\u0BC8",
6411
6510
  conceptIllustration: "\u0B95\u0BB0\u0BC1\u0BA4\u0BCD\u0BA4\u0BC1 \u0BB5\u0BBF\u0BB3\u0B95\u0BCD\u0B95\u0BAA\u0BCD\u0BAA\u0B9F\u0BAE\u0BCD",
@@ -6416,6 +6515,9 @@ var TA = {
6416
6515
  conceptAskQuestion: "{product} \u0B87\u0BB2\u0BCD {title} \u0B8E\u0BAA\u0BCD\u0BAA\u0B9F\u0BBF \u0BB5\u0BC7\u0BB2\u0BC8 \u0B9A\u0BC6\u0BAF\u0BCD\u0B95\u0BBF\u0BB1\u0BA4\u0BC1?",
6417
6516
  copyAnswer: "\u0BAA\u0BA4\u0BBF\u0BB2\u0BC8 \u0BA8\u0B95\u0BB2\u0BC6\u0B9F\u0BC1",
6418
6517
  copyFailed: "\u0BA8\u0B95\u0BB2\u0BC6\u0B9F\u0BC1\u0B95\u0BCD\u0B95 \u0BAE\u0BC1\u0B9F\u0BBF\u0BAF\u0BB5\u0BBF\u0BB2\u0BCD\u0BB2\u0BC8",
6518
+ readAloud: "\u0B9A\u0BA4\u0BCD\u0BA4\u0BAE\u0BBE\u0B95\u0BAA\u0BCD \u0BAA\u0B9F\u0BBF",
6519
+ stopReading: "\u0BAA\u0B9F\u0BBF\u0BAA\u0BCD\u0BAA\u0BA4\u0BC8 \u0BA8\u0BBF\u0BB1\u0BC1\u0BA4\u0BCD\u0BA4\u0BC1",
6520
+ answerTable: "\u0B85\u0B9F\u0BCD\u0B9F\u0BB5\u0BA3\u0BC8",
6419
6521
  groundedIn: "\u0B87\u0BA8\u0BCD\u0BA4\u0BAA\u0BCD \u0BAA\u0BA4\u0BBF\u0BB2\u0BCD \u0B8E\u0BA4\u0BC8 \u0B85\u0B9F\u0BBF\u0BAA\u0BCD\u0BAA\u0B9F\u0BC8\u0BAF\u0BBE\u0B95\u0B95\u0BCD \u0B95\u0BCA\u0BA3\u0BCD\u0B9F\u0BA4\u0BC1",
6420
6522
  sourceCountOne: "1 \u0BAE\u0BC2\u0BB2\u0BAE\u0BCD",
6421
6523
  sourceCountMany: "{count} \u0BAE\u0BC2\u0BB2\u0B99\u0BCD\u0B95\u0BB3\u0BCD",
@@ -6447,6 +6549,17 @@ var STRINGS = {
6447
6549
  ar: AR,
6448
6550
  ta: TA
6449
6551
  };
6552
+ var SPEECH_TAGS = {
6553
+ en: "en-US",
6554
+ zh: "zh-CN",
6555
+ hi: "hi-IN",
6556
+ es: "es-ES",
6557
+ ar: "ar-SA",
6558
+ ta: "ta-IN"
6559
+ };
6560
+ function speechLocaleOf(locale) {
6561
+ return SPEECH_TAGS[locale];
6562
+ }
6450
6563
  function resolveExploreLocale(explicit) {
6451
6564
  const candidates = [
6452
6565
  explicit,
@@ -6468,192 +6581,721 @@ function fill(template, values) {
6468
6581
  return template.replace(/\{(\w+)\}/g, (match, key) => values[key] ?? match);
6469
6582
  }
6470
6583
 
6471
- // src/components/explore-types.ts
6472
- var EXPLORE_FEEDBACK_REASONS = [
6473
- "INACCURATE",
6474
- "INCOMPLETE",
6475
- "OFF_TOPIC",
6476
- "HARD_TO_FOLLOW",
6477
- "OTHER"
6478
- ];
6479
- var EXPLORE_MESSAGE_FIELDS = (
6480
- /* GraphQL */
6481
- `
6482
- id
6483
- conversationId
6484
- role
6485
- status
6486
- content
6487
- partialContent
6488
- activity
6489
- references {
6490
- url
6491
- title
6492
- description
6493
- product
6494
- imageUrl
6495
- index
6584
+ // src/components/answers-i18n.ts
6585
+ var EN2 = {
6586
+ breadcrumbHome: "Home",
6587
+ answers: "Answers",
6588
+ indexHeading: "{product} answers",
6589
+ indexLead: "Questions about {product}, each answered by our own assistant from our published documentation \u2014 with links to the pages the answer came from.",
6590
+ seoIndexTitle: "Answers",
6591
+ seoIndexDescription: "Questions about {product}, answered from our published documentation, each with links to the pages the answer came from.",
6592
+ searchLabel: "Search questions",
6593
+ searchPlaceholder: "Search questions",
6594
+ filterByTopic: "Filter by topic",
6595
+ allTopics: "All",
6596
+ showingCount: "Showing {shown} of {total} questions",
6597
+ noMatchesTitle: "No questions match your filters",
6598
+ noMatchesBody: "Try a different search, or show every topic.",
6599
+ clearFilters: "Clear filters",
6600
+ noneYetTitle: "No answers published yet",
6601
+ noneYetBody: "{product} answers will appear here as they are published.",
6602
+ questionCountOne: "1 question",
6603
+ questionCountMany: "{count} questions",
6604
+ sourceCountOne: "1 source",
6605
+ sourceCountMany: "{count} sources",
6606
+ answerHeading: "Answer",
6607
+ sourcesHeading: "Sources",
6608
+ sourcesLead: "The pages this answer was drawn from.",
6609
+ aboutTitle: "About this answer",
6610
+ aboutBody: "Produced by our own assistant on {date} from our published documentation. The pages it drew on are linked under the answer. It is generated text, not a statement from a person \u2014 where it and a linked page disagree, the page is right.",
6611
+ answeredOn: "Answered {date}",
6612
+ topicsHeading: "Topics",
6613
+ relatedHeading: "Related questions",
6614
+ moreInTopic: "More in {topic}",
6615
+ previousQuestion: "Previous question",
6616
+ nextQuestion: "Next question",
6617
+ allAnswers: "All {product} answers",
6618
+ askYourOwn: "Ask your own question"
6619
+ };
6620
+ var ZH2 = {
6621
+ breadcrumbHome: "\u9996\u9875",
6622
+ answers: "\u95EE\u7B54",
6623
+ indexHeading: "{product} \u95EE\u7B54",
6624
+ indexLead: "\u5173\u4E8E {product} \u7684\u95EE\u9898\uFF0C\u6BCF\u4E2A\u56DE\u7B54\u90FD\u7531\u6211\u4EEC\u81EA\u5DF1\u7684\u52A9\u624B\u4F9D\u636E\u5DF2\u516C\u5F00\u7684\u6587\u6863\u751F\u6210\uFF0C\u5E76\u9644\u4E0A\u56DE\u7B54\u6240\u4F9D\u636E\u9875\u9762\u7684\u94FE\u63A5\u3002",
6625
+ seoIndexTitle: "\u95EE\u7B54",
6626
+ seoIndexDescription: "\u5173\u4E8E {product} \u7684\u95EE\u9898\uFF0C\u4F9D\u636E\u6211\u4EEC\u5DF2\u516C\u5F00\u7684\u6587\u6863\u4F5C\u7B54\uFF0C\u6BCF\u4E2A\u56DE\u7B54\u90FD\u9644\u6709\u6765\u6E90\u9875\u9762\u7684\u94FE\u63A5\u3002",
6627
+ searchLabel: "\u641C\u7D22\u95EE\u9898",
6628
+ searchPlaceholder: "\u641C\u7D22\u95EE\u9898",
6629
+ filterByTopic: "\u6309\u4E3B\u9898\u7B5B\u9009",
6630
+ allTopics: "\u5168\u90E8",
6631
+ showingCount: "\u663E\u793A {total} \u4E2A\u95EE\u9898\u4E2D\u7684 {shown} \u4E2A",
6632
+ noMatchesTitle: "\u6CA1\u6709\u7B26\u5408\u7B5B\u9009\u6761\u4EF6\u7684\u95EE\u9898",
6633
+ noMatchesBody: "\u6362\u4E2A\u641C\u7D22\u8BCD\uFF0C\u6216\u663E\u793A\u5168\u90E8\u4E3B\u9898\u3002",
6634
+ clearFilters: "\u6E05\u9664\u7B5B\u9009",
6635
+ noneYetTitle: "\u5C1A\u672A\u53D1\u5E03\u95EE\u7B54",
6636
+ noneYetBody: "{product} \u7684\u95EE\u7B54\u53D1\u5E03\u540E\u4F1A\u663E\u793A\u5728\u8FD9\u91CC\u3002",
6637
+ questionCountOne: "1 \u4E2A\u95EE\u9898",
6638
+ questionCountMany: "{count} \u4E2A\u95EE\u9898",
6639
+ sourceCountOne: "1 \u4E2A\u6765\u6E90",
6640
+ sourceCountMany: "{count} \u4E2A\u6765\u6E90",
6641
+ answerHeading: "\u56DE\u7B54",
6642
+ sourcesHeading: "\u6765\u6E90",
6643
+ sourcesLead: "\u672C\u56DE\u7B54\u6240\u4F9D\u636E\u7684\u9875\u9762\u3002",
6644
+ aboutTitle: "\u5173\u4E8E\u8FD9\u4E2A\u56DE\u7B54",
6645
+ aboutBody: "\u672C\u56DE\u7B54\u7531\u6211\u4EEC\u81EA\u5DF1\u7684\u52A9\u624B\u4E8E {date} \u4F9D\u636E\u5DF2\u516C\u5F00\u7684\u6587\u6863\u751F\u6210\uFF0C\u6240\u4F9D\u636E\u7684\u9875\u9762\u5217\u5728\u56DE\u7B54\u4E0B\u65B9\u3002\u8FD9\u662F\u81EA\u52A8\u751F\u6210\u7684\u6587\u672C\uFF0C\u5E76\u975E\u67D0\u4F4D\u540C\u4E8B\u7684\u8BF4\u6CD5\u2014\u2014\u5982\u679C\u5B83\u4E0E\u6240\u94FE\u63A5\u7684\u9875\u9762\u4E0D\u4E00\u81F4\uFF0C\u8BF7\u4EE5\u9875\u9762\u4E3A\u51C6\u3002",
6646
+ answeredOn: "\u56DE\u7B54\u4E8E {date}",
6647
+ topicsHeading: "\u4E3B\u9898",
6648
+ relatedHeading: "\u76F8\u5173\u95EE\u9898",
6649
+ moreInTopic: "\u66F4\u591A\u300C{topic}\u300D\u95EE\u9898",
6650
+ previousQuestion: "\u4E0A\u4E00\u4E2A\u95EE\u9898",
6651
+ nextQuestion: "\u4E0B\u4E00\u4E2A\u95EE\u9898",
6652
+ allAnswers: "\u5168\u90E8 {product} \u95EE\u7B54",
6653
+ askYourOwn: "\u63D0\u51FA\u4F60\u7684\u95EE\u9898"
6654
+ };
6655
+ var HI2 = {
6656
+ breadcrumbHome: "\u0939\u094B\u092E",
6657
+ answers: "\u0909\u0924\u094D\u0924\u0930",
6658
+ indexHeading: "{product} \u0915\u0947 \u0909\u0924\u094D\u0924\u0930",
6659
+ indexLead: "{product} \u0938\u0947 \u091C\u0941\u0921\u093C\u0947 \u0938\u0935\u093E\u0932, \u091C\u093F\u0928\u0915\u093E \u0909\u0924\u094D\u0924\u0930 \u0939\u092E\u093E\u0930\u093E \u0905\u092A\u0928\u093E \u0938\u0939\u093E\u092F\u0915 \u0939\u092E\u093E\u0930\u0947 \u092A\u094D\u0930\u0915\u093E\u0936\u093F\u0924 \u0926\u0938\u094D\u0924\u093E\u0935\u0947\u091C\u093C\u094B\u0902 \u0938\u0947 \u0926\u0947\u0924\u093E \u0939\u0948 \u2014 \u0914\u0930 \u091C\u093F\u0928 \u092A\u0928\u094D\u0928\u094B\u0902 \u0938\u0947 \u0909\u0924\u094D\u0924\u0930 \u0906\u092F\u093E, \u0909\u0928\u0915\u0947 \u0932\u093F\u0902\u0915 \u0938\u093E\u0925 \u092E\u0947\u0902 \u0939\u0948\u0902\u0964",
6660
+ seoIndexTitle: "\u0909\u0924\u094D\u0924\u0930",
6661
+ seoIndexDescription: "{product} \u0938\u0947 \u091C\u0941\u0921\u093C\u0947 \u0938\u0935\u093E\u0932\u094B\u0902 \u0915\u0947 \u0909\u0924\u094D\u0924\u0930, \u0939\u092E\u093E\u0930\u0947 \u092A\u094D\u0930\u0915\u093E\u0936\u093F\u0924 \u0926\u0938\u094D\u0924\u093E\u0935\u0947\u091C\u093C\u094B\u0902 \u0938\u0947 \u2014 \u0939\u0930 \u0909\u0924\u094D\u0924\u0930 \u0915\u0947 \u0938\u093E\u0925 \u0938\u094D\u0930\u094B\u0924 \u092A\u0928\u094D\u0928\u094B\u0902 \u0915\u0947 \u0932\u093F\u0902\u0915\u0964",
6662
+ searchLabel: "\u0938\u0935\u093E\u0932 \u0916\u094B\u091C\u0947\u0902",
6663
+ searchPlaceholder: "\u0938\u0935\u093E\u0932 \u0916\u094B\u091C\u0947\u0902",
6664
+ filterByTopic: "\u0935\u093F\u0937\u092F \u0938\u0947 \u091B\u093E\u0901\u091F\u0947\u0902",
6665
+ allTopics: "\u0938\u092D\u0940",
6666
+ showingCount: "{total} \u092E\u0947\u0902 \u0938\u0947 {shown} \u0938\u0935\u093E\u0932 \u0926\u093F\u0916 \u0930\u0939\u0947 \u0939\u0948\u0902",
6667
+ noMatchesTitle: "\u0906\u092A\u0915\u0940 \u091B\u0901\u091F\u093E\u0908 \u0938\u0947 \u0915\u094B\u0908 \u0938\u0935\u093E\u0932 \u092E\u0947\u0932 \u0928\u0939\u0940\u0902 \u0916\u093E\u0924\u093E",
6668
+ noMatchesBody: "\u0915\u0941\u091B \u0914\u0930 \u0916\u094B\u091C\u0947\u0902, \u092F\u093E \u0938\u092D\u0940 \u0935\u093F\u0937\u092F \u0926\u093F\u0916\u093E\u090F\u0901\u0964",
6669
+ clearFilters: "\u091B\u0901\u091F\u093E\u0908 \u0939\u091F\u093E\u090F\u0901",
6670
+ noneYetTitle: "\u0905\u092D\u0940 \u0915\u094B\u0908 \u0909\u0924\u094D\u0924\u0930 \u092A\u094D\u0930\u0915\u093E\u0936\u093F\u0924 \u0928\u0939\u0940\u0902 \u0939\u0941\u0906",
6671
+ noneYetBody: "{product} \u0915\u0947 \u0909\u0924\u094D\u0924\u0930 \u092A\u094D\u0930\u0915\u093E\u0936\u093F\u0924 \u0939\u094B\u0924\u0947 \u0939\u0940 \u092F\u0939\u093E\u0901 \u0926\u093F\u0916\u0947\u0902\u0917\u0947\u0964",
6672
+ questionCountOne: "1 \u0938\u0935\u093E\u0932",
6673
+ questionCountMany: "{count} \u0938\u0935\u093E\u0932",
6674
+ sourceCountOne: "1 \u0938\u094D\u0930\u094B\u0924",
6675
+ sourceCountMany: "{count} \u0938\u094D\u0930\u094B\u0924",
6676
+ answerHeading: "\u0909\u0924\u094D\u0924\u0930",
6677
+ sourcesHeading: "\u0938\u094D\u0930\u094B\u0924",
6678
+ sourcesLead: "\u092F\u0939 \u0909\u0924\u094D\u0924\u0930 \u091C\u093F\u0928 \u092A\u0928\u094D\u0928\u094B\u0902 \u0938\u0947 \u0932\u093F\u092F\u093E \u0917\u092F\u093E \u0939\u0948\u0964",
6679
+ aboutTitle: "\u0907\u0938 \u0909\u0924\u094D\u0924\u0930 \u0915\u0947 \u092C\u093E\u0930\u0947 \u092E\u0947\u0902",
6680
+ aboutBody: "\u092F\u0939 \u0909\u0924\u094D\u0924\u0930 {date} \u0915\u094B \u0939\u092E\u093E\u0930\u0947 \u0905\u092A\u0928\u0947 \u0938\u0939\u093E\u092F\u0915 \u0928\u0947 \u0939\u092E\u093E\u0930\u0947 \u092A\u094D\u0930\u0915\u093E\u0936\u093F\u0924 \u0926\u0938\u094D\u0924\u093E\u0935\u0947\u091C\u093C\u094B\u0902 \u0938\u0947 \u0924\u0948\u092F\u093E\u0930 \u0915\u093F\u092F\u093E \u0925\u093E\u0964 \u091C\u093F\u0928 \u092A\u0928\u094D\u0928\u094B\u0902 \u0915\u093E \u0909\u092A\u092F\u094B\u0917 \u0939\u0941\u0906, \u0935\u0947 \u0909\u0924\u094D\u0924\u0930 \u0915\u0947 \u0928\u0940\u091A\u0947 \u0926\u093F\u090F \u0917\u090F \u0939\u0948\u0902\u0964 \u092F\u0939 \u0905\u092A\u0928\u0947-\u0906\u092A \u0924\u0948\u092F\u093E\u0930 \u0915\u093F\u092F\u093E \u0917\u092F\u093E \u092A\u093E\u0920 \u0939\u0948, \u0915\u093F\u0938\u0940 \u0935\u094D\u092F\u0915\u094D\u0924\u093F \u0915\u093E \u0915\u0925\u0928 \u0928\u0939\u0940\u0902 \u2014 \u0905\u0917\u0930 \u0907\u0938\u092E\u0947\u0902 \u0914\u0930 \u0932\u093F\u0902\u0915 \u0915\u093F\u090F \u0917\u090F \u092A\u0928\u094D\u0928\u0947 \u092E\u0947\u0902 \u092B\u093C\u0930\u094D\u0915\u093C \u0939\u094B, \u0924\u094B \u092A\u0928\u094D\u0928\u093E \u0938\u0939\u0940 \u0939\u0948\u0964",
6681
+ answeredOn: "{date} \u0915\u094B \u0909\u0924\u094D\u0924\u0930 \u0926\u093F\u092F\u093E \u0917\u092F\u093E",
6682
+ topicsHeading: "\u0935\u093F\u0937\u092F",
6683
+ relatedHeading: "\u0938\u0902\u092C\u0902\u0927\u093F\u0924 \u0938\u0935\u093E\u0932",
6684
+ moreInTopic: "{topic} \u092E\u0947\u0902 \u0914\u0930",
6685
+ previousQuestion: "\u092A\u093F\u091B\u0932\u093E \u0938\u0935\u093E\u0932",
6686
+ nextQuestion: "\u0905\u0917\u0932\u093E \u0938\u0935\u093E\u0932",
6687
+ allAnswers: "{product} \u0915\u0947 \u0938\u092D\u0940 \u0909\u0924\u094D\u0924\u0930",
6688
+ askYourOwn: "\u0905\u092A\u0928\u093E \u0938\u0935\u093E\u0932 \u092A\u0942\u091B\u0947\u0902"
6689
+ };
6690
+ var ES2 = {
6691
+ breadcrumbHome: "Inicio",
6692
+ answers: "Respuestas",
6693
+ indexHeading: "Respuestas sobre {product}",
6694
+ indexLead: "Preguntas sobre {product}, respondidas por nuestro propio asistente a partir de nuestra documentaci\xF3n publicada, con enlaces a las p\xE1ginas de las que sali\xF3 cada respuesta.",
6695
+ seoIndexTitle: "Respuestas",
6696
+ seoIndexDescription: "Preguntas sobre {product} respondidas a partir de nuestra documentaci\xF3n publicada, cada una con enlaces a las p\xE1ginas de origen.",
6697
+ searchLabel: "Buscar preguntas",
6698
+ searchPlaceholder: "Buscar preguntas",
6699
+ filterByTopic: "Filtrar por tema",
6700
+ allTopics: "Todas",
6701
+ showingCount: "Mostrando {shown} de {total} preguntas",
6702
+ noMatchesTitle: "Ninguna pregunta coincide con los filtros",
6703
+ noMatchesBody: "Prueba otra b\xFAsqueda o muestra todos los temas.",
6704
+ clearFilters: "Quitar filtros",
6705
+ noneYetTitle: "Todav\xEDa no hay respuestas publicadas",
6706
+ noneYetBody: "Las respuestas sobre {product} aparecer\xE1n aqu\xED a medida que se publiquen.",
6707
+ questionCountOne: "1 pregunta",
6708
+ questionCountMany: "{count} preguntas",
6709
+ sourceCountOne: "1 fuente",
6710
+ sourceCountMany: "{count} fuentes",
6711
+ answerHeading: "Respuesta",
6712
+ sourcesHeading: "Fuentes",
6713
+ sourcesLead: "Las p\xE1ginas de las que sali\xF3 esta respuesta.",
6714
+ aboutTitle: "Sobre esta respuesta",
6715
+ aboutBody: "La prepar\xF3 nuestro propio asistente el {date} a partir de nuestra documentaci\xF3n publicada. Las p\xE1ginas que utiliz\xF3 est\xE1n enlazadas debajo de la respuesta. Es texto generado, no la palabra de una persona: si la respuesta y una p\xE1gina enlazada no coinciden, manda la p\xE1gina.",
6716
+ answeredOn: "Respondida el {date}",
6717
+ topicsHeading: "Temas",
6718
+ relatedHeading: "Preguntas relacionadas",
6719
+ moreInTopic: "M\xE1s de {topic}",
6720
+ previousQuestion: "Pregunta anterior",
6721
+ nextQuestion: "Pregunta siguiente",
6722
+ allAnswers: "Todas las respuestas sobre {product}",
6723
+ askYourOwn: "Haz tu propia pregunta"
6724
+ };
6725
+ var AR2 = {
6726
+ breadcrumbHome: "\u0627\u0644\u0631\u0626\u064A\u0633\u064A\u0629",
6727
+ answers: "\u0627\u0644\u0625\u062C\u0627\u0628\u0627\u062A",
6728
+ indexHeading: "\u0625\u062C\u0627\u0628\u0627\u062A {product}",
6729
+ indexLead: "\u0623\u0633\u0626\u0644\u0629 \u062D\u0648\u0644 {product}\u060C \u064A\u062C\u064A\u0628 \u0639\u0646\u0647\u0627 \u0645\u0633\u0627\u0639\u062F\u0646\u0627 \u0627\u0639\u062A\u0645\u0627\u062F\u064B\u0627 \u0639\u0644\u0649 \u0648\u062B\u0627\u0626\u0642\u0646\u0627 \u0627\u0644\u0645\u0646\u0634\u0648\u0631\u0629\u060C \u0645\u0639 \u0631\u0648\u0627\u0628\u0637 \u0625\u0644\u0649 \u0627\u0644\u0635\u0641\u062D\u0627\u062A \u0627\u0644\u062A\u064A \u062C\u0627\u0621\u062A \u0645\u0646\u0647\u0627 \u0643\u0644 \u0625\u062C\u0627\u0628\u0629.",
6730
+ seoIndexTitle: "\u0627\u0644\u0625\u062C\u0627\u0628\u0627\u062A",
6731
+ seoIndexDescription: "\u0623\u0633\u0626\u0644\u0629 \u062D\u0648\u0644 {product} \u0645\u064F\u062C\u0627\u0628 \u0639\u0646\u0647\u0627 \u0645\u0646 \u0648\u062B\u0627\u0626\u0642\u0646\u0627 \u0627\u0644\u0645\u0646\u0634\u0648\u0631\u0629\u060C \u0645\u0639 \u0631\u0648\u0627\u0628\u0637 \u0625\u0644\u0649 \u0635\u0641\u062D\u0627\u062A \u0627\u0644\u0645\u0635\u062F\u0631 \u0644\u0643\u0644 \u0625\u062C\u0627\u0628\u0629.",
6732
+ searchLabel: "\u0627\u0628\u062D\u062B \u0641\u064A \u0627\u0644\u0623\u0633\u0626\u0644\u0629",
6733
+ searchPlaceholder: "\u0627\u0628\u062D\u062B \u0641\u064A \u0627\u0644\u0623\u0633\u0626\u0644\u0629",
6734
+ filterByTopic: "\u062A\u0635\u0641\u064A\u0629 \u062D\u0633\u0628 \u0627\u0644\u0645\u0648\u0636\u0648\u0639",
6735
+ allTopics: "\u0627\u0644\u0643\u0644",
6736
+ showingCount: "\u0639\u0631\u0636 {shown} \u0645\u0646 {total} \u0633\u0624\u0627\u0644\u064B\u0627",
6737
+ noMatchesTitle: "\u0644\u0627 \u062A\u0648\u062C\u062F \u0623\u0633\u0626\u0644\u0629 \u062A\u0637\u0627\u0628\u0642 \u0627\u0644\u062A\u0635\u0641\u064A\u0629",
6738
+ noMatchesBody: "\u062C\u0631\u0651\u0628 \u0628\u062D\u062B\u064B\u0627 \u0622\u062E\u0631\u060C \u0623\u0648 \u0627\u0639\u0631\u0636 \u0643\u0644 \u0627\u0644\u0645\u0648\u0627\u0636\u064A\u0639.",
6739
+ clearFilters: "\u0645\u0633\u062D \u0627\u0644\u062A\u0635\u0641\u064A\u0629",
6740
+ noneYetTitle: "\u0644\u0645 \u062A\u064F\u0646\u0634\u0631 \u0625\u062C\u0627\u0628\u0627\u062A \u0628\u0639\u062F",
6741
+ noneYetBody: "\u0633\u062A\u0638\u0647\u0631 \u0625\u062C\u0627\u0628\u0627\u062A {product} \u0647\u0646\u0627 \u0641\u0648\u0631 \u0646\u0634\u0631\u0647\u0627.",
6742
+ questionCountOne: "\u0633\u0624\u0627\u0644 \u0648\u0627\u062D\u062F",
6743
+ questionCountMany: "{count} \u0623\u0633\u0626\u0644\u0629",
6744
+ sourceCountOne: "\u0645\u0635\u062F\u0631 \u0648\u0627\u062D\u062F",
6745
+ sourceCountMany: "{count} \u0645\u0635\u0627\u062F\u0631",
6746
+ answerHeading: "\u0627\u0644\u0625\u062C\u0627\u0628\u0629",
6747
+ sourcesHeading: "\u0627\u0644\u0645\u0635\u0627\u062F\u0631",
6748
+ sourcesLead: "\u0627\u0644\u0635\u0641\u062D\u0627\u062A \u0627\u0644\u062A\u064A \u0627\u0633\u062A\u064F\u0645\u062F\u062A \u0645\u0646\u0647\u0627 \u0647\u0630\u0647 \u0627\u0644\u0625\u062C\u0627\u0628\u0629.",
6749
+ aboutTitle: "\u0639\u0646 \u0647\u0630\u0647 \u0627\u0644\u0625\u062C\u0627\u0628\u0629",
6750
+ aboutBody: "\u0623\u0639\u062F\u0651\u0647\u0627 \u0645\u0633\u0627\u0639\u062F\u0646\u0627 \u0641\u064A {date} \u0627\u0639\u062A\u0645\u0627\u062F\u064B\u0627 \u0639\u0644\u0649 \u0648\u062B\u0627\u0626\u0642\u0646\u0627 \u0627\u0644\u0645\u0646\u0634\u0648\u0631\u0629\u060C \u0648\u0627\u0644\u0635\u0641\u062D\u0627\u062A \u0627\u0644\u062A\u064A \u0627\u0633\u062A\u0646\u062F \u0625\u0644\u064A\u0647\u0627 \u0645\u0630\u0643\u0648\u0631\u0629 \u0623\u0633\u0641\u0644 \u0627\u0644\u0625\u062C\u0627\u0628\u0629. \u0647\u0630\u0627 \u0646\u0635 \u0645\u064F\u0648\u0644\u064E\u0651\u062F \u0622\u0644\u064A\u064B\u0627 \u0648\u0644\u064A\u0633 \u0643\u0644\u0627\u0645 \u0634\u062E\u0635 \u2014 \u0648\u0625\u0630\u0627 \u0627\u062E\u062A\u0644\u0641 \u0645\u0639 \u0635\u0641\u062D\u0629 \u0645\u0631\u062A\u0628\u0637\u0629\u060C \u0641\u0627\u0644\u0635\u0641\u062D\u0629 \u0647\u064A \u0627\u0644\u0635\u062D\u064A\u062D\u0629.",
6751
+ answeredOn: "\u0623\u064F\u062C\u064A\u0628 \u0639\u0646\u0647 \u0641\u064A {date}",
6752
+ topicsHeading: "\u0627\u0644\u0645\u0648\u0627\u0636\u064A\u0639",
6753
+ relatedHeading: "\u0623\u0633\u0626\u0644\u0629 \u0630\u0627\u062A \u0635\u0644\u0629",
6754
+ moreInTopic: "\u0627\u0644\u0645\u0632\u064A\u062F \u0641\u064A {topic}",
6755
+ previousQuestion: "\u0627\u0644\u0633\u0624\u0627\u0644 \u0627\u0644\u0633\u0627\u0628\u0642",
6756
+ nextQuestion: "\u0627\u0644\u0633\u0624\u0627\u0644 \u0627\u0644\u062A\u0627\u0644\u064A",
6757
+ allAnswers: "\u0643\u0644 \u0625\u062C\u0627\u0628\u0627\u062A {product}",
6758
+ askYourOwn: "\u0627\u0637\u0631\u062D \u0633\u0624\u0627\u0644\u0643"
6759
+ };
6760
+ var TA2 = {
6761
+ breadcrumbHome: "\u0BAE\u0BC1\u0B95\u0BAA\u0BCD\u0BAA\u0BC1",
6762
+ answers: "\u0BAA\u0BA4\u0BBF\u0BB2\u0BCD\u0B95\u0BB3\u0BCD",
6763
+ indexHeading: "{product} \u0BAA\u0BA4\u0BBF\u0BB2\u0BCD\u0B95\u0BB3\u0BCD",
6764
+ indexLead: "{product} \u0BAA\u0BB1\u0BCD\u0BB1\u0BBF\u0BAF \u0B95\u0BC7\u0BB3\u0BCD\u0BB5\u0BBF\u0B95\u0BB3\u0BCD \u2014 \u0B92\u0BB5\u0BCD\u0BB5\u0BCA\u0BA9\u0BCD\u0BB1\u0BC1\u0B95\u0BCD\u0B95\u0BC1\u0BAE\u0BCD \u0B8E\u0B99\u0BCD\u0B95\u0BB3\u0BCD \u0B89\u0BA4\u0BB5\u0BBF\u0BAF\u0BBE\u0BB3\u0BB0\u0BCD \u0B8E\u0B99\u0BCD\u0B95\u0BB3\u0BCD \u0BB5\u0BC6\u0BB3\u0BBF\u0BAF\u0BBF\u0B9F\u0BAA\u0BCD\u0BAA\u0B9F\u0BCD\u0B9F \u0B86\u0BB5\u0BA3\u0B99\u0BCD\u0B95\u0BB3\u0BBF\u0BB2\u0BBF\u0BB0\u0BC1\u0BA8\u0BCD\u0BA4\u0BC1 \u0B85\u0BB3\u0BBF\u0BA4\u0BCD\u0BA4 \u0BAA\u0BA4\u0BBF\u0BB2\u0BCD, \u0BAA\u0BA4\u0BBF\u0BB2\u0BCD \u0BB5\u0BA8\u0BCD\u0BA4 \u0BAA\u0B95\u0BCD\u0B95\u0B99\u0BCD\u0B95\u0BB3\u0BC1\u0B95\u0BCD\u0B95\u0BBE\u0BA9 \u0B87\u0BA3\u0BC8\u0BAA\u0BCD\u0BAA\u0BC1\u0B95\u0BB3\u0BC1\u0B9F\u0BA9\u0BCD.",
6765
+ seoIndexTitle: "\u0BAA\u0BA4\u0BBF\u0BB2\u0BCD\u0B95\u0BB3\u0BCD",
6766
+ seoIndexDescription: "{product} \u0BAA\u0BB1\u0BCD\u0BB1\u0BBF\u0BAF \u0B95\u0BC7\u0BB3\u0BCD\u0BB5\u0BBF\u0B95\u0BB3\u0BC1\u0B95\u0BCD\u0B95\u0BC1 \u0B8E\u0B99\u0BCD\u0B95\u0BB3\u0BCD \u0BB5\u0BC6\u0BB3\u0BBF\u0BAF\u0BBF\u0B9F\u0BAA\u0BCD\u0BAA\u0B9F\u0BCD\u0B9F \u0B86\u0BB5\u0BA3\u0B99\u0BCD\u0B95\u0BB3\u0BBF\u0BB2\u0BBF\u0BB0\u0BC1\u0BA8\u0BCD\u0BA4\u0BC1 \u0BAA\u0BA4\u0BBF\u0BB2\u0BCD\u0B95\u0BB3\u0BCD \u2014 \u0B92\u0BB5\u0BCD\u0BB5\u0BCA\u0BA9\u0BCD\u0BB1\u0BBF\u0BB2\u0BC1\u0BAE\u0BCD \u0BAE\u0BC2\u0BB2\u0BAA\u0BCD \u0BAA\u0B95\u0BCD\u0B95\u0B99\u0BCD\u0B95\u0BB3\u0BC1\u0B95\u0BCD\u0B95\u0BBE\u0BA9 \u0B87\u0BA3\u0BC8\u0BAA\u0BCD\u0BAA\u0BC1\u0B95\u0BB3\u0BC1\u0B9F\u0BA9\u0BCD.",
6767
+ searchLabel: "\u0B95\u0BC7\u0BB3\u0BCD\u0BB5\u0BBF\u0B95\u0BB3\u0BC8\u0BA4\u0BCD \u0BA4\u0BC7\u0B9F\u0BC1\u0B99\u0BCD\u0B95\u0BB3\u0BCD",
6768
+ searchPlaceholder: "\u0B95\u0BC7\u0BB3\u0BCD\u0BB5\u0BBF\u0B95\u0BB3\u0BC8\u0BA4\u0BCD \u0BA4\u0BC7\u0B9F\u0BC1\u0B99\u0BCD\u0B95\u0BB3\u0BCD",
6769
+ filterByTopic: "\u0BA4\u0BB2\u0BC8\u0BAA\u0BCD\u0BAA\u0BBF\u0BA9\u0BCD\u0BAA\u0B9F\u0BBF \u0BB5\u0B9F\u0BBF\u0B95\u0B9F\u0BCD\u0B9F\u0BC1",
6770
+ allTopics: "\u0B85\u0BA9\u0BC8\u0BA4\u0BCD\u0BA4\u0BC1\u0BAE\u0BCD",
6771
+ showingCount: "{total} \u0B95\u0BC7\u0BB3\u0BCD\u0BB5\u0BBF\u0B95\u0BB3\u0BBF\u0BB2\u0BCD {shown} \u0B95\u0BBE\u0B9F\u0BCD\u0B9F\u0BAA\u0BCD\u0BAA\u0B9F\u0BC1\u0B95\u0BBF\u0BB1\u0BA4\u0BC1",
6772
+ noMatchesTitle: "\u0BB5\u0B9F\u0BBF\u0B95\u0B9F\u0BCD\u0B9F\u0BB2\u0BC1\u0B95\u0BCD\u0B95\u0BC1\u0BAA\u0BCD \u0BAA\u0BCA\u0BB0\u0BC1\u0BA8\u0BCD\u0BA4\u0BC1\u0BAE\u0BCD \u0B95\u0BC7\u0BB3\u0BCD\u0BB5\u0BBF \u0B87\u0BB2\u0BCD\u0BB2\u0BC8",
6773
+ noMatchesBody: "\u0BB5\u0BC7\u0BB1\u0BC1 \u0B92\u0BA9\u0BCD\u0BB1\u0BC8\u0BA4\u0BCD \u0BA4\u0BC7\u0B9F\u0BC1\u0B99\u0BCD\u0B95\u0BB3\u0BCD, \u0B85\u0BB2\u0BCD\u0BB2\u0BA4\u0BC1 \u0B8E\u0BB2\u0BCD\u0BB2\u0BBE\u0BA4\u0BCD \u0BA4\u0BB2\u0BC8\u0BAA\u0BCD\u0BAA\u0BC1\u0B95\u0BB3\u0BC8\u0BAF\u0BC1\u0BAE\u0BCD \u0B95\u0BBE\u0B9F\u0BCD\u0B9F\u0BC1\u0B99\u0BCD\u0B95\u0BB3\u0BCD.",
6774
+ clearFilters: "\u0BB5\u0B9F\u0BBF\u0B95\u0B9F\u0BCD\u0B9F\u0BB2\u0BC8 \u0BA8\u0BC0\u0B95\u0BCD\u0B95\u0BC1",
6775
+ noneYetTitle: "\u0B87\u0BA4\u0BC1\u0BB5\u0BB0\u0BC8 \u0BAA\u0BA4\u0BBF\u0BB2\u0BCD\u0B95\u0BB3\u0BCD \u0BB5\u0BC6\u0BB3\u0BBF\u0BAF\u0BBF\u0B9F\u0BAA\u0BCD\u0BAA\u0B9F\u0BB5\u0BBF\u0BB2\u0BCD\u0BB2\u0BC8",
6776
+ noneYetBody: "{product} \u0BAA\u0BA4\u0BBF\u0BB2\u0BCD\u0B95\u0BB3\u0BCD \u0BB5\u0BC6\u0BB3\u0BBF\u0BAF\u0BBF\u0B9F\u0BAA\u0BCD\u0BAA\u0B9F\u0BC1\u0BAE\u0BCD\u0BAA\u0BCB\u0BA4\u0BC1 \u0B87\u0B99\u0BCD\u0B95\u0BC7 \u0BA4\u0BCB\u0BA9\u0BCD\u0BB1\u0BC1\u0BAE\u0BCD.",
6777
+ questionCountOne: "1 \u0B95\u0BC7\u0BB3\u0BCD\u0BB5\u0BBF",
6778
+ questionCountMany: "{count} \u0B95\u0BC7\u0BB3\u0BCD\u0BB5\u0BBF\u0B95\u0BB3\u0BCD",
6779
+ sourceCountOne: "1 \u0BAE\u0BC2\u0BB2\u0BAE\u0BCD",
6780
+ sourceCountMany: "{count} \u0BAE\u0BC2\u0BB2\u0B99\u0BCD\u0B95\u0BB3\u0BCD",
6781
+ answerHeading: "\u0BAA\u0BA4\u0BBF\u0BB2\u0BCD",
6782
+ sourcesHeading: "\u0BAE\u0BC2\u0BB2\u0B99\u0BCD\u0B95\u0BB3\u0BCD",
6783
+ sourcesLead: "\u0B87\u0BA8\u0BCD\u0BA4\u0BAA\u0BCD \u0BAA\u0BA4\u0BBF\u0BB2\u0BCD \u0B8E\u0B9F\u0BC1\u0B95\u0BCD\u0B95\u0BAA\u0BCD\u0BAA\u0B9F\u0BCD\u0B9F \u0BAA\u0B95\u0BCD\u0B95\u0B99\u0BCD\u0B95\u0BB3\u0BCD.",
6784
+ aboutTitle: "\u0B87\u0BA8\u0BCD\u0BA4\u0BAA\u0BCD \u0BAA\u0BA4\u0BBF\u0BB2\u0BCD \u0BAA\u0BB1\u0BCD\u0BB1\u0BBF",
6785
+ aboutBody: "\u0B87\u0BA4\u0BC8 \u0B8E\u0B99\u0BCD\u0B95\u0BB3\u0BCD \u0B89\u0BA4\u0BB5\u0BBF\u0BAF\u0BBE\u0BB3\u0BB0\u0BCD {date} \u0B85\u0BA9\u0BCD\u0BB1\u0BC1 \u0B8E\u0B99\u0BCD\u0B95\u0BB3\u0BCD \u0BB5\u0BC6\u0BB3\u0BBF\u0BAF\u0BBF\u0B9F\u0BAA\u0BCD\u0BAA\u0B9F\u0BCD\u0B9F \u0B86\u0BB5\u0BA3\u0B99\u0BCD\u0B95\u0BB3\u0BBF\u0BB2\u0BBF\u0BB0\u0BC1\u0BA8\u0BCD\u0BA4\u0BC1 \u0B89\u0BB0\u0BC1\u0BB5\u0BBE\u0B95\u0BCD\u0B95\u0BBF\u0BAF\u0BA4\u0BC1; \u0BAA\u0BAF\u0BA9\u0BCD\u0BAA\u0B9F\u0BC1\u0BA4\u0BCD\u0BA4\u0BBF\u0BAF \u0BAA\u0B95\u0BCD\u0B95\u0B99\u0BCD\u0B95\u0BB3\u0BCD \u0BAA\u0BA4\u0BBF\u0BB2\u0BC1\u0B95\u0BCD\u0B95\u0BC1\u0B95\u0BCD \u0B95\u0BC0\u0BB4\u0BC7 \u0B87\u0BA3\u0BC8\u0B95\u0BCD\u0B95\u0BAA\u0BCD\u0BAA\u0B9F\u0BCD\u0B9F\u0BC1\u0BB3\u0BCD\u0BB3\u0BA9. \u0B87\u0BA4\u0BC1 \u0BA4\u0BBE\u0BA9\u0BBE\u0B95 \u0B89\u0BB0\u0BC1\u0BB5\u0BBE\u0B95\u0BCD\u0B95\u0BAA\u0BCD\u0BAA\u0B9F\u0BCD\u0B9F \u0B89\u0BB0\u0BC8, \u0B92\u0BB0\u0BC1 \u0BA8\u0BAA\u0BB0\u0BBF\u0BA9\u0BCD \u0B95\u0BC2\u0BB1\u0BCD\u0BB1\u0BC1 \u0B85\u0BB2\u0BCD\u0BB2 \u2014 \u0B87\u0BA4\u0BB1\u0BCD\u0B95\u0BC1\u0BAE\u0BCD \u0B87\u0BA3\u0BC8\u0B95\u0BCD\u0B95\u0BAA\u0BCD\u0BAA\u0B9F\u0BCD\u0B9F \u0BAA\u0B95\u0BCD\u0B95\u0BA4\u0BCD\u0BA4\u0BBF\u0BB1\u0BCD\u0B95\u0BC1\u0BAE\u0BCD \u0BB5\u0BC7\u0BB1\u0BC1\u0BAA\u0BBE\u0B9F\u0BC1 \u0B87\u0BB0\u0BC1\u0BA8\u0BCD\u0BA4\u0BBE\u0BB2\u0BCD, \u0BAA\u0B95\u0BCD\u0B95\u0BAE\u0BC7 \u0B9A\u0BB0\u0BBF.",
6786
+ answeredOn: "{date} \u0B85\u0BA9\u0BCD\u0BB1\u0BC1 \u0BAA\u0BA4\u0BBF\u0BB2\u0BB3\u0BBF\u0B95\u0BCD\u0B95\u0BAA\u0BCD\u0BAA\u0B9F\u0BCD\u0B9F\u0BA4\u0BC1",
6787
+ topicsHeading: "\u0BA4\u0BB2\u0BC8\u0BAA\u0BCD\u0BAA\u0BC1\u0B95\u0BB3\u0BCD",
6788
+ relatedHeading: "\u0BA4\u0BCA\u0B9F\u0BB0\u0BCD\u0BAA\u0BC1\u0B9F\u0BC8\u0BAF \u0B95\u0BC7\u0BB3\u0BCD\u0BB5\u0BBF\u0B95\u0BB3\u0BCD",
6789
+ moreInTopic: "{topic} \u0B87\u0BB2\u0BCD \u0BAE\u0BC7\u0BB2\u0BC1\u0BAE\u0BCD",
6790
+ previousQuestion: "\u0BAE\u0BC1\u0BA8\u0BCD\u0BA4\u0BC8\u0BAF \u0B95\u0BC7\u0BB3\u0BCD\u0BB5\u0BBF",
6791
+ nextQuestion: "\u0B85\u0B9F\u0BC1\u0BA4\u0BCD\u0BA4 \u0B95\u0BC7\u0BB3\u0BCD\u0BB5\u0BBF",
6792
+ allAnswers: "{product} \u0B85\u0BA9\u0BC8\u0BA4\u0BCD\u0BA4\u0BC1\u0BAA\u0BCD \u0BAA\u0BA4\u0BBF\u0BB2\u0BCD\u0B95\u0BB3\u0BC1\u0BAE\u0BCD",
6793
+ askYourOwn: "\u0B89\u0B99\u0BCD\u0B95\u0BB3\u0BCD \u0B95\u0BC7\u0BB3\u0BCD\u0BB5\u0BBF\u0BAF\u0BC8\u0B95\u0BCD \u0B95\u0BC7\u0BB3\u0BC1\u0B99\u0BCD\u0B95\u0BB3\u0BCD"
6794
+ };
6795
+ var CHROME = {
6796
+ en: EN2,
6797
+ zh: ZH2,
6798
+ hi: HI2,
6799
+ es: ES2,
6800
+ ar: AR2,
6801
+ ta: TA2
6802
+ };
6803
+ function answerStrings(locale) {
6804
+ const chrome = CHROME[locale] ?? EN2;
6805
+ const explore = exploreStrings(locale);
6806
+ return {
6807
+ ...chrome,
6808
+ answerTable: explore.answerTable,
6809
+ conceptIllustration: explore.conceptIllustration,
6810
+ opensInNewTab: explore.opensInNewTab
6811
+ };
6812
+ }
6813
+ var DATE_TAGS = {
6814
+ en: "en-GB",
6815
+ zh: "zh-CN",
6816
+ hi: "hi-IN",
6817
+ es: "es-ES",
6818
+ ar: "ar",
6819
+ ta: "ta-IN"
6820
+ };
6821
+ function formatAnswerDate(value, locale) {
6822
+ const at = new Date(value);
6823
+ if (Number.isNaN(at.getTime())) return "";
6824
+ try {
6825
+ return new Intl.DateTimeFormat(DATE_TAGS[locale] ?? "en-GB", {
6826
+ year: "numeric",
6827
+ month: "long",
6828
+ day: "numeric",
6829
+ timeZone: "UTC",
6830
+ numberingSystem: "latn"
6831
+ }).format(at);
6832
+ } catch {
6833
+ return value.slice(0, 10);
6496
6834
  }
6497
- ctas {
6498
- kind
6499
- label
6500
- url
6501
- product
6835
+ }
6836
+
6837
+ // src/components/answers-types.ts
6838
+ var PUBLISHED_ANSWER_FIELDS = {
6839
+ slug: true,
6840
+ order: true,
6841
+ question: true,
6842
+ answer: true,
6843
+ topic: true,
6844
+ summary: true,
6845
+ metaDescription: true,
6846
+ keywords: true,
6847
+ sources: true,
6848
+ related: true,
6849
+ answeredAt: true
6850
+ };
6851
+ var ANSWERS_PATH = "/answers";
6852
+ var ANSWER_PATH_PREFIX = "/answer";
6853
+ function answerPath(slug) {
6854
+ return `${ANSWER_PATH_PREFIX}/${encodeURIComponent(slug)}`;
6855
+ }
6856
+ function getAnswerBySlug(answers, slug) {
6857
+ if (!slug) return void 0;
6858
+ const wanted = slug.trim().toLowerCase();
6859
+ if (!wanted) return void 0;
6860
+ return answers.find((answer) => answer.slug === wanted);
6861
+ }
6862
+ function isPublishedSourceUrl(url) {
6863
+ let parsed;
6864
+ try {
6865
+ parsed = new URL(url);
6866
+ } catch {
6867
+ return false;
6502
6868
  }
6503
- followUps
6504
- answered
6505
- attachments {
6506
- name
6507
- mimeType
6508
- size
6509
- textExtracted
6869
+ return parsed.protocol === "https:" && parsed.hostname !== "" && !parsed.username && !parsed.password;
6870
+ }
6871
+ function answerSourceHost(url) {
6872
+ try {
6873
+ return new URL(url).hostname.replace(/^www\./, "");
6874
+ } catch {
6875
+ return "";
6510
6876
  }
6511
- errorCode
6512
- createdAt
6513
- completedAt
6514
- `
6515
- );
6516
- var EXPLORE_OWN_MESSAGE_FIELDS = (
6517
- /* GraphQL */
6518
- `
6519
- ${EXPLORE_MESSAGE_FIELDS}
6520
- feedback {
6521
- rating
6522
- reason
6523
- comment
6524
- createdAt
6877
+ }
6878
+ var EXPLORE_ANSWER_CSS = `
6879
+ /* Nothing inside an answer may widen the page. Model output carries long URLs, code and
6880
+ tables \u2014 each of those overflows a phone by default, and one overflowing child makes the
6881
+ WHOLE document horizontally scrollable, not just the bubble. */
6882
+ .boff-explore-body,
6883
+ .boff-explore-body p,
6884
+ .boff-explore-body li,
6885
+ .boff-explore-body a,
6886
+ .boff-explore-body h1,
6887
+ .boff-explore-body h2,
6888
+ .boff-explore-body h3,
6889
+ /* h4-h6 as well: a published answer page pushes the model's own headings down a level or
6890
+ two so they nest under the page's, and a long unbroken word is no narrower for it. */
6891
+ .boff-explore-body h4,
6892
+ .boff-explore-body h5,
6893
+ .boff-explore-body h6 {
6894
+ overflow-wrap: anywhere;
6895
+ word-break: break-word;
6896
+ }
6897
+ .boff-explore-body pre {
6898
+ overflow-x: auto;
6899
+ max-width: 100%;
6900
+ }
6901
+ .boff-explore-body table {
6902
+ display: block;
6903
+ overflow-x: auto;
6904
+ max-width: 100%;
6905
+ }
6906
+ .boff-explore-body img {
6907
+ max-width: 100%;
6908
+ height: auto;
6909
+ }
6910
+
6911
+ /* ---- Comparison and pricing tables ----------------------------------------------------
6912
+ The harness emits a comparison, and a set of plans, as a GFM table whose FIRST column is
6913
+ the subject \u2014 the product, or the plan (CONTRACT.md \xA77). Two things have to be true of it:
6914
+ the page must not scroll sideways because of it, and it has to be readable on a 320px
6915
+ phone, which a four-column grid of 1px borders is not.
6916
+
6917
+ Wide: a contained scroller. \`max-width: 100%\` keeps the box inside the bubble and
6918
+ \`overflow-x: auto\` keeps the columns inside the box, so the widest possible table still
6919
+ cannot widen the document. \`overscroll-behavior-x: contain\` stops a swipe that runs out
6920
+ of table from chaining to the page \u2014 the same rule the transcript needed. */
6921
+ .boff-explore-body .boff-explore-table {
6922
+ max-width: 100%;
6923
+ overflow-x: auto;
6924
+ overscroll-behavior-x: contain;
6925
+ margin: 0.75rem 0;
6926
+ border: 1px solid hsl(var(--border));
6927
+ border-radius: 0.75rem;
6928
+ background-color: hsl(var(--card));
6929
+ }
6930
+ .boff-explore-body .boff-explore-table:focus-visible {
6931
+ outline: 2px solid hsl(var(--ring));
6932
+ outline-offset: 2px;
6933
+ }
6934
+ .boff-explore-body .boff-explore-table table {
6935
+ /* Beats the blanket \`display: block\` above, which is the unwrapped fallback. */
6936
+ display: table;
6937
+ width: 100%;
6938
+ max-width: none;
6939
+ margin: 0;
6940
+ border-collapse: collapse;
6941
+ font-size: 0.8125rem;
6942
+ }
6943
+ .boff-explore-body .boff-explore-table th,
6944
+ .boff-explore-body .boff-explore-table td {
6945
+ border: 0;
6946
+ border-top: 1px solid hsl(var(--border));
6947
+ padding: 0.5rem 0.75rem;
6948
+ /* \`start\`, never \`left\`: the page root carries dir="rtl" in Arabic, and a left-aligned
6949
+ table there reads against the grain of every other line on the page. */
6950
+ text-align: start;
6951
+ vertical-align: top;
6952
+ overflow-wrap: anywhere;
6953
+ /* Prices in a column line up under each other instead of drifting by digit width. */
6954
+ font-variant-numeric: tabular-nums;
6955
+ min-width: 6rem;
6956
+ }
6957
+ .boff-explore-body .boff-explore-table thead th {
6958
+ border-top: 0;
6959
+ background-color: hsl(var(--muted));
6960
+ color: hsl(var(--foreground));
6961
+ font-weight: 600;
6962
+ white-space: nowrap;
6963
+ }
6964
+ /* The first column is what the row is ABOUT \u2014 the product, or the plan name. Reading it as
6965
+ the row's heading is what makes a price list scannable rather than a grid of strings. */
6966
+ .boff-explore-body .boff-explore-table tbody td:first-child {
6967
+ font-weight: 600;
6968
+ color: hsl(var(--card-foreground));
6969
+ }
6970
+
6971
+ /* Narrow: one card per row. Each cell prints its own column heading, so a value is never
6972
+ stranded without the question it answers, and the subject cell becomes the card's title.
6973
+ A media query rather than a measured width \u2014 these pages are serialised post-hydration,
6974
+ so anything measured here would ship to every phone as static HTML. */
6975
+ @media (max-width: 30rem) {
6976
+ .boff-explore-body .boff-explore-table {
6977
+ overflow-x: visible;
6525
6978
  }
6526
- `
6527
- );
6528
- var EXPLORE_CATALOG_ESTABLISHED_FIELDS = (
6529
- /* GraphQL */
6530
- `
6531
- enabled
6532
- products {
6533
- slug
6534
- name
6535
- tagline
6536
- website
6537
- }
6538
- examplePrompts
6539
- welcomeTitle
6540
- welcomeBody
6541
- limits {
6542
- maxMessageLength
6543
- maxTurnsPerConversation
6544
- messagesPerDay
6545
- historyTurns
6546
- }
6547
- captchaRequired
6548
- recaptchaSiteKey`
6549
- );
6550
- var EXPLORE_CATALOG_HIGHLIGHT_FIELD = (
6551
- /* GraphQL */
6552
- `
6553
- conceptHighlights {
6554
- product
6555
- productName
6556
- title
6557
- url
6558
- imageUrl
6559
- alt
6560
- }`
6561
- );
6562
- function exploreCatalogDocument(extraFields) {
6563
- return (
6564
- /* GraphQL */
6565
- `
6566
- query ExploreCatalog($productSlug: String) {
6567
- exploreCatalog(productSlug: $productSlug) {${EXPLORE_CATALOG_ESTABLISHED_FIELDS}${extraFields}
6568
- }
6979
+ .boff-explore-body .boff-explore-table table,
6980
+ .boff-explore-body .boff-explore-table tbody,
6981
+ .boff-explore-body .boff-explore-table tr,
6982
+ .boff-explore-body .boff-explore-table td {
6983
+ display: block;
6984
+ width: 100%;
6985
+ min-width: 0;
6569
6986
  }
6570
- `
6571
- );
6572
- }
6573
- var EXPLORE_CATALOG_QUERY = exploreCatalogDocument(
6574
- EXPLORE_CATALOG_HIGHLIGHT_FIELD
6575
- );
6576
- var EXPLORE_CATALOG_QUERY_WITHOUT_HIGHLIGHTS = exploreCatalogDocument("");
6577
- var EXPLORE_MESSAGE_QUERY = (
6578
- /* GraphQL */
6579
- `
6580
- query ExploreMessage($conversationToken: String!, $id: ID!) {
6581
- exploreMessage(conversationToken: $conversationToken, id: $id) {
6582
- ${EXPLORE_OWN_MESSAGE_FIELDS}
6583
- }
6987
+ .boff-explore-body .boff-explore-table thead {
6988
+ display: none;
6584
6989
  }
6585
- `
6586
- );
6587
- var SEND_EXPLORE_MESSAGE_MUTATION = (
6588
- /* GraphQL */
6589
- `
6590
- mutation SendExploreMessage($input: SendExploreMessageInput!) {
6591
- sendExploreMessage(input: $input) {
6592
- conversation {
6593
- id
6594
- token
6595
- productSlug
6596
- turnCount
6597
- createdAt
6598
- }
6599
- userMessage {
6600
- ${EXPLORE_OWN_MESSAGE_FIELDS}
6601
- }
6602
- assistantMessage {
6603
- ${EXPLORE_OWN_MESSAGE_FIELDS}
6604
- }
6605
- remainingToday
6606
- }
6990
+ .boff-explore-body .boff-explore-table tr {
6991
+ border-top: 1px solid hsl(var(--border));
6992
+ padding: 0.5rem 0;
6607
6993
  }
6608
- `
6609
- );
6610
- var RECORD_EXPLORE_CLICK_MUTATION = (
6611
- /* GraphQL */
6612
- `
6613
- mutation RecordExploreClick($input: RecordExploreClickInput!) {
6614
- recordExploreClick(input: $input) {
6615
- recorded
6616
- }
6994
+ .boff-explore-body .boff-explore-table tr:first-child {
6995
+ border-top: 0;
6617
6996
  }
6618
- `
6619
- );
6620
- var SUBMIT_EXPLORE_FEEDBACK_MUTATION = (
6621
- /* GraphQL */
6622
- `
6623
- mutation SubmitExploreFeedback($input: SubmitExploreFeedbackInput!) {
6624
- submitExploreFeedback(input: $input) {
6625
- recorded
6626
- feedback {
6627
- rating
6628
- reason
6629
- comment
6630
- createdAt
6631
- }
6632
- }
6997
+ .boff-explore-body .boff-explore-table td {
6998
+ border: 0;
6999
+ padding: 0.125rem 0.75rem;
6633
7000
  }
6634
- `
6635
- );
6636
- var EXPLORE_FEEDBACK_COMMENT_SOFT_MAX = 500;
6637
- var CREATE_EXPLORE_SHARE_LINK_MUTATION = (
6638
- /* GraphQL */
6639
- `
6640
- mutation CreateExploreShareLink($conversationToken: String!) {
6641
- createExploreShareLink(conversationToken: $conversationToken) {
6642
- shareToken
6643
- }
7001
+ .boff-explore-body .boff-explore-table td[data-label]::before {
7002
+ content: attr(data-label);
7003
+ display: block;
7004
+ font-size: 0.6875rem;
7005
+ font-weight: 600;
7006
+ text-transform: uppercase;
7007
+ letter-spacing: 0.04em;
7008
+ color: hsl(var(--muted-foreground));
6644
7009
  }
6645
- `
6646
- );
6647
- var EXPLORE_SHARED_CONVERSATION_QUERY = (
6648
- /* GraphQL */
6649
- `
6650
- query ExploreSharedConversation($shareToken: String!) {
6651
- exploreSharedConversation(shareToken: $shareToken) {
6652
- ${EXPLORE_MESSAGE_FIELDS}
7010
+ .boff-explore-body .boff-explore-table tbody td:first-child {
7011
+ font-size: 0.9375rem;
7012
+ padding-bottom: 0.25rem;
7013
+ }
7014
+ .boff-explore-body .boff-explore-table tbody td:first-child::before {
7015
+ /* The plan's own name is the heading here; repeating "Plan" over it says nothing. */
7016
+ display: none;
7017
+ }
7018
+ }
7019
+ `;
7020
+ function ExploreAnswerStyles() {
7021
+ return /* @__PURE__ */ jsxRuntime.jsx("style", { dangerouslySetInnerHTML: { __html: EXPLORE_ANSWER_CSS } });
7022
+ }
7023
+ function inlineImageOrigins(products) {
7024
+ const origins = /* @__PURE__ */ new Set();
7025
+ for (const product of products) {
7026
+ let url;
7027
+ try {
7028
+ url = new URL(product.website);
7029
+ } catch {
7030
+ continue;
6653
7031
  }
7032
+ if (url.protocol !== "https:") continue;
7033
+ const apex = url.hostname.replace(/^www\./, "");
7034
+ const port = url.port ? `:${url.port}` : "";
7035
+ origins.add(`https://${apex}${port}`);
7036
+ origins.add(`https://www.${apex}${port}`);
6654
7037
  }
6655
- `
6656
- );
7038
+ return origins;
7039
+ }
7040
+ function isInlineImageAllowed(src, origins) {
7041
+ if (typeof src !== "string" || src === "") return false;
7042
+ let url;
7043
+ try {
7044
+ url = new URL(src);
7045
+ } catch {
7046
+ return false;
7047
+ }
7048
+ if (url.protocol !== "https:" || url.username || url.password) return false;
7049
+ return origins.has(url.origin);
7050
+ }
7051
+ var CODE_FENCE = /^\s*(?:```|~~~)/;
7052
+ var TABLE_ROW_LINE = /^\s{0,3}\|/;
7053
+ var TABLE_DELIMITER_ROW = /^\s{0,3}\|[\s:|-]*-[\s:|-]*$/;
7054
+ function readableLine(raw, mode) {
7055
+ let line = raw;
7056
+ line = line.replace(/!\[[^\]]*\]\([^)\s]*(?:\s+"[^"]*")?\)/g, "");
7057
+ line = mode === "speech" ? (
7058
+ // A voice reading "h-t-t-p-s colon slash slash…" mid-sentence is noise, and the
7059
+ // prompt asks for two to five links in every answer. The label IS the words.
7060
+ line.replace(/\[([^\]]+)\]\(([^)\s]+)(?:\s+"[^"]*")?\)/g, "$1")
7061
+ ) : line.replace(/\[([^\]]+)\]\(([^)\s]+)(?:\s+"[^"]*")?\)/g, "$1 ($2)");
7062
+ line = mode === "speech" ? line.replace(/<(https?:\/\/[^>\s]+)>/g, "") : line.replace(/<(https?:\/\/[^>\s]+)>/g, "$1");
7063
+ line = line.replace(/^\s{0,3}#{1,6}\s+/, "");
7064
+ line = line.replace(/^\s{0,3}>\s?/, "");
7065
+ if (/^\s{0,3}([-*_])[ \t]*(?:\1[ \t]*){2,}$/.test(line)) return "";
7066
+ line = line.replace(/`([^`]+)`/g, "$1");
7067
+ line = line.replace(/\*\*([^*]+)\*\*/g, "$1");
7068
+ line = line.replace(/__([^_]+)__/g, "$1");
7069
+ line = line.replace(/(^|[^*\w])\*([^*\n]+)\*(?![*\w])/g, "$1$2");
7070
+ line = line.replace(/(^|[^_\w])_([^_\n]+)_(?![_\w])/g, "$1$2");
7071
+ return line.replace(/[ \t]+$/, "");
7072
+ }
7073
+ function tableCells(row) {
7074
+ const trimmed = row.trim();
7075
+ const cells = [];
7076
+ let cell = "";
7077
+ for (let at = 0; at < trimmed.length; at += 1) {
7078
+ const char = trimmed[at] ?? "";
7079
+ if (char === "\\") {
7080
+ cell += char + (trimmed[at + 1] ?? "");
7081
+ at += 1;
7082
+ continue;
7083
+ }
7084
+ if (char === "|") {
7085
+ cells.push(cell.trim());
7086
+ cell = "";
7087
+ continue;
7088
+ }
7089
+ cell += char;
7090
+ }
7091
+ cells.push(cell.trim());
7092
+ if (trimmed.startsWith("|") && cells[0] === "") cells.shift();
7093
+ if (trimmed.endsWith("|") && cells[cells.length - 1] === "") cells.pop();
7094
+ return cells;
7095
+ }
7096
+ function asSentence(text) {
7097
+ return /[.!?]$/.test(text) ? text : `${text}.`;
7098
+ }
7099
+ function spokenTable(rows) {
7100
+ if (rows.length < 2 || !TABLE_DELIMITER_ROW.test(rows[1] ?? "")) return rows;
7101
+ const labels = tableCells(rows[0] ?? "");
7102
+ const spoken = [];
7103
+ for (const row of rows.slice(2)) {
7104
+ const parts = [];
7105
+ tableCells(row).forEach((value, column) => {
7106
+ if (value === "") return;
7107
+ const label = column === 0 ? "" : labels[column] ?? "";
7108
+ parts.push(label === "" ? value : `${label}: ${value}`);
7109
+ });
7110
+ if (parts.length > 0) spoken.push(asSentence(parts.join(". ")));
7111
+ }
7112
+ return spoken;
7113
+ }
7114
+ function readableText(markdown, mode) {
7115
+ const lines = [];
7116
+ let inFence = false;
7117
+ let table = [];
7118
+ const flushTable = () => {
7119
+ if (table.length === 0) return;
7120
+ for (const line of spokenTable(table)) lines.push(readableLine(line, mode));
7121
+ table = [];
7122
+ };
7123
+ for (const raw of markdown.split("\n")) {
7124
+ if (CODE_FENCE.test(raw)) {
7125
+ flushTable();
7126
+ inFence = !inFence;
7127
+ continue;
7128
+ }
7129
+ if (inFence) {
7130
+ lines.push(raw);
7131
+ continue;
7132
+ }
7133
+ if (mode === "speech" && TABLE_ROW_LINE.test(raw)) {
7134
+ table.push(raw);
7135
+ continue;
7136
+ }
7137
+ flushTable();
7138
+ lines.push(readableLine(raw, mode));
7139
+ }
7140
+ flushTable();
7141
+ return lines.join("\n").replace(/\n{3,}/g, "\n\n").trim();
7142
+ }
7143
+ function answerPlainText(markdown) {
7144
+ return readableText(markdown, "clipboard");
7145
+ }
7146
+ function answerSpeechText(markdown) {
7147
+ return readableText(markdown, "speech");
7148
+ }
7149
+ var AnswerScopeContext = React.createContext(null);
7150
+ var InsideLinkContext = React.createContext(false);
7151
+ function AnswerLink(props) {
7152
+ return /* @__PURE__ */ jsxRuntime.jsx(InsideLinkContext.Provider, { value: true, children: /* @__PURE__ */ jsxRuntime.jsx(MarkdownLink, { ...props }) });
7153
+ }
7154
+ var INLINE_IMAGE_FRAME = "relative inline-block max-w-full overflow-hidden rounded-xl border border-border bg-muted align-top shadow-sm";
7155
+ function InlineConceptImage({ src, alt }) {
7156
+ const scope = React.useContext(AnswerScopeContext);
7157
+ const insideLink = React.useContext(InsideLinkContext);
7158
+ if (!scope || !scope.enabled || !isInlineImageAllowed(src, scope.origins) || scope.failed.has(src)) {
7159
+ return null;
7160
+ }
7161
+ const { strings: T, onFailed } = scope;
7162
+ const picture = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
7163
+ /* @__PURE__ */ jsxRuntime.jsx(
7164
+ "img",
7165
+ {
7166
+ src,
7167
+ alt: alt ?? "",
7168
+ loading: "lazy",
7169
+ decoding: "async",
7170
+ onError: () => onFailed(src),
7171
+ className: "block h-auto max-h-80 w-auto max-w-full object-contain"
7172
+ }
7173
+ ),
7174
+ /* @__PURE__ */ jsxRuntime.jsx(
7175
+ "span",
7176
+ {
7177
+ "aria-hidden": "true",
7178
+ className: "pointer-events-none absolute left-2 top-2 rounded-full border border-border bg-background/90 px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide text-foreground shadow-sm",
7179
+ children: T.conceptIllustration
7180
+ }
7181
+ )
7182
+ ] });
7183
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { "data-boff-explore": "inline-image", className: "my-3 block", children: insideLink ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: INLINE_IMAGE_FRAME, children: picture }) : /* @__PURE__ */ jsxRuntime.jsxs(
7184
+ "a",
7185
+ {
7186
+ href: src,
7187
+ target: "_blank",
7188
+ rel: "noopener noreferrer",
7189
+ className: cn(
7190
+ INLINE_IMAGE_FRAME,
7191
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
7192
+ ),
7193
+ children: [
7194
+ picture,
7195
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "sr-only", children: [
7196
+ "(",
7197
+ T.opensInNewTab,
7198
+ ")"
7199
+ ] })
7200
+ ]
7201
+ }
7202
+ ) });
7203
+ }
7204
+ function markdownText(node) {
7205
+ if (!node) return "";
7206
+ if (typeof node.value === "string") return node.value;
7207
+ return (node.children ?? []).map(markdownText).join("");
7208
+ }
7209
+ function hasHeaderCells(node) {
7210
+ return (node?.children ?? []).some((cell) => cell.tagName === "th");
7211
+ }
7212
+ function findHeaderRow(node) {
7213
+ for (const child of node?.children ?? []) {
7214
+ if (child.tagName === "tr" && hasHeaderCells(child)) return child;
7215
+ const nested = findHeaderRow(child);
7216
+ if (nested !== null) return nested;
7217
+ }
7218
+ return null;
7219
+ }
7220
+ function tableColumnLabels(node) {
7221
+ const row = findHeaderRow(node);
7222
+ if (row === null) return [];
7223
+ return (row.children ?? []).filter((cell) => cell.tagName === "th").map((cell) => markdownText(cell).trim());
7224
+ }
7225
+ var TableColumnsContext = React.createContext([]);
7226
+ function AnswerTable({ node, children }) {
7227
+ const scope = React.useContext(AnswerScopeContext);
7228
+ const table = /* @__PURE__ */ jsxRuntime.jsx(TableColumnsContext.Provider, { value: tableColumnLabels(node), children: /* @__PURE__ */ jsxRuntime.jsx("table", { children }) });
7229
+ if (!scope) return table;
7230
+ return /* @__PURE__ */ jsxRuntime.jsx(
7231
+ "div",
7232
+ {
7233
+ "data-boff-explore": "table",
7234
+ role: "region",
7235
+ "aria-label": scope.strings.answerTable,
7236
+ tabIndex: 0,
7237
+ className: "boff-explore-table",
7238
+ children: table
7239
+ }
7240
+ );
7241
+ }
7242
+ function AnswerTableRow({
7243
+ node,
7244
+ children,
7245
+ ...props
7246
+ }) {
7247
+ const labels = React.useContext(TableColumnsContext);
7248
+ if (labels.length === 0 || hasHeaderCells(node)) {
7249
+ return /* @__PURE__ */ jsxRuntime.jsx("tr", { ...props, children });
7250
+ }
7251
+ let column = 0;
7252
+ const cells = React.Children.map(children, (cell) => {
7253
+ if (!React.isValidElement(cell)) return cell;
7254
+ const label = labels[column] ?? "";
7255
+ column += 1;
7256
+ if (label === "") return cell;
7257
+ return React.cloneElement(cell, {
7258
+ "data-label": label
7259
+ });
7260
+ });
7261
+ return /* @__PURE__ */ jsxRuntime.jsx("tr", { ...props, children: cells });
7262
+ }
7263
+ var ANSWER_MARKDOWN_COMPONENTS = {
7264
+ a: AnswerLink,
7265
+ img: InlineConceptImage,
7266
+ table: AnswerTable,
7267
+ tr: AnswerTableRow
7268
+ };
7269
+ function ExploreAnswerBody({
7270
+ children,
7271
+ strings,
7272
+ imageOrigins,
7273
+ enabled = true,
7274
+ components,
7275
+ className
7276
+ }) {
7277
+ const [failed, setFailed] = React.useState(() => /* @__PURE__ */ new Set());
7278
+ const onFailed = React.useCallback((src) => {
7279
+ setFailed(
7280
+ (current) => current.has(src) ? current : new Set(current).add(src)
7281
+ );
7282
+ }, []);
7283
+ const scope = React.useMemo(
7284
+ () => ({
7285
+ strings,
7286
+ enabled,
7287
+ origins: imageOrigins,
7288
+ failed,
7289
+ onFailed
7290
+ }),
7291
+ [strings, enabled, imageOrigins, failed, onFailed]
7292
+ );
7293
+ const overrides = React.useMemo(
7294
+ () => components ? { ...ANSWER_MARKDOWN_COMPONENTS, ...components } : ANSWER_MARKDOWN_COMPONENTS,
7295
+ [components]
7296
+ );
7297
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("boff-prose boff-explore-body min-w-0", className), children: /* @__PURE__ */ jsxRuntime.jsx(AnswerScopeContext.Provider, { value: scope, children: /* @__PURE__ */ jsxRuntime.jsx(Markdown, { components: overrides, children }) }) });
7298
+ }
6657
7299
  var PROSE_CSS = `
6658
7300
  .boff-prose {
6659
7301
  max-width: none;
@@ -6830,6 +7472,1130 @@ var PROSE_CSS = `
6830
7472
  function ProseStyles() {
6831
7473
  return /* @__PURE__ */ jsxRuntime.jsx("style", { dangerouslySetInnerHTML: { __html: PROSE_CSS } });
6832
7474
  }
7475
+ var META_DESCRIPTION_LIMIT2 = 160;
7476
+ var TITLE_LIMIT = 100;
7477
+ var RELATED_LIMIT2 = 4;
7478
+ function normaliseSiteUrl2(siteUrl) {
7479
+ return siteUrl.trim().replace(/\/+$/, "");
7480
+ }
7481
+ function absoluteUrl2(base, path) {
7482
+ if (/^https?:\/\//i.test(path)) return path;
7483
+ return `${base}${path.startsWith("/") ? path : `/${path}`}`;
7484
+ }
7485
+ function sortByOrder2(answers) {
7486
+ return [...answers].sort(
7487
+ (a, b) => a.order - b.order || a.slug.localeCompare(b.slug)
7488
+ );
7489
+ }
7490
+ function clampText2(text, limit) {
7491
+ if (text.length <= limit) return text;
7492
+ const cut = text.slice(0, limit - 1);
7493
+ const lastSpace = cut.lastIndexOf(" ");
7494
+ return `${(lastSpace > 0 ? cut.slice(0, lastSpace) : cut).replace(/[\s,;:—–-]+$/, "")}\u2026`;
7495
+ }
7496
+ function questionCount(T, count) {
7497
+ return count === 1 ? T.questionCountOne : fill(T.questionCountMany, { count: String(count) });
7498
+ }
7499
+ function sourceCount(T, count) {
7500
+ return count === 1 ? T.sourceCountOne : fill(T.sourceCountMany, { count: String(count) });
7501
+ }
7502
+ function slugifyAnchor2(value) {
7503
+ return value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
7504
+ }
7505
+ function publishableSources(sources) {
7506
+ const seen = /* @__PURE__ */ new Set();
7507
+ const kept = [];
7508
+ for (const source of sources) {
7509
+ if (!isPublishedSourceUrl(source.url) || seen.has(source.url)) continue;
7510
+ seen.add(source.url);
7511
+ kept.push(source);
7512
+ }
7513
+ return kept;
7514
+ }
7515
+ function groupByTopic(ordered, topics) {
7516
+ const byName = /* @__PURE__ */ new Map();
7517
+ for (const answer of ordered) {
7518
+ const list = byName.get(answer.topic);
7519
+ if (list) list.push(answer);
7520
+ else byName.set(answer.topic, [answer]);
7521
+ }
7522
+ const described = [];
7523
+ for (const topic of topics ?? []) {
7524
+ const list = byName.get(topic.name);
7525
+ if (!list) continue;
7526
+ described.push({
7527
+ name: topic.name,
7528
+ description: topic.description,
7529
+ answers: list
7530
+ });
7531
+ byName.delete(topic.name);
7532
+ }
7533
+ for (const [name, list] of byName) {
7534
+ described.push({ name, description: "", answers: list });
7535
+ }
7536
+ const used = /* @__PURE__ */ new Set();
7537
+ return described.map((group) => {
7538
+ const base = `answers-${slugifyAnchor2(group.name) || "topic"}`;
7539
+ let anchor = base;
7540
+ for (let n = 2; used.has(anchor); n += 1) anchor = `${base}-${n}`;
7541
+ used.add(anchor);
7542
+ return { ...group, anchor };
7543
+ });
7544
+ }
7545
+ function searchTokens2(query) {
7546
+ return query.toLowerCase().split(/\s+/).filter(Boolean);
7547
+ }
7548
+ function matchesSearch2(answer, tokens) {
7549
+ if (tokens.length === 0) return true;
7550
+ const haystack = [
7551
+ answer.question,
7552
+ answer.summary,
7553
+ answer.topic,
7554
+ ...answer.keywords
7555
+ ].join(" ").toLowerCase();
7556
+ return tokens.every((token) => haystack.includes(token));
7557
+ }
7558
+ function copyKey2(index, text) {
7559
+ return `${index}-${text}`;
7560
+ }
7561
+ function demoteHeading(Tag) {
7562
+ function DemotedHeading({
7563
+ node: _node,
7564
+ ...props
7565
+ }) {
7566
+ return /* @__PURE__ */ jsxRuntime.jsx(Tag, { ...props });
7567
+ }
7568
+ DemotedHeading.displayName = `DemotedHeading(${Tag})`;
7569
+ return DemotedHeading;
7570
+ }
7571
+ var ANSWER_HEADING_SHIFT = {
7572
+ h1: demoteHeading("h3"),
7573
+ h2: demoteHeading("h3"),
7574
+ h3: demoteHeading("h4"),
7575
+ h4: demoteHeading("h5"),
7576
+ h5: demoteHeading("h6"),
7577
+ h6: demoteHeading("h6")
7578
+ };
7579
+ var ENGLISH_TEXT = { lang: "en" };
7580
+ function DefaultAnswerLink({
7581
+ href,
7582
+ className,
7583
+ children,
7584
+ "aria-label": ariaLabel
7585
+ }) {
7586
+ return /* @__PURE__ */ jsxRuntime.jsx("a", { href, className, "aria-label": ariaLabel, children });
7587
+ }
7588
+ function AnswerCard({
7589
+ answer,
7590
+ strings: T,
7591
+ Link
7592
+ }) {
7593
+ const sources = publishableSources(answer.sources).length;
7594
+ return /* @__PURE__ */ jsxRuntime.jsxs(
7595
+ Link,
7596
+ {
7597
+ href: answerPath(answer.slug),
7598
+ className: "group flex h-full flex-col gap-2 rounded-2xl border border-border bg-card p-5 text-card-foreground shadow-sm transition hover:-translate-y-0.5 hover:border-primary/40 hover:shadow-md focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring motion-reduce:transform-none motion-reduce:transition-none",
7599
+ children: [
7600
+ /* @__PURE__ */ jsxRuntime.jsx(
7601
+ "h3",
7602
+ {
7603
+ ...ENGLISH_TEXT,
7604
+ className: "text-base font-semibold leading-snug text-card-foreground transition-colors group-hover:text-primary",
7605
+ children: answer.question
7606
+ }
7607
+ ),
7608
+ /* @__PURE__ */ jsxRuntime.jsx(
7609
+ "p",
7610
+ {
7611
+ ...ENGLISH_TEXT,
7612
+ className: "line-clamp-3 text-sm leading-relaxed text-muted-foreground",
7613
+ children: answer.summary
7614
+ }
7615
+ ),
7616
+ sources > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "mt-auto inline-flex items-center gap-1.5 pt-2 text-xs font-medium text-muted-foreground", children: [
7617
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.BookOpenText, { "aria-hidden": "true", className: "h-3.5 w-3.5" }),
7618
+ sourceCount(T, sources)
7619
+ ] }) : null
7620
+ ]
7621
+ }
7622
+ );
7623
+ }
7624
+ function FilterChip2({
7625
+ label,
7626
+ count,
7627
+ active,
7628
+ topic,
7629
+ onSelect
7630
+ }) {
7631
+ return /* @__PURE__ */ jsxRuntime.jsxs(
7632
+ "button",
7633
+ {
7634
+ type: "button",
7635
+ "aria-pressed": active,
7636
+ "data-topic": topic,
7637
+ onClick: onSelect,
7638
+ className: cn(
7639
+ "inline-flex items-center gap-2 rounded-full border px-3 py-1.5 text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
7640
+ active ? "border-primary bg-primary text-primary-foreground" : "border-border bg-card text-foreground hover:border-primary/40 hover:bg-muted"
7641
+ ),
7642
+ children: [
7643
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: label }),
7644
+ /* @__PURE__ */ jsxRuntime.jsx(
7645
+ "span",
7646
+ {
7647
+ className: cn(
7648
+ "rounded-full px-1.5 text-xs tabular-nums",
7649
+ active ? "bg-primary-foreground/20 text-primary-foreground" : "bg-muted text-muted-foreground"
7650
+ ),
7651
+ children: count
7652
+ }
7653
+ )
7654
+ ]
7655
+ }
7656
+ );
7657
+ }
7658
+ function AnswersPage({
7659
+ productName,
7660
+ siteUrl,
7661
+ answers,
7662
+ topics,
7663
+ cta,
7664
+ linkComponent,
7665
+ title,
7666
+ description,
7667
+ locale,
7668
+ className
7669
+ }) {
7670
+ const Link = linkComponent ?? DefaultAnswerLink;
7671
+ const base = normaliseSiteUrl2(siteUrl);
7672
+ const searchId = React.useId();
7673
+ const activeLocale = React.useMemo(() => resolveExploreLocale(locale), [locale]);
7674
+ const T = React.useMemo(() => answerStrings(activeLocale), [activeLocale]);
7675
+ const rtl = isRtlLocale(activeLocale);
7676
+ const ordered = React.useMemo(() => sortByOrder2(answers), [answers]);
7677
+ const groups = React.useMemo(
7678
+ () => groupByTopic(ordered, topics),
7679
+ [ordered, topics]
7680
+ );
7681
+ const [query, setQuery] = React.useState("");
7682
+ const [activeTopic, setActiveTopic] = React.useState(null);
7683
+ const hasAnswers = ordered.length > 0;
7684
+ const tokens = React.useMemo(() => searchTokens2(query), [query]);
7685
+ const searched = React.useMemo(
7686
+ () => ordered.filter((answer) => matchesSearch2(answer, tokens)),
7687
+ [ordered, tokens]
7688
+ );
7689
+ const countsByTopic = React.useMemo(() => {
7690
+ const counts = /* @__PURE__ */ new Map();
7691
+ for (const answer of searched) {
7692
+ counts.set(answer.topic, (counts.get(answer.topic) ?? 0) + 1);
7693
+ }
7694
+ return counts;
7695
+ }, [searched]);
7696
+ const visibleGroups = React.useMemo(() => {
7697
+ const visible = new Set(
7698
+ searched.filter(
7699
+ (answer) => activeTopic === null || answer.topic === activeTopic
7700
+ )
7701
+ );
7702
+ return groups.map((group) => ({
7703
+ ...group,
7704
+ answers: group.answers.filter((answer) => visible.has(answer))
7705
+ })).filter((group) => group.answers.length > 0);
7706
+ }, [groups, searched, activeTopic]);
7707
+ const visibleTotal = visibleGroups.reduce(
7708
+ (sum, group) => sum + group.answers.length,
7709
+ 0
7710
+ );
7711
+ const filtering = tokens.length > 0 || activeTopic !== null;
7712
+ const clearFilters = React.useCallback(() => {
7713
+ setQuery("");
7714
+ setActiveTopic(null);
7715
+ }, []);
7716
+ const heading = title ?? fill(T.indexHeading, { product: productName });
7717
+ const metaDescription = description ?? clampText2(
7718
+ fill(T.seoIndexDescription, { product: productName }),
7719
+ META_DESCRIPTION_LIMIT2
7720
+ );
7721
+ const lead = description ?? fill(T.indexLead, { product: productName });
7722
+ const canonical = `${base}${ANSWERS_PATH}`;
7723
+ const structuredData = React.useMemo(
7724
+ () => [
7725
+ {
7726
+ "@context": "https://schema.org",
7727
+ "@type": "CollectionPage",
7728
+ name: heading,
7729
+ description: metaDescription,
7730
+ url: canonical,
7731
+ isPartOf: { "@type": "WebSite", name: productName, url: `${base}/` },
7732
+ mainEntity: {
7733
+ "@type": "ItemList",
7734
+ numberOfItems: ordered.length,
7735
+ itemListElement: ordered.map((answer, index) => ({
7736
+ "@type": "ListItem",
7737
+ position: index + 1,
7738
+ url: absoluteUrl2(base, answerPath(answer.slug)),
7739
+ name: answer.question
7740
+ }))
7741
+ }
7742
+ },
7743
+ {
7744
+ "@context": "https://schema.org",
7745
+ "@type": "BreadcrumbList",
7746
+ itemListElement: [
7747
+ {
7748
+ "@type": "ListItem",
7749
+ position: 1,
7750
+ name: T.breadcrumbHome,
7751
+ item: `${base}/`
7752
+ },
7753
+ {
7754
+ "@type": "ListItem",
7755
+ position: 2,
7756
+ name: T.answers,
7757
+ item: canonical
7758
+ }
7759
+ ]
7760
+ }
7761
+ ],
7762
+ [base, canonical, heading, metaDescription, ordered, productName, T]
7763
+ );
7764
+ return /* @__PURE__ */ jsxRuntime.jsxs(
7765
+ "div",
7766
+ {
7767
+ "data-answers": "landing",
7768
+ "data-locale": activeLocale,
7769
+ dir: rtl ? "rtl" : void 0,
7770
+ className: cn("bg-background text-foreground", className),
7771
+ children: [
7772
+ /* @__PURE__ */ jsxRuntime.jsx(
7773
+ PageHead,
7774
+ {
7775
+ title: T.seoIndexTitle,
7776
+ description: metaDescription,
7777
+ productName,
7778
+ keywords: [
7779
+ fill(T.indexHeading, { product: productName }),
7780
+ ...groups.map((group) => group.name)
7781
+ ].join(", "),
7782
+ url: canonical,
7783
+ structuredData
7784
+ }
7785
+ ),
7786
+ /* @__PURE__ */ jsxRuntime.jsx("section", { className: "border-b border-border bg-muted/30", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mx-auto max-w-6xl px-4 py-14 sm:px-6 sm:py-20 lg:px-8", children: [
7787
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs font-semibold uppercase tracking-[0.2em] text-primary", children: T.answers }),
7788
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "mt-3 max-w-3xl text-4xl font-bold tracking-tight text-foreground sm:text-5xl", children: heading }),
7789
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-4 max-w-2xl text-lg leading-relaxed text-muted-foreground", children: lead }),
7790
+ hasAnswers ? /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "mt-6 text-sm text-muted-foreground", children: [
7791
+ /* @__PURE__ */ jsxRuntime.jsx("strong", { className: "text-lg font-semibold text-foreground", children: ordered.length }),
7792
+ " ",
7793
+ questionCount(T, ordered.length)
7794
+ ] }) : null,
7795
+ cta ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-8 flex flex-wrap gap-3", children: cta }) : null
7796
+ ] }) }),
7797
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mx-auto max-w-6xl px-4 pb-20 sm:px-6 lg:px-8", children: hasAnswers ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
7798
+ /* @__PURE__ */ jsxRuntime.jsxs(
7799
+ "div",
7800
+ {
7801
+ role: "search",
7802
+ "data-answers": "filter",
7803
+ className: "flex flex-col gap-4 py-8",
7804
+ children: [
7805
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative w-full max-w-md", children: [
7806
+ /* @__PURE__ */ jsxRuntime.jsx(
7807
+ lucideReact.Search,
7808
+ {
7809
+ "aria-hidden": "true",
7810
+ className: "pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground"
7811
+ }
7812
+ ),
7813
+ /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: searchId, className: "sr-only", children: T.searchLabel }),
7814
+ /* @__PURE__ */ jsxRuntime.jsx(
7815
+ "input",
7816
+ {
7817
+ id: searchId,
7818
+ type: "search",
7819
+ value: query,
7820
+ onChange: (event) => setQuery(event.target.value),
7821
+ placeholder: T.searchPlaceholder,
7822
+ autoComplete: "off",
7823
+ className: "h-10 w-full rounded-lg border border-border bg-background pl-9 pr-3 text-sm text-foreground shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
7824
+ }
7825
+ )
7826
+ ] }),
7827
+ /* @__PURE__ */ jsxRuntime.jsxs(
7828
+ "div",
7829
+ {
7830
+ role: "group",
7831
+ "aria-label": T.filterByTopic,
7832
+ className: "flex flex-wrap gap-2",
7833
+ children: [
7834
+ /* @__PURE__ */ jsxRuntime.jsx(
7835
+ FilterChip2,
7836
+ {
7837
+ label: T.allTopics,
7838
+ topic: "all",
7839
+ count: searched.length,
7840
+ active: activeTopic === null,
7841
+ onSelect: () => setActiveTopic(null)
7842
+ }
7843
+ ),
7844
+ groups.map((group) => /* @__PURE__ */ jsxRuntime.jsx(
7845
+ FilterChip2,
7846
+ {
7847
+ label: group.name,
7848
+ topic: group.name,
7849
+ count: countsByTopic.get(group.name) ?? 0,
7850
+ active: activeTopic === group.name,
7851
+ onSelect: () => setActiveTopic(
7852
+ (current) => current === group.name ? null : group.name
7853
+ )
7854
+ },
7855
+ group.anchor
7856
+ ))
7857
+ ]
7858
+ }
7859
+ ),
7860
+ /* @__PURE__ */ jsxRuntime.jsx(
7861
+ "p",
7862
+ {
7863
+ "aria-live": "polite",
7864
+ className: filtering ? "text-sm text-muted-foreground" : "sr-only",
7865
+ children: fill(T.showingCount, {
7866
+ shown: String(visibleTotal),
7867
+ total: String(ordered.length)
7868
+ })
7869
+ }
7870
+ )
7871
+ ]
7872
+ }
7873
+ ),
7874
+ visibleTotal === 0 ? /* @__PURE__ */ jsxRuntime.jsxs(
7875
+ "div",
7876
+ {
7877
+ "data-answers": "empty",
7878
+ className: "rounded-2xl border border-dashed border-border bg-muted/30 px-6 py-14 text-center",
7879
+ children: [
7880
+ /* @__PURE__ */ jsxRuntime.jsx(
7881
+ lucideReact.Search,
7882
+ {
7883
+ "aria-hidden": "true",
7884
+ className: "mx-auto h-8 w-8 text-muted-foreground"
7885
+ }
7886
+ ),
7887
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "mt-4 text-lg font-semibold text-foreground", children: T.noMatchesTitle }),
7888
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 text-sm text-muted-foreground", children: T.noMatchesBody }),
7889
+ /* @__PURE__ */ jsxRuntime.jsx(
7890
+ "button",
7891
+ {
7892
+ type: "button",
7893
+ onClick: clearFilters,
7894
+ className: "mt-6 inline-flex items-center rounded-full border border-border bg-card px-4 py-2 text-sm font-medium text-foreground transition-colors hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
7895
+ children: T.clearFilters
7896
+ }
7897
+ )
7898
+ ]
7899
+ }
7900
+ ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-14", children: visibleGroups.map((group) => /* @__PURE__ */ jsxRuntime.jsxs("section", { "aria-labelledby": group.anchor, children: [
7901
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "max-w-3xl", children: [
7902
+ /* @__PURE__ */ jsxRuntime.jsx(
7903
+ "h2",
7904
+ {
7905
+ id: group.anchor,
7906
+ className: "scroll-mt-24 text-2xl font-semibold tracking-tight text-foreground",
7907
+ children: group.name
7908
+ }
7909
+ ),
7910
+ group.description ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 leading-relaxed text-muted-foreground", children: group.description }) : null
7911
+ ] }),
7912
+ /* @__PURE__ */ jsxRuntime.jsx(
7913
+ "ul",
7914
+ {
7915
+ role: "list",
7916
+ className: "mt-6 grid grid-cols-1 gap-5 sm:grid-cols-2 lg:grid-cols-3",
7917
+ children: group.answers.map((answer) => /* @__PURE__ */ jsxRuntime.jsx(
7918
+ "li",
7919
+ {
7920
+ "data-answers": "card",
7921
+ "data-slug": answer.slug,
7922
+ children: /* @__PURE__ */ jsxRuntime.jsx(AnswerCard, { answer, strings: T, Link })
7923
+ },
7924
+ answer.slug
7925
+ ))
7926
+ }
7927
+ )
7928
+ ] }, group.anchor)) })
7929
+ ] }) : (
7930
+ // Nothing published yet: no filter bar with an "All 0" chip, and no empty state
7931
+ // that blames filters the visitor never set.
7932
+ /* @__PURE__ */ jsxRuntime.jsxs(
7933
+ "div",
7934
+ {
7935
+ "data-answers": "none",
7936
+ className: "mt-10 rounded-2xl border border-dashed border-border bg-muted/30 px-6 py-14 text-center",
7937
+ children: [
7938
+ /* @__PURE__ */ jsxRuntime.jsx(
7939
+ lucideReact.Sparkles,
7940
+ {
7941
+ "aria-hidden": "true",
7942
+ className: "mx-auto h-8 w-8 text-muted-foreground"
7943
+ }
7944
+ ),
7945
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "mt-4 text-lg font-semibold text-foreground", children: T.noneYetTitle }),
7946
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 text-sm text-muted-foreground", children: fill(T.noneYetBody, { product: productName }) })
7947
+ ]
7948
+ }
7949
+ )
7950
+ ) })
7951
+ ]
7952
+ }
7953
+ );
7954
+ }
7955
+ var SECTION_HEADING2 = "scroll-mt-24 text-2xl font-semibold tracking-tight text-foreground";
7956
+ var CHIP2 = "inline-flex items-center rounded-full border border-border bg-muted/50 px-3 py-1 text-sm text-foreground";
7957
+ function ProvenanceNote({
7958
+ strings: T,
7959
+ date,
7960
+ className
7961
+ }) {
7962
+ return /* @__PURE__ */ jsxRuntime.jsxs(
7963
+ "div",
7964
+ {
7965
+ role: "note",
7966
+ "aria-label": T.aboutTitle,
7967
+ "data-answers": "provenance",
7968
+ className: cn(
7969
+ "flex items-start gap-3 rounded-xl border border-primary/30 bg-primary/10 px-4 py-3 text-sm leading-relaxed text-foreground",
7970
+ className
7971
+ ),
7972
+ children: [
7973
+ /* @__PURE__ */ jsxRuntime.jsx(
7974
+ lucideReact.Info,
7975
+ {
7976
+ "aria-hidden": "true",
7977
+ className: "mt-0.5 h-4 w-4 shrink-0 text-primary"
7978
+ }
7979
+ ),
7980
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
7981
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-semibold", children: T.aboutTitle }),
7982
+ " \u2014 ",
7983
+ fill(T.aboutBody, { date })
7984
+ ] })
7985
+ ]
7986
+ }
7987
+ );
7988
+ }
7989
+ function SourceLink({
7990
+ source,
7991
+ strings: T
7992
+ }) {
7993
+ const host = answerSourceHost(source.url);
7994
+ return /* @__PURE__ */ jsxRuntime.jsxs(
7995
+ "a",
7996
+ {
7997
+ "data-answers": "source",
7998
+ href: source.url,
7999
+ target: "_blank",
8000
+ rel: "noopener noreferrer",
8001
+ className: "group flex h-full flex-col gap-1.5 rounded-xl border border-border bg-card p-4 text-card-foreground transition-colors hover:border-primary/40 hover:bg-accent/40 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
8002
+ children: [
8003
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-semibold leading-snug transition-colors group-hover:text-primary", children: source.title || host || source.url }),
8004
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "mt-auto flex items-center gap-2 pt-1 text-xs text-muted-foreground", children: [
8005
+ source.product ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "rounded-full bg-secondary px-2 py-0.5 font-medium text-secondary-foreground", children: source.product }) : null,
8006
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex min-w-0 items-center gap-1", children: [
8007
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ExternalLink, { "aria-hidden": "true", className: "h-3 w-3 shrink-0" }),
8008
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: host })
8009
+ ] })
8010
+ ] }),
8011
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "sr-only", children: [
8012
+ "(",
8013
+ T.opensInNewTab,
8014
+ ")"
8015
+ ] })
8016
+ ]
8017
+ }
8018
+ );
8019
+ }
8020
+ function AnswerDetailPage(props) {
8021
+ return /* @__PURE__ */ jsxRuntime.jsx(AnswerDetail, { ...props }, props.answer.slug);
8022
+ }
8023
+ function AnswerDetail({
8024
+ productName,
8025
+ siteUrl,
8026
+ answer,
8027
+ answers,
8028
+ topics,
8029
+ imageOrigins,
8030
+ askHref = "/explore",
8031
+ cta,
8032
+ linkComponent,
8033
+ locale,
8034
+ className
8035
+ }) {
8036
+ const Link = linkComponent ?? DefaultAnswerLink;
8037
+ const base = normaliseSiteUrl2(siteUrl);
8038
+ const headingId = React.useId();
8039
+ const activeLocale = React.useMemo(() => resolveExploreLocale(locale), [locale]);
8040
+ const T = React.useMemo(() => answerStrings(activeLocale), [activeLocale]);
8041
+ const rtl = isRtlLocale(activeLocale);
8042
+ const dateLabel = React.useMemo(
8043
+ () => formatAnswerDate(answer.answeredAt, activeLocale),
8044
+ [answer.answeredAt, activeLocale]
8045
+ );
8046
+ const ordered = React.useMemo(() => sortByOrder2(answers), [answers]);
8047
+ const position = ordered.findIndex((item) => item.slug === answer.slug);
8048
+ const previous = position > 0 ? ordered[position - 1] : void 0;
8049
+ const next = position >= 0 && position < ordered.length - 1 ? ordered[position + 1] : void 0;
8050
+ const related = React.useMemo(() => {
8051
+ const bySlug = new Map(ordered.map((item) => [item.slug, item]));
8052
+ const curated = [...new Set(answer.related)].map((slug) => bySlug.get(slug)).filter(
8053
+ (item) => item !== void 0 && item.slug !== answer.slug
8054
+ );
8055
+ const list = curated.length > 0 ? curated : ordered.filter(
8056
+ (item) => item.topic === answer.topic && item.slug !== answer.slug
8057
+ );
8058
+ return list.slice(0, RELATED_LIMIT2);
8059
+ }, [answer, ordered]);
8060
+ const relatedIsCurated = answer.related.some(
8061
+ (slug) => related.some((item) => item.slug === slug)
8062
+ );
8063
+ const topicDescription = topics?.find(
8064
+ (topic) => topic.name === answer.topic
8065
+ )?.description;
8066
+ const sources = React.useMemo(
8067
+ () => publishableSources(answer.sources),
8068
+ [answer.sources]
8069
+ );
8070
+ const answerImageOrigins = React.useMemo(
8071
+ () => inlineImageOrigins([
8072
+ { website: base },
8073
+ ...sources.map((source) => ({ website: source.url })),
8074
+ ...(imageOrigins ?? []).map((origin) => ({ website: origin }))
8075
+ ]),
8076
+ [base, sources, imageOrigins]
8077
+ );
8078
+ const canonical = absoluteUrl2(base, answerPath(answer.slug));
8079
+ const answerText = React.useMemo(
8080
+ () => answerSpeechText(answer.answer),
8081
+ [answer.answer]
8082
+ );
8083
+ const structuredData = React.useMemo(
8084
+ () => [
8085
+ {
8086
+ "@context": "https://schema.org",
8087
+ "@type": "FAQPage",
8088
+ name: answer.question,
8089
+ description: answer.metaDescription,
8090
+ url: canonical,
8091
+ inLanguage: "en",
8092
+ isPartOf: { "@type": "WebSite", name: productName, url: `${base}/` },
8093
+ mainEntity: {
8094
+ "@type": "Question",
8095
+ name: answer.question,
8096
+ text: answer.question,
8097
+ answerCount: 1,
8098
+ acceptedAnswer: {
8099
+ "@type": "Answer",
8100
+ text: answerText,
8101
+ url: canonical,
8102
+ dateCreated: answer.answeredAt,
8103
+ // The organisation published it. Naming a person would be the one outright
8104
+ // false claim these pages could make.
8105
+ author: { "@type": "Organization", name: productName },
8106
+ ...sources.length > 0 ? {
8107
+ citation: sources.map((source) => ({
8108
+ "@type": "WebPage",
8109
+ name: source.title,
8110
+ url: source.url
8111
+ }))
8112
+ } : {}
8113
+ }
8114
+ }
8115
+ },
8116
+ {
8117
+ "@context": "https://schema.org",
8118
+ "@type": "BreadcrumbList",
8119
+ itemListElement: [
8120
+ {
8121
+ "@type": "ListItem",
8122
+ position: 1,
8123
+ name: T.breadcrumbHome,
8124
+ item: `${base}/`
8125
+ },
8126
+ {
8127
+ "@type": "ListItem",
8128
+ position: 2,
8129
+ name: T.answers,
8130
+ item: `${base}${ANSWERS_PATH}`
8131
+ },
8132
+ {
8133
+ "@type": "ListItem",
8134
+ position: 3,
8135
+ name: answer.question,
8136
+ item: canonical
8137
+ }
8138
+ ]
8139
+ }
8140
+ ],
8141
+ [answer, answerText, base, canonical, productName, sources, T]
8142
+ );
8143
+ return /* @__PURE__ */ jsxRuntime.jsxs(
8144
+ "article",
8145
+ {
8146
+ "data-answers": "detail",
8147
+ "data-slug": answer.slug,
8148
+ "data-locale": activeLocale,
8149
+ "aria-labelledby": headingId,
8150
+ dir: rtl ? "rtl" : void 0,
8151
+ className: cn("bg-background text-foreground", className),
8152
+ children: [
8153
+ /* @__PURE__ */ jsxRuntime.jsx(
8154
+ PageHead,
8155
+ {
8156
+ title: clampText2(answer.question, TITLE_LIMIT),
8157
+ description: answer.metaDescription,
8158
+ productName,
8159
+ keywords: answer.keywords.join(", "),
8160
+ url: canonical,
8161
+ structuredData
8162
+ }
8163
+ ),
8164
+ /* @__PURE__ */ jsxRuntime.jsx(ProseStyles, {}),
8165
+ /* @__PURE__ */ jsxRuntime.jsx(ExploreAnswerStyles, {}),
8166
+ /* @__PURE__ */ jsxRuntime.jsx("header", { className: "border-b border-border bg-muted/30", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mx-auto max-w-4xl px-4 pb-10 pt-8 sm:px-6 lg:px-8", children: [
8167
+ /* @__PURE__ */ jsxRuntime.jsx("nav", { "aria-label": "Breadcrumb", children: /* @__PURE__ */ jsxRuntime.jsxs("ol", { className: "flex flex-wrap items-center gap-1.5 text-sm text-muted-foreground", children: [
8168
+ /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "inline-flex items-center gap-1.5", children: [
8169
+ /* @__PURE__ */ jsxRuntime.jsx(
8170
+ Link,
8171
+ {
8172
+ href: "/",
8173
+ className: "rounded hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
8174
+ children: T.breadcrumbHome
8175
+ }
8176
+ ),
8177
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { "aria-hidden": "true", className: "h-3.5 w-3.5" })
8178
+ ] }),
8179
+ /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "inline-flex items-center gap-1.5", children: [
8180
+ /* @__PURE__ */ jsxRuntime.jsx(
8181
+ Link,
8182
+ {
8183
+ href: ANSWERS_PATH,
8184
+ className: "rounded hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
8185
+ children: T.answers
8186
+ }
8187
+ ),
8188
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { "aria-hidden": "true", className: "h-3.5 w-3.5" })
8189
+ ] }),
8190
+ /* @__PURE__ */ jsxRuntime.jsx(
8191
+ "li",
8192
+ {
8193
+ "aria-current": "page",
8194
+ ...ENGLISH_TEXT,
8195
+ className: "min-w-0 truncate text-foreground",
8196
+ children: answer.question
8197
+ }
8198
+ )
8199
+ ] }) }),
8200
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-6 flex flex-wrap items-center gap-2", children: [
8201
+ /* @__PURE__ */ jsxRuntime.jsx(
8202
+ "span",
8203
+ {
8204
+ "data-answers": "topic",
8205
+ title: topicDescription,
8206
+ className: "inline-flex items-center rounded-full border border-primary/30 bg-primary/10 px-3 py-1 text-xs font-semibold text-primary",
8207
+ children: answer.topic
8208
+ }
8209
+ ),
8210
+ dateLabel ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-flex items-center rounded-full border border-border bg-background px-3 py-1 text-xs font-medium text-muted-foreground", children: /* @__PURE__ */ jsxRuntime.jsx("time", { dateTime: answer.answeredAt, children: fill(T.answeredOn, { date: dateLabel }) }) }) : null
8211
+ ] }),
8212
+ /* @__PURE__ */ jsxRuntime.jsx(
8213
+ "h1",
8214
+ {
8215
+ id: headingId,
8216
+ ...ENGLISH_TEXT,
8217
+ className: "mt-4 text-3xl font-bold tracking-tight text-foreground sm:text-4xl",
8218
+ children: answer.question
8219
+ }
8220
+ ),
8221
+ answer.summary ? /* @__PURE__ */ jsxRuntime.jsx(
8222
+ "p",
8223
+ {
8224
+ ...ENGLISH_TEXT,
8225
+ className: "mt-4 text-lg leading-relaxed text-muted-foreground",
8226
+ children: answer.summary
8227
+ }
8228
+ ) : null,
8229
+ /* @__PURE__ */ jsxRuntime.jsx(ProvenanceNote, { strings: T, date: dateLabel, className: "mt-6" })
8230
+ ] }) }),
8231
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mx-auto max-w-4xl px-4 py-12 sm:px-6 lg:px-8", children: [
8232
+ /* @__PURE__ */ jsxRuntime.jsxs("section", { "aria-labelledby": `${headingId}-answer`, children: [
8233
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { id: `${headingId}-answer`, className: SECTION_HEADING2, children: T.answerHeading }),
8234
+ /* @__PURE__ */ jsxRuntime.jsx("div", { "data-answers": "body", ...ENGLISH_TEXT, dir: "ltr", children: /* @__PURE__ */ jsxRuntime.jsx(
8235
+ ExploreAnswerBody,
8236
+ {
8237
+ strings: T,
8238
+ imageOrigins: answerImageOrigins,
8239
+ components: ANSWER_HEADING_SHIFT,
8240
+ className: "mt-4",
8241
+ children: answer.answer
8242
+ }
8243
+ ) })
8244
+ ] }),
8245
+ sources.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs(
8246
+ "section",
8247
+ {
8248
+ "aria-labelledby": `${headingId}-sources`,
8249
+ "data-answers": "sources",
8250
+ className: "mt-14",
8251
+ children: [
8252
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { id: `${headingId}-sources`, className: SECTION_HEADING2, children: T.sourcesHeading }),
8253
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 text-muted-foreground", children: T.sourcesLead }),
8254
+ /* @__PURE__ */ jsxRuntime.jsx(
8255
+ "ul",
8256
+ {
8257
+ role: "list",
8258
+ className: "mt-6 grid grid-cols-1 gap-4 sm:grid-cols-2",
8259
+ children: sources.map((source) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsx(SourceLink, { source, strings: T }) }, source.url))
8260
+ }
8261
+ )
8262
+ ]
8263
+ }
8264
+ ) : null,
8265
+ answer.keywords.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("section", { "aria-labelledby": `${headingId}-topics`, className: "mt-14", children: [
8266
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { id: `${headingId}-topics`, className: SECTION_HEADING2, children: T.topicsHeading }),
8267
+ /* @__PURE__ */ jsxRuntime.jsx("ul", { role: "list", className: "mt-4 flex flex-wrap gap-2", children: answer.keywords.map((keyword, index) => /* @__PURE__ */ jsxRuntime.jsx("li", { className: CHIP2, children: keyword }, copyKey2(index, keyword))) })
8268
+ ] }) : null,
8269
+ related.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs(
8270
+ "section",
8271
+ {
8272
+ "aria-labelledby": `${headingId}-related`,
8273
+ "data-answers": "related",
8274
+ className: "mt-14",
8275
+ children: [
8276
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { id: `${headingId}-related`, className: SECTION_HEADING2, children: relatedIsCurated ? T.relatedHeading : fill(T.moreInTopic, { topic: answer.topic }) }),
8277
+ /* @__PURE__ */ jsxRuntime.jsx(
8278
+ "ul",
8279
+ {
8280
+ role: "list",
8281
+ className: "mt-6 grid grid-cols-1 gap-5 sm:grid-cols-2",
8282
+ children: related.map((item) => /* @__PURE__ */ jsxRuntime.jsx("li", { "data-answers": "card", "data-slug": item.slug, children: /* @__PURE__ */ jsxRuntime.jsx(AnswerCard, { answer: item, strings: T, Link }) }, item.slug))
8283
+ }
8284
+ )
8285
+ ]
8286
+ }
8287
+ ) : null,
8288
+ previous || next ? /* @__PURE__ */ jsxRuntime.jsxs(
8289
+ "nav",
8290
+ {
8291
+ "aria-label": `${T.previousQuestion} / ${T.nextQuestion}`,
8292
+ "data-answers": "pager",
8293
+ className: "mt-14 grid gap-4 sm:grid-cols-2",
8294
+ children: [
8295
+ previous ? /* @__PURE__ */ jsxRuntime.jsxs(
8296
+ Link,
8297
+ {
8298
+ href: answerPath(previous.slug),
8299
+ className: "group flex items-center gap-3 rounded-2xl border border-border bg-card p-4 text-card-foreground transition-colors hover:border-primary/40 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
8300
+ children: [
8301
+ /* @__PURE__ */ jsxRuntime.jsx(
8302
+ lucideReact.ArrowLeft,
8303
+ {
8304
+ "aria-hidden": "true",
8305
+ className: "h-5 w-5 shrink-0 text-muted-foreground transition-colors group-hover:text-primary"
8306
+ }
8307
+ ),
8308
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "min-w-0", children: [
8309
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "block text-xs font-medium uppercase tracking-wide text-muted-foreground", children: T.previousQuestion }),
8310
+ /* @__PURE__ */ jsxRuntime.jsx(
8311
+ "span",
8312
+ {
8313
+ ...ENGLISH_TEXT,
8314
+ className: "block truncate font-semibold",
8315
+ children: previous.question
8316
+ }
8317
+ )
8318
+ ] })
8319
+ ]
8320
+ }
8321
+ ) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "hidden sm:block" }),
8322
+ next ? /* @__PURE__ */ jsxRuntime.jsxs(
8323
+ Link,
8324
+ {
8325
+ href: answerPath(next.slug),
8326
+ className: "group flex items-center justify-end gap-3 rounded-2xl border border-border bg-card p-4 text-right text-card-foreground transition-colors hover:border-primary/40 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
8327
+ children: [
8328
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "min-w-0", children: [
8329
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "block text-xs font-medium uppercase tracking-wide text-muted-foreground", children: T.nextQuestion }),
8330
+ /* @__PURE__ */ jsxRuntime.jsx(
8331
+ "span",
8332
+ {
8333
+ ...ENGLISH_TEXT,
8334
+ className: "block truncate font-semibold",
8335
+ children: next.question
8336
+ }
8337
+ )
8338
+ ] }),
8339
+ /* @__PURE__ */ jsxRuntime.jsx(
8340
+ lucideReact.ArrowRight,
8341
+ {
8342
+ "aria-hidden": "true",
8343
+ className: "h-5 w-5 shrink-0 text-muted-foreground transition-colors group-hover:text-primary"
8344
+ }
8345
+ )
8346
+ ]
8347
+ }
8348
+ ) : null
8349
+ ]
8350
+ }
8351
+ ) : null,
8352
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-10 flex flex-wrap items-center gap-x-6 gap-y-3", children: [
8353
+ /* @__PURE__ */ jsxRuntime.jsxs(
8354
+ Link,
8355
+ {
8356
+ href: ANSWERS_PATH,
8357
+ className: "inline-flex items-center gap-2 rounded text-sm font-medium text-primary hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
8358
+ children: [
8359
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowLeft, { "aria-hidden": "true", className: "h-4 w-4" }),
8360
+ fill(T.allAnswers, { product: productName })
8361
+ ]
8362
+ }
8363
+ ),
8364
+ askHref ? /* @__PURE__ */ jsxRuntime.jsxs(
8365
+ Link,
8366
+ {
8367
+ href: askHref,
8368
+ className: "inline-flex items-center gap-2 rounded text-sm font-medium text-primary hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
8369
+ children: [
8370
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Sparkles, { "aria-hidden": "true", className: "h-4 w-4" }),
8371
+ T.askYourOwn
8372
+ ]
8373
+ }
8374
+ ) : null
8375
+ ] })
8376
+ ] }),
8377
+ cta ? /* @__PURE__ */ jsxRuntime.jsx(
8378
+ "section",
8379
+ {
8380
+ "data-answers": "cta",
8381
+ className: "border-t border-border bg-muted/30",
8382
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mx-auto flex max-w-4xl flex-wrap items-center gap-4 px-4 py-12 sm:px-6 lg:px-8", children: cta })
8383
+ }
8384
+ ) : null
8385
+ ]
8386
+ }
8387
+ );
8388
+ }
8389
+
8390
+ // src/components/explore-types.ts
8391
+ var EXPLORE_FEEDBACK_REASONS = [
8392
+ "INACCURATE",
8393
+ "INCOMPLETE",
8394
+ "OFF_TOPIC",
8395
+ "HARD_TO_FOLLOW",
8396
+ "OTHER"
8397
+ ];
8398
+ var EXPLORE_MESSAGE_FIELDS = (
8399
+ /* GraphQL */
8400
+ `
8401
+ id
8402
+ conversationId
8403
+ role
8404
+ status
8405
+ content
8406
+ partialContent
8407
+ activity
8408
+ references {
8409
+ url
8410
+ title
8411
+ description
8412
+ product
8413
+ imageUrl
8414
+ index
8415
+ }
8416
+ ctas {
8417
+ kind
8418
+ label
8419
+ url
8420
+ product
8421
+ }
8422
+ followUps
8423
+ answered
8424
+ attachments {
8425
+ name
8426
+ mimeType
8427
+ size
8428
+ textExtracted
8429
+ }
8430
+ errorCode
8431
+ createdAt
8432
+ completedAt
8433
+ `
8434
+ );
8435
+ var EXPLORE_OWN_MESSAGE_FIELDS = (
8436
+ /* GraphQL */
8437
+ `
8438
+ ${EXPLORE_MESSAGE_FIELDS}
8439
+ feedback {
8440
+ rating
8441
+ reason
8442
+ comment
8443
+ createdAt
8444
+ }
8445
+ `
8446
+ );
8447
+ var EXPLORE_CATALOG_ESTABLISHED_FIELDS = (
8448
+ /* GraphQL */
8449
+ `
8450
+ enabled
8451
+ products {
8452
+ slug
8453
+ name
8454
+ tagline
8455
+ website
8456
+ }
8457
+ examplePrompts
8458
+ welcomeTitle
8459
+ welcomeBody
8460
+ limits {
8461
+ maxMessageLength
8462
+ maxTurnsPerConversation
8463
+ messagesPerDay
8464
+ historyTurns
8465
+ }
8466
+ captchaRequired
8467
+ recaptchaSiteKey`
8468
+ );
8469
+ var EXPLORE_CATALOG_HIGHLIGHT_FIELD = (
8470
+ /* GraphQL */
8471
+ `
8472
+ conceptHighlights {
8473
+ product
8474
+ productName
8475
+ title
8476
+ url
8477
+ imageUrl
8478
+ alt
8479
+ }`
8480
+ );
8481
+ function exploreCatalogDocument(extraFields) {
8482
+ return (
8483
+ /* GraphQL */
8484
+ `
8485
+ query ExploreCatalog($productSlug: String) {
8486
+ exploreCatalog(productSlug: $productSlug) {${EXPLORE_CATALOG_ESTABLISHED_FIELDS}${extraFields}
8487
+ }
8488
+ }
8489
+ `
8490
+ );
8491
+ }
8492
+ var EXPLORE_CATALOG_QUERY = exploreCatalogDocument(
8493
+ EXPLORE_CATALOG_HIGHLIGHT_FIELD
8494
+ );
8495
+ var EXPLORE_CATALOG_QUERY_WITHOUT_HIGHLIGHTS = exploreCatalogDocument("");
8496
+ var EXPLORE_MESSAGE_QUERY = (
8497
+ /* GraphQL */
8498
+ `
8499
+ query ExploreMessage($conversationToken: String!, $id: ID!) {
8500
+ exploreMessage(conversationToken: $conversationToken, id: $id) {
8501
+ ${EXPLORE_OWN_MESSAGE_FIELDS}
8502
+ }
8503
+ }
8504
+ `
8505
+ );
8506
+ var SEND_EXPLORE_MESSAGE_MUTATION = (
8507
+ /* GraphQL */
8508
+ `
8509
+ mutation SendExploreMessage($input: SendExploreMessageInput!) {
8510
+ sendExploreMessage(input: $input) {
8511
+ conversation {
8512
+ id
8513
+ token
8514
+ productSlug
8515
+ turnCount
8516
+ createdAt
8517
+ }
8518
+ userMessage {
8519
+ ${EXPLORE_OWN_MESSAGE_FIELDS}
8520
+ }
8521
+ assistantMessage {
8522
+ ${EXPLORE_OWN_MESSAGE_FIELDS}
8523
+ }
8524
+ remainingToday
8525
+ }
8526
+ }
8527
+ `
8528
+ );
8529
+ var RECORD_EXPLORE_CLICK_MUTATION = (
8530
+ /* GraphQL */
8531
+ `
8532
+ mutation RecordExploreClick($input: RecordExploreClickInput!) {
8533
+ recordExploreClick(input: $input) {
8534
+ recorded
8535
+ }
8536
+ }
8537
+ `
8538
+ );
8539
+ var SUBMIT_EXPLORE_FEEDBACK_MUTATION = (
8540
+ /* GraphQL */
8541
+ `
8542
+ mutation SubmitExploreFeedback($input: SubmitExploreFeedbackInput!) {
8543
+ submitExploreFeedback(input: $input) {
8544
+ recorded
8545
+ feedback {
8546
+ rating
8547
+ reason
8548
+ comment
8549
+ createdAt
8550
+ }
8551
+ }
8552
+ }
8553
+ `
8554
+ );
8555
+ var EXPLORE_FEEDBACK_COMMENT_SOFT_MAX = 500;
8556
+ var ESCALATE_EXPLORE_CONVERSATION_MUTATION = (
8557
+ /* GraphQL */
8558
+ `
8559
+ mutation EscalateExploreConversation(
8560
+ $input: EscalateExploreConversationInput!
8561
+ ) {
8562
+ escalateExploreConversation(input: $input) {
8563
+ created
8564
+ escalation {
8565
+ email
8566
+ createdAt
8567
+ }
8568
+ }
8569
+ }
8570
+ `
8571
+ );
8572
+ var EXPLORE_ESCALATION_NOTE_SOFT_MAX = 2e3;
8573
+ var DELIVERABLE_EMAIL = /^[A-Za-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[A-Za-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[A-Za-z0-9](?:[A-Za-z0-9-]*[A-Za-z0-9])?\.)+[A-Za-z]{2,}$/;
8574
+ function looksLikeDeliverableEmail(value) {
8575
+ const trimmed = value.trim();
8576
+ if (trimmed.length === 0 || trimmed.length > 254) return false;
8577
+ return DELIVERABLE_EMAIL.test(trimmed);
8578
+ }
8579
+ var CREATE_EXPLORE_SHARE_LINK_MUTATION = (
8580
+ /* GraphQL */
8581
+ `
8582
+ mutation CreateExploreShareLink($conversationToken: String!) {
8583
+ createExploreShareLink(conversationToken: $conversationToken) {
8584
+ shareToken
8585
+ }
8586
+ }
8587
+ `
8588
+ );
8589
+ var EXPLORE_SHARED_CONVERSATION_QUERY = (
8590
+ /* GraphQL */
8591
+ `
8592
+ query ExploreSharedConversation($shareToken: String!) {
8593
+ exploreSharedConversation(shareToken: $shareToken) {
8594
+ ${EXPLORE_MESSAGE_FIELDS}
8595
+ }
8596
+ }
8597
+ `
8598
+ );
6833
8599
 
6834
8600
  // src/data/products.ts
6835
8601
  var ECOSYSTEM_PRODUCTS = [
@@ -7176,6 +8942,25 @@ var VALIDATION_CODES = /* @__PURE__ */ new Set([
7176
8942
  "CONVERSATION_LIMIT",
7177
8943
  "INVALID_INPUT"
7178
8944
  ]);
8945
+ function escalateOutcomeForCode(code) {
8946
+ switch (code) {
8947
+ case "INVALID_EMAIL":
8948
+ return "invalid-email";
8949
+ case "RATE_LIMITED":
8950
+ case "HTTP_429":
8951
+ return "rate-limited";
8952
+ case "CAPTCHA_REQUIRED":
8953
+ case "CAPTCHA_FAILED":
8954
+ return "captcha";
8955
+ // The token owns nothing, or owns a different conversation. The server answers NOT_FOUND
8956
+ // rather than FORBIDDEN so the endpoint is not an oracle for whether a thread exists;
8957
+ // either way there is nothing this visitor can do about it, so it reads as a failure.
8958
+ case "NOT_FOUND":
8959
+ return "failed";
8960
+ default:
8961
+ return "failed";
8962
+ }
8963
+ }
7179
8964
  function classifyExploreError(code, serverMessage) {
7180
8965
  const c = code ?? "UNKNOWN";
7181
8966
  if (RATE_LIMIT_CODES.has(c)) {
@@ -7342,6 +9127,7 @@ function useExploreChat(options = {}) {
7342
9127
  onSend
7343
9128
  } = options;
7344
9129
  const client = useWebSDK();
9130
+ const { productId } = useWebSDKConfig();
7345
9131
  const promptKey = JSON.stringify(examplePrompts ?? []);
7346
9132
  const welcomeKey = JSON.stringify(fallbackWelcome ?? null);
7347
9133
  const fallbackCatalog = React.useMemo(
@@ -7365,6 +9151,7 @@ function useExploreChat(options = {}) {
7365
9151
  const pollGenerationRef = React.useRef(0);
7366
9152
  const pollTimerRef = React.useRef(null);
7367
9153
  const conversationTokenRef = React.useRef(null);
9154
+ const [hasConversation, setHasConversation] = React.useState(false);
7368
9155
  const shareTokenRef = React.useRef(void 0);
7369
9156
  if (shareTokenRef.current === void 0) {
7370
9157
  shareTokenRef.current = readShareToken();
@@ -7379,6 +9166,10 @@ function useExploreChat(options = {}) {
7379
9166
  );
7380
9167
  const inFlightRef = React.useRef(false);
7381
9168
  catalogRef.current = catalog;
9169
+ const rememberConversationToken = React.useCallback((token) => {
9170
+ conversationTokenRef.current = token;
9171
+ setHasConversation(token !== null);
9172
+ }, []);
7382
9173
  const clearPollTimer = React.useCallback(() => {
7383
9174
  if (pollTimerRef.current !== null) {
7384
9175
  clearTimeout(pollTimerRef.current);
@@ -7445,7 +9236,7 @@ function useExploreChat(options = {}) {
7445
9236
  setArchive(readArchive(storageKey));
7446
9237
  const stored = readPersisted(storageKey);
7447
9238
  if (stored) {
7448
- conversationTokenRef.current = stored.conversationToken;
9239
+ rememberConversationToken(stored.conversationToken);
7449
9240
  focusProductRef.current = stored.focusProduct;
7450
9241
  const settled = stored.messages.flatMap((m) => {
7451
9242
  if (m.role !== "ASSISTANT") return [m];
@@ -7461,7 +9252,7 @@ function useExploreChat(options = {}) {
7461
9252
  setTurnCount(turns);
7462
9253
  }
7463
9254
  setHydrated(true);
7464
- }, [persist, storageKey]);
9255
+ }, [persist, rememberConversationToken, storageKey]);
7465
9256
  React.useEffect(() => {
7466
9257
  if (!persist || !hydrated || typeof window === "undefined") return;
7467
9258
  try {
@@ -7654,7 +9445,7 @@ function useExploreChat(options = {}) {
7654
9445
  setPhase(classified.kind === "rate-limit" ? "limited" : "error");
7655
9446
  return;
7656
9447
  }
7657
- conversationTokenRef.current = result.conversation.token;
9448
+ rememberConversationToken(result.conversation.token);
7658
9449
  turnCountRef.current = result.conversation.turnCount;
7659
9450
  setTurnCount(result.conversation.turnCount);
7660
9451
  setRemainingToday(result.remainingToday ?? null);
@@ -7680,7 +9471,14 @@ function useExploreChat(options = {}) {
7680
9471
  setPhase("streaming");
7681
9472
  startPolling(result.conversation.token, assistantMessage.id);
7682
9473
  },
7683
- [client, locale, pageUrl, productSlug, startPolling]
9474
+ [
9475
+ client,
9476
+ locale,
9477
+ pageUrl,
9478
+ productSlug,
9479
+ rememberConversationToken,
9480
+ startPolling
9481
+ ]
7684
9482
  );
7685
9483
  const send = React.useCallback(
7686
9484
  async (message, attachments = []) => {
@@ -7797,7 +9595,7 @@ function useExploreChat(options = {}) {
7797
9595
  );
7798
9596
  cancelPolling();
7799
9597
  inFlightRef.current = false;
7800
- conversationTokenRef.current = null;
9598
+ rememberConversationToken(null);
7801
9599
  lastSentTextRef.current = null;
7802
9600
  lastSentAttachmentsRef.current = [];
7803
9601
  turnCountRef.current = 0;
@@ -7812,7 +9610,7 @@ function useExploreChat(options = {}) {
7812
9610
  } catch {
7813
9611
  }
7814
9612
  }
7815
- }, [cancelPolling, storageKey]);
9613
+ }, [cancelPolling, rememberConversationToken, storageKey]);
7816
9614
  const openConversation = React.useCallback(
7817
9615
  (token) => {
7818
9616
  const entry = readArchive(storageKey).find((e) => e.token === token);
@@ -7824,7 +9622,7 @@ function useExploreChat(options = {}) {
7824
9622
  });
7825
9623
  cancelPolling();
7826
9624
  inFlightRef.current = false;
7827
- conversationTokenRef.current = entry.token;
9625
+ rememberConversationToken(entry.token);
7828
9626
  turnCountRef.current = entry.messages.filter(
7829
9627
  (m) => m.role === "USER"
7830
9628
  ).length;
@@ -7836,7 +9634,7 @@ function useExploreChat(options = {}) {
7836
9634
  setPhase(catalogRef.current.enabled ? "ready" : "disabled");
7837
9635
  setArchive(readArchive(storageKey));
7838
9636
  },
7839
- [cancelPolling, storageKey]
9637
+ [cancelPolling, rememberConversationToken, storageKey]
7840
9638
  );
7841
9639
  const deleteConversation = React.useCallback(
7842
9640
  (token) => {
@@ -7925,6 +9723,69 @@ function useExploreChat(options = {}) {
7925
9723
  },
7926
9724
  [client]
7927
9725
  );
9726
+ const escalate = React.useCallback(
9727
+ async (email, note) => {
9728
+ const token = conversationTokenRef.current;
9729
+ if (!token) {
9730
+ return { outcome: "no-conversation", email: null, createdAt: null };
9731
+ }
9732
+ const attempt = async (captchaAttempt) => {
9733
+ const activeCatalog = catalogRef.current;
9734
+ let recaptchaToken;
9735
+ if (activeCatalog.captchaRequired && activeCatalog.recaptchaSiteKey) {
9736
+ try {
9737
+ recaptchaToken = await getRecaptchaV3Token(
9738
+ activeCatalog.recaptchaSiteKey
9739
+ );
9740
+ } catch (err) {
9741
+ console.warn(
9742
+ "[WebSDK] reCAPTCHA v3 token could not be minted",
9743
+ err
9744
+ );
9745
+ }
9746
+ }
9747
+ const input = {
9748
+ conversationToken: token,
9749
+ email: email.trim(),
9750
+ note: note?.trim() ? note.trim() : null,
9751
+ ...recaptchaToken ? { recaptchaToken } : {},
9752
+ ...productId ? { productId } : {}
9753
+ };
9754
+ try {
9755
+ const res = await client.mutate(
9756
+ ESCALATE_EXPLORE_CONVERSATION_MUTATION,
9757
+ { input }
9758
+ );
9759
+ const first = res?.errors?.[0];
9760
+ const result = res?.data?.escalateExploreConversation;
9761
+ if (first || !result) {
9762
+ const code = typeof first?.extensions?.code === "string" ? first.extensions.code : "ESCALATION_FAILED";
9763
+ if (code === "CAPTCHA_FAILED" && captchaAttempt === 0) {
9764
+ return attempt(1);
9765
+ }
9766
+ return {
9767
+ outcome: escalateOutcomeForCode(code),
9768
+ email: null,
9769
+ createdAt: null
9770
+ };
9771
+ }
9772
+ return {
9773
+ // `created: false` is the double-click, the retry, the reload. The handover
9774
+ // exists, so this is a success — and the address comes from the SERVER, because
9775
+ // on a repeat submit the reply goes to whatever the FIRST handover used.
9776
+ outcome: result.created ? "sent" : "already-handed-over",
9777
+ email: result.escalation?.email ?? null,
9778
+ createdAt: result.escalation?.createdAt ?? null
9779
+ };
9780
+ } catch {
9781
+ return { outcome: "failed", email: null, createdAt: null };
9782
+ }
9783
+ };
9784
+ return attempt(0);
9785
+ },
9786
+ [client, productId]
9787
+ );
9788
+ const canEscalate = hasConversation && !isSharedView;
7928
9789
  return {
7929
9790
  phase,
7930
9791
  catalog,
@@ -7945,6 +9806,8 @@ function useExploreChat(options = {}) {
7945
9806
  clearHistory,
7946
9807
  recordClick,
7947
9808
  submitFeedback,
9809
+ escalate,
9810
+ canEscalate,
7948
9811
  createShareLink,
7949
9812
  isSharedView
7950
9813
  };
@@ -7954,6 +9817,224 @@ function makeOptimisticId() {
7954
9817
  optimisticCounter += 1;
7955
9818
  return `boff-explore-local-${Date.now()}-${optimisticCounter}`;
7956
9819
  }
9820
+ var DRAIN_TARGET_MS = 1200;
9821
+ var MIN_CHARS_PER_SECOND = 90;
9822
+ var MAX_CHARS_PER_SECOND = 2200;
9823
+ var MAX_STEP_MS = 250;
9824
+ var COMMIT_INTERVAL_MS = 45;
9825
+ var FALLBACK_STEP_MS = 50;
9826
+ var FENCE = /^ {0,3}(?:```|~~~)/;
9827
+ var TABLE_ROW = /^ {0,3}\|/;
9828
+ var EMPTY_BLOCK_MARKER = /^ {0,3}(?:[-+>]|#{1,6}|\d{1,9}[.)])\s*$/;
9829
+ function isWordCharacter(char) {
9830
+ return char !== void 0 && /[\p{L}\p{N}]/u.test(char);
9831
+ }
9832
+ function clamp(value, min, max) {
9833
+ return Math.min(Math.max(value, min), max);
9834
+ }
9835
+ function now() {
9836
+ return typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
9837
+ }
9838
+ function isHighSurrogate(code) {
9839
+ return code >= 55296 && code <= 56319;
9840
+ }
9841
+ function safeInlineEnd(line) {
9842
+ let codeSpan = null;
9843
+ let link = null;
9844
+ const emphasis = [];
9845
+ let at = 0;
9846
+ while (at < line.length) {
9847
+ const char = line[at] ?? "";
9848
+ if (char === "\\") {
9849
+ at += 2;
9850
+ continue;
9851
+ }
9852
+ if (char === "`") {
9853
+ let run = 1;
9854
+ while (line[at + run] === "`") run += 1;
9855
+ codeSpan = codeSpan === null ? at : null;
9856
+ at += run;
9857
+ continue;
9858
+ }
9859
+ if (codeSpan !== null) {
9860
+ at += 1;
9861
+ continue;
9862
+ }
9863
+ if (char === "[") {
9864
+ if (link === null) link = line[at - 1] === "!" ? at - 1 : at;
9865
+ at += 1;
9866
+ continue;
9867
+ }
9868
+ if (char === "]") {
9869
+ if (link !== null && line[at + 1] !== "(") link = null;
9870
+ at += 1;
9871
+ continue;
9872
+ }
9873
+ if (char === ")") {
9874
+ link = null;
9875
+ at += 1;
9876
+ continue;
9877
+ }
9878
+ if (char === "*" || char === "_" || char === "~") {
9879
+ let run = 1;
9880
+ while (line[at + run] === char) run += 1;
9881
+ const start = at;
9882
+ at += run;
9883
+ const before = line[start - 1];
9884
+ const after = line[start + run];
9885
+ if (run < 2) continue;
9886
+ if (char === "_" && isWordCharacter(before) && isWordCharacter(after)) {
9887
+ continue;
9888
+ }
9889
+ const marker = char.repeat(run);
9890
+ const open2 = emphasis.findIndex((entry) => entry.marker === marker);
9891
+ if (open2 !== -1) {
9892
+ emphasis.splice(open2, 1);
9893
+ continue;
9894
+ }
9895
+ if (after !== void 0 && /\s/.test(after)) continue;
9896
+ emphasis.push({ marker, start });
9897
+ continue;
9898
+ }
9899
+ at += 1;
9900
+ }
9901
+ const open = [codeSpan, link, emphasis[0]?.start ?? null].filter(
9902
+ (value) => value !== null
9903
+ );
9904
+ return open.length === 0 ? line.length : Math.min(...open);
9905
+ }
9906
+ function revealBoundary(text, limit) {
9907
+ if (limit <= 0) return 0;
9908
+ const caughtUp = limit >= text.length;
9909
+ const head = caughtUp ? text : text.slice(0, limit);
9910
+ const lineStart = head.lastIndexOf("\n") + 1;
9911
+ const line = head.slice(lineStart);
9912
+ let fenceStart = null;
9913
+ let tableStart = null;
9914
+ let tableRows = 0;
9915
+ let at = 0;
9916
+ while (at < lineStart) {
9917
+ const breakAt = head.indexOf("\n", at);
9918
+ const end = breakAt === -1 ? lineStart : breakAt;
9919
+ const row = head.slice(at, end);
9920
+ if (fenceStart !== null) {
9921
+ if (FENCE.test(row)) fenceStart = null;
9922
+ } else if (FENCE.test(row)) {
9923
+ fenceStart = at;
9924
+ } else if (TABLE_ROW.test(row)) {
9925
+ if (tableStart === null) {
9926
+ tableStart = at;
9927
+ tableRows = 0;
9928
+ }
9929
+ tableRows += 1;
9930
+ } else if (tableStart !== null) {
9931
+ tableStart = null;
9932
+ tableRows = 0;
9933
+ }
9934
+ at = end + 1;
9935
+ }
9936
+ if (fenceStart === null) {
9937
+ const lastIsRow = TABLE_ROW.test(line);
9938
+ if (lastIsRow && tableStart === null) {
9939
+ tableStart = lineStart;
9940
+ tableRows = 0;
9941
+ } else if (!lastIsRow && line !== "") {
9942
+ tableStart = null;
9943
+ tableRows = 0;
9944
+ }
9945
+ if (tableStart !== null && tableRows < 2) return tableStart;
9946
+ }
9947
+ if (caughtUp) return text.length;
9948
+ if (fenceStart !== null) return fenceStart;
9949
+ if (TABLE_ROW.test(line)) return lineStart;
9950
+ if (EMPTY_BLOCK_MARKER.test(line)) return lineStart;
9951
+ const cut = lineStart + safeInlineEnd(line);
9952
+ return isHighSurrogate(text.charCodeAt(cut - 1)) ? cut - 1 : cut;
9953
+ }
9954
+ function prefersReducedMotion() {
9955
+ if (typeof window === "undefined") return true;
9956
+ try {
9957
+ return window.matchMedia?.("(prefers-reduced-motion: reduce)").matches === true;
9958
+ } catch {
9959
+ return false;
9960
+ }
9961
+ }
9962
+ function useProgressiveReveal(text, settled) {
9963
+ const [, setFrame] = React.useState(0);
9964
+ const [reduced] = React.useState(prefersReducedMotion);
9965
+ const immediate = settled || reduced;
9966
+ const textRef = React.useRef(text);
9967
+ const cursorRef = React.useRef(immediate ? text.length : 0);
9968
+ const cutRef = React.useRef(immediate ? text.length : 0);
9969
+ const committedRef = React.useRef(0);
9970
+ if (text !== textRef.current) {
9971
+ const revealed = textRef.current.slice(0, Math.floor(cursorRef.current));
9972
+ if (revealed !== "" && !text.startsWith(revealed)) {
9973
+ cursorRef.current = text.length;
9974
+ }
9975
+ cursorRef.current = Math.min(cursorRef.current, text.length);
9976
+ cutRef.current = Math.min(cutRef.current, text.length);
9977
+ textRef.current = text;
9978
+ }
9979
+ if (immediate) cursorRef.current = text.length;
9980
+ const cut = immediate ? text.length : Math.max(
9981
+ cutRef.current,
9982
+ revealBoundary(text, Math.floor(cursorRef.current))
9983
+ );
9984
+ cutRef.current = cut;
9985
+ React.useEffect(() => {
9986
+ if (immediate) return;
9987
+ if (cursorRef.current >= text.length) return;
9988
+ let cancelled = false;
9989
+ let cancelStep = null;
9990
+ let previous = now();
9991
+ const commit = (at, force) => {
9992
+ if (!force && at - committedRef.current < COMMIT_INTERVAL_MS) return;
9993
+ committedRef.current = at;
9994
+ setFrame((value) => value + 1);
9995
+ };
9996
+ const step = () => {
9997
+ cancelStep = null;
9998
+ if (cancelled) return;
9999
+ const at = now();
10000
+ const elapsed = clamp(at - previous, 0, MAX_STEP_MS);
10001
+ previous = at;
10002
+ const length = textRef.current.length;
10003
+ const pending = length - cursorRef.current;
10004
+ if (pending <= 0) {
10005
+ commit(at, true);
10006
+ return;
10007
+ }
10008
+ const perSecond = clamp(
10009
+ pending / (DRAIN_TARGET_MS / 1e3),
10010
+ MIN_CHARS_PER_SECOND,
10011
+ MAX_CHARS_PER_SECOND
10012
+ );
10013
+ cursorRef.current = Math.min(
10014
+ length,
10015
+ cursorRef.current + perSecond * elapsed / 1e3
10016
+ );
10017
+ const done = cursorRef.current >= length;
10018
+ commit(at, done);
10019
+ if (!done) schedule();
10020
+ };
10021
+ const schedule = () => {
10022
+ if (typeof window.requestAnimationFrame === "function") {
10023
+ const id2 = window.requestAnimationFrame(step);
10024
+ cancelStep = () => window.cancelAnimationFrame(id2);
10025
+ return;
10026
+ }
10027
+ const id = setTimeout(step, FALLBACK_STEP_MS);
10028
+ cancelStep = () => clearTimeout(id);
10029
+ };
10030
+ schedule();
10031
+ return () => {
10032
+ cancelled = true;
10033
+ cancelStep?.();
10034
+ };
10035
+ }, [text, immediate]);
10036
+ return text.slice(0, cut);
10037
+ }
7957
10038
  function getRecognitionCtor() {
7958
10039
  if (typeof window === "undefined") return null;
7959
10040
  const w = window;
@@ -8172,6 +10253,141 @@ function useSpeechInput({
8172
10253
  );
8173
10254
  return { supported, listening, interim, error, start, stop, toggle };
8174
10255
  }
10256
+ var SILENT_FAILURE_MS = 1500;
10257
+ function speechPlatform() {
10258
+ if (typeof window === "undefined") return null;
10259
+ const scope = window;
10260
+ const synth = scope.speechSynthesis;
10261
+ const Utterance = scope.SpeechSynthesisUtterance;
10262
+ if (!synth || typeof synth.speak !== "function") return null;
10263
+ if (typeof Utterance !== "function") return null;
10264
+ return { synth, Utterance };
10265
+ }
10266
+ function normaliseTag(tag) {
10267
+ return tag.trim().toLowerCase().replace(/_/g, "-");
10268
+ }
10269
+ function primaryOf(tag) {
10270
+ return normaliseTag(tag).split("-")[0] ?? "";
10271
+ }
10272
+ function pickVoice(voices, lang) {
10273
+ const wanted = normaliseTag(lang);
10274
+ if (wanted === "") return null;
10275
+ const primary = primaryOf(wanted);
10276
+ const exact = voices.filter((voice) => normaliseTag(voice.lang) === wanted);
10277
+ const related = voices.filter((voice) => primaryOf(voice.lang) === primary);
10278
+ return exact.find((voice) => voice.default) ?? exact[0] ?? related.find((voice) => voice.default) ?? related[0] ?? null;
10279
+ }
10280
+ var activeOwner = null;
10281
+ var activeStop = null;
10282
+ function stopSpeaking() {
10283
+ activeStop?.();
10284
+ }
10285
+ function useSpeechOutput({
10286
+ lang
10287
+ } = {}) {
10288
+ const [available, setAvailable] = React.useState(() => speechPlatform() !== null);
10289
+ const [speaking, setSpeaking] = React.useState(false);
10290
+ const utteranceRef = React.useRef(null);
10291
+ const watchdogRef = React.useRef(null);
10292
+ const ownerRef = React.useRef({});
10293
+ const stopRef = React.useRef(() => void 0);
10294
+ const langRef = React.useRef(lang);
10295
+ langRef.current = lang;
10296
+ const clearWatchdog = React.useCallback(() => {
10297
+ if (watchdogRef.current === null) return;
10298
+ clearTimeout(watchdogRef.current);
10299
+ watchdogRef.current = null;
10300
+ }, []);
10301
+ const settle = React.useCallback(() => {
10302
+ clearWatchdog();
10303
+ utteranceRef.current = null;
10304
+ if (activeOwner === ownerRef.current) {
10305
+ activeOwner = null;
10306
+ activeStop = null;
10307
+ }
10308
+ setSpeaking(false);
10309
+ }, [clearWatchdog]);
10310
+ const stop = React.useCallback(() => {
10311
+ const owned = utteranceRef.current !== null;
10312
+ settle();
10313
+ if (owned) speechPlatform()?.synth.cancel();
10314
+ }, [settle]);
10315
+ stopRef.current = stop;
10316
+ const speak = React.useCallback(
10317
+ (text) => {
10318
+ const platform = speechPlatform();
10319
+ if (!platform) {
10320
+ setAvailable(false);
10321
+ return;
10322
+ }
10323
+ const spoken = text.trim();
10324
+ if (spoken === "") return;
10325
+ if (activeStop && activeOwner !== ownerRef.current) activeStop();
10326
+ platform.synth.cancel();
10327
+ const utterance = new platform.Utterance(spoken);
10328
+ const wanted = langRef.current;
10329
+ if (wanted !== void 0 && wanted !== "") {
10330
+ const voice = pickVoice(platform.synth.getVoices(), wanted);
10331
+ utterance.lang = voice?.lang ?? wanted;
10332
+ if (voice) utterance.voice = voice;
10333
+ }
10334
+ const mine = () => utteranceRef.current === utterance;
10335
+ utterance.onstart = () => {
10336
+ if (!mine()) return;
10337
+ clearWatchdog();
10338
+ setSpeaking(true);
10339
+ };
10340
+ utterance.onend = () => {
10341
+ if (!mine()) return;
10342
+ settle();
10343
+ };
10344
+ utterance.onerror = (event) => {
10345
+ if (!mine()) return;
10346
+ const code = typeof event?.error === "string" ? event.error : "";
10347
+ settle();
10348
+ if (code !== "interrupted" && code !== "canceled") setAvailable(false);
10349
+ };
10350
+ utteranceRef.current = utterance;
10351
+ activeOwner = ownerRef.current;
10352
+ activeStop = () => {
10353
+ stopRef.current();
10354
+ };
10355
+ setSpeaking(true);
10356
+ platform.synth.speak(utterance);
10357
+ clearWatchdog();
10358
+ watchdogRef.current = setTimeout(() => {
10359
+ watchdogRef.current = null;
10360
+ if (!mine()) return;
10361
+ if (platform.synth.speaking) return;
10362
+ settle();
10363
+ setAvailable(false);
10364
+ }, SILENT_FAILURE_MS);
10365
+ },
10366
+ [clearWatchdog, settle]
10367
+ );
10368
+ const toggle = React.useCallback(
10369
+ (text) => {
10370
+ if (speaking) stop();
10371
+ else speak(text);
10372
+ },
10373
+ [speak, speaking, stop]
10374
+ );
10375
+ React.useEffect(() => {
10376
+ if (!speaking || typeof window === "undefined") return;
10377
+ const onHide = () => {
10378
+ stopRef.current();
10379
+ };
10380
+ window.addEventListener("pagehide", onHide);
10381
+ return () => window.removeEventListener("pagehide", onHide);
10382
+ }, [speaking]);
10383
+ React.useEffect(
10384
+ () => () => {
10385
+ stopRef.current();
10386
+ },
10387
+ []
10388
+ );
10389
+ return { supported: available, speaking, speak, stop, toggle };
10390
+ }
8175
10391
  var SWIPE_THRESHOLD = 40;
8176
10392
  function useSwipe({
8177
10393
  onSwipeLeft,
@@ -8412,33 +10628,6 @@ var EXPLORE_CSS = `
8412
10628
  .boff-explore-fade { animation: none; }
8413
10629
  }
8414
10630
 
8415
- /* Nothing inside an answer may widen the page. Model output carries long URLs, code and
8416
- tables \u2014 each of those overflows a phone by default, and one overflowing child makes the
8417
- WHOLE document horizontally scrollable, not just the bubble. */
8418
- .boff-explore-body,
8419
- .boff-explore-body p,
8420
- .boff-explore-body li,
8421
- .boff-explore-body a,
8422
- .boff-explore-body h1,
8423
- .boff-explore-body h2,
8424
- .boff-explore-body h3 {
8425
- overflow-wrap: anywhere;
8426
- word-break: break-word;
8427
- }
8428
- .boff-explore-body pre {
8429
- overflow-x: auto;
8430
- max-width: 100%;
8431
- }
8432
- .boff-explore-body table {
8433
- display: block;
8434
- overflow-x: auto;
8435
- max-width: 100%;
8436
- }
8437
- .boff-explore-body img {
8438
- max-width: 100%;
8439
- height: auto;
8440
- }
8441
-
8442
10631
  /* ---- Ambient backdrop -----------------------------------------------------------------
8443
10632
  Two very low-opacity radial washes behind the welcome state, drifting slowly. Painted on
8444
10633
  a pseudo-element with pointer-events:none so it can never intercept a click \u2014 a
@@ -8495,11 +10684,40 @@ var EXPLORE_CSS = `
8495
10684
  animation: boff-explore-sheen 1.5s ease-in-out infinite;
8496
10685
  }
8497
10686
 
10687
+ /* ---- The composer, before anyone has typed -----------------------------------------
10688
+ On the welcome screen the box IS the page: everything above it is a way of explaining
10689
+ what to put in it. Unhighlighted it reads as a search bar at the bottom of a landing
10690
+ page, which people scroll past \u2014 so while the conversation is empty it gets a soft halo
10691
+ in the site's own --primary and one slow breath of it, and the moment there is a
10692
+ transcript, or the visitor focuses or types, it drops back to the ordinary card it was.
10693
+ An input that keeps pulsing while you are using it is nagging, not inviting.
10694
+
10695
+ Colour comes from the product's --primary token, so it is whatever that site's palette
10696
+ already is, never a colour chosen here. */
10697
+ .boff-explore-invite {
10698
+ border-color: hsl(var(--primary) / 0.45);
10699
+ box-shadow:
10700
+ 0 0 0 4px hsl(var(--primary) / 0.08),
10701
+ 0 8px 24px -12px hsl(var(--primary) / 0.45);
10702
+ animation: boff-explore-breathe 3.2s ease-in-out infinite;
10703
+ }
10704
+ /* Focus and typing both mean "I have found it", and the hint has done its job. */
10705
+ .boff-explore-invite:focus-within,
10706
+ .boff-explore-invite.boff-explore-invite-quiet {
10707
+ animation: none;
10708
+ box-shadow: 0 0 0 4px hsl(var(--primary) / 0.10);
10709
+ }
10710
+ @keyframes boff-explore-breathe {
10711
+ 0%, 100% { box-shadow: 0 0 0 4px hsl(var(--primary) / 0.07), 0 8px 24px -12px hsl(var(--primary) / 0.40); }
10712
+ 50% { box-shadow: 0 0 0 7px hsl(var(--primary) / 0.13), 0 8px 28px -12px hsl(var(--primary) / 0.55); }
10713
+ }
10714
+
8498
10715
  /* Every one of the above is decoration. Reduced motion removes the movement and keeps the
8499
10716
  final state, rather than leaving content mid-animation and invisible. */
8500
10717
  @media (prefers-reduced-motion: reduce) {
8501
10718
  .boff-explore-aura::before,
8502
- .boff-explore-busy::after { animation: none; }
10719
+ .boff-explore-busy::after,
10720
+ .boff-explore-invite { animation: none; }
8503
10721
  .boff-explore-rise { animation: none; opacity: 1; transform: none; }
8504
10722
  }
8505
10723
 
@@ -8610,7 +10828,7 @@ function isOwnElement(el, root) {
8610
10828
  function visualViewportHeight() {
8611
10829
  return window.visualViewport?.height ?? window.innerHeight;
8612
10830
  }
8613
- function clamp(value, min, max) {
10831
+ function clamp2(value, min, max) {
8614
10832
  return Math.min(Math.max(value, min), max);
8615
10833
  }
8616
10834
  function isRestoredNavigation() {
@@ -8629,51 +10847,23 @@ function isInternalPath(url) {
8629
10847
  }
8630
10848
  function hostnameOf(url) {
8631
10849
  try {
8632
- return new URL(url).hostname.replace(/^www\./, "");
8633
- } catch {
8634
- return "";
8635
- }
8636
- }
8637
- function initialOf(value, fallback) {
8638
- const source = (value || fallback).trim();
8639
- return source ? source.slice(0, 1).toUpperCase() : "?";
8640
- }
8641
- function logoUrlOf(url) {
8642
- try {
8643
- const { origin, protocol } = new URL(url);
8644
- if (protocol !== "https:" && protocol !== "http:") return null;
8645
- return `${origin}/favicon.svg`;
8646
- } catch {
8647
- return null;
8648
- }
8649
- }
8650
- function inlineImageOrigins(products) {
8651
- const origins = /* @__PURE__ */ new Set();
8652
- for (const product of products) {
8653
- let url;
8654
- try {
8655
- url = new URL(product.website);
8656
- } catch {
8657
- continue;
8658
- }
8659
- if (url.protocol !== "https:") continue;
8660
- const apex = url.hostname.replace(/^www\./, "");
8661
- const port = url.port ? `:${url.port}` : "";
8662
- origins.add(`https://${apex}${port}`);
8663
- origins.add(`https://www.${apex}${port}`);
10850
+ return new URL(url).hostname.replace(/^www\./, "");
10851
+ } catch {
10852
+ return "";
8664
10853
  }
8665
- return origins;
8666
10854
  }
8667
- function isInlineImageAllowed(src, origins) {
8668
- if (typeof src !== "string" || src === "") return false;
8669
- let url;
10855
+ function initialOf(value, fallback) {
10856
+ const source = (value || fallback).trim();
10857
+ return source ? source.slice(0, 1).toUpperCase() : "?";
10858
+ }
10859
+ function logoUrlOf(url) {
8670
10860
  try {
8671
- url = new URL(src);
10861
+ const { origin, protocol } = new URL(url);
10862
+ if (protocol !== "https:" && protocol !== "http:") return null;
10863
+ return `${origin}/favicon.svg`;
8672
10864
  } catch {
8673
- return false;
10865
+ return null;
8674
10866
  }
8675
- if (url.protocol !== "https:" || url.username || url.password) return false;
8676
- return origins.has(url.origin);
8677
10867
  }
8678
10868
  var REFERENCE_KIND_ORDER = [
8679
10869
  "CONCEPT",
@@ -8759,97 +10949,6 @@ function summariseReferences(references, origins, productNames) {
8759
10949
  products
8760
10950
  };
8761
10951
  }
8762
- var CODE_FENCE = /^\s*(?:```|~~~)/;
8763
- function answerPlainText(markdown) {
8764
- const lines = [];
8765
- let inFence = false;
8766
- for (const raw of markdown.split("\n")) {
8767
- if (CODE_FENCE.test(raw)) {
8768
- inFence = !inFence;
8769
- continue;
8770
- }
8771
- if (inFence) {
8772
- lines.push(raw);
8773
- continue;
8774
- }
8775
- let line = raw;
8776
- line = line.replace(/!\[[^\]]*\]\([^)\s]*(?:\s+"[^"]*")?\)/g, "");
8777
- line = line.replace(/\[([^\]]+)\]\(([^)\s]+)(?:\s+"[^"]*")?\)/g, "$1 ($2)");
8778
- line = line.replace(/<(https?:\/\/[^>\s]+)>/g, "$1");
8779
- line = line.replace(/^\s{0,3}#{1,6}\s+/, "");
8780
- line = line.replace(/^\s{0,3}>\s?/, "");
8781
- if (/^\s{0,3}([-*_])[ \t]*(?:\1[ \t]*){2,}$/.test(line)) {
8782
- lines.push("");
8783
- continue;
8784
- }
8785
- line = line.replace(/`([^`]+)`/g, "$1");
8786
- line = line.replace(/\*\*([^*]+)\*\*/g, "$1");
8787
- line = line.replace(/__([^_]+)__/g, "$1");
8788
- line = line.replace(/(^|[^*\w])\*([^*\n]+)\*(?![*\w])/g, "$1$2");
8789
- line = line.replace(/(^|[^_\w])_([^_\n]+)_(?![_\w])/g, "$1$2");
8790
- lines.push(line.replace(/[ \t]+$/, ""));
8791
- }
8792
- return lines.join("\n").replace(/\n{3,}/g, "\n\n").trim();
8793
- }
8794
- var InlineImageScopeContext = React.createContext(null);
8795
- var InsideLinkContext = React.createContext(false);
8796
- function AnswerLink(props) {
8797
- return /* @__PURE__ */ jsxRuntime.jsx(InsideLinkContext.Provider, { value: true, children: /* @__PURE__ */ jsxRuntime.jsx(MarkdownLink, { ...props }) });
8798
- }
8799
- var INLINE_IMAGE_FRAME = "relative inline-block max-w-full overflow-hidden rounded-xl border border-border bg-muted align-top shadow-sm";
8800
- function InlineConceptImage({ src, alt }) {
8801
- const scope = React.useContext(InlineImageScopeContext);
8802
- const insideLink = React.useContext(InsideLinkContext);
8803
- if (!scope || !scope.enabled || !isInlineImageAllowed(src, scope.origins) || scope.failed.has(src)) {
8804
- return null;
8805
- }
8806
- const { strings: T, onFailed } = scope;
8807
- const picture = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
8808
- /* @__PURE__ */ jsxRuntime.jsx(
8809
- "img",
8810
- {
8811
- src,
8812
- alt: alt ?? "",
8813
- loading: "lazy",
8814
- decoding: "async",
8815
- onError: () => onFailed(src),
8816
- className: "block h-auto max-h-80 w-auto max-w-full object-contain"
8817
- }
8818
- ),
8819
- /* @__PURE__ */ jsxRuntime.jsx(
8820
- "span",
8821
- {
8822
- "aria-hidden": "true",
8823
- className: "pointer-events-none absolute left-2 top-2 rounded-full border border-border bg-background/90 px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide text-foreground shadow-sm",
8824
- children: T.conceptIllustration
8825
- }
8826
- )
8827
- ] });
8828
- return /* @__PURE__ */ jsxRuntime.jsx("span", { "data-boff-explore": "inline-image", className: "my-3 block", children: insideLink ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: INLINE_IMAGE_FRAME, children: picture }) : /* @__PURE__ */ jsxRuntime.jsxs(
8829
- "a",
8830
- {
8831
- href: src,
8832
- target: "_blank",
8833
- rel: "noopener noreferrer",
8834
- className: cn(
8835
- INLINE_IMAGE_FRAME,
8836
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
8837
- ),
8838
- children: [
8839
- picture,
8840
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "sr-only", children: [
8841
- "(",
8842
- T.opensInNewTab,
8843
- ")"
8844
- ] })
8845
- ]
8846
- }
8847
- ) });
8848
- }
8849
- var ANSWER_MARKDOWN_COMPONENTS = {
8850
- a: AnswerLink,
8851
- img: InlineConceptImage
8852
- };
8853
10952
  function ReferenceCard({
8854
10953
  reference,
8855
10954
  onFollow
@@ -9188,6 +11287,195 @@ function AnswerFeedback({
9188
11287
  }
9189
11288
  );
9190
11289
  }
11290
+ function EscalateForm({
11291
+ strings: T,
11292
+ formId,
11293
+ onEscalate,
11294
+ onClose,
11295
+ onBusyChange
11296
+ }) {
11297
+ const [email, setEmail] = React.useState("");
11298
+ const [note, setNote] = React.useState("");
11299
+ const [error, setError] = React.useState(null);
11300
+ const [sending, setSending] = React.useState(false);
11301
+ const [sentTo, setSentTo] = React.useState(null);
11302
+ const emailRef = React.useRef(null);
11303
+ const inFlightRef = React.useRef(false);
11304
+ const titleId = `${formId}-title`;
11305
+ const emailId = `${formId}-email`;
11306
+ const noteId = `${formId}-note`;
11307
+ const errorId = `${formId}-error`;
11308
+ React.useEffect(() => {
11309
+ emailRef.current?.focus();
11310
+ }, []);
11311
+ React.useEffect(() => {
11312
+ onBusyChange?.(sending);
11313
+ return () => onBusyChange?.(false);
11314
+ }, [sending, onBusyChange]);
11315
+ const handleSubmit = React.useCallback(
11316
+ async (event) => {
11317
+ event.preventDefault();
11318
+ if (inFlightRef.current) return;
11319
+ const address = email.trim();
11320
+ if (!looksLikeDeliverableEmail(address)) {
11321
+ setError(T.escalateInvalidEmail);
11322
+ emailRef.current?.focus();
11323
+ return;
11324
+ }
11325
+ inFlightRef.current = true;
11326
+ setSending(true);
11327
+ setError(null);
11328
+ const result = await onEscalate(address, note);
11329
+ inFlightRef.current = false;
11330
+ setSending(false);
11331
+ switch (result.outcome) {
11332
+ case "sent":
11333
+ case "already-handed-over":
11334
+ setSentTo(result.email ?? address);
11335
+ return;
11336
+ case "invalid-email":
11337
+ setError(T.escalateInvalidEmail);
11338
+ emailRef.current?.focus();
11339
+ return;
11340
+ case "rate-limited":
11341
+ setError(T.escalateRateLimited);
11342
+ return;
11343
+ case "captcha":
11344
+ setError(T.escalateCaptcha);
11345
+ return;
11346
+ // `no-conversation` included: the form should not have been offered at all, and the
11347
+ // honest thing to show is that nothing was passed on.
11348
+ default:
11349
+ setError(T.escalateFailed);
11350
+ return;
11351
+ }
11352
+ },
11353
+ [T, email, note, onEscalate]
11354
+ );
11355
+ if (sentTo !== null) {
11356
+ return /* @__PURE__ */ jsxRuntime.jsx(
11357
+ "p",
11358
+ {
11359
+ id: formId,
11360
+ "data-boff-explore": "escalate-sent",
11361
+ role: "status",
11362
+ className: "boff-explore-fade mt-2 rounded-xl border border-border bg-card px-3 py-2 text-xs leading-relaxed text-card-foreground",
11363
+ children: fill(T.escalateSent, { email: sentTo })
11364
+ }
11365
+ );
11366
+ }
11367
+ return /* @__PURE__ */ jsxRuntime.jsxs(
11368
+ "form",
11369
+ {
11370
+ id: formId,
11371
+ "data-boff-explore": "escalate-form",
11372
+ "aria-labelledby": titleId,
11373
+ noValidate: true,
11374
+ onSubmit: handleSubmit,
11375
+ onKeyDown: (event) => {
11376
+ if (event.key !== "Escape") return;
11377
+ event.stopPropagation();
11378
+ if (sending) return;
11379
+ onClose();
11380
+ },
11381
+ className: "boff-explore-fade mt-2 space-y-2 rounded-xl border border-border bg-card p-3",
11382
+ children: [
11383
+ /* @__PURE__ */ jsxRuntime.jsx("p", { id: titleId, className: "text-xs font-medium text-card-foreground", children: T.escalateTitle }),
11384
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs leading-relaxed text-muted-foreground", children: T.escalateBody }),
11385
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
11386
+ /* @__PURE__ */ jsxRuntime.jsx(
11387
+ "label",
11388
+ {
11389
+ htmlFor: emailId,
11390
+ className: "block text-xs font-medium text-card-foreground",
11391
+ children: T.escalateEmailLabel
11392
+ }
11393
+ ),
11394
+ /* @__PURE__ */ jsxRuntime.jsx(
11395
+ "input",
11396
+ {
11397
+ ref: emailRef,
11398
+ id: emailId,
11399
+ name: "email",
11400
+ "data-boff-explore": "escalate-email",
11401
+ type: "email",
11402
+ inputMode: "email",
11403
+ autoComplete: "email",
11404
+ required: true,
11405
+ value: email,
11406
+ onChange: (event) => {
11407
+ setEmail(event.target.value);
11408
+ if (error) setError(null);
11409
+ },
11410
+ "aria-invalid": error ? "true" : void 0,
11411
+ "aria-describedby": error ? errorId : void 0,
11412
+ placeholder: T.escalateEmailPlaceholder,
11413
+ className: "w-full rounded-md border border-border bg-background px-2 py-1 text-base text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring sm:text-sm"
11414
+ }
11415
+ )
11416
+ ] }),
11417
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
11418
+ /* @__PURE__ */ jsxRuntime.jsx(
11419
+ "label",
11420
+ {
11421
+ htmlFor: noteId,
11422
+ className: "block text-xs font-medium text-card-foreground",
11423
+ children: T.escalateNoteLabel
11424
+ }
11425
+ ),
11426
+ /* @__PURE__ */ jsxRuntime.jsx(
11427
+ Textarea,
11428
+ {
11429
+ id: noteId,
11430
+ name: "note",
11431
+ "data-boff-explore": "escalate-note",
11432
+ rows: 2,
11433
+ value: note,
11434
+ onChange: (event) => setNote(event.target.value),
11435
+ maxLength: EXPLORE_ESCALATION_NOTE_SOFT_MAX,
11436
+ className: "min-h-0 border-border bg-background"
11437
+ }
11438
+ )
11439
+ ] }),
11440
+ error ? /* @__PURE__ */ jsxRuntime.jsx(
11441
+ "p",
11442
+ {
11443
+ id: errorId,
11444
+ "data-boff-explore": "escalate-error",
11445
+ role: "alert",
11446
+ className: "text-xs leading-relaxed text-destructive",
11447
+ children: error
11448
+ }
11449
+ ) : null,
11450
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
11451
+ /* @__PURE__ */ jsxRuntime.jsx(
11452
+ Button,
11453
+ {
11454
+ "data-boff-explore": "escalate-send",
11455
+ type: "submit",
11456
+ size: "sm",
11457
+ disabled: sending,
11458
+ children: sending ? T.escalateSending : T.escalateSubmit
11459
+ }
11460
+ ),
11461
+ /* @__PURE__ */ jsxRuntime.jsx(
11462
+ Button,
11463
+ {
11464
+ "data-boff-explore": "escalate-cancel",
11465
+ type: "button",
11466
+ size: "sm",
11467
+ variant: "ghost",
11468
+ className: "text-muted-foreground",
11469
+ disabled: sending,
11470
+ onClick: onClose,
11471
+ children: T.escalateCancel
11472
+ }
11473
+ )
11474
+ ] })
11475
+ ]
11476
+ }
11477
+ );
11478
+ }
9191
11479
  var PROVENANCE_CHIP = "inline-flex max-w-full items-center gap-1 rounded-full border border-border bg-muted/60 px-2 py-0.5 text-[11px] leading-5 text-muted-foreground";
9192
11480
  function ProvenanceChips({
9193
11481
  strings: T,
@@ -9237,9 +11525,42 @@ function ProvenanceChips({
9237
11525
  );
9238
11526
  }
9239
11527
  var COPY_FEEDBACK_MS = 2500;
11528
+ var ANSWER_ACTION_PILL = "inline-flex max-w-full items-center gap-1.5 rounded-full border px-2.5 py-1 text-xs transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring";
11529
+ var ANSWER_ACTION_IDLE = "border-border bg-card text-muted-foreground hover:border-primary/40 hover:bg-accent hover:text-foreground";
11530
+ var ANSWER_ACTION_ACTIVE = "border-primary/40 bg-accent text-primary";
11531
+ function ReadAloudButton({
11532
+ strings: T,
11533
+ text,
11534
+ lang
11535
+ }) {
11536
+ const speech = useSpeechOutput({ lang });
11537
+ if (!speech.supported) return null;
11538
+ const label = speech.speaking ? T.stopReading : T.readAloud;
11539
+ return /* @__PURE__ */ jsxRuntime.jsxs(
11540
+ "button",
11541
+ {
11542
+ "data-boff-explore": "read-aloud",
11543
+ "data-speaking": speech.speaking ? "true" : "false",
11544
+ type: "button",
11545
+ title: label,
11546
+ "aria-pressed": speech.speaking,
11547
+ onClick: () => speech.toggle(text),
11548
+ className: cn(
11549
+ ANSWER_ACTION_PILL,
11550
+ speech.speaking ? ANSWER_ACTION_ACTIVE : ANSWER_ACTION_IDLE
11551
+ ),
11552
+ children: [
11553
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Volume2, { className: "h-3 w-3 shrink-0", "aria-hidden": "true" }),
11554
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: label })
11555
+ ]
11556
+ }
11557
+ );
11558
+ }
9240
11559
  function AnswerActions({
9241
11560
  strings: T,
9242
- text
11561
+ text,
11562
+ speechText,
11563
+ speechLang
9243
11564
  }) {
9244
11565
  const [outcome, setOutcome] = React.useState("idle");
9245
11566
  const resetRef = React.useRef(null);
@@ -9282,9 +11603,8 @@ function AnswerActions({
9282
11603
  void copy();
9283
11604
  },
9284
11605
  className: cn(
9285
- "inline-flex max-w-full items-center gap-1.5 rounded-full border px-2.5 py-1 text-xs transition-colors",
9286
- "focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
9287
- outcome === "failed" ? "border-destructive/40 bg-card text-destructive" : "border-border bg-card text-muted-foreground hover:border-primary/40 hover:bg-accent hover:text-foreground"
11606
+ ANSWER_ACTION_PILL,
11607
+ outcome === "failed" ? "border-destructive/40 bg-card text-destructive" : ANSWER_ACTION_IDLE
9288
11608
  ),
9289
11609
  children: [
9290
11610
  outcome === "copied" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "h-3 w-3 shrink-0", "aria-hidden": "true" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Copy, { className: "h-3 w-3 shrink-0", "aria-hidden": "true" }),
@@ -9292,6 +11612,7 @@ function AnswerActions({
9292
11612
  ]
9293
11613
  }
9294
11614
  ),
11615
+ /* @__PURE__ */ jsxRuntime.jsx(ReadAloudButton, { strings: T, text: speechText, lang: speechLang }),
9295
11616
  /* @__PURE__ */ jsxRuntime.jsx("span", { "data-boff-explore": "copy-status", role: "status", className: "sr-only", children: outcome === "idle" ? "" : label })
9296
11617
  ]
9297
11618
  }
@@ -9343,34 +11664,20 @@ function AssistantBubble({
9343
11664
  activity,
9344
11665
  imageOrigins,
9345
11666
  productNames,
11667
+ speechLang,
9346
11668
  onNavigate,
9347
11669
  anchorRef,
9348
11670
  onFollow,
9349
11671
  onFollowUp,
9350
- onFeedback
11672
+ onFeedback,
11673
+ onEscalate,
11674
+ isLatestAnswer = false
9351
11675
  }) {
9352
11676
  const streaming = message.status === "PENDING" || message.status === "RUNNING";
9353
11677
  const body = message.content || message.partialContent || "";
9354
11678
  const failed = message.status === "FAILED";
9355
11679
  const completed = message.status === "COMPLETED";
9356
- const [failedImages, setFailedImages] = React.useState(
9357
- () => /* @__PURE__ */ new Set()
9358
- );
9359
- const markImageFailed = React.useCallback((src) => {
9360
- setFailedImages(
9361
- (current) => current.has(src) ? current : new Set(current).add(src)
9362
- );
9363
- }, []);
9364
- const imageScope = React.useMemo(
9365
- () => ({
9366
- strings: T,
9367
- enabled: completed,
9368
- origins: imageOrigins,
9369
- failed: failedImages,
9370
- onFailed: markImageFailed
9371
- }),
9372
- [T, completed, imageOrigins, failedImages, markImageFailed]
9373
- );
11680
+ const visible = useProgressiveReveal(body, !streaming);
9374
11681
  const provenance = React.useMemo(
9375
11682
  () => summariseReferences(message.references, imageOrigins, productNames),
9376
11683
  [message.references, imageOrigins, productNames]
@@ -9379,7 +11686,25 @@ function AssistantBubble({
9379
11686
  () => answerPlainText(message.content),
9380
11687
  [message.content]
9381
11688
  );
11689
+ const speechText = React.useMemo(
11690
+ () => answerSpeechText(message.content),
11691
+ [message.content]
11692
+ );
9382
11693
  const grounded = completed && message.answered !== false;
11694
+ const [escalateOpen, setEscalateOpen] = React.useState(false);
11695
+ const [escalateBusy, setEscalateBusy] = React.useState(false);
11696
+ const escalateTriggerRef = React.useRef(null);
11697
+ const escalateFormId = `boff-explore-escalate-${message.id}`;
11698
+ const unanswered = completed && message.answered === false;
11699
+ const offerEscalate = Boolean(onEscalate) && completed;
11700
+ const showQuietEscalate = offerEscalate && !unanswered && isLatestAnswer;
11701
+ const closeEscalate = React.useCallback(() => {
11702
+ setEscalateOpen(false);
11703
+ escalateTriggerRef.current?.focus();
11704
+ }, []);
11705
+ const handleEscalateBusy = React.useCallback((busy) => {
11706
+ setEscalateBusy(busy);
11707
+ }, []);
9383
11708
  return /* @__PURE__ */ jsxRuntime.jsxs(
9384
11709
  "div",
9385
11710
  {
@@ -9397,7 +11722,7 @@ function AssistantBubble({
9397
11722
  }
9398
11723
  ),
9399
11724
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1 space-y-3", children: [
9400
- message.status === "COMPLETED" && message.answered === false ? /* @__PURE__ */ jsxRuntime.jsxs(
11725
+ unanswered ? /* @__PURE__ */ jsxRuntime.jsxs(
9401
11726
  "div",
9402
11727
  {
9403
11728
  "data-boff-explore": "no-answer",
@@ -9407,26 +11732,56 @@ function AssistantBubble({
9407
11732
  /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
9408
11733
  T.noAnswer,
9409
11734
  " ",
9410
- /* @__PURE__ */ jsxRuntime.jsx(
9411
- "a",
9412
- {
9413
- href: "/contact",
9414
- className: "underline underline-offset-2 hover:text-primary",
9415
- onClick: (event) => {
9416
- if (!onNavigate) return;
9417
- event.preventDefault();
9418
- onNavigate("/contact");
9419
- },
9420
- children: T.askHuman
9421
- }
11735
+ offerEscalate ? (
11736
+ /* The point of the wave: the same words, but they now open a form that
11737
+ sends the conversation we are both looking at, instead of a link to a
11738
+ blank contact page that asks the visitor to type it all again. */
11739
+ /* @__PURE__ */ jsxRuntime.jsx(
11740
+ "button",
11741
+ {
11742
+ ref: escalateTriggerRef,
11743
+ "data-boff-explore": "escalate-open",
11744
+ type: "button",
11745
+ "aria-expanded": escalateOpen,
11746
+ "aria-controls": escalateOpen ? escalateFormId : void 0,
11747
+ onClick: () => setEscalateOpen(true),
11748
+ className: "rounded-sm underline underline-offset-2 hover:text-primary focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
11749
+ children: T.askHuman
11750
+ }
11751
+ )
11752
+ ) : (
11753
+ /* No conversation to hand over (a shared, read-only view). The old dead end
11754
+ is still better than a control whose submit could only fail. */
11755
+ /* @__PURE__ */ jsxRuntime.jsx(
11756
+ "a",
11757
+ {
11758
+ href: "/contact",
11759
+ className: "underline underline-offset-2 hover:text-primary",
11760
+ onClick: (event) => {
11761
+ if (!onNavigate) return;
11762
+ event.preventDefault();
11763
+ onNavigate("/contact");
11764
+ },
11765
+ children: T.askHuman
11766
+ }
11767
+ )
9422
11768
  ),
9423
11769
  "."
9424
11770
  ] })
9425
11771
  ]
9426
11772
  }
9427
11773
  ) : null,
9428
- body ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-2xl rounded-tl-md border border-border bg-card px-4 py-3 shadow-sm", children: [
9429
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "boff-prose boff-prose-sm boff-explore-body min-w-0 text-card-foreground", children: /* @__PURE__ */ jsxRuntime.jsx(InlineImageScopeContext.Provider, { value: imageScope, children: /* @__PURE__ */ jsxRuntime.jsx(Markdown, { components: ANSWER_MARKDOWN_COMPONENTS, children: body }) }) }),
11774
+ visible ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-2xl rounded-tl-md border border-border bg-card px-4 py-3 shadow-sm", children: [
11775
+ /* @__PURE__ */ jsxRuntime.jsx(
11776
+ ExploreAnswerBody,
11777
+ {
11778
+ strings: T,
11779
+ imageOrigins,
11780
+ enabled: completed,
11781
+ className: "boff-prose-sm text-card-foreground",
11782
+ children: visible
11783
+ }
11784
+ ),
9430
11785
  streaming ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "boff-explore-caret", "aria-hidden": "true" }) : null
9431
11786
  ] }) : null,
9432
11787
  grounded && provenance.total > 0 ? /* @__PURE__ */ jsxRuntime.jsx(ProvenanceChips, { strings: T, provenance }) : null,
@@ -9469,7 +11824,15 @@ function AssistantBubble({
9469
11824
  question
9470
11825
  )) })
9471
11826
  ] }) : null,
9472
- completed && copyText !== "" ? /* @__PURE__ */ jsxRuntime.jsx(AnswerActions, { strings: T, text: copyText }) : null,
11827
+ completed && copyText !== "" ? /* @__PURE__ */ jsxRuntime.jsx(
11828
+ AnswerActions,
11829
+ {
11830
+ strings: T,
11831
+ text: copyText,
11832
+ speechText,
11833
+ speechLang
11834
+ }
11835
+ ) : null,
9473
11836
  completed && onFeedback ? /* @__PURE__ */ jsxRuntime.jsx(
9474
11837
  AnswerFeedback,
9475
11838
  {
@@ -9478,6 +11841,30 @@ function AssistantBubble({
9478
11841
  feedback: message.feedback,
9479
11842
  onSubmit: onFeedback
9480
11843
  }
11844
+ ) : null,
11845
+ showQuietEscalate ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pt-0.5", children: /* @__PURE__ */ jsxRuntime.jsx(
11846
+ "button",
11847
+ {
11848
+ ref: escalateTriggerRef,
11849
+ "data-boff-explore": "escalate-open",
11850
+ type: "button",
11851
+ "aria-expanded": escalateOpen,
11852
+ "aria-controls": escalateOpen ? escalateFormId : void 0,
11853
+ disabled: escalateBusy,
11854
+ onClick: () => setEscalateOpen((open) => !open),
11855
+ className: "rounded-sm text-xs text-muted-foreground underline underline-offset-2 hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
11856
+ children: T.escalateOpen
11857
+ }
11858
+ ) }) : null,
11859
+ escalateOpen && onEscalate ? /* @__PURE__ */ jsxRuntime.jsx(
11860
+ EscalateForm,
11861
+ {
11862
+ strings: T,
11863
+ formId: escalateFormId,
11864
+ onEscalate,
11865
+ onClose: closeEscalate,
11866
+ onBusyChange: handleEscalateBusy
11867
+ }
9481
11868
  ) : null
9482
11869
  ] })
9483
11870
  ]
@@ -9917,15 +12304,6 @@ function WelcomeState({
9917
12304
  }
9918
12305
  )
9919
12306
  ] }) : null,
9920
- /* @__PURE__ */ jsxRuntime.jsx(
9921
- ConceptStrip,
9922
- {
9923
- strings: T,
9924
- highlights: conceptHighlights,
9925
- onAsk: onPrompt,
9926
- disabled
9927
- }
9928
- ),
9929
12307
  products.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "boff-explore-rise boff-explore-rise-3 mt-6", children: [
9930
12308
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mb-2 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: T.focusProduct }),
9931
12309
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -9937,7 +12315,16 @@ function WelcomeState({
9937
12315
  onFocus
9938
12316
  }
9939
12317
  )
9940
- ] }) : null
12318
+ ] }) : null,
12319
+ /* @__PURE__ */ jsxRuntime.jsx(
12320
+ ConceptStrip,
12321
+ {
12322
+ strings: T,
12323
+ highlights: conceptHighlights,
12324
+ onAsk: onPrompt,
12325
+ disabled
12326
+ }
12327
+ )
9941
12328
  ] });
9942
12329
  }
9943
12330
  function ExplorePage({
@@ -9963,6 +12350,7 @@ function ExplorePage({
9963
12350
  );
9964
12351
  const T = React.useMemo(() => exploreStrings(activeLocale), [activeLocale]);
9965
12352
  const rtl = isRtlLocale(activeLocale);
12353
+ const speechLang = speechLocaleOf(activeLocale);
9966
12354
  const {
9967
12355
  phase,
9968
12356
  catalog,
@@ -9983,6 +12371,8 @@ function ExplorePage({
9983
12371
  clearHistory,
9984
12372
  recordClick,
9985
12373
  submitFeedback,
12374
+ escalate,
12375
+ canEscalate,
9986
12376
  createShareLink,
9987
12377
  isSharedView
9988
12378
  } = useExploreChat({
@@ -10067,11 +12457,11 @@ function ExplorePage({
10067
12457
  const layoutHeight = window.innerHeight;
10068
12458
  if (layoutHeight === 0) return;
10069
12459
  const top = Math.round(
10070
- clamp(el.getBoundingClientRect().top, 0, layoutHeight)
12460
+ clamp2(el.getBoundingClientRect().top, 0, layoutHeight)
10071
12461
  );
10072
12462
  const viewport = window.visualViewport;
10073
12463
  const inset = viewport ? Math.round(
10074
- clamp(
12464
+ clamp2(
10075
12465
  layoutHeight - viewport.height - viewport.offsetTop,
10076
12466
  0,
10077
12467
  layoutHeight
@@ -10352,6 +12742,7 @@ function ExplorePage({
10352
12742
  const text = draft.trim();
10353
12743
  if (!text || overLimit || busy || !canSend) return;
10354
12744
  stopDictation();
12745
+ stopSpeaking();
10355
12746
  setDraft("");
10356
12747
  stickToBottomRef.current = true;
10357
12748
  void send(text, toPayload(stagedRef.current));
@@ -10362,6 +12753,7 @@ function ExplorePage({
10362
12753
  const sendPrompt = React.useCallback(
10363
12754
  (prompt) => {
10364
12755
  if (!canSend || busy) return;
12756
+ stopSpeaking();
10365
12757
  setDraft("");
10366
12758
  stickToBottomRef.current = true;
10367
12759
  void send(prompt, toPayload(stagedRef.current));
@@ -10424,6 +12816,7 @@ function ExplorePage({
10424
12816
  ),
10425
12817
  /* @__PURE__ */ jsxRuntime.jsx(ProseStyles, {}),
10426
12818
  /* @__PURE__ */ jsxRuntime.jsx(ExploreStyles, {}),
12819
+ /* @__PURE__ */ jsxRuntime.jsx(ExploreAnswerStyles, {}),
10427
12820
  !showWelcome ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2.5 border-b border-border px-4 py-2.5", children: [
10428
12821
  /* @__PURE__ */ jsxRuntime.jsx(
10429
12822
  "span",
@@ -10597,11 +12990,14 @@ function ExplorePage({
10597
12990
  activity,
10598
12991
  imageOrigins,
10599
12992
  productNames,
12993
+ speechLang,
10600
12994
  onNavigate,
10601
12995
  anchorRef: message.id === latestAssistantId ? latestAssistantRef : void 0,
10602
12996
  onFollow: (kind, url) => recordClick(message.id, kind, url),
10603
12997
  onFollowUp: sendPrompt,
10604
- onFeedback: isSharedView ? void 0 : (rating, detail) => submitFeedback(message.id, rating, detail)
12998
+ onFeedback: isSharedView ? void 0 : (rating, detail) => submitFeedback(message.id, rating, detail),
12999
+ onEscalate: canEscalate ? escalate : void 0,
13000
+ isLatestAnswer: message.id === latestAssistantId
10605
13001
  },
10606
13002
  message.id
10607
13003
  )
@@ -10708,10 +13104,19 @@ function ExplorePage({
10708
13104
  /* @__PURE__ */ jsxRuntime.jsxs(
10709
13105
  "div",
10710
13106
  {
13107
+ "data-boff-explore": "composer-field",
10711
13108
  className: cn(
10712
13109
  "flex min-w-0 items-end gap-2 rounded-2xl border bg-card p-2 shadow-sm transition-all",
10713
13110
  busy && "boff-explore-busy",
10714
- overLimit ? "border-destructive/60" : "border-border focus-within:border-primary/40 focus-within:ring-1 focus-within:ring-ring"
13111
+ overLimit ? "border-destructive/60" : "border-border focus-within:border-primary/40 focus-within:ring-1 focus-within:ring-ring",
13112
+ // The halo is an invitation, and an invitation is only useful before it has
13113
+ // been accepted: while the conversation is empty, the composer is usable, and
13114
+ // nothing has been typed. Once any of those stops being true the class goes
13115
+ // and the box is an ordinary card again. `-quiet` keeps the ring but stops the
13116
+ // movement the moment there are characters in the field, so it does not pulse
13117
+ // at someone who is mid-sentence.
13118
+ showWelcome && !composerDisabled && !overLimit && "boff-explore-invite",
13119
+ showWelcome && draft.length > 0 && "boff-explore-invite-quiet"
10715
13120
  ),
10716
13121
  children: [
10717
13122
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -15558,6 +17963,11 @@ function StoreProductDetailPage({
15558
17963
  ] });
15559
17964
  }
15560
17965
 
17966
+ exports.ANSWERS_PATH = ANSWERS_PATH;
17967
+ exports.ANSWER_HEADING_SHIFT = ANSWER_HEADING_SHIFT;
17968
+ exports.ANSWER_PATH_PREFIX = ANSWER_PATH_PREFIX;
17969
+ exports.AnswerDetailPage = AnswerDetailPage;
17970
+ exports.AnswersPage = AnswersPage;
15561
17971
  exports.BlogListPage = BlogListPage;
15562
17972
  exports.BlogPostPage = BlogPostPage;
15563
17973
  exports.Button = Button;
@@ -15577,12 +17987,16 @@ exports.ContractsPage = ContractsPage;
15577
17987
  exports.DEFAULT_CONTACT_CATEGORIES = DEFAULT_CONTACT_CATEGORIES;
15578
17988
  exports.DEFAULT_EXPLORE_EXAMPLE_PROMPTS = DEFAULT_EXPLORE_EXAMPLE_PROMPTS;
15579
17989
  exports.ECOSYSTEM_PRODUCTS = ECOSYSTEM_PRODUCTS;
17990
+ exports.ESCALATE_EXPLORE_CONVERSATION_MUTATION = ESCALATE_EXPLORE_CONVERSATION_MUTATION;
15580
17991
  exports.EXPLORE_CATALOG_QUERY = EXPLORE_CATALOG_QUERY;
15581
17992
  exports.EXPLORE_CATALOG_QUERY_WITHOUT_HIGHLIGHTS = EXPLORE_CATALOG_QUERY_WITHOUT_HIGHLIGHTS;
17993
+ exports.EXPLORE_ESCALATION_NOTE_SOFT_MAX = EXPLORE_ESCALATION_NOTE_SOFT_MAX;
15582
17994
  exports.EXPLORE_LOCALES = EXPLORE_LOCALES;
15583
17995
  exports.EXPLORE_MESSAGE_QUERY = EXPLORE_MESSAGE_QUERY;
15584
17996
  exports.EXPLORE_RECAPTCHA_ACTION = EXPLORE_RECAPTCHA_ACTION;
15585
17997
  exports.ElectronDownloadLink = ElectronDownloadLink;
17998
+ exports.ExploreAnswerBody = ExploreAnswerBody;
17999
+ exports.ExploreAnswerStyles = ExploreAnswerStyles;
15586
18000
  exports.ExploreCta = ExploreCta;
15587
18001
  exports.ExplorePage = ExplorePage;
15588
18002
  exports.FALLBACK_EXPLORE_LIMITS = FALLBACK_EXPLORE_LIMITS;
@@ -15592,6 +18006,7 @@ exports.LaunchCountdown = LaunchCountdown;
15592
18006
  exports.Markdown = Markdown;
15593
18007
  exports.NewsletterForm = NewsletterForm;
15594
18008
  exports.NewsletterPage = NewsletterPage;
18009
+ exports.PUBLISHED_ANSWER_FIELDS = PUBLISHED_ANSWER_FIELDS;
15595
18010
  exports.PageHead = PageHead;
15596
18011
  exports.PartnersPage = PartnersPage;
15597
18012
  exports.PressKitPage = PressKitPage;
@@ -15617,6 +18032,11 @@ exports.WaitlistPage = WaitlistPage;
15617
18032
  exports.WebSDKClient = WebSDKClient;
15618
18033
  exports.WebSDKProvider = WebSDKProvider;
15619
18034
  exports.WebsiteSwitcher = WebsiteSwitcher;
18035
+ exports.answerPath = answerPath;
18036
+ exports.answerPlainText = answerPlainText;
18037
+ exports.answerSourceHost = answerSourceHost;
18038
+ exports.answerSpeechText = answerSpeechText;
18039
+ exports.answerStrings = answerStrings;
15620
18040
  exports.buttonVariants = buttonVariants;
15621
18041
  exports.classifyExploreError = classifyExploreError;
15622
18042
  exports.cn = cn;
@@ -15625,20 +18045,30 @@ exports.detectElectronPlatform = detectElectronPlatform;
15625
18045
  exports.fetchPublicJobPosting = fetchPublicJobPosting;
15626
18046
  exports.fetchPublicJobPostings = fetchPublicJobPostings;
15627
18047
  exports.fetchPublicJobPostingsForSubmission = fetchPublicJobPostingsForSubmission;
18048
+ exports.formatAnswerDate = formatAnswerDate;
15628
18049
  exports.formatDownloads = formatDownloads;
15629
18050
  exports.formatPrice = formatPrice2;
18051
+ exports.getAnswerBySlug = getAnswerBySlug;
15630
18052
  exports.getConceptBySlug = getConceptBySlug;
15631
18053
  exports.getRecaptchaV3Token = getRecaptchaV3Token;
18054
+ exports.inlineImageOrigins = inlineImageOrigins;
18055
+ exports.isInlineImageAllowed = isInlineImageAllowed;
18056
+ exports.isPublishedSourceUrl = isPublishedSourceUrl;
15632
18057
  exports.isValidUrl = isValidUrl;
15633
18058
  exports.loadRecaptchaV3 = loadRecaptchaV3;
18059
+ exports.looksLikeDeliverableEmail = looksLikeDeliverableEmail;
18060
+ exports.speechLocaleOf = speechLocaleOf;
18061
+ exports.stopSpeaking = stopSpeaking;
15634
18062
  exports.useContentPage = useContentPage;
15635
18063
  exports.useContentPages = useContentPages;
15636
18064
  exports.useExploreChat = useExploreChat;
15637
18065
  exports.useProduct = useProduct;
15638
18066
  exports.useProductConfig = useProductConfig;
18067
+ exports.useProgressiveReveal = useProgressiveReveal;
15639
18068
  exports.usePublicJobPosting = usePublicJobPosting;
15640
18069
  exports.usePublicJobPostings = usePublicJobPostings;
15641
18070
  exports.usePublicJobPostingsForSubmission = usePublicJobPostingsForSubmission;
18071
+ exports.useSpeechOutput = useSpeechOutput;
15642
18072
  exports.useWebSDK = useWebSDK;
15643
18073
  exports.useWebSDKConfig = useWebSDKConfig;
15644
18074
  //# sourceMappingURL=index.js.map