@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.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as React from 'react';
2
- import { createContext, useMemo, useContext, useState, useCallback, useLayoutEffect, useRef, useEffect, useId, version } from 'react';
2
+ import { createContext, useMemo, useContext, useState, useCallback, useLayoutEffect, useRef, useEffect, useId, version, Children, isValidElement, cloneElement } from 'react';
3
3
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
4
- import { Instagram, Youtube, Facebook, Github, Linkedin, Twitter, Mail, Phone, MapPin, Clock, Send, CheckCircle, Upload, Globe, ChevronDown, Search, Rocket, ArrowRight, Download, ImageIcon, ChevronRight, Maximize2, Check, ArrowLeft, Sparkles, RotateCcw, Link2, History, Trash2, Paperclip, X, Mic, Square, ArrowUp, Info, ChevronLeft, BookOpenText, Layers, TriangleAlert, FileText, ExternalLink, Copy, ThumbsUp, ThumbsDown } from 'lucide-react';
4
+ import { Instagram, Youtube, Facebook, Github, Linkedin, Twitter, Mail, Phone, MapPin, Clock, Send, CheckCircle, Upload, Globe, ChevronDown, Search, Rocket, ArrowRight, Download, ImageIcon, ChevronRight, Maximize2, Check, ArrowLeft, Sparkles, RotateCcw, Link2, History, Trash2, Paperclip, X, Mic, Square, ArrowUp, Info, ChevronLeft, BookOpenText, ExternalLink, Layers, TriangleAlert, FileText, Copy, ThumbsUp, ThumbsDown, Volume2 } from 'lucide-react';
5
5
  import ReCAPTCHA4 from 'react-google-recaptcha';
6
6
  import { toast } from 'sonner';
7
7
  import { Helmet } from 'react-helmet-async';
@@ -2408,16 +2408,16 @@ function useRateLimit(maxAttempts, windowMinutes) {
2408
2408
  }
2409
2409
  }, [maxAttempts]);
2410
2410
  function recordAttempt() {
2411
- const now = Date.now();
2411
+ const now2 = Date.now();
2412
2412
  const state = rateLimitRef.current;
2413
- if (state && now > state.resetTime) {
2413
+ if (state && now2 > state.resetTime) {
2414
2414
  rateLimitRef.current = null;
2415
2415
  }
2416
2416
  const current = rateLimitRef.current;
2417
2417
  if (!current) {
2418
2418
  rateLimitRef.current = {
2419
2419
  attempts: 1,
2420
- resetTime: now + windowMinutes * 60 * 1e3
2420
+ resetTime: now2 + windowMinutes * 60 * 1e3
2421
2421
  };
2422
2422
  return false;
2423
2423
  }
@@ -3512,16 +3512,16 @@ function useRateLimit2(maxAttempts, windowMinutes) {
3512
3512
  const [isLimited, setIsLimited] = useState(false);
3513
3513
  const [resetTime, setResetTime] = useState(null);
3514
3514
  function recordAttempt() {
3515
- const now = Date.now();
3515
+ const now2 = Date.now();
3516
3516
  const state = rateLimitRef.current;
3517
- if (state && now > state.resetTime) {
3517
+ if (state && now2 > state.resetTime) {
3518
3518
  rateLimitRef.current = null;
3519
3519
  }
3520
3520
  const current = rateLimitRef.current;
3521
3521
  if (!current) {
3522
3522
  rateLimitRef.current = {
3523
3523
  attempts: 1,
3524
- resetTime: now + windowMinutes * 60 * 1e3
3524
+ resetTime: now2 + windowMinutes * 60 * 1e3
3525
3525
  };
3526
3526
  return false;
3527
3527
  }
@@ -4555,8 +4555,8 @@ function LaunchCountdown({
4555
4555
  launchedMessage = "We have launched!",
4556
4556
  className
4557
4557
  }) {
4558
- const [now, setNow] = useState(() => Date.now());
4559
- const remainingMs = launchDate - now;
4558
+ const [now2, setNow] = useState(() => Date.now());
4559
+ const remainingMs = launchDate - now2;
4560
4560
  const hasLaunched = remainingMs <= 0;
4561
4561
  useEffect(() => {
4562
4562
  if (hasLaunched) return;
@@ -5929,7 +5929,7 @@ var EN = {
5929
5929
  showLess: "Show less",
5930
5930
  sources: "Sources",
5931
5931
  nextYouCouldAsk: "Next you could ask",
5932
- placeholder: "Describe the problem you're facing\u2026",
5932
+ placeholder: "Describe the problem\u2026",
5933
5933
  placeholderProduct: "Describe a problem, or ask about {product}\u2026",
5934
5934
  send: "Send",
5935
5935
  stop: "Stop",
@@ -5970,6 +5970,20 @@ var EN = {
5970
5970
  feedbackDismiss: "Dismiss",
5971
5971
  feedbackThanks: "Thanks \u2014 that helps.",
5972
5972
  feedbackNotSent: "That didn't send.",
5973
+ escalateOpen: "Talk to a person",
5974
+ escalateTitle: "Send this conversation to a person",
5975
+ escalateBody: "We'll pass the whole conversation on, so you don't have to type any of it again.",
5976
+ escalateEmailLabel: "Your email address",
5977
+ escalateEmailPlaceholder: "you@example.com",
5978
+ escalateNoteLabel: "Anything else a person should know? (optional)",
5979
+ escalateSubmit: "Send to a person",
5980
+ escalateSending: "Sending\u2026",
5981
+ escalateCancel: "Cancel",
5982
+ escalateInvalidEmail: "That doesn't look like an address we can reply to. Please check it.",
5983
+ escalateSent: "A person now has this conversation. We'll reply to {email}.",
5984
+ escalateRateLimited: "That's a lot of requests in a short time. Please try again in a few minutes.",
5985
+ escalateCaptcha: "We couldn't verify that you're human. Please try that again.",
5986
+ escalateFailed: "We couldn't pass that on just now. Please try again.",
5973
5987
  prevSuggestion: "Previous suggestion",
5974
5988
  nextSuggestion: "Next suggestion",
5975
5989
  conceptIllustration: "Concept illustration",
@@ -5980,6 +5994,9 @@ var EN = {
5980
5994
  conceptAskQuestion: "How does {title} work in {product}?",
5981
5995
  copyAnswer: "Copy answer",
5982
5996
  copyFailed: "Couldn't copy",
5997
+ readAloud: "Read aloud",
5998
+ stopReading: "Stop reading",
5999
+ answerTable: "Table",
5983
6000
  groundedIn: "What this answer is based on",
5984
6001
  sourceCountOne: "1 source",
5985
6002
  sourceCountMany: "{count} sources",
@@ -6014,7 +6031,7 @@ var ZH = {
6014
6031
  showLess: "\u6536\u8D77",
6015
6032
  sources: "\u6765\u6E90",
6016
6033
  nextYouCouldAsk: "\u4F60\u8FD8\u53EF\u4EE5\u95EE",
6017
- placeholder: "\u63CF\u8FF0\u4F60\u9047\u5230\u7684\u95EE\u9898\u2026",
6034
+ placeholder: "\u63CF\u8FF0\u4F60\u7684\u95EE\u9898\u2026",
6018
6035
  placeholderProduct: "\u63CF\u8FF0\u95EE\u9898\uFF0C\u6216\u8BE2\u95EE {product}\u2026",
6019
6036
  send: "\u53D1\u9001",
6020
6037
  stop: "\u505C\u6B62",
@@ -6052,6 +6069,20 @@ var ZH = {
6052
6069
  feedbackDismiss: "\u5173\u95ED",
6053
6070
  feedbackThanks: "\u8C22\u8C22\uFF0C\u8FD9\u5BF9\u6211\u4EEC\u5F88\u6709\u5E2E\u52A9\u3002",
6054
6071
  feedbackNotSent: "\u6CA1\u6709\u63D0\u4EA4\u6210\u529F\u3002",
6072
+ escalateOpen: "\u8054\u7CFB\u771F\u4EBA",
6073
+ escalateTitle: "\u628A\u8FD9\u6BB5\u5BF9\u8BDD\u8F6C\u7ED9\u771F\u4EBA",
6074
+ 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",
6075
+ escalateEmailLabel: "\u60A8\u7684\u90AE\u7BB1\u5730\u5740",
6076
+ escalateEmailPlaceholder: "you@example.com",
6077
+ escalateNoteLabel: "\u8FD8\u6709\u4EC0\u4E48\u9700\u8981\u544A\u8BC9\u6211\u4EEC\u7684\u5417\uFF1F\uFF08\u9009\u586B\uFF09",
6078
+ escalateSubmit: "\u8F6C\u7ED9\u771F\u4EBA",
6079
+ escalateSending: "\u6B63\u5728\u53D1\u9001\u2026",
6080
+ escalateCancel: "\u53D6\u6D88",
6081
+ 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",
6082
+ escalateSent: "\u5DF2\u6709\u540C\u4E8B\u63A5\u624B\u8FD9\u6BB5\u5BF9\u8BDD\uFF0C\u6211\u4EEC\u4F1A\u56DE\u590D\u5230 {email}\u3002",
6083
+ escalateRateLimited: "\u77ED\u65F6\u95F4\u5185\u8BF7\u6C42\u8FC7\u591A\uFF0C\u8BF7\u51E0\u5206\u949F\u540E\u518D\u8BD5\u3002",
6084
+ escalateCaptcha: "\u6211\u4EEC\u65E0\u6CD5\u9A8C\u8BC1\u60A8\u662F\u771F\u4EBA\uFF0C\u8BF7\u518D\u8BD5\u4E00\u6B21\u3002",
6085
+ escalateFailed: "\u6682\u65F6\u65E0\u6CD5\u8F6C\u4EA4\uFF0C\u8BF7\u518D\u8BD5\u4E00\u6B21\u3002",
6055
6086
  prevSuggestion: "\u4E0A\u4E00\u4E2A\u5EFA\u8BAE",
6056
6087
  nextSuggestion: "\u4E0B\u4E00\u4E2A\u5EFA\u8BAE",
6057
6088
  conceptIllustration: "\u6982\u5FF5\u793A\u610F\u56FE",
@@ -6062,6 +6093,9 @@ var ZH = {
6062
6093
  conceptAskQuestion: "{product} \u7684 {title} \u662F\u600E\u4E48\u8FD0\u4F5C\u7684\uFF1F",
6063
6094
  copyAnswer: "\u590D\u5236\u56DE\u7B54",
6064
6095
  copyFailed: "\u590D\u5236\u5931\u8D25",
6096
+ readAloud: "\u6717\u8BFB",
6097
+ stopReading: "\u505C\u6B62\u6717\u8BFB",
6098
+ answerTable: "\u8868\u683C",
6065
6099
  groundedIn: "\u8FD9\u4E2A\u56DE\u7B54\u7684\u4F9D\u636E",
6066
6100
  sourceCountOne: "1 \u4E2A\u6765\u6E90",
6067
6101
  sourceCountMany: "{count} \u4E2A\u6765\u6E90",
@@ -6092,7 +6126,7 @@ var HI = {
6092
6126
  showLess: "\u0915\u092E \u0926\u093F\u0916\u093E\u090F\u0901",
6093
6127
  sources: "\u0938\u094D\u0930\u094B\u0924",
6094
6128
  nextYouCouldAsk: "\u0906\u0917\u0947 \u0906\u092A \u092A\u0942\u091B \u0938\u0915\u0924\u0947 \u0939\u0948\u0902",
6095
- placeholder: "\u0905\u092A\u0928\u0940 \u0938\u092E\u0938\u094D\u092F\u093E \u092F\u0939\u093E\u0901 \u092C\u0924\u093E\u090F\u0902\u2026",
6129
+ placeholder: "\u0905\u092A\u0928\u0940 \u0938\u092E\u0938\u094D\u092F\u093E \u092C\u0924\u093E\u090F\u0902\u2026",
6096
6130
  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",
6097
6131
  send: "\u092D\u0947\u091C\u0947\u0902",
6098
6132
  stop: "\u0930\u094B\u0915\u0947\u0902",
@@ -6130,6 +6164,20 @@ var HI = {
6130
6164
  feedbackDismiss: "\u092C\u0902\u0926 \u0915\u0930\u0947\u0902",
6131
6165
  feedbackThanks: "\u0927\u0928\u094D\u092F\u0935\u093E\u0926, \u0907\u0938\u0938\u0947 \u092E\u0926\u0926 \u092E\u093F\u0932\u0924\u0940 \u0939\u0948\u0964",
6132
6166
  feedbackNotSent: "\u092F\u0939 \u092D\u0947\u091C\u093E \u0928\u0939\u0940\u0902 \u091C\u093E \u0938\u0915\u093E\u0964",
6167
+ escalateOpen: "\u0915\u093F\u0938\u0940 \u0935\u094D\u092F\u0915\u094D\u0924\u093F \u0938\u0947 \u092C\u093E\u0924 \u0915\u0930\u0947\u0902",
6168
+ 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",
6169
+ 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",
6170
+ escalateEmailLabel: "\u0906\u092A\u0915\u093E \u0908\u092E\u0947\u0932 \u092A\u0924\u093E",
6171
+ escalateEmailPlaceholder: "you@example.com",
6172
+ 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)",
6173
+ escalateSubmit: "\u0915\u093F\u0938\u0940 \u0935\u094D\u092F\u0915\u094D\u0924\u093F \u0915\u094B \u092D\u0947\u091C\u0947\u0902",
6174
+ escalateSending: "\u092D\u0947\u091C\u093E \u091C\u093E \u0930\u0939\u093E \u0939\u0948\u2026",
6175
+ escalateCancel: "\u0930\u0926\u094D\u0926 \u0915\u0930\u0947\u0902",
6176
+ 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",
6177
+ 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",
6178
+ 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",
6179
+ 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",
6180
+ 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",
6133
6181
  prevSuggestion: "\u092A\u093F\u091B\u0932\u093E \u0938\u0941\u091D\u093E\u0935",
6134
6182
  nextSuggestion: "\u0905\u0917\u0932\u093E \u0938\u0941\u091D\u093E\u0935",
6135
6183
  conceptIllustration: "\u0905\u0935\u0927\u093E\u0930\u0923\u093E \u091A\u093F\u0924\u094D\u0930\u0923",
@@ -6140,6 +6188,9 @@ var HI = {
6140
6188
  conceptAskQuestion: "{product} \u092E\u0947\u0902 {title} \u0915\u0948\u0938\u0947 \u0915\u093E\u092E \u0915\u0930\u0924\u093E \u0939\u0948?",
6141
6189
  copyAnswer: "\u0909\u0924\u094D\u0924\u0930 \u0915\u0949\u092A\u0940 \u0915\u0930\u0947\u0902",
6142
6190
  copyFailed: "\u0915\u0949\u092A\u0940 \u0928\u0939\u0940\u0902 \u0939\u094B \u0938\u0915\u093E",
6191
+ readAloud: "\u091C\u093C\u094B\u0930 \u0938\u0947 \u092A\u0922\u093C\u0947\u0902",
6192
+ stopReading: "\u092A\u0922\u093C\u0928\u093E \u092C\u0902\u0926 \u0915\u0930\u0947\u0902",
6193
+ answerTable: "\u0924\u093E\u0932\u093F\u0915\u093E",
6143
6194
  groundedIn: "\u092F\u0939 \u0909\u0924\u094D\u0924\u0930 \u0915\u093F\u0938 \u092A\u0930 \u0906\u0927\u093E\u0930\u093F\u0924 \u0939\u0948",
6144
6195
  sourceCountOne: "1 \u0938\u094D\u0930\u094B\u0924",
6145
6196
  sourceCountMany: "{count} \u0938\u094D\u0930\u094B\u0924",
@@ -6174,7 +6225,7 @@ var ES = {
6174
6225
  showLess: "Ver menos",
6175
6226
  sources: "Fuentes",
6176
6227
  nextYouCouldAsk: "Tambi\xE9n puedes preguntar",
6177
- placeholder: "Describe el problema que tienes\u2026",
6228
+ placeholder: "Describe el problema\u2026",
6178
6229
  placeholderProduct: "Describe un problema o pregunta por {product}\u2026",
6179
6230
  send: "Enviar",
6180
6231
  stop: "Detener",
@@ -6212,6 +6263,20 @@ var ES = {
6212
6263
  feedbackDismiss: "Cerrar",
6213
6264
  feedbackThanks: "Gracias, nos sirve.",
6214
6265
  feedbackNotSent: "No se ha podido enviar.",
6266
+ escalateOpen: "Hablar con una persona",
6267
+ escalateTitle: "Env\xEDa esta conversaci\xF3n a una persona",
6268
+ escalateBody: "Le pasaremos la conversaci\xF3n entera, as\xED no tienes que volver a escribirla.",
6269
+ escalateEmailLabel: "Tu direcci\xF3n de correo",
6270
+ escalateEmailPlaceholder: "tu@ejemplo.com",
6271
+ escalateNoteLabel: "\xBFAlgo m\xE1s que deber\xEDamos saber? (opcional)",
6272
+ escalateSubmit: "Enviar a una persona",
6273
+ escalateSending: "Enviando\u2026",
6274
+ escalateCancel: "Cancelar",
6275
+ escalateInvalidEmail: "No parece una direcci\xF3n a la que podamos responder. Rev\xEDsala, por favor.",
6276
+ escalateSent: "Una persona ya tiene esta conversaci\xF3n. Te responderemos a {email}.",
6277
+ escalateRateLimited: "Han sido muchas peticiones en poco tiempo. Int\xE9ntalo de nuevo en unos minutos.",
6278
+ escalateCaptcha: "No hemos podido verificar que eres una persona. Int\xE9ntalo de nuevo.",
6279
+ escalateFailed: "No hemos podido pasarlo ahora mismo. Int\xE9ntalo de nuevo.",
6215
6280
  prevSuggestion: "Sugerencia anterior",
6216
6281
  nextSuggestion: "Sugerencia siguiente",
6217
6282
  conceptIllustration: "Ilustraci\xF3n del concepto",
@@ -6222,6 +6287,9 @@ var ES = {
6222
6287
  conceptAskQuestion: "\xBFC\xF3mo funciona {title} en {product}?",
6223
6288
  copyAnswer: "Copiar respuesta",
6224
6289
  copyFailed: "No se pudo copiar",
6290
+ readAloud: "Leer en voz alta",
6291
+ stopReading: "Dejar de leer",
6292
+ answerTable: "Tabla",
6225
6293
  groundedIn: "En qu\xE9 se basa esta respuesta",
6226
6294
  sourceCountOne: "1 fuente",
6227
6295
  sourceCountMany: "{count} fuentes",
@@ -6256,7 +6324,7 @@ var AR = {
6256
6324
  showLess: "\u0639\u0631\u0636 \u0623\u0642\u0644",
6257
6325
  sources: "\u0627\u0644\u0645\u0635\u0627\u062F\u0631",
6258
6326
  nextYouCouldAsk: "\u064A\u0645\u0643\u0646\u0643 \u0623\u0646 \u062A\u0633\u0623\u0644 \u0628\u0639\u062F \u0630\u0644\u0643",
6259
- placeholder: "\u0635\u0641 \u0627\u0644\u0645\u0634\u0643\u0644\u0629 \u0627\u0644\u062A\u064A \u062A\u0648\u0627\u062C\u0647\u0647\u0627\u2026",
6327
+ placeholder: "\u0635\u0641 \u0627\u0644\u0645\u0634\u0643\u0644\u0629\u2026",
6260
6328
  placeholderProduct: "\u0635\u0641 \u0645\u0634\u0643\u0644\u062A\u0643 \u0623\u0648 \u0627\u0633\u0623\u0644 \u0639\u0646 {product}\u2026",
6261
6329
  send: "\u0625\u0631\u0633\u0627\u0644",
6262
6330
  stop: "\u0625\u064A\u0642\u0627\u0641",
@@ -6294,6 +6362,20 @@ var AR = {
6294
6362
  feedbackDismiss: "\u0625\u063A\u0644\u0627\u0642",
6295
6363
  feedbackThanks: "\u0634\u0643\u0631\u064B\u0627\u060C \u0647\u0630\u0627 \u064A\u0633\u0627\u0639\u062F\u0646\u0627.",
6296
6364
  feedbackNotSent: "\u0644\u0645 \u064A\u062A\u0645 \u0627\u0644\u0625\u0631\u0633\u0627\u0644.",
6365
+ escalateOpen: "\u062A\u0648\u0627\u0635\u0644 \u0645\u0639 \u0634\u062E\u0635",
6366
+ escalateTitle: "\u0623\u0631\u0633\u0644 \u0647\u0630\u0647 \u0627\u0644\u0645\u062D\u0627\u062F\u062B\u0629 \u0625\u0644\u0649 \u0634\u062E\u0635",
6367
+ 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.",
6368
+ escalateEmailLabel: "\u0628\u0631\u064A\u062F\u0643 \u0627\u0644\u0625\u0644\u0643\u062A\u0631\u0648\u0646\u064A",
6369
+ escalateEmailPlaceholder: "you@example.com",
6370
+ 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)",
6371
+ escalateSubmit: "\u0625\u0631\u0633\u0627\u0644 \u0625\u0644\u0649 \u0634\u062E\u0635",
6372
+ escalateSending: "\u062C\u0627\u0631\u064D \u0627\u0644\u0625\u0631\u0633\u0627\u0644\u2026",
6373
+ escalateCancel: "\u0625\u0644\u063A\u0627\u0621",
6374
+ 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.",
6375
+ 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}.",
6376
+ 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.",
6377
+ 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.",
6378
+ 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.",
6297
6379
  prevSuggestion: "\u0627\u0644\u0627\u0642\u062A\u0631\u0627\u062D \u0627\u0644\u0633\u0627\u0628\u0642",
6298
6380
  nextSuggestion: "\u0627\u0644\u0627\u0642\u062A\u0631\u0627\u062D \u0627\u0644\u062A\u0627\u0644\u064A",
6299
6381
  conceptIllustration: "\u0631\u0633\u0645 \u062A\u0648\u0636\u064A\u062D\u064A \u0644\u0644\u0645\u0641\u0647\u0648\u0645",
@@ -6304,6 +6386,9 @@ var AR = {
6304
6386
  conceptAskQuestion: "\u0643\u064A\u0641 \u064A\u0639\u0645\u0644 {title} \u0641\u064A {product}\u061F",
6305
6387
  copyAnswer: "\u0646\u0633\u062E \u0627\u0644\u0625\u062C\u0627\u0628\u0629",
6306
6388
  copyFailed: "\u062A\u0639\u0630\u0651\u0631 \u0627\u0644\u0646\u0633\u062E",
6389
+ readAloud: "\u0627\u0642\u0631\u0623 \u0628\u0635\u0648\u062A \u0639\u0627\u0644\u064D",
6390
+ stopReading: "\u0625\u064A\u0642\u0627\u0641 \u0627\u0644\u0642\u0631\u0627\u0621\u0629",
6391
+ answerTable: "\u062C\u062F\u0648\u0644",
6307
6392
  groundedIn: "\u0639\u0644\u0649 \u0645\u0627\u0630\u0627 \u062A\u0633\u062A\u0646\u062F \u0647\u0630\u0647 \u0627\u0644\u0625\u062C\u0627\u0628\u0629",
6308
6393
  sourceCountOne: "\u0645\u0635\u062F\u0631 \u0648\u0627\u062D\u062F",
6309
6394
  sourceCountMany: "{count} \u0645\u0635\u0627\u062F\u0631",
@@ -6338,7 +6423,7 @@ var TA = {
6338
6423
  showLess: "\u0B95\u0BC1\u0BB1\u0BC8\u0BB5\u0BBE\u0B95\u0B95\u0BCD \u0B95\u0BBE\u0B9F\u0BCD\u0B9F\u0BC1",
6339
6424
  sources: "\u0BAE\u0BC2\u0BB2\u0B99\u0BCD\u0B95\u0BB3\u0BCD",
6340
6425
  nextYouCouldAsk: "\u0B85\u0B9F\u0BC1\u0BA4\u0BCD\u0BA4\u0BC1 \u0BA8\u0BC0\u0B99\u0BCD\u0B95\u0BB3\u0BCD \u0B95\u0BC7\u0B9F\u0BCD\u0B95\u0BB2\u0BBE\u0BAE\u0BCD",
6341
- 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",
6426
+ placeholder: "\u0B9A\u0BBF\u0B95\u0BCD\u0B95\u0BB2\u0BC8 \u0BB5\u0BBF\u0BB5\u0BB0\u0BBF\u0BAF\u0BC1\u0B99\u0BCD\u0B95\u0BB3\u0BCD\u2026",
6342
6427
  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",
6343
6428
  send: "\u0B85\u0BA9\u0BC1\u0BAA\u0BCD\u0BAA\u0BC1",
6344
6429
  stop: "\u0BA8\u0BBF\u0BB1\u0BC1\u0BA4\u0BCD\u0BA4\u0BC1",
@@ -6376,6 +6461,20 @@ var TA = {
6376
6461
  feedbackDismiss: "\u0BAE\u0BC2\u0B9F\u0BC1",
6377
6462
  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.",
6378
6463
  feedbackNotSent: "\u0B85\u0BA9\u0BC1\u0BAA\u0BCD\u0BAA \u0BAE\u0BC1\u0B9F\u0BBF\u0BAF\u0BB5\u0BBF\u0BB2\u0BCD\u0BB2\u0BC8.",
6464
+ escalateOpen: "\u0B92\u0BB0\u0BC1\u0BB5\u0BB0\u0BBF\u0B9F\u0BAE\u0BCD \u0BAA\u0BC7\u0B9A\u0BC1\u0B99\u0BCD\u0B95\u0BB3\u0BCD",
6465
+ 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",
6466
+ 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.",
6467
+ escalateEmailLabel: "\u0B89\u0B99\u0BCD\u0B95\u0BB3\u0BCD \u0BAE\u0BBF\u0BA9\u0BCD\u0BA9\u0B9E\u0BCD\u0B9A\u0BB2\u0BCD \u0BAE\u0BC1\u0B95\u0BB5\u0BB0\u0BBF",
6468
+ escalateEmailPlaceholder: "you@example.com",
6469
+ 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)",
6470
+ escalateSubmit: "\u0B92\u0BB0\u0BC1\u0BB5\u0BB0\u0BC1\u0B95\u0BCD\u0B95\u0BC1 \u0B85\u0BA9\u0BC1\u0BAA\u0BCD\u0BAA\u0BC1",
6471
+ escalateSending: "\u0B85\u0BA9\u0BC1\u0BAA\u0BCD\u0BAA\u0BAA\u0BCD\u0BAA\u0B9F\u0BC1\u0B95\u0BBF\u0BB1\u0BA4\u0BC1\u2026",
6472
+ escalateCancel: "\u0BB0\u0BA4\u0BCD\u0BA4\u0BC1 \u0B9A\u0BC6\u0BAF\u0BCD",
6473
+ 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.",
6474
+ 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.",
6475
+ 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.",
6476
+ 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.",
6477
+ 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.",
6379
6478
  prevSuggestion: "\u0BAE\u0BC1\u0BA8\u0BCD\u0BA4\u0BC8\u0BAF \u0BAA\u0BB0\u0BBF\u0BA8\u0BCD\u0BA4\u0BC1\u0BB0\u0BC8",
6380
6479
  nextSuggestion: "\u0B85\u0B9F\u0BC1\u0BA4\u0BCD\u0BA4 \u0BAA\u0BB0\u0BBF\u0BA8\u0BCD\u0BA4\u0BC1\u0BB0\u0BC8",
6381
6480
  conceptIllustration: "\u0B95\u0BB0\u0BC1\u0BA4\u0BCD\u0BA4\u0BC1 \u0BB5\u0BBF\u0BB3\u0B95\u0BCD\u0B95\u0BAA\u0BCD\u0BAA\u0B9F\u0BAE\u0BCD",
@@ -6386,6 +6485,9 @@ var TA = {
6386
6485
  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?",
6387
6486
  copyAnswer: "\u0BAA\u0BA4\u0BBF\u0BB2\u0BC8 \u0BA8\u0B95\u0BB2\u0BC6\u0B9F\u0BC1",
6388
6487
  copyFailed: "\u0BA8\u0B95\u0BB2\u0BC6\u0B9F\u0BC1\u0B95\u0BCD\u0B95 \u0BAE\u0BC1\u0B9F\u0BBF\u0BAF\u0BB5\u0BBF\u0BB2\u0BCD\u0BB2\u0BC8",
6488
+ readAloud: "\u0B9A\u0BA4\u0BCD\u0BA4\u0BAE\u0BBE\u0B95\u0BAA\u0BCD \u0BAA\u0B9F\u0BBF",
6489
+ stopReading: "\u0BAA\u0B9F\u0BBF\u0BAA\u0BCD\u0BAA\u0BA4\u0BC8 \u0BA8\u0BBF\u0BB1\u0BC1\u0BA4\u0BCD\u0BA4\u0BC1",
6490
+ answerTable: "\u0B85\u0B9F\u0BCD\u0B9F\u0BB5\u0BA3\u0BC8",
6389
6491
  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",
6390
6492
  sourceCountOne: "1 \u0BAE\u0BC2\u0BB2\u0BAE\u0BCD",
6391
6493
  sourceCountMany: "{count} \u0BAE\u0BC2\u0BB2\u0B99\u0BCD\u0B95\u0BB3\u0BCD",
@@ -6417,6 +6519,17 @@ var STRINGS = {
6417
6519
  ar: AR,
6418
6520
  ta: TA
6419
6521
  };
6522
+ var SPEECH_TAGS = {
6523
+ en: "en-US",
6524
+ zh: "zh-CN",
6525
+ hi: "hi-IN",
6526
+ es: "es-ES",
6527
+ ar: "ar-SA",
6528
+ ta: "ta-IN"
6529
+ };
6530
+ function speechLocaleOf(locale) {
6531
+ return SPEECH_TAGS[locale];
6532
+ }
6420
6533
  function resolveExploreLocale(explicit) {
6421
6534
  const candidates = [
6422
6535
  explicit,
@@ -6438,192 +6551,721 @@ function fill(template, values) {
6438
6551
  return template.replace(/\{(\w+)\}/g, (match, key) => values[key] ?? match);
6439
6552
  }
6440
6553
 
6441
- // src/components/explore-types.ts
6442
- var EXPLORE_FEEDBACK_REASONS = [
6443
- "INACCURATE",
6444
- "INCOMPLETE",
6445
- "OFF_TOPIC",
6446
- "HARD_TO_FOLLOW",
6447
- "OTHER"
6448
- ];
6449
- var EXPLORE_MESSAGE_FIELDS = (
6450
- /* GraphQL */
6451
- `
6452
- id
6453
- conversationId
6454
- role
6455
- status
6456
- content
6457
- partialContent
6458
- activity
6459
- references {
6460
- url
6461
- title
6462
- description
6463
- product
6464
- imageUrl
6465
- index
6554
+ // src/components/answers-i18n.ts
6555
+ var EN2 = {
6556
+ breadcrumbHome: "Home",
6557
+ answers: "Answers",
6558
+ indexHeading: "{product} answers",
6559
+ indexLead: "Questions about {product}, each answered by our own assistant from our published documentation \u2014 with links to the pages the answer came from.",
6560
+ seoIndexTitle: "Answers",
6561
+ seoIndexDescription: "Questions about {product}, answered from our published documentation, each with links to the pages the answer came from.",
6562
+ searchLabel: "Search questions",
6563
+ searchPlaceholder: "Search questions",
6564
+ filterByTopic: "Filter by topic",
6565
+ allTopics: "All",
6566
+ showingCount: "Showing {shown} of {total} questions",
6567
+ noMatchesTitle: "No questions match your filters",
6568
+ noMatchesBody: "Try a different search, or show every topic.",
6569
+ clearFilters: "Clear filters",
6570
+ noneYetTitle: "No answers published yet",
6571
+ noneYetBody: "{product} answers will appear here as they are published.",
6572
+ questionCountOne: "1 question",
6573
+ questionCountMany: "{count} questions",
6574
+ sourceCountOne: "1 source",
6575
+ sourceCountMany: "{count} sources",
6576
+ answerHeading: "Answer",
6577
+ sourcesHeading: "Sources",
6578
+ sourcesLead: "The pages this answer was drawn from.",
6579
+ aboutTitle: "About this answer",
6580
+ 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.",
6581
+ answeredOn: "Answered {date}",
6582
+ topicsHeading: "Topics",
6583
+ relatedHeading: "Related questions",
6584
+ moreInTopic: "More in {topic}",
6585
+ previousQuestion: "Previous question",
6586
+ nextQuestion: "Next question",
6587
+ allAnswers: "All {product} answers",
6588
+ askYourOwn: "Ask your own question"
6589
+ };
6590
+ var ZH2 = {
6591
+ breadcrumbHome: "\u9996\u9875",
6592
+ answers: "\u95EE\u7B54",
6593
+ indexHeading: "{product} \u95EE\u7B54",
6594
+ 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",
6595
+ seoIndexTitle: "\u95EE\u7B54",
6596
+ 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",
6597
+ searchLabel: "\u641C\u7D22\u95EE\u9898",
6598
+ searchPlaceholder: "\u641C\u7D22\u95EE\u9898",
6599
+ filterByTopic: "\u6309\u4E3B\u9898\u7B5B\u9009",
6600
+ allTopics: "\u5168\u90E8",
6601
+ showingCount: "\u663E\u793A {total} \u4E2A\u95EE\u9898\u4E2D\u7684 {shown} \u4E2A",
6602
+ noMatchesTitle: "\u6CA1\u6709\u7B26\u5408\u7B5B\u9009\u6761\u4EF6\u7684\u95EE\u9898",
6603
+ noMatchesBody: "\u6362\u4E2A\u641C\u7D22\u8BCD\uFF0C\u6216\u663E\u793A\u5168\u90E8\u4E3B\u9898\u3002",
6604
+ clearFilters: "\u6E05\u9664\u7B5B\u9009",
6605
+ noneYetTitle: "\u5C1A\u672A\u53D1\u5E03\u95EE\u7B54",
6606
+ noneYetBody: "{product} \u7684\u95EE\u7B54\u53D1\u5E03\u540E\u4F1A\u663E\u793A\u5728\u8FD9\u91CC\u3002",
6607
+ questionCountOne: "1 \u4E2A\u95EE\u9898",
6608
+ questionCountMany: "{count} \u4E2A\u95EE\u9898",
6609
+ sourceCountOne: "1 \u4E2A\u6765\u6E90",
6610
+ sourceCountMany: "{count} \u4E2A\u6765\u6E90",
6611
+ answerHeading: "\u56DE\u7B54",
6612
+ sourcesHeading: "\u6765\u6E90",
6613
+ sourcesLead: "\u672C\u56DE\u7B54\u6240\u4F9D\u636E\u7684\u9875\u9762\u3002",
6614
+ aboutTitle: "\u5173\u4E8E\u8FD9\u4E2A\u56DE\u7B54",
6615
+ 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",
6616
+ answeredOn: "\u56DE\u7B54\u4E8E {date}",
6617
+ topicsHeading: "\u4E3B\u9898",
6618
+ relatedHeading: "\u76F8\u5173\u95EE\u9898",
6619
+ moreInTopic: "\u66F4\u591A\u300C{topic}\u300D\u95EE\u9898",
6620
+ previousQuestion: "\u4E0A\u4E00\u4E2A\u95EE\u9898",
6621
+ nextQuestion: "\u4E0B\u4E00\u4E2A\u95EE\u9898",
6622
+ allAnswers: "\u5168\u90E8 {product} \u95EE\u7B54",
6623
+ askYourOwn: "\u63D0\u51FA\u4F60\u7684\u95EE\u9898"
6624
+ };
6625
+ var HI2 = {
6626
+ breadcrumbHome: "\u0939\u094B\u092E",
6627
+ answers: "\u0909\u0924\u094D\u0924\u0930",
6628
+ indexHeading: "{product} \u0915\u0947 \u0909\u0924\u094D\u0924\u0930",
6629
+ 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",
6630
+ seoIndexTitle: "\u0909\u0924\u094D\u0924\u0930",
6631
+ 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",
6632
+ searchLabel: "\u0938\u0935\u093E\u0932 \u0916\u094B\u091C\u0947\u0902",
6633
+ searchPlaceholder: "\u0938\u0935\u093E\u0932 \u0916\u094B\u091C\u0947\u0902",
6634
+ filterByTopic: "\u0935\u093F\u0937\u092F \u0938\u0947 \u091B\u093E\u0901\u091F\u0947\u0902",
6635
+ allTopics: "\u0938\u092D\u0940",
6636
+ showingCount: "{total} \u092E\u0947\u0902 \u0938\u0947 {shown} \u0938\u0935\u093E\u0932 \u0926\u093F\u0916 \u0930\u0939\u0947 \u0939\u0948\u0902",
6637
+ 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",
6638
+ 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",
6639
+ clearFilters: "\u091B\u0901\u091F\u093E\u0908 \u0939\u091F\u093E\u090F\u0901",
6640
+ 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",
6641
+ 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",
6642
+ questionCountOne: "1 \u0938\u0935\u093E\u0932",
6643
+ questionCountMany: "{count} \u0938\u0935\u093E\u0932",
6644
+ sourceCountOne: "1 \u0938\u094D\u0930\u094B\u0924",
6645
+ sourceCountMany: "{count} \u0938\u094D\u0930\u094B\u0924",
6646
+ answerHeading: "\u0909\u0924\u094D\u0924\u0930",
6647
+ sourcesHeading: "\u0938\u094D\u0930\u094B\u0924",
6648
+ 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",
6649
+ aboutTitle: "\u0907\u0938 \u0909\u0924\u094D\u0924\u0930 \u0915\u0947 \u092C\u093E\u0930\u0947 \u092E\u0947\u0902",
6650
+ 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",
6651
+ answeredOn: "{date} \u0915\u094B \u0909\u0924\u094D\u0924\u0930 \u0926\u093F\u092F\u093E \u0917\u092F\u093E",
6652
+ topicsHeading: "\u0935\u093F\u0937\u092F",
6653
+ relatedHeading: "\u0938\u0902\u092C\u0902\u0927\u093F\u0924 \u0938\u0935\u093E\u0932",
6654
+ moreInTopic: "{topic} \u092E\u0947\u0902 \u0914\u0930",
6655
+ previousQuestion: "\u092A\u093F\u091B\u0932\u093E \u0938\u0935\u093E\u0932",
6656
+ nextQuestion: "\u0905\u0917\u0932\u093E \u0938\u0935\u093E\u0932",
6657
+ allAnswers: "{product} \u0915\u0947 \u0938\u092D\u0940 \u0909\u0924\u094D\u0924\u0930",
6658
+ askYourOwn: "\u0905\u092A\u0928\u093E \u0938\u0935\u093E\u0932 \u092A\u0942\u091B\u0947\u0902"
6659
+ };
6660
+ var ES2 = {
6661
+ breadcrumbHome: "Inicio",
6662
+ answers: "Respuestas",
6663
+ indexHeading: "Respuestas sobre {product}",
6664
+ 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.",
6665
+ seoIndexTitle: "Respuestas",
6666
+ seoIndexDescription: "Preguntas sobre {product} respondidas a partir de nuestra documentaci\xF3n publicada, cada una con enlaces a las p\xE1ginas de origen.",
6667
+ searchLabel: "Buscar preguntas",
6668
+ searchPlaceholder: "Buscar preguntas",
6669
+ filterByTopic: "Filtrar por tema",
6670
+ allTopics: "Todas",
6671
+ showingCount: "Mostrando {shown} de {total} preguntas",
6672
+ noMatchesTitle: "Ninguna pregunta coincide con los filtros",
6673
+ noMatchesBody: "Prueba otra b\xFAsqueda o muestra todos los temas.",
6674
+ clearFilters: "Quitar filtros",
6675
+ noneYetTitle: "Todav\xEDa no hay respuestas publicadas",
6676
+ noneYetBody: "Las respuestas sobre {product} aparecer\xE1n aqu\xED a medida que se publiquen.",
6677
+ questionCountOne: "1 pregunta",
6678
+ questionCountMany: "{count} preguntas",
6679
+ sourceCountOne: "1 fuente",
6680
+ sourceCountMany: "{count} fuentes",
6681
+ answerHeading: "Respuesta",
6682
+ sourcesHeading: "Fuentes",
6683
+ sourcesLead: "Las p\xE1ginas de las que sali\xF3 esta respuesta.",
6684
+ aboutTitle: "Sobre esta respuesta",
6685
+ 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.",
6686
+ answeredOn: "Respondida el {date}",
6687
+ topicsHeading: "Temas",
6688
+ relatedHeading: "Preguntas relacionadas",
6689
+ moreInTopic: "M\xE1s de {topic}",
6690
+ previousQuestion: "Pregunta anterior",
6691
+ nextQuestion: "Pregunta siguiente",
6692
+ allAnswers: "Todas las respuestas sobre {product}",
6693
+ askYourOwn: "Haz tu propia pregunta"
6694
+ };
6695
+ var AR2 = {
6696
+ breadcrumbHome: "\u0627\u0644\u0631\u0626\u064A\u0633\u064A\u0629",
6697
+ answers: "\u0627\u0644\u0625\u062C\u0627\u0628\u0627\u062A",
6698
+ indexHeading: "\u0625\u062C\u0627\u0628\u0627\u062A {product}",
6699
+ 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.",
6700
+ seoIndexTitle: "\u0627\u0644\u0625\u062C\u0627\u0628\u0627\u062A",
6701
+ 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.",
6702
+ searchLabel: "\u0627\u0628\u062D\u062B \u0641\u064A \u0627\u0644\u0623\u0633\u0626\u0644\u0629",
6703
+ searchPlaceholder: "\u0627\u0628\u062D\u062B \u0641\u064A \u0627\u0644\u0623\u0633\u0626\u0644\u0629",
6704
+ filterByTopic: "\u062A\u0635\u0641\u064A\u0629 \u062D\u0633\u0628 \u0627\u0644\u0645\u0648\u0636\u0648\u0639",
6705
+ allTopics: "\u0627\u0644\u0643\u0644",
6706
+ showingCount: "\u0639\u0631\u0636 {shown} \u0645\u0646 {total} \u0633\u0624\u0627\u0644\u064B\u0627",
6707
+ noMatchesTitle: "\u0644\u0627 \u062A\u0648\u062C\u062F \u0623\u0633\u0626\u0644\u0629 \u062A\u0637\u0627\u0628\u0642 \u0627\u0644\u062A\u0635\u0641\u064A\u0629",
6708
+ 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.",
6709
+ clearFilters: "\u0645\u0633\u062D \u0627\u0644\u062A\u0635\u0641\u064A\u0629",
6710
+ noneYetTitle: "\u0644\u0645 \u062A\u064F\u0646\u0634\u0631 \u0625\u062C\u0627\u0628\u0627\u062A \u0628\u0639\u062F",
6711
+ noneYetBody: "\u0633\u062A\u0638\u0647\u0631 \u0625\u062C\u0627\u0628\u0627\u062A {product} \u0647\u0646\u0627 \u0641\u0648\u0631 \u0646\u0634\u0631\u0647\u0627.",
6712
+ questionCountOne: "\u0633\u0624\u0627\u0644 \u0648\u0627\u062D\u062F",
6713
+ questionCountMany: "{count} \u0623\u0633\u0626\u0644\u0629",
6714
+ sourceCountOne: "\u0645\u0635\u062F\u0631 \u0648\u0627\u062D\u062F",
6715
+ sourceCountMany: "{count} \u0645\u0635\u0627\u062F\u0631",
6716
+ answerHeading: "\u0627\u0644\u0625\u062C\u0627\u0628\u0629",
6717
+ sourcesHeading: "\u0627\u0644\u0645\u0635\u0627\u062F\u0631",
6718
+ 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.",
6719
+ aboutTitle: "\u0639\u0646 \u0647\u0630\u0647 \u0627\u0644\u0625\u062C\u0627\u0628\u0629",
6720
+ 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.",
6721
+ answeredOn: "\u0623\u064F\u062C\u064A\u0628 \u0639\u0646\u0647 \u0641\u064A {date}",
6722
+ topicsHeading: "\u0627\u0644\u0645\u0648\u0627\u0636\u064A\u0639",
6723
+ relatedHeading: "\u0623\u0633\u0626\u0644\u0629 \u0630\u0627\u062A \u0635\u0644\u0629",
6724
+ moreInTopic: "\u0627\u0644\u0645\u0632\u064A\u062F \u0641\u064A {topic}",
6725
+ previousQuestion: "\u0627\u0644\u0633\u0624\u0627\u0644 \u0627\u0644\u0633\u0627\u0628\u0642",
6726
+ nextQuestion: "\u0627\u0644\u0633\u0624\u0627\u0644 \u0627\u0644\u062A\u0627\u0644\u064A",
6727
+ allAnswers: "\u0643\u0644 \u0625\u062C\u0627\u0628\u0627\u062A {product}",
6728
+ askYourOwn: "\u0627\u0637\u0631\u062D \u0633\u0624\u0627\u0644\u0643"
6729
+ };
6730
+ var TA2 = {
6731
+ breadcrumbHome: "\u0BAE\u0BC1\u0B95\u0BAA\u0BCD\u0BAA\u0BC1",
6732
+ answers: "\u0BAA\u0BA4\u0BBF\u0BB2\u0BCD\u0B95\u0BB3\u0BCD",
6733
+ indexHeading: "{product} \u0BAA\u0BA4\u0BBF\u0BB2\u0BCD\u0B95\u0BB3\u0BCD",
6734
+ 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.",
6735
+ seoIndexTitle: "\u0BAA\u0BA4\u0BBF\u0BB2\u0BCD\u0B95\u0BB3\u0BCD",
6736
+ 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.",
6737
+ searchLabel: "\u0B95\u0BC7\u0BB3\u0BCD\u0BB5\u0BBF\u0B95\u0BB3\u0BC8\u0BA4\u0BCD \u0BA4\u0BC7\u0B9F\u0BC1\u0B99\u0BCD\u0B95\u0BB3\u0BCD",
6738
+ searchPlaceholder: "\u0B95\u0BC7\u0BB3\u0BCD\u0BB5\u0BBF\u0B95\u0BB3\u0BC8\u0BA4\u0BCD \u0BA4\u0BC7\u0B9F\u0BC1\u0B99\u0BCD\u0B95\u0BB3\u0BCD",
6739
+ filterByTopic: "\u0BA4\u0BB2\u0BC8\u0BAA\u0BCD\u0BAA\u0BBF\u0BA9\u0BCD\u0BAA\u0B9F\u0BBF \u0BB5\u0B9F\u0BBF\u0B95\u0B9F\u0BCD\u0B9F\u0BC1",
6740
+ allTopics: "\u0B85\u0BA9\u0BC8\u0BA4\u0BCD\u0BA4\u0BC1\u0BAE\u0BCD",
6741
+ 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",
6742
+ 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",
6743
+ 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.",
6744
+ clearFilters: "\u0BB5\u0B9F\u0BBF\u0B95\u0B9F\u0BCD\u0B9F\u0BB2\u0BC8 \u0BA8\u0BC0\u0B95\u0BCD\u0B95\u0BC1",
6745
+ 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",
6746
+ 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.",
6747
+ questionCountOne: "1 \u0B95\u0BC7\u0BB3\u0BCD\u0BB5\u0BBF",
6748
+ questionCountMany: "{count} \u0B95\u0BC7\u0BB3\u0BCD\u0BB5\u0BBF\u0B95\u0BB3\u0BCD",
6749
+ sourceCountOne: "1 \u0BAE\u0BC2\u0BB2\u0BAE\u0BCD",
6750
+ sourceCountMany: "{count} \u0BAE\u0BC2\u0BB2\u0B99\u0BCD\u0B95\u0BB3\u0BCD",
6751
+ answerHeading: "\u0BAA\u0BA4\u0BBF\u0BB2\u0BCD",
6752
+ sourcesHeading: "\u0BAE\u0BC2\u0BB2\u0B99\u0BCD\u0B95\u0BB3\u0BCD",
6753
+ 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.",
6754
+ aboutTitle: "\u0B87\u0BA8\u0BCD\u0BA4\u0BAA\u0BCD \u0BAA\u0BA4\u0BBF\u0BB2\u0BCD \u0BAA\u0BB1\u0BCD\u0BB1\u0BBF",
6755
+ 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.",
6756
+ answeredOn: "{date} \u0B85\u0BA9\u0BCD\u0BB1\u0BC1 \u0BAA\u0BA4\u0BBF\u0BB2\u0BB3\u0BBF\u0B95\u0BCD\u0B95\u0BAA\u0BCD\u0BAA\u0B9F\u0BCD\u0B9F\u0BA4\u0BC1",
6757
+ topicsHeading: "\u0BA4\u0BB2\u0BC8\u0BAA\u0BCD\u0BAA\u0BC1\u0B95\u0BB3\u0BCD",
6758
+ relatedHeading: "\u0BA4\u0BCA\u0B9F\u0BB0\u0BCD\u0BAA\u0BC1\u0B9F\u0BC8\u0BAF \u0B95\u0BC7\u0BB3\u0BCD\u0BB5\u0BBF\u0B95\u0BB3\u0BCD",
6759
+ moreInTopic: "{topic} \u0B87\u0BB2\u0BCD \u0BAE\u0BC7\u0BB2\u0BC1\u0BAE\u0BCD",
6760
+ previousQuestion: "\u0BAE\u0BC1\u0BA8\u0BCD\u0BA4\u0BC8\u0BAF \u0B95\u0BC7\u0BB3\u0BCD\u0BB5\u0BBF",
6761
+ nextQuestion: "\u0B85\u0B9F\u0BC1\u0BA4\u0BCD\u0BA4 \u0B95\u0BC7\u0BB3\u0BCD\u0BB5\u0BBF",
6762
+ allAnswers: "{product} \u0B85\u0BA9\u0BC8\u0BA4\u0BCD\u0BA4\u0BC1\u0BAA\u0BCD \u0BAA\u0BA4\u0BBF\u0BB2\u0BCD\u0B95\u0BB3\u0BC1\u0BAE\u0BCD",
6763
+ 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"
6764
+ };
6765
+ var CHROME = {
6766
+ en: EN2,
6767
+ zh: ZH2,
6768
+ hi: HI2,
6769
+ es: ES2,
6770
+ ar: AR2,
6771
+ ta: TA2
6772
+ };
6773
+ function answerStrings(locale) {
6774
+ const chrome = CHROME[locale] ?? EN2;
6775
+ const explore = exploreStrings(locale);
6776
+ return {
6777
+ ...chrome,
6778
+ answerTable: explore.answerTable,
6779
+ conceptIllustration: explore.conceptIllustration,
6780
+ opensInNewTab: explore.opensInNewTab
6781
+ };
6782
+ }
6783
+ var DATE_TAGS = {
6784
+ en: "en-GB",
6785
+ zh: "zh-CN",
6786
+ hi: "hi-IN",
6787
+ es: "es-ES",
6788
+ ar: "ar",
6789
+ ta: "ta-IN"
6790
+ };
6791
+ function formatAnswerDate(value, locale) {
6792
+ const at = new Date(value);
6793
+ if (Number.isNaN(at.getTime())) return "";
6794
+ try {
6795
+ return new Intl.DateTimeFormat(DATE_TAGS[locale] ?? "en-GB", {
6796
+ year: "numeric",
6797
+ month: "long",
6798
+ day: "numeric",
6799
+ timeZone: "UTC",
6800
+ numberingSystem: "latn"
6801
+ }).format(at);
6802
+ } catch {
6803
+ return value.slice(0, 10);
6466
6804
  }
6467
- ctas {
6468
- kind
6469
- label
6470
- url
6471
- product
6805
+ }
6806
+
6807
+ // src/components/answers-types.ts
6808
+ var PUBLISHED_ANSWER_FIELDS = {
6809
+ slug: true,
6810
+ order: true,
6811
+ question: true,
6812
+ answer: true,
6813
+ topic: true,
6814
+ summary: true,
6815
+ metaDescription: true,
6816
+ keywords: true,
6817
+ sources: true,
6818
+ related: true,
6819
+ answeredAt: true
6820
+ };
6821
+ var ANSWERS_PATH = "/answers";
6822
+ var ANSWER_PATH_PREFIX = "/answer";
6823
+ function answerPath(slug) {
6824
+ return `${ANSWER_PATH_PREFIX}/${encodeURIComponent(slug)}`;
6825
+ }
6826
+ function getAnswerBySlug(answers, slug) {
6827
+ if (!slug) return void 0;
6828
+ const wanted = slug.trim().toLowerCase();
6829
+ if (!wanted) return void 0;
6830
+ return answers.find((answer) => answer.slug === wanted);
6831
+ }
6832
+ function isPublishedSourceUrl(url) {
6833
+ let parsed;
6834
+ try {
6835
+ parsed = new URL(url);
6836
+ } catch {
6837
+ return false;
6472
6838
  }
6473
- followUps
6474
- answered
6475
- attachments {
6476
- name
6477
- mimeType
6478
- size
6479
- textExtracted
6839
+ return parsed.protocol === "https:" && parsed.hostname !== "" && !parsed.username && !parsed.password;
6840
+ }
6841
+ function answerSourceHost(url) {
6842
+ try {
6843
+ return new URL(url).hostname.replace(/^www\./, "");
6844
+ } catch {
6845
+ return "";
6480
6846
  }
6481
- errorCode
6482
- createdAt
6483
- completedAt
6484
- `
6485
- );
6486
- var EXPLORE_OWN_MESSAGE_FIELDS = (
6487
- /* GraphQL */
6488
- `
6489
- ${EXPLORE_MESSAGE_FIELDS}
6490
- feedback {
6491
- rating
6492
- reason
6493
- comment
6494
- createdAt
6847
+ }
6848
+ var EXPLORE_ANSWER_CSS = `
6849
+ /* Nothing inside an answer may widen the page. Model output carries long URLs, code and
6850
+ tables \u2014 each of those overflows a phone by default, and one overflowing child makes the
6851
+ WHOLE document horizontally scrollable, not just the bubble. */
6852
+ .boff-explore-body,
6853
+ .boff-explore-body p,
6854
+ .boff-explore-body li,
6855
+ .boff-explore-body a,
6856
+ .boff-explore-body h1,
6857
+ .boff-explore-body h2,
6858
+ .boff-explore-body h3,
6859
+ /* h4-h6 as well: a published answer page pushes the model's own headings down a level or
6860
+ two so they nest under the page's, and a long unbroken word is no narrower for it. */
6861
+ .boff-explore-body h4,
6862
+ .boff-explore-body h5,
6863
+ .boff-explore-body h6 {
6864
+ overflow-wrap: anywhere;
6865
+ word-break: break-word;
6866
+ }
6867
+ .boff-explore-body pre {
6868
+ overflow-x: auto;
6869
+ max-width: 100%;
6870
+ }
6871
+ .boff-explore-body table {
6872
+ display: block;
6873
+ overflow-x: auto;
6874
+ max-width: 100%;
6875
+ }
6876
+ .boff-explore-body img {
6877
+ max-width: 100%;
6878
+ height: auto;
6879
+ }
6880
+
6881
+ /* ---- Comparison and pricing tables ----------------------------------------------------
6882
+ The harness emits a comparison, and a set of plans, as a GFM table whose FIRST column is
6883
+ the subject \u2014 the product, or the plan (CONTRACT.md \xA77). Two things have to be true of it:
6884
+ the page must not scroll sideways because of it, and it has to be readable on a 320px
6885
+ phone, which a four-column grid of 1px borders is not.
6886
+
6887
+ Wide: a contained scroller. \`max-width: 100%\` keeps the box inside the bubble and
6888
+ \`overflow-x: auto\` keeps the columns inside the box, so the widest possible table still
6889
+ cannot widen the document. \`overscroll-behavior-x: contain\` stops a swipe that runs out
6890
+ of table from chaining to the page \u2014 the same rule the transcript needed. */
6891
+ .boff-explore-body .boff-explore-table {
6892
+ max-width: 100%;
6893
+ overflow-x: auto;
6894
+ overscroll-behavior-x: contain;
6895
+ margin: 0.75rem 0;
6896
+ border: 1px solid hsl(var(--border));
6897
+ border-radius: 0.75rem;
6898
+ background-color: hsl(var(--card));
6899
+ }
6900
+ .boff-explore-body .boff-explore-table:focus-visible {
6901
+ outline: 2px solid hsl(var(--ring));
6902
+ outline-offset: 2px;
6903
+ }
6904
+ .boff-explore-body .boff-explore-table table {
6905
+ /* Beats the blanket \`display: block\` above, which is the unwrapped fallback. */
6906
+ display: table;
6907
+ width: 100%;
6908
+ max-width: none;
6909
+ margin: 0;
6910
+ border-collapse: collapse;
6911
+ font-size: 0.8125rem;
6912
+ }
6913
+ .boff-explore-body .boff-explore-table th,
6914
+ .boff-explore-body .boff-explore-table td {
6915
+ border: 0;
6916
+ border-top: 1px solid hsl(var(--border));
6917
+ padding: 0.5rem 0.75rem;
6918
+ /* \`start\`, never \`left\`: the page root carries dir="rtl" in Arabic, and a left-aligned
6919
+ table there reads against the grain of every other line on the page. */
6920
+ text-align: start;
6921
+ vertical-align: top;
6922
+ overflow-wrap: anywhere;
6923
+ /* Prices in a column line up under each other instead of drifting by digit width. */
6924
+ font-variant-numeric: tabular-nums;
6925
+ min-width: 6rem;
6926
+ }
6927
+ .boff-explore-body .boff-explore-table thead th {
6928
+ border-top: 0;
6929
+ background-color: hsl(var(--muted));
6930
+ color: hsl(var(--foreground));
6931
+ font-weight: 600;
6932
+ white-space: nowrap;
6933
+ }
6934
+ /* The first column is what the row is ABOUT \u2014 the product, or the plan name. Reading it as
6935
+ the row's heading is what makes a price list scannable rather than a grid of strings. */
6936
+ .boff-explore-body .boff-explore-table tbody td:first-child {
6937
+ font-weight: 600;
6938
+ color: hsl(var(--card-foreground));
6939
+ }
6940
+
6941
+ /* Narrow: one card per row. Each cell prints its own column heading, so a value is never
6942
+ stranded without the question it answers, and the subject cell becomes the card's title.
6943
+ A media query rather than a measured width \u2014 these pages are serialised post-hydration,
6944
+ so anything measured here would ship to every phone as static HTML. */
6945
+ @media (max-width: 30rem) {
6946
+ .boff-explore-body .boff-explore-table {
6947
+ overflow-x: visible;
6495
6948
  }
6496
- `
6497
- );
6498
- var EXPLORE_CATALOG_ESTABLISHED_FIELDS = (
6499
- /* GraphQL */
6500
- `
6501
- enabled
6502
- products {
6503
- slug
6504
- name
6505
- tagline
6506
- website
6507
- }
6508
- examplePrompts
6509
- welcomeTitle
6510
- welcomeBody
6511
- limits {
6512
- maxMessageLength
6513
- maxTurnsPerConversation
6514
- messagesPerDay
6515
- historyTurns
6516
- }
6517
- captchaRequired
6518
- recaptchaSiteKey`
6519
- );
6520
- var EXPLORE_CATALOG_HIGHLIGHT_FIELD = (
6521
- /* GraphQL */
6522
- `
6523
- conceptHighlights {
6524
- product
6525
- productName
6526
- title
6527
- url
6528
- imageUrl
6529
- alt
6530
- }`
6531
- );
6532
- function exploreCatalogDocument(extraFields) {
6533
- return (
6534
- /* GraphQL */
6535
- `
6536
- query ExploreCatalog($productSlug: String) {
6537
- exploreCatalog(productSlug: $productSlug) {${EXPLORE_CATALOG_ESTABLISHED_FIELDS}${extraFields}
6538
- }
6949
+ .boff-explore-body .boff-explore-table table,
6950
+ .boff-explore-body .boff-explore-table tbody,
6951
+ .boff-explore-body .boff-explore-table tr,
6952
+ .boff-explore-body .boff-explore-table td {
6953
+ display: block;
6954
+ width: 100%;
6955
+ min-width: 0;
6539
6956
  }
6540
- `
6541
- );
6542
- }
6543
- var EXPLORE_CATALOG_QUERY = exploreCatalogDocument(
6544
- EXPLORE_CATALOG_HIGHLIGHT_FIELD
6545
- );
6546
- var EXPLORE_CATALOG_QUERY_WITHOUT_HIGHLIGHTS = exploreCatalogDocument("");
6547
- var EXPLORE_MESSAGE_QUERY = (
6548
- /* GraphQL */
6549
- `
6550
- query ExploreMessage($conversationToken: String!, $id: ID!) {
6551
- exploreMessage(conversationToken: $conversationToken, id: $id) {
6552
- ${EXPLORE_OWN_MESSAGE_FIELDS}
6553
- }
6957
+ .boff-explore-body .boff-explore-table thead {
6958
+ display: none;
6554
6959
  }
6555
- `
6556
- );
6557
- var SEND_EXPLORE_MESSAGE_MUTATION = (
6558
- /* GraphQL */
6559
- `
6560
- mutation SendExploreMessage($input: SendExploreMessageInput!) {
6561
- sendExploreMessage(input: $input) {
6562
- conversation {
6563
- id
6564
- token
6565
- productSlug
6566
- turnCount
6567
- createdAt
6568
- }
6569
- userMessage {
6570
- ${EXPLORE_OWN_MESSAGE_FIELDS}
6571
- }
6572
- assistantMessage {
6573
- ${EXPLORE_OWN_MESSAGE_FIELDS}
6574
- }
6575
- remainingToday
6576
- }
6960
+ .boff-explore-body .boff-explore-table tr {
6961
+ border-top: 1px solid hsl(var(--border));
6962
+ padding: 0.5rem 0;
6577
6963
  }
6578
- `
6579
- );
6580
- var RECORD_EXPLORE_CLICK_MUTATION = (
6581
- /* GraphQL */
6582
- `
6583
- mutation RecordExploreClick($input: RecordExploreClickInput!) {
6584
- recordExploreClick(input: $input) {
6585
- recorded
6586
- }
6964
+ .boff-explore-body .boff-explore-table tr:first-child {
6965
+ border-top: 0;
6587
6966
  }
6588
- `
6589
- );
6590
- var SUBMIT_EXPLORE_FEEDBACK_MUTATION = (
6591
- /* GraphQL */
6592
- `
6593
- mutation SubmitExploreFeedback($input: SubmitExploreFeedbackInput!) {
6594
- submitExploreFeedback(input: $input) {
6595
- recorded
6596
- feedback {
6597
- rating
6598
- reason
6599
- comment
6600
- createdAt
6601
- }
6602
- }
6967
+ .boff-explore-body .boff-explore-table td {
6968
+ border: 0;
6969
+ padding: 0.125rem 0.75rem;
6603
6970
  }
6604
- `
6605
- );
6606
- var EXPLORE_FEEDBACK_COMMENT_SOFT_MAX = 500;
6607
- var CREATE_EXPLORE_SHARE_LINK_MUTATION = (
6608
- /* GraphQL */
6609
- `
6610
- mutation CreateExploreShareLink($conversationToken: String!) {
6611
- createExploreShareLink(conversationToken: $conversationToken) {
6612
- shareToken
6613
- }
6971
+ .boff-explore-body .boff-explore-table td[data-label]::before {
6972
+ content: attr(data-label);
6973
+ display: block;
6974
+ font-size: 0.6875rem;
6975
+ font-weight: 600;
6976
+ text-transform: uppercase;
6977
+ letter-spacing: 0.04em;
6978
+ color: hsl(var(--muted-foreground));
6614
6979
  }
6615
- `
6616
- );
6617
- var EXPLORE_SHARED_CONVERSATION_QUERY = (
6618
- /* GraphQL */
6619
- `
6620
- query ExploreSharedConversation($shareToken: String!) {
6621
- exploreSharedConversation(shareToken: $shareToken) {
6622
- ${EXPLORE_MESSAGE_FIELDS}
6980
+ .boff-explore-body .boff-explore-table tbody td:first-child {
6981
+ font-size: 0.9375rem;
6982
+ padding-bottom: 0.25rem;
6983
+ }
6984
+ .boff-explore-body .boff-explore-table tbody td:first-child::before {
6985
+ /* The plan's own name is the heading here; repeating "Plan" over it says nothing. */
6986
+ display: none;
6987
+ }
6988
+ }
6989
+ `;
6990
+ function ExploreAnswerStyles() {
6991
+ return /* @__PURE__ */ jsx("style", { dangerouslySetInnerHTML: { __html: EXPLORE_ANSWER_CSS } });
6992
+ }
6993
+ function inlineImageOrigins(products) {
6994
+ const origins = /* @__PURE__ */ new Set();
6995
+ for (const product of products) {
6996
+ let url;
6997
+ try {
6998
+ url = new URL(product.website);
6999
+ } catch {
7000
+ continue;
6623
7001
  }
7002
+ if (url.protocol !== "https:") continue;
7003
+ const apex = url.hostname.replace(/^www\./, "");
7004
+ const port = url.port ? `:${url.port}` : "";
7005
+ origins.add(`https://${apex}${port}`);
7006
+ origins.add(`https://www.${apex}${port}`);
6624
7007
  }
6625
- `
6626
- );
7008
+ return origins;
7009
+ }
7010
+ function isInlineImageAllowed(src, origins) {
7011
+ if (typeof src !== "string" || src === "") return false;
7012
+ let url;
7013
+ try {
7014
+ url = new URL(src);
7015
+ } catch {
7016
+ return false;
7017
+ }
7018
+ if (url.protocol !== "https:" || url.username || url.password) return false;
7019
+ return origins.has(url.origin);
7020
+ }
7021
+ var CODE_FENCE = /^\s*(?:```|~~~)/;
7022
+ var TABLE_ROW_LINE = /^\s{0,3}\|/;
7023
+ var TABLE_DELIMITER_ROW = /^\s{0,3}\|[\s:|-]*-[\s:|-]*$/;
7024
+ function readableLine(raw, mode) {
7025
+ let line = raw;
7026
+ line = line.replace(/!\[[^\]]*\]\([^)\s]*(?:\s+"[^"]*")?\)/g, "");
7027
+ line = mode === "speech" ? (
7028
+ // A voice reading "h-t-t-p-s colon slash slash…" mid-sentence is noise, and the
7029
+ // prompt asks for two to five links in every answer. The label IS the words.
7030
+ line.replace(/\[([^\]]+)\]\(([^)\s]+)(?:\s+"[^"]*")?\)/g, "$1")
7031
+ ) : line.replace(/\[([^\]]+)\]\(([^)\s]+)(?:\s+"[^"]*")?\)/g, "$1 ($2)");
7032
+ line = mode === "speech" ? line.replace(/<(https?:\/\/[^>\s]+)>/g, "") : line.replace(/<(https?:\/\/[^>\s]+)>/g, "$1");
7033
+ line = line.replace(/^\s{0,3}#{1,6}\s+/, "");
7034
+ line = line.replace(/^\s{0,3}>\s?/, "");
7035
+ if (/^\s{0,3}([-*_])[ \t]*(?:\1[ \t]*){2,}$/.test(line)) return "";
7036
+ line = line.replace(/`([^`]+)`/g, "$1");
7037
+ line = line.replace(/\*\*([^*]+)\*\*/g, "$1");
7038
+ line = line.replace(/__([^_]+)__/g, "$1");
7039
+ line = line.replace(/(^|[^*\w])\*([^*\n]+)\*(?![*\w])/g, "$1$2");
7040
+ line = line.replace(/(^|[^_\w])_([^_\n]+)_(?![_\w])/g, "$1$2");
7041
+ return line.replace(/[ \t]+$/, "");
7042
+ }
7043
+ function tableCells(row) {
7044
+ const trimmed = row.trim();
7045
+ const cells = [];
7046
+ let cell = "";
7047
+ for (let at = 0; at < trimmed.length; at += 1) {
7048
+ const char = trimmed[at] ?? "";
7049
+ if (char === "\\") {
7050
+ cell += char + (trimmed[at + 1] ?? "");
7051
+ at += 1;
7052
+ continue;
7053
+ }
7054
+ if (char === "|") {
7055
+ cells.push(cell.trim());
7056
+ cell = "";
7057
+ continue;
7058
+ }
7059
+ cell += char;
7060
+ }
7061
+ cells.push(cell.trim());
7062
+ if (trimmed.startsWith("|") && cells[0] === "") cells.shift();
7063
+ if (trimmed.endsWith("|") && cells[cells.length - 1] === "") cells.pop();
7064
+ return cells;
7065
+ }
7066
+ function asSentence(text) {
7067
+ return /[.!?]$/.test(text) ? text : `${text}.`;
7068
+ }
7069
+ function spokenTable(rows) {
7070
+ if (rows.length < 2 || !TABLE_DELIMITER_ROW.test(rows[1] ?? "")) return rows;
7071
+ const labels = tableCells(rows[0] ?? "");
7072
+ const spoken = [];
7073
+ for (const row of rows.slice(2)) {
7074
+ const parts = [];
7075
+ tableCells(row).forEach((value, column) => {
7076
+ if (value === "") return;
7077
+ const label = column === 0 ? "" : labels[column] ?? "";
7078
+ parts.push(label === "" ? value : `${label}: ${value}`);
7079
+ });
7080
+ if (parts.length > 0) spoken.push(asSentence(parts.join(". ")));
7081
+ }
7082
+ return spoken;
7083
+ }
7084
+ function readableText(markdown, mode) {
7085
+ const lines = [];
7086
+ let inFence = false;
7087
+ let table = [];
7088
+ const flushTable = () => {
7089
+ if (table.length === 0) return;
7090
+ for (const line of spokenTable(table)) lines.push(readableLine(line, mode));
7091
+ table = [];
7092
+ };
7093
+ for (const raw of markdown.split("\n")) {
7094
+ if (CODE_FENCE.test(raw)) {
7095
+ flushTable();
7096
+ inFence = !inFence;
7097
+ continue;
7098
+ }
7099
+ if (inFence) {
7100
+ lines.push(raw);
7101
+ continue;
7102
+ }
7103
+ if (mode === "speech" && TABLE_ROW_LINE.test(raw)) {
7104
+ table.push(raw);
7105
+ continue;
7106
+ }
7107
+ flushTable();
7108
+ lines.push(readableLine(raw, mode));
7109
+ }
7110
+ flushTable();
7111
+ return lines.join("\n").replace(/\n{3,}/g, "\n\n").trim();
7112
+ }
7113
+ function answerPlainText(markdown) {
7114
+ return readableText(markdown, "clipboard");
7115
+ }
7116
+ function answerSpeechText(markdown) {
7117
+ return readableText(markdown, "speech");
7118
+ }
7119
+ var AnswerScopeContext = createContext(null);
7120
+ var InsideLinkContext = createContext(false);
7121
+ function AnswerLink(props) {
7122
+ return /* @__PURE__ */ jsx(InsideLinkContext.Provider, { value: true, children: /* @__PURE__ */ jsx(MarkdownLink, { ...props }) });
7123
+ }
7124
+ var INLINE_IMAGE_FRAME = "relative inline-block max-w-full overflow-hidden rounded-xl border border-border bg-muted align-top shadow-sm";
7125
+ function InlineConceptImage({ src, alt }) {
7126
+ const scope = useContext(AnswerScopeContext);
7127
+ const insideLink = useContext(InsideLinkContext);
7128
+ if (!scope || !scope.enabled || !isInlineImageAllowed(src, scope.origins) || scope.failed.has(src)) {
7129
+ return null;
7130
+ }
7131
+ const { strings: T, onFailed } = scope;
7132
+ const picture = /* @__PURE__ */ jsxs(Fragment, { children: [
7133
+ /* @__PURE__ */ jsx(
7134
+ "img",
7135
+ {
7136
+ src,
7137
+ alt: alt ?? "",
7138
+ loading: "lazy",
7139
+ decoding: "async",
7140
+ onError: () => onFailed(src),
7141
+ className: "block h-auto max-h-80 w-auto max-w-full object-contain"
7142
+ }
7143
+ ),
7144
+ /* @__PURE__ */ jsx(
7145
+ "span",
7146
+ {
7147
+ "aria-hidden": "true",
7148
+ 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",
7149
+ children: T.conceptIllustration
7150
+ }
7151
+ )
7152
+ ] });
7153
+ return /* @__PURE__ */ jsx("span", { "data-boff-explore": "inline-image", className: "my-3 block", children: insideLink ? /* @__PURE__ */ jsx("span", { className: INLINE_IMAGE_FRAME, children: picture }) : /* @__PURE__ */ jsxs(
7154
+ "a",
7155
+ {
7156
+ href: src,
7157
+ target: "_blank",
7158
+ rel: "noopener noreferrer",
7159
+ className: cn(
7160
+ INLINE_IMAGE_FRAME,
7161
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
7162
+ ),
7163
+ children: [
7164
+ picture,
7165
+ /* @__PURE__ */ jsxs("span", { className: "sr-only", children: [
7166
+ "(",
7167
+ T.opensInNewTab,
7168
+ ")"
7169
+ ] })
7170
+ ]
7171
+ }
7172
+ ) });
7173
+ }
7174
+ function markdownText(node) {
7175
+ if (!node) return "";
7176
+ if (typeof node.value === "string") return node.value;
7177
+ return (node.children ?? []).map(markdownText).join("");
7178
+ }
7179
+ function hasHeaderCells(node) {
7180
+ return (node?.children ?? []).some((cell) => cell.tagName === "th");
7181
+ }
7182
+ function findHeaderRow(node) {
7183
+ for (const child of node?.children ?? []) {
7184
+ if (child.tagName === "tr" && hasHeaderCells(child)) return child;
7185
+ const nested = findHeaderRow(child);
7186
+ if (nested !== null) return nested;
7187
+ }
7188
+ return null;
7189
+ }
7190
+ function tableColumnLabels(node) {
7191
+ const row = findHeaderRow(node);
7192
+ if (row === null) return [];
7193
+ return (row.children ?? []).filter((cell) => cell.tagName === "th").map((cell) => markdownText(cell).trim());
7194
+ }
7195
+ var TableColumnsContext = createContext([]);
7196
+ function AnswerTable({ node, children }) {
7197
+ const scope = useContext(AnswerScopeContext);
7198
+ const table = /* @__PURE__ */ jsx(TableColumnsContext.Provider, { value: tableColumnLabels(node), children: /* @__PURE__ */ jsx("table", { children }) });
7199
+ if (!scope) return table;
7200
+ return /* @__PURE__ */ jsx(
7201
+ "div",
7202
+ {
7203
+ "data-boff-explore": "table",
7204
+ role: "region",
7205
+ "aria-label": scope.strings.answerTable,
7206
+ tabIndex: 0,
7207
+ className: "boff-explore-table",
7208
+ children: table
7209
+ }
7210
+ );
7211
+ }
7212
+ function AnswerTableRow({
7213
+ node,
7214
+ children,
7215
+ ...props
7216
+ }) {
7217
+ const labels = useContext(TableColumnsContext);
7218
+ if (labels.length === 0 || hasHeaderCells(node)) {
7219
+ return /* @__PURE__ */ jsx("tr", { ...props, children });
7220
+ }
7221
+ let column = 0;
7222
+ const cells = Children.map(children, (cell) => {
7223
+ if (!isValidElement(cell)) return cell;
7224
+ const label = labels[column] ?? "";
7225
+ column += 1;
7226
+ if (label === "") return cell;
7227
+ return cloneElement(cell, {
7228
+ "data-label": label
7229
+ });
7230
+ });
7231
+ return /* @__PURE__ */ jsx("tr", { ...props, children: cells });
7232
+ }
7233
+ var ANSWER_MARKDOWN_COMPONENTS = {
7234
+ a: AnswerLink,
7235
+ img: InlineConceptImage,
7236
+ table: AnswerTable,
7237
+ tr: AnswerTableRow
7238
+ };
7239
+ function ExploreAnswerBody({
7240
+ children,
7241
+ strings,
7242
+ imageOrigins,
7243
+ enabled = true,
7244
+ components,
7245
+ className
7246
+ }) {
7247
+ const [failed, setFailed] = useState(() => /* @__PURE__ */ new Set());
7248
+ const onFailed = useCallback((src) => {
7249
+ setFailed(
7250
+ (current) => current.has(src) ? current : new Set(current).add(src)
7251
+ );
7252
+ }, []);
7253
+ const scope = useMemo(
7254
+ () => ({
7255
+ strings,
7256
+ enabled,
7257
+ origins: imageOrigins,
7258
+ failed,
7259
+ onFailed
7260
+ }),
7261
+ [strings, enabled, imageOrigins, failed, onFailed]
7262
+ );
7263
+ const overrides = useMemo(
7264
+ () => components ? { ...ANSWER_MARKDOWN_COMPONENTS, ...components } : ANSWER_MARKDOWN_COMPONENTS,
7265
+ [components]
7266
+ );
7267
+ return /* @__PURE__ */ jsx("div", { className: cn("boff-prose boff-explore-body min-w-0", className), children: /* @__PURE__ */ jsx(AnswerScopeContext.Provider, { value: scope, children: /* @__PURE__ */ jsx(Markdown, { components: overrides, children }) }) });
7268
+ }
6627
7269
  var PROSE_CSS = `
6628
7270
  .boff-prose {
6629
7271
  max-width: none;
@@ -6800,6 +7442,1130 @@ var PROSE_CSS = `
6800
7442
  function ProseStyles() {
6801
7443
  return /* @__PURE__ */ jsx("style", { dangerouslySetInnerHTML: { __html: PROSE_CSS } });
6802
7444
  }
7445
+ var META_DESCRIPTION_LIMIT2 = 160;
7446
+ var TITLE_LIMIT = 100;
7447
+ var RELATED_LIMIT2 = 4;
7448
+ function normaliseSiteUrl2(siteUrl) {
7449
+ return siteUrl.trim().replace(/\/+$/, "");
7450
+ }
7451
+ function absoluteUrl2(base, path) {
7452
+ if (/^https?:\/\//i.test(path)) return path;
7453
+ return `${base}${path.startsWith("/") ? path : `/${path}`}`;
7454
+ }
7455
+ function sortByOrder2(answers) {
7456
+ return [...answers].sort(
7457
+ (a, b) => a.order - b.order || a.slug.localeCompare(b.slug)
7458
+ );
7459
+ }
7460
+ function clampText2(text, limit) {
7461
+ if (text.length <= limit) return text;
7462
+ const cut = text.slice(0, limit - 1);
7463
+ const lastSpace = cut.lastIndexOf(" ");
7464
+ return `${(lastSpace > 0 ? cut.slice(0, lastSpace) : cut).replace(/[\s,;:—–-]+$/, "")}\u2026`;
7465
+ }
7466
+ function questionCount(T, count) {
7467
+ return count === 1 ? T.questionCountOne : fill(T.questionCountMany, { count: String(count) });
7468
+ }
7469
+ function sourceCount(T, count) {
7470
+ return count === 1 ? T.sourceCountOne : fill(T.sourceCountMany, { count: String(count) });
7471
+ }
7472
+ function slugifyAnchor2(value) {
7473
+ return value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
7474
+ }
7475
+ function publishableSources(sources) {
7476
+ const seen = /* @__PURE__ */ new Set();
7477
+ const kept = [];
7478
+ for (const source of sources) {
7479
+ if (!isPublishedSourceUrl(source.url) || seen.has(source.url)) continue;
7480
+ seen.add(source.url);
7481
+ kept.push(source);
7482
+ }
7483
+ return kept;
7484
+ }
7485
+ function groupByTopic(ordered, topics) {
7486
+ const byName = /* @__PURE__ */ new Map();
7487
+ for (const answer of ordered) {
7488
+ const list = byName.get(answer.topic);
7489
+ if (list) list.push(answer);
7490
+ else byName.set(answer.topic, [answer]);
7491
+ }
7492
+ const described = [];
7493
+ for (const topic of topics ?? []) {
7494
+ const list = byName.get(topic.name);
7495
+ if (!list) continue;
7496
+ described.push({
7497
+ name: topic.name,
7498
+ description: topic.description,
7499
+ answers: list
7500
+ });
7501
+ byName.delete(topic.name);
7502
+ }
7503
+ for (const [name, list] of byName) {
7504
+ described.push({ name, description: "", answers: list });
7505
+ }
7506
+ const used = /* @__PURE__ */ new Set();
7507
+ return described.map((group) => {
7508
+ const base = `answers-${slugifyAnchor2(group.name) || "topic"}`;
7509
+ let anchor = base;
7510
+ for (let n = 2; used.has(anchor); n += 1) anchor = `${base}-${n}`;
7511
+ used.add(anchor);
7512
+ return { ...group, anchor };
7513
+ });
7514
+ }
7515
+ function searchTokens2(query) {
7516
+ return query.toLowerCase().split(/\s+/).filter(Boolean);
7517
+ }
7518
+ function matchesSearch2(answer, tokens) {
7519
+ if (tokens.length === 0) return true;
7520
+ const haystack = [
7521
+ answer.question,
7522
+ answer.summary,
7523
+ answer.topic,
7524
+ ...answer.keywords
7525
+ ].join(" ").toLowerCase();
7526
+ return tokens.every((token) => haystack.includes(token));
7527
+ }
7528
+ function copyKey2(index, text) {
7529
+ return `${index}-${text}`;
7530
+ }
7531
+ function demoteHeading(Tag) {
7532
+ function DemotedHeading({
7533
+ node: _node,
7534
+ ...props
7535
+ }) {
7536
+ return /* @__PURE__ */ jsx(Tag, { ...props });
7537
+ }
7538
+ DemotedHeading.displayName = `DemotedHeading(${Tag})`;
7539
+ return DemotedHeading;
7540
+ }
7541
+ var ANSWER_HEADING_SHIFT = {
7542
+ h1: demoteHeading("h3"),
7543
+ h2: demoteHeading("h3"),
7544
+ h3: demoteHeading("h4"),
7545
+ h4: demoteHeading("h5"),
7546
+ h5: demoteHeading("h6"),
7547
+ h6: demoteHeading("h6")
7548
+ };
7549
+ var ENGLISH_TEXT = { lang: "en" };
7550
+ function DefaultAnswerLink({
7551
+ href,
7552
+ className,
7553
+ children,
7554
+ "aria-label": ariaLabel
7555
+ }) {
7556
+ return /* @__PURE__ */ jsx("a", { href, className, "aria-label": ariaLabel, children });
7557
+ }
7558
+ function AnswerCard({
7559
+ answer,
7560
+ strings: T,
7561
+ Link
7562
+ }) {
7563
+ const sources = publishableSources(answer.sources).length;
7564
+ return /* @__PURE__ */ jsxs(
7565
+ Link,
7566
+ {
7567
+ href: answerPath(answer.slug),
7568
+ 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",
7569
+ children: [
7570
+ /* @__PURE__ */ jsx(
7571
+ "h3",
7572
+ {
7573
+ ...ENGLISH_TEXT,
7574
+ className: "text-base font-semibold leading-snug text-card-foreground transition-colors group-hover:text-primary",
7575
+ children: answer.question
7576
+ }
7577
+ ),
7578
+ /* @__PURE__ */ jsx(
7579
+ "p",
7580
+ {
7581
+ ...ENGLISH_TEXT,
7582
+ className: "line-clamp-3 text-sm leading-relaxed text-muted-foreground",
7583
+ children: answer.summary
7584
+ }
7585
+ ),
7586
+ sources > 0 ? /* @__PURE__ */ jsxs("span", { className: "mt-auto inline-flex items-center gap-1.5 pt-2 text-xs font-medium text-muted-foreground", children: [
7587
+ /* @__PURE__ */ jsx(BookOpenText, { "aria-hidden": "true", className: "h-3.5 w-3.5" }),
7588
+ sourceCount(T, sources)
7589
+ ] }) : null
7590
+ ]
7591
+ }
7592
+ );
7593
+ }
7594
+ function FilterChip2({
7595
+ label,
7596
+ count,
7597
+ active,
7598
+ topic,
7599
+ onSelect
7600
+ }) {
7601
+ return /* @__PURE__ */ jsxs(
7602
+ "button",
7603
+ {
7604
+ type: "button",
7605
+ "aria-pressed": active,
7606
+ "data-topic": topic,
7607
+ onClick: onSelect,
7608
+ className: cn(
7609
+ "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",
7610
+ active ? "border-primary bg-primary text-primary-foreground" : "border-border bg-card text-foreground hover:border-primary/40 hover:bg-muted"
7611
+ ),
7612
+ children: [
7613
+ /* @__PURE__ */ jsx("span", { children: label }),
7614
+ /* @__PURE__ */ jsx(
7615
+ "span",
7616
+ {
7617
+ className: cn(
7618
+ "rounded-full px-1.5 text-xs tabular-nums",
7619
+ active ? "bg-primary-foreground/20 text-primary-foreground" : "bg-muted text-muted-foreground"
7620
+ ),
7621
+ children: count
7622
+ }
7623
+ )
7624
+ ]
7625
+ }
7626
+ );
7627
+ }
7628
+ function AnswersPage({
7629
+ productName,
7630
+ siteUrl,
7631
+ answers,
7632
+ topics,
7633
+ cta,
7634
+ linkComponent,
7635
+ title,
7636
+ description,
7637
+ locale,
7638
+ className
7639
+ }) {
7640
+ const Link = linkComponent ?? DefaultAnswerLink;
7641
+ const base = normaliseSiteUrl2(siteUrl);
7642
+ const searchId = useId();
7643
+ const activeLocale = useMemo(() => resolveExploreLocale(locale), [locale]);
7644
+ const T = useMemo(() => answerStrings(activeLocale), [activeLocale]);
7645
+ const rtl = isRtlLocale(activeLocale);
7646
+ const ordered = useMemo(() => sortByOrder2(answers), [answers]);
7647
+ const groups = useMemo(
7648
+ () => groupByTopic(ordered, topics),
7649
+ [ordered, topics]
7650
+ );
7651
+ const [query, setQuery] = useState("");
7652
+ const [activeTopic, setActiveTopic] = useState(null);
7653
+ const hasAnswers = ordered.length > 0;
7654
+ const tokens = useMemo(() => searchTokens2(query), [query]);
7655
+ const searched = useMemo(
7656
+ () => ordered.filter((answer) => matchesSearch2(answer, tokens)),
7657
+ [ordered, tokens]
7658
+ );
7659
+ const countsByTopic = useMemo(() => {
7660
+ const counts = /* @__PURE__ */ new Map();
7661
+ for (const answer of searched) {
7662
+ counts.set(answer.topic, (counts.get(answer.topic) ?? 0) + 1);
7663
+ }
7664
+ return counts;
7665
+ }, [searched]);
7666
+ const visibleGroups = useMemo(() => {
7667
+ const visible = new Set(
7668
+ searched.filter(
7669
+ (answer) => activeTopic === null || answer.topic === activeTopic
7670
+ )
7671
+ );
7672
+ return groups.map((group) => ({
7673
+ ...group,
7674
+ answers: group.answers.filter((answer) => visible.has(answer))
7675
+ })).filter((group) => group.answers.length > 0);
7676
+ }, [groups, searched, activeTopic]);
7677
+ const visibleTotal = visibleGroups.reduce(
7678
+ (sum, group) => sum + group.answers.length,
7679
+ 0
7680
+ );
7681
+ const filtering = tokens.length > 0 || activeTopic !== null;
7682
+ const clearFilters = useCallback(() => {
7683
+ setQuery("");
7684
+ setActiveTopic(null);
7685
+ }, []);
7686
+ const heading = title ?? fill(T.indexHeading, { product: productName });
7687
+ const metaDescription = description ?? clampText2(
7688
+ fill(T.seoIndexDescription, { product: productName }),
7689
+ META_DESCRIPTION_LIMIT2
7690
+ );
7691
+ const lead = description ?? fill(T.indexLead, { product: productName });
7692
+ const canonical = `${base}${ANSWERS_PATH}`;
7693
+ const structuredData = useMemo(
7694
+ () => [
7695
+ {
7696
+ "@context": "https://schema.org",
7697
+ "@type": "CollectionPage",
7698
+ name: heading,
7699
+ description: metaDescription,
7700
+ url: canonical,
7701
+ isPartOf: { "@type": "WebSite", name: productName, url: `${base}/` },
7702
+ mainEntity: {
7703
+ "@type": "ItemList",
7704
+ numberOfItems: ordered.length,
7705
+ itemListElement: ordered.map((answer, index) => ({
7706
+ "@type": "ListItem",
7707
+ position: index + 1,
7708
+ url: absoluteUrl2(base, answerPath(answer.slug)),
7709
+ name: answer.question
7710
+ }))
7711
+ }
7712
+ },
7713
+ {
7714
+ "@context": "https://schema.org",
7715
+ "@type": "BreadcrumbList",
7716
+ itemListElement: [
7717
+ {
7718
+ "@type": "ListItem",
7719
+ position: 1,
7720
+ name: T.breadcrumbHome,
7721
+ item: `${base}/`
7722
+ },
7723
+ {
7724
+ "@type": "ListItem",
7725
+ position: 2,
7726
+ name: T.answers,
7727
+ item: canonical
7728
+ }
7729
+ ]
7730
+ }
7731
+ ],
7732
+ [base, canonical, heading, metaDescription, ordered, productName, T]
7733
+ );
7734
+ return /* @__PURE__ */ jsxs(
7735
+ "div",
7736
+ {
7737
+ "data-answers": "landing",
7738
+ "data-locale": activeLocale,
7739
+ dir: rtl ? "rtl" : void 0,
7740
+ className: cn("bg-background text-foreground", className),
7741
+ children: [
7742
+ /* @__PURE__ */ jsx(
7743
+ PageHead,
7744
+ {
7745
+ title: T.seoIndexTitle,
7746
+ description: metaDescription,
7747
+ productName,
7748
+ keywords: [
7749
+ fill(T.indexHeading, { product: productName }),
7750
+ ...groups.map((group) => group.name)
7751
+ ].join(", "),
7752
+ url: canonical,
7753
+ structuredData
7754
+ }
7755
+ ),
7756
+ /* @__PURE__ */ jsx("section", { className: "border-b border-border bg-muted/30", children: /* @__PURE__ */ jsxs("div", { className: "mx-auto max-w-6xl px-4 py-14 sm:px-6 sm:py-20 lg:px-8", children: [
7757
+ /* @__PURE__ */ jsx("p", { className: "text-xs font-semibold uppercase tracking-[0.2em] text-primary", children: T.answers }),
7758
+ /* @__PURE__ */ jsx("h1", { className: "mt-3 max-w-3xl text-4xl font-bold tracking-tight text-foreground sm:text-5xl", children: heading }),
7759
+ /* @__PURE__ */ jsx("p", { className: "mt-4 max-w-2xl text-lg leading-relaxed text-muted-foreground", children: lead }),
7760
+ hasAnswers ? /* @__PURE__ */ jsxs("p", { className: "mt-6 text-sm text-muted-foreground", children: [
7761
+ /* @__PURE__ */ jsx("strong", { className: "text-lg font-semibold text-foreground", children: ordered.length }),
7762
+ " ",
7763
+ questionCount(T, ordered.length)
7764
+ ] }) : null,
7765
+ cta ? /* @__PURE__ */ jsx("div", { className: "mt-8 flex flex-wrap gap-3", children: cta }) : null
7766
+ ] }) }),
7767
+ /* @__PURE__ */ jsx("div", { className: "mx-auto max-w-6xl px-4 pb-20 sm:px-6 lg:px-8", children: hasAnswers ? /* @__PURE__ */ jsxs(Fragment, { children: [
7768
+ /* @__PURE__ */ jsxs(
7769
+ "div",
7770
+ {
7771
+ role: "search",
7772
+ "data-answers": "filter",
7773
+ className: "flex flex-col gap-4 py-8",
7774
+ children: [
7775
+ /* @__PURE__ */ jsxs("div", { className: "relative w-full max-w-md", children: [
7776
+ /* @__PURE__ */ jsx(
7777
+ Search,
7778
+ {
7779
+ "aria-hidden": "true",
7780
+ className: "pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground"
7781
+ }
7782
+ ),
7783
+ /* @__PURE__ */ jsx("label", { htmlFor: searchId, className: "sr-only", children: T.searchLabel }),
7784
+ /* @__PURE__ */ jsx(
7785
+ "input",
7786
+ {
7787
+ id: searchId,
7788
+ type: "search",
7789
+ value: query,
7790
+ onChange: (event) => setQuery(event.target.value),
7791
+ placeholder: T.searchPlaceholder,
7792
+ autoComplete: "off",
7793
+ 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"
7794
+ }
7795
+ )
7796
+ ] }),
7797
+ /* @__PURE__ */ jsxs(
7798
+ "div",
7799
+ {
7800
+ role: "group",
7801
+ "aria-label": T.filterByTopic,
7802
+ className: "flex flex-wrap gap-2",
7803
+ children: [
7804
+ /* @__PURE__ */ jsx(
7805
+ FilterChip2,
7806
+ {
7807
+ label: T.allTopics,
7808
+ topic: "all",
7809
+ count: searched.length,
7810
+ active: activeTopic === null,
7811
+ onSelect: () => setActiveTopic(null)
7812
+ }
7813
+ ),
7814
+ groups.map((group) => /* @__PURE__ */ jsx(
7815
+ FilterChip2,
7816
+ {
7817
+ label: group.name,
7818
+ topic: group.name,
7819
+ count: countsByTopic.get(group.name) ?? 0,
7820
+ active: activeTopic === group.name,
7821
+ onSelect: () => setActiveTopic(
7822
+ (current) => current === group.name ? null : group.name
7823
+ )
7824
+ },
7825
+ group.anchor
7826
+ ))
7827
+ ]
7828
+ }
7829
+ ),
7830
+ /* @__PURE__ */ jsx(
7831
+ "p",
7832
+ {
7833
+ "aria-live": "polite",
7834
+ className: filtering ? "text-sm text-muted-foreground" : "sr-only",
7835
+ children: fill(T.showingCount, {
7836
+ shown: String(visibleTotal),
7837
+ total: String(ordered.length)
7838
+ })
7839
+ }
7840
+ )
7841
+ ]
7842
+ }
7843
+ ),
7844
+ visibleTotal === 0 ? /* @__PURE__ */ jsxs(
7845
+ "div",
7846
+ {
7847
+ "data-answers": "empty",
7848
+ className: "rounded-2xl border border-dashed border-border bg-muted/30 px-6 py-14 text-center",
7849
+ children: [
7850
+ /* @__PURE__ */ jsx(
7851
+ Search,
7852
+ {
7853
+ "aria-hidden": "true",
7854
+ className: "mx-auto h-8 w-8 text-muted-foreground"
7855
+ }
7856
+ ),
7857
+ /* @__PURE__ */ jsx("h2", { className: "mt-4 text-lg font-semibold text-foreground", children: T.noMatchesTitle }),
7858
+ /* @__PURE__ */ jsx("p", { className: "mt-2 text-sm text-muted-foreground", children: T.noMatchesBody }),
7859
+ /* @__PURE__ */ jsx(
7860
+ "button",
7861
+ {
7862
+ type: "button",
7863
+ onClick: clearFilters,
7864
+ 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",
7865
+ children: T.clearFilters
7866
+ }
7867
+ )
7868
+ ]
7869
+ }
7870
+ ) : /* @__PURE__ */ jsx("div", { className: "space-y-14", children: visibleGroups.map((group) => /* @__PURE__ */ jsxs("section", { "aria-labelledby": group.anchor, children: [
7871
+ /* @__PURE__ */ jsxs("div", { className: "max-w-3xl", children: [
7872
+ /* @__PURE__ */ jsx(
7873
+ "h2",
7874
+ {
7875
+ id: group.anchor,
7876
+ className: "scroll-mt-24 text-2xl font-semibold tracking-tight text-foreground",
7877
+ children: group.name
7878
+ }
7879
+ ),
7880
+ group.description ? /* @__PURE__ */ jsx("p", { className: "mt-2 leading-relaxed text-muted-foreground", children: group.description }) : null
7881
+ ] }),
7882
+ /* @__PURE__ */ jsx(
7883
+ "ul",
7884
+ {
7885
+ role: "list",
7886
+ className: "mt-6 grid grid-cols-1 gap-5 sm:grid-cols-2 lg:grid-cols-3",
7887
+ children: group.answers.map((answer) => /* @__PURE__ */ jsx(
7888
+ "li",
7889
+ {
7890
+ "data-answers": "card",
7891
+ "data-slug": answer.slug,
7892
+ children: /* @__PURE__ */ jsx(AnswerCard, { answer, strings: T, Link })
7893
+ },
7894
+ answer.slug
7895
+ ))
7896
+ }
7897
+ )
7898
+ ] }, group.anchor)) })
7899
+ ] }) : (
7900
+ // Nothing published yet: no filter bar with an "All 0" chip, and no empty state
7901
+ // that blames filters the visitor never set.
7902
+ /* @__PURE__ */ jsxs(
7903
+ "div",
7904
+ {
7905
+ "data-answers": "none",
7906
+ className: "mt-10 rounded-2xl border border-dashed border-border bg-muted/30 px-6 py-14 text-center",
7907
+ children: [
7908
+ /* @__PURE__ */ jsx(
7909
+ Sparkles,
7910
+ {
7911
+ "aria-hidden": "true",
7912
+ className: "mx-auto h-8 w-8 text-muted-foreground"
7913
+ }
7914
+ ),
7915
+ /* @__PURE__ */ jsx("h2", { className: "mt-4 text-lg font-semibold text-foreground", children: T.noneYetTitle }),
7916
+ /* @__PURE__ */ jsx("p", { className: "mt-2 text-sm text-muted-foreground", children: fill(T.noneYetBody, { product: productName }) })
7917
+ ]
7918
+ }
7919
+ )
7920
+ ) })
7921
+ ]
7922
+ }
7923
+ );
7924
+ }
7925
+ var SECTION_HEADING2 = "scroll-mt-24 text-2xl font-semibold tracking-tight text-foreground";
7926
+ var CHIP2 = "inline-flex items-center rounded-full border border-border bg-muted/50 px-3 py-1 text-sm text-foreground";
7927
+ function ProvenanceNote({
7928
+ strings: T,
7929
+ date,
7930
+ className
7931
+ }) {
7932
+ return /* @__PURE__ */ jsxs(
7933
+ "div",
7934
+ {
7935
+ role: "note",
7936
+ "aria-label": T.aboutTitle,
7937
+ "data-answers": "provenance",
7938
+ className: cn(
7939
+ "flex items-start gap-3 rounded-xl border border-primary/30 bg-primary/10 px-4 py-3 text-sm leading-relaxed text-foreground",
7940
+ className
7941
+ ),
7942
+ children: [
7943
+ /* @__PURE__ */ jsx(
7944
+ Info,
7945
+ {
7946
+ "aria-hidden": "true",
7947
+ className: "mt-0.5 h-4 w-4 shrink-0 text-primary"
7948
+ }
7949
+ ),
7950
+ /* @__PURE__ */ jsxs("p", { children: [
7951
+ /* @__PURE__ */ jsx("span", { className: "font-semibold", children: T.aboutTitle }),
7952
+ " \u2014 ",
7953
+ fill(T.aboutBody, { date })
7954
+ ] })
7955
+ ]
7956
+ }
7957
+ );
7958
+ }
7959
+ function SourceLink({
7960
+ source,
7961
+ strings: T
7962
+ }) {
7963
+ const host = answerSourceHost(source.url);
7964
+ return /* @__PURE__ */ jsxs(
7965
+ "a",
7966
+ {
7967
+ "data-answers": "source",
7968
+ href: source.url,
7969
+ target: "_blank",
7970
+ rel: "noopener noreferrer",
7971
+ 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",
7972
+ children: [
7973
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold leading-snug transition-colors group-hover:text-primary", children: source.title || host || source.url }),
7974
+ /* @__PURE__ */ jsxs("span", { className: "mt-auto flex items-center gap-2 pt-1 text-xs text-muted-foreground", children: [
7975
+ source.product ? /* @__PURE__ */ jsx("span", { className: "rounded-full bg-secondary px-2 py-0.5 font-medium text-secondary-foreground", children: source.product }) : null,
7976
+ /* @__PURE__ */ jsxs("span", { className: "inline-flex min-w-0 items-center gap-1", children: [
7977
+ /* @__PURE__ */ jsx(ExternalLink, { "aria-hidden": "true", className: "h-3 w-3 shrink-0" }),
7978
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: host })
7979
+ ] })
7980
+ ] }),
7981
+ /* @__PURE__ */ jsxs("span", { className: "sr-only", children: [
7982
+ "(",
7983
+ T.opensInNewTab,
7984
+ ")"
7985
+ ] })
7986
+ ]
7987
+ }
7988
+ );
7989
+ }
7990
+ function AnswerDetailPage(props) {
7991
+ return /* @__PURE__ */ jsx(AnswerDetail, { ...props }, props.answer.slug);
7992
+ }
7993
+ function AnswerDetail({
7994
+ productName,
7995
+ siteUrl,
7996
+ answer,
7997
+ answers,
7998
+ topics,
7999
+ imageOrigins,
8000
+ askHref = "/explore",
8001
+ cta,
8002
+ linkComponent,
8003
+ locale,
8004
+ className
8005
+ }) {
8006
+ const Link = linkComponent ?? DefaultAnswerLink;
8007
+ const base = normaliseSiteUrl2(siteUrl);
8008
+ const headingId = useId();
8009
+ const activeLocale = useMemo(() => resolveExploreLocale(locale), [locale]);
8010
+ const T = useMemo(() => answerStrings(activeLocale), [activeLocale]);
8011
+ const rtl = isRtlLocale(activeLocale);
8012
+ const dateLabel = useMemo(
8013
+ () => formatAnswerDate(answer.answeredAt, activeLocale),
8014
+ [answer.answeredAt, activeLocale]
8015
+ );
8016
+ const ordered = useMemo(() => sortByOrder2(answers), [answers]);
8017
+ const position = ordered.findIndex((item) => item.slug === answer.slug);
8018
+ const previous = position > 0 ? ordered[position - 1] : void 0;
8019
+ const next = position >= 0 && position < ordered.length - 1 ? ordered[position + 1] : void 0;
8020
+ const related = useMemo(() => {
8021
+ const bySlug = new Map(ordered.map((item) => [item.slug, item]));
8022
+ const curated = [...new Set(answer.related)].map((slug) => bySlug.get(slug)).filter(
8023
+ (item) => item !== void 0 && item.slug !== answer.slug
8024
+ );
8025
+ const list = curated.length > 0 ? curated : ordered.filter(
8026
+ (item) => item.topic === answer.topic && item.slug !== answer.slug
8027
+ );
8028
+ return list.slice(0, RELATED_LIMIT2);
8029
+ }, [answer, ordered]);
8030
+ const relatedIsCurated = answer.related.some(
8031
+ (slug) => related.some((item) => item.slug === slug)
8032
+ );
8033
+ const topicDescription = topics?.find(
8034
+ (topic) => topic.name === answer.topic
8035
+ )?.description;
8036
+ const sources = useMemo(
8037
+ () => publishableSources(answer.sources),
8038
+ [answer.sources]
8039
+ );
8040
+ const answerImageOrigins = useMemo(
8041
+ () => inlineImageOrigins([
8042
+ { website: base },
8043
+ ...sources.map((source) => ({ website: source.url })),
8044
+ ...(imageOrigins ?? []).map((origin) => ({ website: origin }))
8045
+ ]),
8046
+ [base, sources, imageOrigins]
8047
+ );
8048
+ const canonical = absoluteUrl2(base, answerPath(answer.slug));
8049
+ const answerText = useMemo(
8050
+ () => answerSpeechText(answer.answer),
8051
+ [answer.answer]
8052
+ );
8053
+ const structuredData = useMemo(
8054
+ () => [
8055
+ {
8056
+ "@context": "https://schema.org",
8057
+ "@type": "FAQPage",
8058
+ name: answer.question,
8059
+ description: answer.metaDescription,
8060
+ url: canonical,
8061
+ inLanguage: "en",
8062
+ isPartOf: { "@type": "WebSite", name: productName, url: `${base}/` },
8063
+ mainEntity: {
8064
+ "@type": "Question",
8065
+ name: answer.question,
8066
+ text: answer.question,
8067
+ answerCount: 1,
8068
+ acceptedAnswer: {
8069
+ "@type": "Answer",
8070
+ text: answerText,
8071
+ url: canonical,
8072
+ dateCreated: answer.answeredAt,
8073
+ // The organisation published it. Naming a person would be the one outright
8074
+ // false claim these pages could make.
8075
+ author: { "@type": "Organization", name: productName },
8076
+ ...sources.length > 0 ? {
8077
+ citation: sources.map((source) => ({
8078
+ "@type": "WebPage",
8079
+ name: source.title,
8080
+ url: source.url
8081
+ }))
8082
+ } : {}
8083
+ }
8084
+ }
8085
+ },
8086
+ {
8087
+ "@context": "https://schema.org",
8088
+ "@type": "BreadcrumbList",
8089
+ itemListElement: [
8090
+ {
8091
+ "@type": "ListItem",
8092
+ position: 1,
8093
+ name: T.breadcrumbHome,
8094
+ item: `${base}/`
8095
+ },
8096
+ {
8097
+ "@type": "ListItem",
8098
+ position: 2,
8099
+ name: T.answers,
8100
+ item: `${base}${ANSWERS_PATH}`
8101
+ },
8102
+ {
8103
+ "@type": "ListItem",
8104
+ position: 3,
8105
+ name: answer.question,
8106
+ item: canonical
8107
+ }
8108
+ ]
8109
+ }
8110
+ ],
8111
+ [answer, answerText, base, canonical, productName, sources, T]
8112
+ );
8113
+ return /* @__PURE__ */ jsxs(
8114
+ "article",
8115
+ {
8116
+ "data-answers": "detail",
8117
+ "data-slug": answer.slug,
8118
+ "data-locale": activeLocale,
8119
+ "aria-labelledby": headingId,
8120
+ dir: rtl ? "rtl" : void 0,
8121
+ className: cn("bg-background text-foreground", className),
8122
+ children: [
8123
+ /* @__PURE__ */ jsx(
8124
+ PageHead,
8125
+ {
8126
+ title: clampText2(answer.question, TITLE_LIMIT),
8127
+ description: answer.metaDescription,
8128
+ productName,
8129
+ keywords: answer.keywords.join(", "),
8130
+ url: canonical,
8131
+ structuredData
8132
+ }
8133
+ ),
8134
+ /* @__PURE__ */ jsx(ProseStyles, {}),
8135
+ /* @__PURE__ */ jsx(ExploreAnswerStyles, {}),
8136
+ /* @__PURE__ */ jsx("header", { className: "border-b border-border bg-muted/30", children: /* @__PURE__ */ jsxs("div", { className: "mx-auto max-w-4xl px-4 pb-10 pt-8 sm:px-6 lg:px-8", children: [
8137
+ /* @__PURE__ */ jsx("nav", { "aria-label": "Breadcrumb", children: /* @__PURE__ */ jsxs("ol", { className: "flex flex-wrap items-center gap-1.5 text-sm text-muted-foreground", children: [
8138
+ /* @__PURE__ */ jsxs("li", { className: "inline-flex items-center gap-1.5", children: [
8139
+ /* @__PURE__ */ jsx(
8140
+ Link,
8141
+ {
8142
+ href: "/",
8143
+ className: "rounded hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
8144
+ children: T.breadcrumbHome
8145
+ }
8146
+ ),
8147
+ /* @__PURE__ */ jsx(ChevronRight, { "aria-hidden": "true", className: "h-3.5 w-3.5" })
8148
+ ] }),
8149
+ /* @__PURE__ */ jsxs("li", { className: "inline-flex items-center gap-1.5", children: [
8150
+ /* @__PURE__ */ jsx(
8151
+ Link,
8152
+ {
8153
+ href: ANSWERS_PATH,
8154
+ className: "rounded hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
8155
+ children: T.answers
8156
+ }
8157
+ ),
8158
+ /* @__PURE__ */ jsx(ChevronRight, { "aria-hidden": "true", className: "h-3.5 w-3.5" })
8159
+ ] }),
8160
+ /* @__PURE__ */ jsx(
8161
+ "li",
8162
+ {
8163
+ "aria-current": "page",
8164
+ ...ENGLISH_TEXT,
8165
+ className: "min-w-0 truncate text-foreground",
8166
+ children: answer.question
8167
+ }
8168
+ )
8169
+ ] }) }),
8170
+ /* @__PURE__ */ jsxs("div", { className: "mt-6 flex flex-wrap items-center gap-2", children: [
8171
+ /* @__PURE__ */ jsx(
8172
+ "span",
8173
+ {
8174
+ "data-answers": "topic",
8175
+ title: topicDescription,
8176
+ className: "inline-flex items-center rounded-full border border-primary/30 bg-primary/10 px-3 py-1 text-xs font-semibold text-primary",
8177
+ children: answer.topic
8178
+ }
8179
+ ),
8180
+ dateLabel ? /* @__PURE__ */ 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__ */ jsx("time", { dateTime: answer.answeredAt, children: fill(T.answeredOn, { date: dateLabel }) }) }) : null
8181
+ ] }),
8182
+ /* @__PURE__ */ jsx(
8183
+ "h1",
8184
+ {
8185
+ id: headingId,
8186
+ ...ENGLISH_TEXT,
8187
+ className: "mt-4 text-3xl font-bold tracking-tight text-foreground sm:text-4xl",
8188
+ children: answer.question
8189
+ }
8190
+ ),
8191
+ answer.summary ? /* @__PURE__ */ jsx(
8192
+ "p",
8193
+ {
8194
+ ...ENGLISH_TEXT,
8195
+ className: "mt-4 text-lg leading-relaxed text-muted-foreground",
8196
+ children: answer.summary
8197
+ }
8198
+ ) : null,
8199
+ /* @__PURE__ */ jsx(ProvenanceNote, { strings: T, date: dateLabel, className: "mt-6" })
8200
+ ] }) }),
8201
+ /* @__PURE__ */ jsxs("div", { className: "mx-auto max-w-4xl px-4 py-12 sm:px-6 lg:px-8", children: [
8202
+ /* @__PURE__ */ jsxs("section", { "aria-labelledby": `${headingId}-answer`, children: [
8203
+ /* @__PURE__ */ jsx("h2", { id: `${headingId}-answer`, className: SECTION_HEADING2, children: T.answerHeading }),
8204
+ /* @__PURE__ */ jsx("div", { "data-answers": "body", ...ENGLISH_TEXT, dir: "ltr", children: /* @__PURE__ */ jsx(
8205
+ ExploreAnswerBody,
8206
+ {
8207
+ strings: T,
8208
+ imageOrigins: answerImageOrigins,
8209
+ components: ANSWER_HEADING_SHIFT,
8210
+ className: "mt-4",
8211
+ children: answer.answer
8212
+ }
8213
+ ) })
8214
+ ] }),
8215
+ sources.length > 0 ? /* @__PURE__ */ jsxs(
8216
+ "section",
8217
+ {
8218
+ "aria-labelledby": `${headingId}-sources`,
8219
+ "data-answers": "sources",
8220
+ className: "mt-14",
8221
+ children: [
8222
+ /* @__PURE__ */ jsx("h2", { id: `${headingId}-sources`, className: SECTION_HEADING2, children: T.sourcesHeading }),
8223
+ /* @__PURE__ */ jsx("p", { className: "mt-2 text-muted-foreground", children: T.sourcesLead }),
8224
+ /* @__PURE__ */ jsx(
8225
+ "ul",
8226
+ {
8227
+ role: "list",
8228
+ className: "mt-6 grid grid-cols-1 gap-4 sm:grid-cols-2",
8229
+ children: sources.map((source) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(SourceLink, { source, strings: T }) }, source.url))
8230
+ }
8231
+ )
8232
+ ]
8233
+ }
8234
+ ) : null,
8235
+ answer.keywords.length > 0 ? /* @__PURE__ */ jsxs("section", { "aria-labelledby": `${headingId}-topics`, className: "mt-14", children: [
8236
+ /* @__PURE__ */ jsx("h2", { id: `${headingId}-topics`, className: SECTION_HEADING2, children: T.topicsHeading }),
8237
+ /* @__PURE__ */ jsx("ul", { role: "list", className: "mt-4 flex flex-wrap gap-2", children: answer.keywords.map((keyword, index) => /* @__PURE__ */ jsx("li", { className: CHIP2, children: keyword }, copyKey2(index, keyword))) })
8238
+ ] }) : null,
8239
+ related.length > 0 ? /* @__PURE__ */ jsxs(
8240
+ "section",
8241
+ {
8242
+ "aria-labelledby": `${headingId}-related`,
8243
+ "data-answers": "related",
8244
+ className: "mt-14",
8245
+ children: [
8246
+ /* @__PURE__ */ jsx("h2", { id: `${headingId}-related`, className: SECTION_HEADING2, children: relatedIsCurated ? T.relatedHeading : fill(T.moreInTopic, { topic: answer.topic }) }),
8247
+ /* @__PURE__ */ jsx(
8248
+ "ul",
8249
+ {
8250
+ role: "list",
8251
+ className: "mt-6 grid grid-cols-1 gap-5 sm:grid-cols-2",
8252
+ children: related.map((item) => /* @__PURE__ */ jsx("li", { "data-answers": "card", "data-slug": item.slug, children: /* @__PURE__ */ jsx(AnswerCard, { answer: item, strings: T, Link }) }, item.slug))
8253
+ }
8254
+ )
8255
+ ]
8256
+ }
8257
+ ) : null,
8258
+ previous || next ? /* @__PURE__ */ jsxs(
8259
+ "nav",
8260
+ {
8261
+ "aria-label": `${T.previousQuestion} / ${T.nextQuestion}`,
8262
+ "data-answers": "pager",
8263
+ className: "mt-14 grid gap-4 sm:grid-cols-2",
8264
+ children: [
8265
+ previous ? /* @__PURE__ */ jsxs(
8266
+ Link,
8267
+ {
8268
+ href: answerPath(previous.slug),
8269
+ 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",
8270
+ children: [
8271
+ /* @__PURE__ */ jsx(
8272
+ ArrowLeft,
8273
+ {
8274
+ "aria-hidden": "true",
8275
+ className: "h-5 w-5 shrink-0 text-muted-foreground transition-colors group-hover:text-primary"
8276
+ }
8277
+ ),
8278
+ /* @__PURE__ */ jsxs("span", { className: "min-w-0", children: [
8279
+ /* @__PURE__ */ jsx("span", { className: "block text-xs font-medium uppercase tracking-wide text-muted-foreground", children: T.previousQuestion }),
8280
+ /* @__PURE__ */ jsx(
8281
+ "span",
8282
+ {
8283
+ ...ENGLISH_TEXT,
8284
+ className: "block truncate font-semibold",
8285
+ children: previous.question
8286
+ }
8287
+ )
8288
+ ] })
8289
+ ]
8290
+ }
8291
+ ) : /* @__PURE__ */ jsx("span", { className: "hidden sm:block" }),
8292
+ next ? /* @__PURE__ */ jsxs(
8293
+ Link,
8294
+ {
8295
+ href: answerPath(next.slug),
8296
+ 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",
8297
+ children: [
8298
+ /* @__PURE__ */ jsxs("span", { className: "min-w-0", children: [
8299
+ /* @__PURE__ */ jsx("span", { className: "block text-xs font-medium uppercase tracking-wide text-muted-foreground", children: T.nextQuestion }),
8300
+ /* @__PURE__ */ jsx(
8301
+ "span",
8302
+ {
8303
+ ...ENGLISH_TEXT,
8304
+ className: "block truncate font-semibold",
8305
+ children: next.question
8306
+ }
8307
+ )
8308
+ ] }),
8309
+ /* @__PURE__ */ jsx(
8310
+ ArrowRight,
8311
+ {
8312
+ "aria-hidden": "true",
8313
+ className: "h-5 w-5 shrink-0 text-muted-foreground transition-colors group-hover:text-primary"
8314
+ }
8315
+ )
8316
+ ]
8317
+ }
8318
+ ) : null
8319
+ ]
8320
+ }
8321
+ ) : null,
8322
+ /* @__PURE__ */ jsxs("div", { className: "mt-10 flex flex-wrap items-center gap-x-6 gap-y-3", children: [
8323
+ /* @__PURE__ */ jsxs(
8324
+ Link,
8325
+ {
8326
+ href: ANSWERS_PATH,
8327
+ 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",
8328
+ children: [
8329
+ /* @__PURE__ */ jsx(ArrowLeft, { "aria-hidden": "true", className: "h-4 w-4" }),
8330
+ fill(T.allAnswers, { product: productName })
8331
+ ]
8332
+ }
8333
+ ),
8334
+ askHref ? /* @__PURE__ */ jsxs(
8335
+ Link,
8336
+ {
8337
+ href: askHref,
8338
+ 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",
8339
+ children: [
8340
+ /* @__PURE__ */ jsx(Sparkles, { "aria-hidden": "true", className: "h-4 w-4" }),
8341
+ T.askYourOwn
8342
+ ]
8343
+ }
8344
+ ) : null
8345
+ ] })
8346
+ ] }),
8347
+ cta ? /* @__PURE__ */ jsx(
8348
+ "section",
8349
+ {
8350
+ "data-answers": "cta",
8351
+ className: "border-t border-border bg-muted/30",
8352
+ children: /* @__PURE__ */ 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 })
8353
+ }
8354
+ ) : null
8355
+ ]
8356
+ }
8357
+ );
8358
+ }
8359
+
8360
+ // src/components/explore-types.ts
8361
+ var EXPLORE_FEEDBACK_REASONS = [
8362
+ "INACCURATE",
8363
+ "INCOMPLETE",
8364
+ "OFF_TOPIC",
8365
+ "HARD_TO_FOLLOW",
8366
+ "OTHER"
8367
+ ];
8368
+ var EXPLORE_MESSAGE_FIELDS = (
8369
+ /* GraphQL */
8370
+ `
8371
+ id
8372
+ conversationId
8373
+ role
8374
+ status
8375
+ content
8376
+ partialContent
8377
+ activity
8378
+ references {
8379
+ url
8380
+ title
8381
+ description
8382
+ product
8383
+ imageUrl
8384
+ index
8385
+ }
8386
+ ctas {
8387
+ kind
8388
+ label
8389
+ url
8390
+ product
8391
+ }
8392
+ followUps
8393
+ answered
8394
+ attachments {
8395
+ name
8396
+ mimeType
8397
+ size
8398
+ textExtracted
8399
+ }
8400
+ errorCode
8401
+ createdAt
8402
+ completedAt
8403
+ `
8404
+ );
8405
+ var EXPLORE_OWN_MESSAGE_FIELDS = (
8406
+ /* GraphQL */
8407
+ `
8408
+ ${EXPLORE_MESSAGE_FIELDS}
8409
+ feedback {
8410
+ rating
8411
+ reason
8412
+ comment
8413
+ createdAt
8414
+ }
8415
+ `
8416
+ );
8417
+ var EXPLORE_CATALOG_ESTABLISHED_FIELDS = (
8418
+ /* GraphQL */
8419
+ `
8420
+ enabled
8421
+ products {
8422
+ slug
8423
+ name
8424
+ tagline
8425
+ website
8426
+ }
8427
+ examplePrompts
8428
+ welcomeTitle
8429
+ welcomeBody
8430
+ limits {
8431
+ maxMessageLength
8432
+ maxTurnsPerConversation
8433
+ messagesPerDay
8434
+ historyTurns
8435
+ }
8436
+ captchaRequired
8437
+ recaptchaSiteKey`
8438
+ );
8439
+ var EXPLORE_CATALOG_HIGHLIGHT_FIELD = (
8440
+ /* GraphQL */
8441
+ `
8442
+ conceptHighlights {
8443
+ product
8444
+ productName
8445
+ title
8446
+ url
8447
+ imageUrl
8448
+ alt
8449
+ }`
8450
+ );
8451
+ function exploreCatalogDocument(extraFields) {
8452
+ return (
8453
+ /* GraphQL */
8454
+ `
8455
+ query ExploreCatalog($productSlug: String) {
8456
+ exploreCatalog(productSlug: $productSlug) {${EXPLORE_CATALOG_ESTABLISHED_FIELDS}${extraFields}
8457
+ }
8458
+ }
8459
+ `
8460
+ );
8461
+ }
8462
+ var EXPLORE_CATALOG_QUERY = exploreCatalogDocument(
8463
+ EXPLORE_CATALOG_HIGHLIGHT_FIELD
8464
+ );
8465
+ var EXPLORE_CATALOG_QUERY_WITHOUT_HIGHLIGHTS = exploreCatalogDocument("");
8466
+ var EXPLORE_MESSAGE_QUERY = (
8467
+ /* GraphQL */
8468
+ `
8469
+ query ExploreMessage($conversationToken: String!, $id: ID!) {
8470
+ exploreMessage(conversationToken: $conversationToken, id: $id) {
8471
+ ${EXPLORE_OWN_MESSAGE_FIELDS}
8472
+ }
8473
+ }
8474
+ `
8475
+ );
8476
+ var SEND_EXPLORE_MESSAGE_MUTATION = (
8477
+ /* GraphQL */
8478
+ `
8479
+ mutation SendExploreMessage($input: SendExploreMessageInput!) {
8480
+ sendExploreMessage(input: $input) {
8481
+ conversation {
8482
+ id
8483
+ token
8484
+ productSlug
8485
+ turnCount
8486
+ createdAt
8487
+ }
8488
+ userMessage {
8489
+ ${EXPLORE_OWN_MESSAGE_FIELDS}
8490
+ }
8491
+ assistantMessage {
8492
+ ${EXPLORE_OWN_MESSAGE_FIELDS}
8493
+ }
8494
+ remainingToday
8495
+ }
8496
+ }
8497
+ `
8498
+ );
8499
+ var RECORD_EXPLORE_CLICK_MUTATION = (
8500
+ /* GraphQL */
8501
+ `
8502
+ mutation RecordExploreClick($input: RecordExploreClickInput!) {
8503
+ recordExploreClick(input: $input) {
8504
+ recorded
8505
+ }
8506
+ }
8507
+ `
8508
+ );
8509
+ var SUBMIT_EXPLORE_FEEDBACK_MUTATION = (
8510
+ /* GraphQL */
8511
+ `
8512
+ mutation SubmitExploreFeedback($input: SubmitExploreFeedbackInput!) {
8513
+ submitExploreFeedback(input: $input) {
8514
+ recorded
8515
+ feedback {
8516
+ rating
8517
+ reason
8518
+ comment
8519
+ createdAt
8520
+ }
8521
+ }
8522
+ }
8523
+ `
8524
+ );
8525
+ var EXPLORE_FEEDBACK_COMMENT_SOFT_MAX = 500;
8526
+ var ESCALATE_EXPLORE_CONVERSATION_MUTATION = (
8527
+ /* GraphQL */
8528
+ `
8529
+ mutation EscalateExploreConversation(
8530
+ $input: EscalateExploreConversationInput!
8531
+ ) {
8532
+ escalateExploreConversation(input: $input) {
8533
+ created
8534
+ escalation {
8535
+ email
8536
+ createdAt
8537
+ }
8538
+ }
8539
+ }
8540
+ `
8541
+ );
8542
+ var EXPLORE_ESCALATION_NOTE_SOFT_MAX = 2e3;
8543
+ 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,}$/;
8544
+ function looksLikeDeliverableEmail(value) {
8545
+ const trimmed = value.trim();
8546
+ if (trimmed.length === 0 || trimmed.length > 254) return false;
8547
+ return DELIVERABLE_EMAIL.test(trimmed);
8548
+ }
8549
+ var CREATE_EXPLORE_SHARE_LINK_MUTATION = (
8550
+ /* GraphQL */
8551
+ `
8552
+ mutation CreateExploreShareLink($conversationToken: String!) {
8553
+ createExploreShareLink(conversationToken: $conversationToken) {
8554
+ shareToken
8555
+ }
8556
+ }
8557
+ `
8558
+ );
8559
+ var EXPLORE_SHARED_CONVERSATION_QUERY = (
8560
+ /* GraphQL */
8561
+ `
8562
+ query ExploreSharedConversation($shareToken: String!) {
8563
+ exploreSharedConversation(shareToken: $shareToken) {
8564
+ ${EXPLORE_MESSAGE_FIELDS}
8565
+ }
8566
+ }
8567
+ `
8568
+ );
6803
8569
 
6804
8570
  // src/data/products.ts
6805
8571
  var ECOSYSTEM_PRODUCTS = [
@@ -7146,6 +8912,25 @@ var VALIDATION_CODES = /* @__PURE__ */ new Set([
7146
8912
  "CONVERSATION_LIMIT",
7147
8913
  "INVALID_INPUT"
7148
8914
  ]);
8915
+ function escalateOutcomeForCode(code) {
8916
+ switch (code) {
8917
+ case "INVALID_EMAIL":
8918
+ return "invalid-email";
8919
+ case "RATE_LIMITED":
8920
+ case "HTTP_429":
8921
+ return "rate-limited";
8922
+ case "CAPTCHA_REQUIRED":
8923
+ case "CAPTCHA_FAILED":
8924
+ return "captcha";
8925
+ // The token owns nothing, or owns a different conversation. The server answers NOT_FOUND
8926
+ // rather than FORBIDDEN so the endpoint is not an oracle for whether a thread exists;
8927
+ // either way there is nothing this visitor can do about it, so it reads as a failure.
8928
+ case "NOT_FOUND":
8929
+ return "failed";
8930
+ default:
8931
+ return "failed";
8932
+ }
8933
+ }
7149
8934
  function classifyExploreError(code, serverMessage) {
7150
8935
  const c = code ?? "UNKNOWN";
7151
8936
  if (RATE_LIMIT_CODES.has(c)) {
@@ -7312,6 +9097,7 @@ function useExploreChat(options = {}) {
7312
9097
  onSend
7313
9098
  } = options;
7314
9099
  const client = useWebSDK();
9100
+ const { productId } = useWebSDKConfig();
7315
9101
  const promptKey = JSON.stringify(examplePrompts ?? []);
7316
9102
  const welcomeKey = JSON.stringify(fallbackWelcome ?? null);
7317
9103
  const fallbackCatalog = useMemo(
@@ -7335,6 +9121,7 @@ function useExploreChat(options = {}) {
7335
9121
  const pollGenerationRef = useRef(0);
7336
9122
  const pollTimerRef = useRef(null);
7337
9123
  const conversationTokenRef = useRef(null);
9124
+ const [hasConversation, setHasConversation] = useState(false);
7338
9125
  const shareTokenRef = useRef(void 0);
7339
9126
  if (shareTokenRef.current === void 0) {
7340
9127
  shareTokenRef.current = readShareToken();
@@ -7349,6 +9136,10 @@ function useExploreChat(options = {}) {
7349
9136
  );
7350
9137
  const inFlightRef = useRef(false);
7351
9138
  catalogRef.current = catalog;
9139
+ const rememberConversationToken = useCallback((token) => {
9140
+ conversationTokenRef.current = token;
9141
+ setHasConversation(token !== null);
9142
+ }, []);
7352
9143
  const clearPollTimer = useCallback(() => {
7353
9144
  if (pollTimerRef.current !== null) {
7354
9145
  clearTimeout(pollTimerRef.current);
@@ -7415,7 +9206,7 @@ function useExploreChat(options = {}) {
7415
9206
  setArchive(readArchive(storageKey));
7416
9207
  const stored = readPersisted(storageKey);
7417
9208
  if (stored) {
7418
- conversationTokenRef.current = stored.conversationToken;
9209
+ rememberConversationToken(stored.conversationToken);
7419
9210
  focusProductRef.current = stored.focusProduct;
7420
9211
  const settled = stored.messages.flatMap((m) => {
7421
9212
  if (m.role !== "ASSISTANT") return [m];
@@ -7431,7 +9222,7 @@ function useExploreChat(options = {}) {
7431
9222
  setTurnCount(turns);
7432
9223
  }
7433
9224
  setHydrated(true);
7434
- }, [persist, storageKey]);
9225
+ }, [persist, rememberConversationToken, storageKey]);
7435
9226
  useEffect(() => {
7436
9227
  if (!persist || !hydrated || typeof window === "undefined") return;
7437
9228
  try {
@@ -7624,7 +9415,7 @@ function useExploreChat(options = {}) {
7624
9415
  setPhase(classified.kind === "rate-limit" ? "limited" : "error");
7625
9416
  return;
7626
9417
  }
7627
- conversationTokenRef.current = result.conversation.token;
9418
+ rememberConversationToken(result.conversation.token);
7628
9419
  turnCountRef.current = result.conversation.turnCount;
7629
9420
  setTurnCount(result.conversation.turnCount);
7630
9421
  setRemainingToday(result.remainingToday ?? null);
@@ -7650,7 +9441,14 @@ function useExploreChat(options = {}) {
7650
9441
  setPhase("streaming");
7651
9442
  startPolling(result.conversation.token, assistantMessage.id);
7652
9443
  },
7653
- [client, locale, pageUrl, productSlug, startPolling]
9444
+ [
9445
+ client,
9446
+ locale,
9447
+ pageUrl,
9448
+ productSlug,
9449
+ rememberConversationToken,
9450
+ startPolling
9451
+ ]
7654
9452
  );
7655
9453
  const send = useCallback(
7656
9454
  async (message, attachments = []) => {
@@ -7767,7 +9565,7 @@ function useExploreChat(options = {}) {
7767
9565
  );
7768
9566
  cancelPolling();
7769
9567
  inFlightRef.current = false;
7770
- conversationTokenRef.current = null;
9568
+ rememberConversationToken(null);
7771
9569
  lastSentTextRef.current = null;
7772
9570
  lastSentAttachmentsRef.current = [];
7773
9571
  turnCountRef.current = 0;
@@ -7782,7 +9580,7 @@ function useExploreChat(options = {}) {
7782
9580
  } catch {
7783
9581
  }
7784
9582
  }
7785
- }, [cancelPolling, storageKey]);
9583
+ }, [cancelPolling, rememberConversationToken, storageKey]);
7786
9584
  const openConversation = useCallback(
7787
9585
  (token) => {
7788
9586
  const entry = readArchive(storageKey).find((e) => e.token === token);
@@ -7794,7 +9592,7 @@ function useExploreChat(options = {}) {
7794
9592
  });
7795
9593
  cancelPolling();
7796
9594
  inFlightRef.current = false;
7797
- conversationTokenRef.current = entry.token;
9595
+ rememberConversationToken(entry.token);
7798
9596
  turnCountRef.current = entry.messages.filter(
7799
9597
  (m) => m.role === "USER"
7800
9598
  ).length;
@@ -7806,7 +9604,7 @@ function useExploreChat(options = {}) {
7806
9604
  setPhase(catalogRef.current.enabled ? "ready" : "disabled");
7807
9605
  setArchive(readArchive(storageKey));
7808
9606
  },
7809
- [cancelPolling, storageKey]
9607
+ [cancelPolling, rememberConversationToken, storageKey]
7810
9608
  );
7811
9609
  const deleteConversation = useCallback(
7812
9610
  (token) => {
@@ -7895,6 +9693,69 @@ function useExploreChat(options = {}) {
7895
9693
  },
7896
9694
  [client]
7897
9695
  );
9696
+ const escalate = useCallback(
9697
+ async (email, note) => {
9698
+ const token = conversationTokenRef.current;
9699
+ if (!token) {
9700
+ return { outcome: "no-conversation", email: null, createdAt: null };
9701
+ }
9702
+ const attempt = async (captchaAttempt) => {
9703
+ const activeCatalog = catalogRef.current;
9704
+ let recaptchaToken;
9705
+ if (activeCatalog.captchaRequired && activeCatalog.recaptchaSiteKey) {
9706
+ try {
9707
+ recaptchaToken = await getRecaptchaV3Token(
9708
+ activeCatalog.recaptchaSiteKey
9709
+ );
9710
+ } catch (err) {
9711
+ console.warn(
9712
+ "[WebSDK] reCAPTCHA v3 token could not be minted",
9713
+ err
9714
+ );
9715
+ }
9716
+ }
9717
+ const input = {
9718
+ conversationToken: token,
9719
+ email: email.trim(),
9720
+ note: note?.trim() ? note.trim() : null,
9721
+ ...recaptchaToken ? { recaptchaToken } : {},
9722
+ ...productId ? { productId } : {}
9723
+ };
9724
+ try {
9725
+ const res = await client.mutate(
9726
+ ESCALATE_EXPLORE_CONVERSATION_MUTATION,
9727
+ { input }
9728
+ );
9729
+ const first = res?.errors?.[0];
9730
+ const result = res?.data?.escalateExploreConversation;
9731
+ if (first || !result) {
9732
+ const code = typeof first?.extensions?.code === "string" ? first.extensions.code : "ESCALATION_FAILED";
9733
+ if (code === "CAPTCHA_FAILED" && captchaAttempt === 0) {
9734
+ return attempt(1);
9735
+ }
9736
+ return {
9737
+ outcome: escalateOutcomeForCode(code),
9738
+ email: null,
9739
+ createdAt: null
9740
+ };
9741
+ }
9742
+ return {
9743
+ // `created: false` is the double-click, the retry, the reload. The handover
9744
+ // exists, so this is a success — and the address comes from the SERVER, because
9745
+ // on a repeat submit the reply goes to whatever the FIRST handover used.
9746
+ outcome: result.created ? "sent" : "already-handed-over",
9747
+ email: result.escalation?.email ?? null,
9748
+ createdAt: result.escalation?.createdAt ?? null
9749
+ };
9750
+ } catch {
9751
+ return { outcome: "failed", email: null, createdAt: null };
9752
+ }
9753
+ };
9754
+ return attempt(0);
9755
+ },
9756
+ [client, productId]
9757
+ );
9758
+ const canEscalate = hasConversation && !isSharedView;
7898
9759
  return {
7899
9760
  phase,
7900
9761
  catalog,
@@ -7915,6 +9776,8 @@ function useExploreChat(options = {}) {
7915
9776
  clearHistory,
7916
9777
  recordClick,
7917
9778
  submitFeedback,
9779
+ escalate,
9780
+ canEscalate,
7918
9781
  createShareLink,
7919
9782
  isSharedView
7920
9783
  };
@@ -7924,6 +9787,224 @@ function makeOptimisticId() {
7924
9787
  optimisticCounter += 1;
7925
9788
  return `boff-explore-local-${Date.now()}-${optimisticCounter}`;
7926
9789
  }
9790
+ var DRAIN_TARGET_MS = 1200;
9791
+ var MIN_CHARS_PER_SECOND = 90;
9792
+ var MAX_CHARS_PER_SECOND = 2200;
9793
+ var MAX_STEP_MS = 250;
9794
+ var COMMIT_INTERVAL_MS = 45;
9795
+ var FALLBACK_STEP_MS = 50;
9796
+ var FENCE = /^ {0,3}(?:```|~~~)/;
9797
+ var TABLE_ROW = /^ {0,3}\|/;
9798
+ var EMPTY_BLOCK_MARKER = /^ {0,3}(?:[-+>]|#{1,6}|\d{1,9}[.)])\s*$/;
9799
+ function isWordCharacter(char) {
9800
+ return char !== void 0 && /[\p{L}\p{N}]/u.test(char);
9801
+ }
9802
+ function clamp(value, min, max) {
9803
+ return Math.min(Math.max(value, min), max);
9804
+ }
9805
+ function now() {
9806
+ return typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
9807
+ }
9808
+ function isHighSurrogate(code) {
9809
+ return code >= 55296 && code <= 56319;
9810
+ }
9811
+ function safeInlineEnd(line) {
9812
+ let codeSpan = null;
9813
+ let link = null;
9814
+ const emphasis = [];
9815
+ let at = 0;
9816
+ while (at < line.length) {
9817
+ const char = line[at] ?? "";
9818
+ if (char === "\\") {
9819
+ at += 2;
9820
+ continue;
9821
+ }
9822
+ if (char === "`") {
9823
+ let run = 1;
9824
+ while (line[at + run] === "`") run += 1;
9825
+ codeSpan = codeSpan === null ? at : null;
9826
+ at += run;
9827
+ continue;
9828
+ }
9829
+ if (codeSpan !== null) {
9830
+ at += 1;
9831
+ continue;
9832
+ }
9833
+ if (char === "[") {
9834
+ if (link === null) link = line[at - 1] === "!" ? at - 1 : at;
9835
+ at += 1;
9836
+ continue;
9837
+ }
9838
+ if (char === "]") {
9839
+ if (link !== null && line[at + 1] !== "(") link = null;
9840
+ at += 1;
9841
+ continue;
9842
+ }
9843
+ if (char === ")") {
9844
+ link = null;
9845
+ at += 1;
9846
+ continue;
9847
+ }
9848
+ if (char === "*" || char === "_" || char === "~") {
9849
+ let run = 1;
9850
+ while (line[at + run] === char) run += 1;
9851
+ const start = at;
9852
+ at += run;
9853
+ const before = line[start - 1];
9854
+ const after = line[start + run];
9855
+ if (run < 2) continue;
9856
+ if (char === "_" && isWordCharacter(before) && isWordCharacter(after)) {
9857
+ continue;
9858
+ }
9859
+ const marker = char.repeat(run);
9860
+ const open2 = emphasis.findIndex((entry) => entry.marker === marker);
9861
+ if (open2 !== -1) {
9862
+ emphasis.splice(open2, 1);
9863
+ continue;
9864
+ }
9865
+ if (after !== void 0 && /\s/.test(after)) continue;
9866
+ emphasis.push({ marker, start });
9867
+ continue;
9868
+ }
9869
+ at += 1;
9870
+ }
9871
+ const open = [codeSpan, link, emphasis[0]?.start ?? null].filter(
9872
+ (value) => value !== null
9873
+ );
9874
+ return open.length === 0 ? line.length : Math.min(...open);
9875
+ }
9876
+ function revealBoundary(text, limit) {
9877
+ if (limit <= 0) return 0;
9878
+ const caughtUp = limit >= text.length;
9879
+ const head = caughtUp ? text : text.slice(0, limit);
9880
+ const lineStart = head.lastIndexOf("\n") + 1;
9881
+ const line = head.slice(lineStart);
9882
+ let fenceStart = null;
9883
+ let tableStart = null;
9884
+ let tableRows = 0;
9885
+ let at = 0;
9886
+ while (at < lineStart) {
9887
+ const breakAt = head.indexOf("\n", at);
9888
+ const end = breakAt === -1 ? lineStart : breakAt;
9889
+ const row = head.slice(at, end);
9890
+ if (fenceStart !== null) {
9891
+ if (FENCE.test(row)) fenceStart = null;
9892
+ } else if (FENCE.test(row)) {
9893
+ fenceStart = at;
9894
+ } else if (TABLE_ROW.test(row)) {
9895
+ if (tableStart === null) {
9896
+ tableStart = at;
9897
+ tableRows = 0;
9898
+ }
9899
+ tableRows += 1;
9900
+ } else if (tableStart !== null) {
9901
+ tableStart = null;
9902
+ tableRows = 0;
9903
+ }
9904
+ at = end + 1;
9905
+ }
9906
+ if (fenceStart === null) {
9907
+ const lastIsRow = TABLE_ROW.test(line);
9908
+ if (lastIsRow && tableStart === null) {
9909
+ tableStart = lineStart;
9910
+ tableRows = 0;
9911
+ } else if (!lastIsRow && line !== "") {
9912
+ tableStart = null;
9913
+ tableRows = 0;
9914
+ }
9915
+ if (tableStart !== null && tableRows < 2) return tableStart;
9916
+ }
9917
+ if (caughtUp) return text.length;
9918
+ if (fenceStart !== null) return fenceStart;
9919
+ if (TABLE_ROW.test(line)) return lineStart;
9920
+ if (EMPTY_BLOCK_MARKER.test(line)) return lineStart;
9921
+ const cut = lineStart + safeInlineEnd(line);
9922
+ return isHighSurrogate(text.charCodeAt(cut - 1)) ? cut - 1 : cut;
9923
+ }
9924
+ function prefersReducedMotion() {
9925
+ if (typeof window === "undefined") return true;
9926
+ try {
9927
+ return window.matchMedia?.("(prefers-reduced-motion: reduce)").matches === true;
9928
+ } catch {
9929
+ return false;
9930
+ }
9931
+ }
9932
+ function useProgressiveReveal(text, settled) {
9933
+ const [, setFrame] = useState(0);
9934
+ const [reduced] = useState(prefersReducedMotion);
9935
+ const immediate = settled || reduced;
9936
+ const textRef = useRef(text);
9937
+ const cursorRef = useRef(immediate ? text.length : 0);
9938
+ const cutRef = useRef(immediate ? text.length : 0);
9939
+ const committedRef = useRef(0);
9940
+ if (text !== textRef.current) {
9941
+ const revealed = textRef.current.slice(0, Math.floor(cursorRef.current));
9942
+ if (revealed !== "" && !text.startsWith(revealed)) {
9943
+ cursorRef.current = text.length;
9944
+ }
9945
+ cursorRef.current = Math.min(cursorRef.current, text.length);
9946
+ cutRef.current = Math.min(cutRef.current, text.length);
9947
+ textRef.current = text;
9948
+ }
9949
+ if (immediate) cursorRef.current = text.length;
9950
+ const cut = immediate ? text.length : Math.max(
9951
+ cutRef.current,
9952
+ revealBoundary(text, Math.floor(cursorRef.current))
9953
+ );
9954
+ cutRef.current = cut;
9955
+ useEffect(() => {
9956
+ if (immediate) return;
9957
+ if (cursorRef.current >= text.length) return;
9958
+ let cancelled = false;
9959
+ let cancelStep = null;
9960
+ let previous = now();
9961
+ const commit = (at, force) => {
9962
+ if (!force && at - committedRef.current < COMMIT_INTERVAL_MS) return;
9963
+ committedRef.current = at;
9964
+ setFrame((value) => value + 1);
9965
+ };
9966
+ const step = () => {
9967
+ cancelStep = null;
9968
+ if (cancelled) return;
9969
+ const at = now();
9970
+ const elapsed = clamp(at - previous, 0, MAX_STEP_MS);
9971
+ previous = at;
9972
+ const length = textRef.current.length;
9973
+ const pending = length - cursorRef.current;
9974
+ if (pending <= 0) {
9975
+ commit(at, true);
9976
+ return;
9977
+ }
9978
+ const perSecond = clamp(
9979
+ pending / (DRAIN_TARGET_MS / 1e3),
9980
+ MIN_CHARS_PER_SECOND,
9981
+ MAX_CHARS_PER_SECOND
9982
+ );
9983
+ cursorRef.current = Math.min(
9984
+ length,
9985
+ cursorRef.current + perSecond * elapsed / 1e3
9986
+ );
9987
+ const done = cursorRef.current >= length;
9988
+ commit(at, done);
9989
+ if (!done) schedule();
9990
+ };
9991
+ const schedule = () => {
9992
+ if (typeof window.requestAnimationFrame === "function") {
9993
+ const id2 = window.requestAnimationFrame(step);
9994
+ cancelStep = () => window.cancelAnimationFrame(id2);
9995
+ return;
9996
+ }
9997
+ const id = setTimeout(step, FALLBACK_STEP_MS);
9998
+ cancelStep = () => clearTimeout(id);
9999
+ };
10000
+ schedule();
10001
+ return () => {
10002
+ cancelled = true;
10003
+ cancelStep?.();
10004
+ };
10005
+ }, [text, immediate]);
10006
+ return text.slice(0, cut);
10007
+ }
7927
10008
  function getRecognitionCtor() {
7928
10009
  if (typeof window === "undefined") return null;
7929
10010
  const w = window;
@@ -8142,6 +10223,141 @@ function useSpeechInput({
8142
10223
  );
8143
10224
  return { supported, listening, interim, error, start, stop, toggle };
8144
10225
  }
10226
+ var SILENT_FAILURE_MS = 1500;
10227
+ function speechPlatform() {
10228
+ if (typeof window === "undefined") return null;
10229
+ const scope = window;
10230
+ const synth = scope.speechSynthesis;
10231
+ const Utterance = scope.SpeechSynthesisUtterance;
10232
+ if (!synth || typeof synth.speak !== "function") return null;
10233
+ if (typeof Utterance !== "function") return null;
10234
+ return { synth, Utterance };
10235
+ }
10236
+ function normaliseTag(tag) {
10237
+ return tag.trim().toLowerCase().replace(/_/g, "-");
10238
+ }
10239
+ function primaryOf(tag) {
10240
+ return normaliseTag(tag).split("-")[0] ?? "";
10241
+ }
10242
+ function pickVoice(voices, lang) {
10243
+ const wanted = normaliseTag(lang);
10244
+ if (wanted === "") return null;
10245
+ const primary = primaryOf(wanted);
10246
+ const exact = voices.filter((voice) => normaliseTag(voice.lang) === wanted);
10247
+ const related = voices.filter((voice) => primaryOf(voice.lang) === primary);
10248
+ return exact.find((voice) => voice.default) ?? exact[0] ?? related.find((voice) => voice.default) ?? related[0] ?? null;
10249
+ }
10250
+ var activeOwner = null;
10251
+ var activeStop = null;
10252
+ function stopSpeaking() {
10253
+ activeStop?.();
10254
+ }
10255
+ function useSpeechOutput({
10256
+ lang
10257
+ } = {}) {
10258
+ const [available, setAvailable] = useState(() => speechPlatform() !== null);
10259
+ const [speaking, setSpeaking] = useState(false);
10260
+ const utteranceRef = useRef(null);
10261
+ const watchdogRef = useRef(null);
10262
+ const ownerRef = useRef({});
10263
+ const stopRef = useRef(() => void 0);
10264
+ const langRef = useRef(lang);
10265
+ langRef.current = lang;
10266
+ const clearWatchdog = useCallback(() => {
10267
+ if (watchdogRef.current === null) return;
10268
+ clearTimeout(watchdogRef.current);
10269
+ watchdogRef.current = null;
10270
+ }, []);
10271
+ const settle = useCallback(() => {
10272
+ clearWatchdog();
10273
+ utteranceRef.current = null;
10274
+ if (activeOwner === ownerRef.current) {
10275
+ activeOwner = null;
10276
+ activeStop = null;
10277
+ }
10278
+ setSpeaking(false);
10279
+ }, [clearWatchdog]);
10280
+ const stop = useCallback(() => {
10281
+ const owned = utteranceRef.current !== null;
10282
+ settle();
10283
+ if (owned) speechPlatform()?.synth.cancel();
10284
+ }, [settle]);
10285
+ stopRef.current = stop;
10286
+ const speak = useCallback(
10287
+ (text) => {
10288
+ const platform = speechPlatform();
10289
+ if (!platform) {
10290
+ setAvailable(false);
10291
+ return;
10292
+ }
10293
+ const spoken = text.trim();
10294
+ if (spoken === "") return;
10295
+ if (activeStop && activeOwner !== ownerRef.current) activeStop();
10296
+ platform.synth.cancel();
10297
+ const utterance = new platform.Utterance(spoken);
10298
+ const wanted = langRef.current;
10299
+ if (wanted !== void 0 && wanted !== "") {
10300
+ const voice = pickVoice(platform.synth.getVoices(), wanted);
10301
+ utterance.lang = voice?.lang ?? wanted;
10302
+ if (voice) utterance.voice = voice;
10303
+ }
10304
+ const mine = () => utteranceRef.current === utterance;
10305
+ utterance.onstart = () => {
10306
+ if (!mine()) return;
10307
+ clearWatchdog();
10308
+ setSpeaking(true);
10309
+ };
10310
+ utterance.onend = () => {
10311
+ if (!mine()) return;
10312
+ settle();
10313
+ };
10314
+ utterance.onerror = (event) => {
10315
+ if (!mine()) return;
10316
+ const code = typeof event?.error === "string" ? event.error : "";
10317
+ settle();
10318
+ if (code !== "interrupted" && code !== "canceled") setAvailable(false);
10319
+ };
10320
+ utteranceRef.current = utterance;
10321
+ activeOwner = ownerRef.current;
10322
+ activeStop = () => {
10323
+ stopRef.current();
10324
+ };
10325
+ setSpeaking(true);
10326
+ platform.synth.speak(utterance);
10327
+ clearWatchdog();
10328
+ watchdogRef.current = setTimeout(() => {
10329
+ watchdogRef.current = null;
10330
+ if (!mine()) return;
10331
+ if (platform.synth.speaking) return;
10332
+ settle();
10333
+ setAvailable(false);
10334
+ }, SILENT_FAILURE_MS);
10335
+ },
10336
+ [clearWatchdog, settle]
10337
+ );
10338
+ const toggle = useCallback(
10339
+ (text) => {
10340
+ if (speaking) stop();
10341
+ else speak(text);
10342
+ },
10343
+ [speak, speaking, stop]
10344
+ );
10345
+ useEffect(() => {
10346
+ if (!speaking || typeof window === "undefined") return;
10347
+ const onHide = () => {
10348
+ stopRef.current();
10349
+ };
10350
+ window.addEventListener("pagehide", onHide);
10351
+ return () => window.removeEventListener("pagehide", onHide);
10352
+ }, [speaking]);
10353
+ useEffect(
10354
+ () => () => {
10355
+ stopRef.current();
10356
+ },
10357
+ []
10358
+ );
10359
+ return { supported: available, speaking, speak, stop, toggle };
10360
+ }
8145
10361
  var SWIPE_THRESHOLD = 40;
8146
10362
  function useSwipe({
8147
10363
  onSwipeLeft,
@@ -8382,33 +10598,6 @@ var EXPLORE_CSS = `
8382
10598
  .boff-explore-fade { animation: none; }
8383
10599
  }
8384
10600
 
8385
- /* Nothing inside an answer may widen the page. Model output carries long URLs, code and
8386
- tables \u2014 each of those overflows a phone by default, and one overflowing child makes the
8387
- WHOLE document horizontally scrollable, not just the bubble. */
8388
- .boff-explore-body,
8389
- .boff-explore-body p,
8390
- .boff-explore-body li,
8391
- .boff-explore-body a,
8392
- .boff-explore-body h1,
8393
- .boff-explore-body h2,
8394
- .boff-explore-body h3 {
8395
- overflow-wrap: anywhere;
8396
- word-break: break-word;
8397
- }
8398
- .boff-explore-body pre {
8399
- overflow-x: auto;
8400
- max-width: 100%;
8401
- }
8402
- .boff-explore-body table {
8403
- display: block;
8404
- overflow-x: auto;
8405
- max-width: 100%;
8406
- }
8407
- .boff-explore-body img {
8408
- max-width: 100%;
8409
- height: auto;
8410
- }
8411
-
8412
10601
  /* ---- Ambient backdrop -----------------------------------------------------------------
8413
10602
  Two very low-opacity radial washes behind the welcome state, drifting slowly. Painted on
8414
10603
  a pseudo-element with pointer-events:none so it can never intercept a click \u2014 a
@@ -8465,11 +10654,40 @@ var EXPLORE_CSS = `
8465
10654
  animation: boff-explore-sheen 1.5s ease-in-out infinite;
8466
10655
  }
8467
10656
 
10657
+ /* ---- The composer, before anyone has typed -----------------------------------------
10658
+ On the welcome screen the box IS the page: everything above it is a way of explaining
10659
+ what to put in it. Unhighlighted it reads as a search bar at the bottom of a landing
10660
+ page, which people scroll past \u2014 so while the conversation is empty it gets a soft halo
10661
+ in the site's own --primary and one slow breath of it, and the moment there is a
10662
+ transcript, or the visitor focuses or types, it drops back to the ordinary card it was.
10663
+ An input that keeps pulsing while you are using it is nagging, not inviting.
10664
+
10665
+ Colour comes from the product's --primary token, so it is whatever that site's palette
10666
+ already is, never a colour chosen here. */
10667
+ .boff-explore-invite {
10668
+ border-color: hsl(var(--primary) / 0.45);
10669
+ box-shadow:
10670
+ 0 0 0 4px hsl(var(--primary) / 0.08),
10671
+ 0 8px 24px -12px hsl(var(--primary) / 0.45);
10672
+ animation: boff-explore-breathe 3.2s ease-in-out infinite;
10673
+ }
10674
+ /* Focus and typing both mean "I have found it", and the hint has done its job. */
10675
+ .boff-explore-invite:focus-within,
10676
+ .boff-explore-invite.boff-explore-invite-quiet {
10677
+ animation: none;
10678
+ box-shadow: 0 0 0 4px hsl(var(--primary) / 0.10);
10679
+ }
10680
+ @keyframes boff-explore-breathe {
10681
+ 0%, 100% { box-shadow: 0 0 0 4px hsl(var(--primary) / 0.07), 0 8px 24px -12px hsl(var(--primary) / 0.40); }
10682
+ 50% { box-shadow: 0 0 0 7px hsl(var(--primary) / 0.13), 0 8px 28px -12px hsl(var(--primary) / 0.55); }
10683
+ }
10684
+
8468
10685
  /* Every one of the above is decoration. Reduced motion removes the movement and keeps the
8469
10686
  final state, rather than leaving content mid-animation and invisible. */
8470
10687
  @media (prefers-reduced-motion: reduce) {
8471
10688
  .boff-explore-aura::before,
8472
- .boff-explore-busy::after { animation: none; }
10689
+ .boff-explore-busy::after,
10690
+ .boff-explore-invite { animation: none; }
8473
10691
  .boff-explore-rise { animation: none; opacity: 1; transform: none; }
8474
10692
  }
8475
10693
 
@@ -8580,7 +10798,7 @@ function isOwnElement(el, root) {
8580
10798
  function visualViewportHeight() {
8581
10799
  return window.visualViewport?.height ?? window.innerHeight;
8582
10800
  }
8583
- function clamp(value, min, max) {
10801
+ function clamp2(value, min, max) {
8584
10802
  return Math.min(Math.max(value, min), max);
8585
10803
  }
8586
10804
  function isRestoredNavigation() {
@@ -8599,51 +10817,23 @@ function isInternalPath(url) {
8599
10817
  }
8600
10818
  function hostnameOf(url) {
8601
10819
  try {
8602
- return new URL(url).hostname.replace(/^www\./, "");
8603
- } catch {
8604
- return "";
8605
- }
8606
- }
8607
- function initialOf(value, fallback) {
8608
- const source = (value || fallback).trim();
8609
- return source ? source.slice(0, 1).toUpperCase() : "?";
8610
- }
8611
- function logoUrlOf(url) {
8612
- try {
8613
- const { origin, protocol } = new URL(url);
8614
- if (protocol !== "https:" && protocol !== "http:") return null;
8615
- return `${origin}/favicon.svg`;
8616
- } catch {
8617
- return null;
8618
- }
8619
- }
8620
- function inlineImageOrigins(products) {
8621
- const origins = /* @__PURE__ */ new Set();
8622
- for (const product of products) {
8623
- let url;
8624
- try {
8625
- url = new URL(product.website);
8626
- } catch {
8627
- continue;
8628
- }
8629
- if (url.protocol !== "https:") continue;
8630
- const apex = url.hostname.replace(/^www\./, "");
8631
- const port = url.port ? `:${url.port}` : "";
8632
- origins.add(`https://${apex}${port}`);
8633
- origins.add(`https://www.${apex}${port}`);
10820
+ return new URL(url).hostname.replace(/^www\./, "");
10821
+ } catch {
10822
+ return "";
8634
10823
  }
8635
- return origins;
8636
10824
  }
8637
- function isInlineImageAllowed(src, origins) {
8638
- if (typeof src !== "string" || src === "") return false;
8639
- let url;
10825
+ function initialOf(value, fallback) {
10826
+ const source = (value || fallback).trim();
10827
+ return source ? source.slice(0, 1).toUpperCase() : "?";
10828
+ }
10829
+ function logoUrlOf(url) {
8640
10830
  try {
8641
- url = new URL(src);
10831
+ const { origin, protocol } = new URL(url);
10832
+ if (protocol !== "https:" && protocol !== "http:") return null;
10833
+ return `${origin}/favicon.svg`;
8642
10834
  } catch {
8643
- return false;
10835
+ return null;
8644
10836
  }
8645
- if (url.protocol !== "https:" || url.username || url.password) return false;
8646
- return origins.has(url.origin);
8647
10837
  }
8648
10838
  var REFERENCE_KIND_ORDER = [
8649
10839
  "CONCEPT",
@@ -8729,97 +10919,6 @@ function summariseReferences(references, origins, productNames) {
8729
10919
  products
8730
10920
  };
8731
10921
  }
8732
- var CODE_FENCE = /^\s*(?:```|~~~)/;
8733
- function answerPlainText(markdown) {
8734
- const lines = [];
8735
- let inFence = false;
8736
- for (const raw of markdown.split("\n")) {
8737
- if (CODE_FENCE.test(raw)) {
8738
- inFence = !inFence;
8739
- continue;
8740
- }
8741
- if (inFence) {
8742
- lines.push(raw);
8743
- continue;
8744
- }
8745
- let line = raw;
8746
- line = line.replace(/!\[[^\]]*\]\([^)\s]*(?:\s+"[^"]*")?\)/g, "");
8747
- line = line.replace(/\[([^\]]+)\]\(([^)\s]+)(?:\s+"[^"]*")?\)/g, "$1 ($2)");
8748
- line = line.replace(/<(https?:\/\/[^>\s]+)>/g, "$1");
8749
- line = line.replace(/^\s{0,3}#{1,6}\s+/, "");
8750
- line = line.replace(/^\s{0,3}>\s?/, "");
8751
- if (/^\s{0,3}([-*_])[ \t]*(?:\1[ \t]*){2,}$/.test(line)) {
8752
- lines.push("");
8753
- continue;
8754
- }
8755
- line = line.replace(/`([^`]+)`/g, "$1");
8756
- line = line.replace(/\*\*([^*]+)\*\*/g, "$1");
8757
- line = line.replace(/__([^_]+)__/g, "$1");
8758
- line = line.replace(/(^|[^*\w])\*([^*\n]+)\*(?![*\w])/g, "$1$2");
8759
- line = line.replace(/(^|[^_\w])_([^_\n]+)_(?![_\w])/g, "$1$2");
8760
- lines.push(line.replace(/[ \t]+$/, ""));
8761
- }
8762
- return lines.join("\n").replace(/\n{3,}/g, "\n\n").trim();
8763
- }
8764
- var InlineImageScopeContext = createContext(null);
8765
- var InsideLinkContext = createContext(false);
8766
- function AnswerLink(props) {
8767
- return /* @__PURE__ */ jsx(InsideLinkContext.Provider, { value: true, children: /* @__PURE__ */ jsx(MarkdownLink, { ...props }) });
8768
- }
8769
- var INLINE_IMAGE_FRAME = "relative inline-block max-w-full overflow-hidden rounded-xl border border-border bg-muted align-top shadow-sm";
8770
- function InlineConceptImage({ src, alt }) {
8771
- const scope = useContext(InlineImageScopeContext);
8772
- const insideLink = useContext(InsideLinkContext);
8773
- if (!scope || !scope.enabled || !isInlineImageAllowed(src, scope.origins) || scope.failed.has(src)) {
8774
- return null;
8775
- }
8776
- const { strings: T, onFailed } = scope;
8777
- const picture = /* @__PURE__ */ jsxs(Fragment, { children: [
8778
- /* @__PURE__ */ jsx(
8779
- "img",
8780
- {
8781
- src,
8782
- alt: alt ?? "",
8783
- loading: "lazy",
8784
- decoding: "async",
8785
- onError: () => onFailed(src),
8786
- className: "block h-auto max-h-80 w-auto max-w-full object-contain"
8787
- }
8788
- ),
8789
- /* @__PURE__ */ jsx(
8790
- "span",
8791
- {
8792
- "aria-hidden": "true",
8793
- 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",
8794
- children: T.conceptIllustration
8795
- }
8796
- )
8797
- ] });
8798
- return /* @__PURE__ */ jsx("span", { "data-boff-explore": "inline-image", className: "my-3 block", children: insideLink ? /* @__PURE__ */ jsx("span", { className: INLINE_IMAGE_FRAME, children: picture }) : /* @__PURE__ */ jsxs(
8799
- "a",
8800
- {
8801
- href: src,
8802
- target: "_blank",
8803
- rel: "noopener noreferrer",
8804
- className: cn(
8805
- INLINE_IMAGE_FRAME,
8806
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
8807
- ),
8808
- children: [
8809
- picture,
8810
- /* @__PURE__ */ jsxs("span", { className: "sr-only", children: [
8811
- "(",
8812
- T.opensInNewTab,
8813
- ")"
8814
- ] })
8815
- ]
8816
- }
8817
- ) });
8818
- }
8819
- var ANSWER_MARKDOWN_COMPONENTS = {
8820
- a: AnswerLink,
8821
- img: InlineConceptImage
8822
- };
8823
10922
  function ReferenceCard({
8824
10923
  reference,
8825
10924
  onFollow
@@ -9158,6 +11257,195 @@ function AnswerFeedback({
9158
11257
  }
9159
11258
  );
9160
11259
  }
11260
+ function EscalateForm({
11261
+ strings: T,
11262
+ formId,
11263
+ onEscalate,
11264
+ onClose,
11265
+ onBusyChange
11266
+ }) {
11267
+ const [email, setEmail] = useState("");
11268
+ const [note, setNote] = useState("");
11269
+ const [error, setError] = useState(null);
11270
+ const [sending, setSending] = useState(false);
11271
+ const [sentTo, setSentTo] = useState(null);
11272
+ const emailRef = useRef(null);
11273
+ const inFlightRef = useRef(false);
11274
+ const titleId = `${formId}-title`;
11275
+ const emailId = `${formId}-email`;
11276
+ const noteId = `${formId}-note`;
11277
+ const errorId = `${formId}-error`;
11278
+ useEffect(() => {
11279
+ emailRef.current?.focus();
11280
+ }, []);
11281
+ useEffect(() => {
11282
+ onBusyChange?.(sending);
11283
+ return () => onBusyChange?.(false);
11284
+ }, [sending, onBusyChange]);
11285
+ const handleSubmit = useCallback(
11286
+ async (event) => {
11287
+ event.preventDefault();
11288
+ if (inFlightRef.current) return;
11289
+ const address = email.trim();
11290
+ if (!looksLikeDeliverableEmail(address)) {
11291
+ setError(T.escalateInvalidEmail);
11292
+ emailRef.current?.focus();
11293
+ return;
11294
+ }
11295
+ inFlightRef.current = true;
11296
+ setSending(true);
11297
+ setError(null);
11298
+ const result = await onEscalate(address, note);
11299
+ inFlightRef.current = false;
11300
+ setSending(false);
11301
+ switch (result.outcome) {
11302
+ case "sent":
11303
+ case "already-handed-over":
11304
+ setSentTo(result.email ?? address);
11305
+ return;
11306
+ case "invalid-email":
11307
+ setError(T.escalateInvalidEmail);
11308
+ emailRef.current?.focus();
11309
+ return;
11310
+ case "rate-limited":
11311
+ setError(T.escalateRateLimited);
11312
+ return;
11313
+ case "captcha":
11314
+ setError(T.escalateCaptcha);
11315
+ return;
11316
+ // `no-conversation` included: the form should not have been offered at all, and the
11317
+ // honest thing to show is that nothing was passed on.
11318
+ default:
11319
+ setError(T.escalateFailed);
11320
+ return;
11321
+ }
11322
+ },
11323
+ [T, email, note, onEscalate]
11324
+ );
11325
+ if (sentTo !== null) {
11326
+ return /* @__PURE__ */ jsx(
11327
+ "p",
11328
+ {
11329
+ id: formId,
11330
+ "data-boff-explore": "escalate-sent",
11331
+ role: "status",
11332
+ className: "boff-explore-fade mt-2 rounded-xl border border-border bg-card px-3 py-2 text-xs leading-relaxed text-card-foreground",
11333
+ children: fill(T.escalateSent, { email: sentTo })
11334
+ }
11335
+ );
11336
+ }
11337
+ return /* @__PURE__ */ jsxs(
11338
+ "form",
11339
+ {
11340
+ id: formId,
11341
+ "data-boff-explore": "escalate-form",
11342
+ "aria-labelledby": titleId,
11343
+ noValidate: true,
11344
+ onSubmit: handleSubmit,
11345
+ onKeyDown: (event) => {
11346
+ if (event.key !== "Escape") return;
11347
+ event.stopPropagation();
11348
+ if (sending) return;
11349
+ onClose();
11350
+ },
11351
+ className: "boff-explore-fade mt-2 space-y-2 rounded-xl border border-border bg-card p-3",
11352
+ children: [
11353
+ /* @__PURE__ */ jsx("p", { id: titleId, className: "text-xs font-medium text-card-foreground", children: T.escalateTitle }),
11354
+ /* @__PURE__ */ jsx("p", { className: "text-xs leading-relaxed text-muted-foreground", children: T.escalateBody }),
11355
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
11356
+ /* @__PURE__ */ jsx(
11357
+ "label",
11358
+ {
11359
+ htmlFor: emailId,
11360
+ className: "block text-xs font-medium text-card-foreground",
11361
+ children: T.escalateEmailLabel
11362
+ }
11363
+ ),
11364
+ /* @__PURE__ */ jsx(
11365
+ "input",
11366
+ {
11367
+ ref: emailRef,
11368
+ id: emailId,
11369
+ name: "email",
11370
+ "data-boff-explore": "escalate-email",
11371
+ type: "email",
11372
+ inputMode: "email",
11373
+ autoComplete: "email",
11374
+ required: true,
11375
+ value: email,
11376
+ onChange: (event) => {
11377
+ setEmail(event.target.value);
11378
+ if (error) setError(null);
11379
+ },
11380
+ "aria-invalid": error ? "true" : void 0,
11381
+ "aria-describedby": error ? errorId : void 0,
11382
+ placeholder: T.escalateEmailPlaceholder,
11383
+ 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"
11384
+ }
11385
+ )
11386
+ ] }),
11387
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
11388
+ /* @__PURE__ */ jsx(
11389
+ "label",
11390
+ {
11391
+ htmlFor: noteId,
11392
+ className: "block text-xs font-medium text-card-foreground",
11393
+ children: T.escalateNoteLabel
11394
+ }
11395
+ ),
11396
+ /* @__PURE__ */ jsx(
11397
+ Textarea,
11398
+ {
11399
+ id: noteId,
11400
+ name: "note",
11401
+ "data-boff-explore": "escalate-note",
11402
+ rows: 2,
11403
+ value: note,
11404
+ onChange: (event) => setNote(event.target.value),
11405
+ maxLength: EXPLORE_ESCALATION_NOTE_SOFT_MAX,
11406
+ className: "min-h-0 border-border bg-background"
11407
+ }
11408
+ )
11409
+ ] }),
11410
+ error ? /* @__PURE__ */ jsx(
11411
+ "p",
11412
+ {
11413
+ id: errorId,
11414
+ "data-boff-explore": "escalate-error",
11415
+ role: "alert",
11416
+ className: "text-xs leading-relaxed text-destructive",
11417
+ children: error
11418
+ }
11419
+ ) : null,
11420
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
11421
+ /* @__PURE__ */ jsx(
11422
+ Button,
11423
+ {
11424
+ "data-boff-explore": "escalate-send",
11425
+ type: "submit",
11426
+ size: "sm",
11427
+ disabled: sending,
11428
+ children: sending ? T.escalateSending : T.escalateSubmit
11429
+ }
11430
+ ),
11431
+ /* @__PURE__ */ jsx(
11432
+ Button,
11433
+ {
11434
+ "data-boff-explore": "escalate-cancel",
11435
+ type: "button",
11436
+ size: "sm",
11437
+ variant: "ghost",
11438
+ className: "text-muted-foreground",
11439
+ disabled: sending,
11440
+ onClick: onClose,
11441
+ children: T.escalateCancel
11442
+ }
11443
+ )
11444
+ ] })
11445
+ ]
11446
+ }
11447
+ );
11448
+ }
9161
11449
  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";
9162
11450
  function ProvenanceChips({
9163
11451
  strings: T,
@@ -9207,9 +11495,42 @@ function ProvenanceChips({
9207
11495
  );
9208
11496
  }
9209
11497
  var COPY_FEEDBACK_MS = 2500;
11498
+ 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";
11499
+ var ANSWER_ACTION_IDLE = "border-border bg-card text-muted-foreground hover:border-primary/40 hover:bg-accent hover:text-foreground";
11500
+ var ANSWER_ACTION_ACTIVE = "border-primary/40 bg-accent text-primary";
11501
+ function ReadAloudButton({
11502
+ strings: T,
11503
+ text,
11504
+ lang
11505
+ }) {
11506
+ const speech = useSpeechOutput({ lang });
11507
+ if (!speech.supported) return null;
11508
+ const label = speech.speaking ? T.stopReading : T.readAloud;
11509
+ return /* @__PURE__ */ jsxs(
11510
+ "button",
11511
+ {
11512
+ "data-boff-explore": "read-aloud",
11513
+ "data-speaking": speech.speaking ? "true" : "false",
11514
+ type: "button",
11515
+ title: label,
11516
+ "aria-pressed": speech.speaking,
11517
+ onClick: () => speech.toggle(text),
11518
+ className: cn(
11519
+ ANSWER_ACTION_PILL,
11520
+ speech.speaking ? ANSWER_ACTION_ACTIVE : ANSWER_ACTION_IDLE
11521
+ ),
11522
+ children: [
11523
+ /* @__PURE__ */ jsx(Volume2, { className: "h-3 w-3 shrink-0", "aria-hidden": "true" }),
11524
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: label })
11525
+ ]
11526
+ }
11527
+ );
11528
+ }
9210
11529
  function AnswerActions({
9211
11530
  strings: T,
9212
- text
11531
+ text,
11532
+ speechText,
11533
+ speechLang
9213
11534
  }) {
9214
11535
  const [outcome, setOutcome] = useState("idle");
9215
11536
  const resetRef = useRef(null);
@@ -9252,9 +11573,8 @@ function AnswerActions({
9252
11573
  void copy();
9253
11574
  },
9254
11575
  className: cn(
9255
- "inline-flex max-w-full items-center gap-1.5 rounded-full border px-2.5 py-1 text-xs transition-colors",
9256
- "focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
9257
- 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"
11576
+ ANSWER_ACTION_PILL,
11577
+ outcome === "failed" ? "border-destructive/40 bg-card text-destructive" : ANSWER_ACTION_IDLE
9258
11578
  ),
9259
11579
  children: [
9260
11580
  outcome === "copied" ? /* @__PURE__ */ jsx(Check, { className: "h-3 w-3 shrink-0", "aria-hidden": "true" }) : /* @__PURE__ */ jsx(Copy, { className: "h-3 w-3 shrink-0", "aria-hidden": "true" }),
@@ -9262,6 +11582,7 @@ function AnswerActions({
9262
11582
  ]
9263
11583
  }
9264
11584
  ),
11585
+ /* @__PURE__ */ jsx(ReadAloudButton, { strings: T, text: speechText, lang: speechLang }),
9265
11586
  /* @__PURE__ */ jsx("span", { "data-boff-explore": "copy-status", role: "status", className: "sr-only", children: outcome === "idle" ? "" : label })
9266
11587
  ]
9267
11588
  }
@@ -9313,34 +11634,20 @@ function AssistantBubble({
9313
11634
  activity,
9314
11635
  imageOrigins,
9315
11636
  productNames,
11637
+ speechLang,
9316
11638
  onNavigate,
9317
11639
  anchorRef,
9318
11640
  onFollow,
9319
11641
  onFollowUp,
9320
- onFeedback
11642
+ onFeedback,
11643
+ onEscalate,
11644
+ isLatestAnswer = false
9321
11645
  }) {
9322
11646
  const streaming = message.status === "PENDING" || message.status === "RUNNING";
9323
11647
  const body = message.content || message.partialContent || "";
9324
11648
  const failed = message.status === "FAILED";
9325
11649
  const completed = message.status === "COMPLETED";
9326
- const [failedImages, setFailedImages] = useState(
9327
- () => /* @__PURE__ */ new Set()
9328
- );
9329
- const markImageFailed = useCallback((src) => {
9330
- setFailedImages(
9331
- (current) => current.has(src) ? current : new Set(current).add(src)
9332
- );
9333
- }, []);
9334
- const imageScope = useMemo(
9335
- () => ({
9336
- strings: T,
9337
- enabled: completed,
9338
- origins: imageOrigins,
9339
- failed: failedImages,
9340
- onFailed: markImageFailed
9341
- }),
9342
- [T, completed, imageOrigins, failedImages, markImageFailed]
9343
- );
11650
+ const visible = useProgressiveReveal(body, !streaming);
9344
11651
  const provenance = useMemo(
9345
11652
  () => summariseReferences(message.references, imageOrigins, productNames),
9346
11653
  [message.references, imageOrigins, productNames]
@@ -9349,7 +11656,25 @@ function AssistantBubble({
9349
11656
  () => answerPlainText(message.content),
9350
11657
  [message.content]
9351
11658
  );
11659
+ const speechText = useMemo(
11660
+ () => answerSpeechText(message.content),
11661
+ [message.content]
11662
+ );
9352
11663
  const grounded = completed && message.answered !== false;
11664
+ const [escalateOpen, setEscalateOpen] = useState(false);
11665
+ const [escalateBusy, setEscalateBusy] = useState(false);
11666
+ const escalateTriggerRef = useRef(null);
11667
+ const escalateFormId = `boff-explore-escalate-${message.id}`;
11668
+ const unanswered = completed && message.answered === false;
11669
+ const offerEscalate = Boolean(onEscalate) && completed;
11670
+ const showQuietEscalate = offerEscalate && !unanswered && isLatestAnswer;
11671
+ const closeEscalate = useCallback(() => {
11672
+ setEscalateOpen(false);
11673
+ escalateTriggerRef.current?.focus();
11674
+ }, []);
11675
+ const handleEscalateBusy = useCallback((busy) => {
11676
+ setEscalateBusy(busy);
11677
+ }, []);
9353
11678
  return /* @__PURE__ */ jsxs(
9354
11679
  "div",
9355
11680
  {
@@ -9367,7 +11692,7 @@ function AssistantBubble({
9367
11692
  }
9368
11693
  ),
9369
11694
  /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1 space-y-3", children: [
9370
- message.status === "COMPLETED" && message.answered === false ? /* @__PURE__ */ jsxs(
11695
+ unanswered ? /* @__PURE__ */ jsxs(
9371
11696
  "div",
9372
11697
  {
9373
11698
  "data-boff-explore": "no-answer",
@@ -9377,26 +11702,56 @@ function AssistantBubble({
9377
11702
  /* @__PURE__ */ jsxs("span", { children: [
9378
11703
  T.noAnswer,
9379
11704
  " ",
9380
- /* @__PURE__ */ jsx(
9381
- "a",
9382
- {
9383
- href: "/contact",
9384
- className: "underline underline-offset-2 hover:text-primary",
9385
- onClick: (event) => {
9386
- if (!onNavigate) return;
9387
- event.preventDefault();
9388
- onNavigate("/contact");
9389
- },
9390
- children: T.askHuman
9391
- }
11705
+ offerEscalate ? (
11706
+ /* The point of the wave: the same words, but they now open a form that
11707
+ sends the conversation we are both looking at, instead of a link to a
11708
+ blank contact page that asks the visitor to type it all again. */
11709
+ /* @__PURE__ */ jsx(
11710
+ "button",
11711
+ {
11712
+ ref: escalateTriggerRef,
11713
+ "data-boff-explore": "escalate-open",
11714
+ type: "button",
11715
+ "aria-expanded": escalateOpen,
11716
+ "aria-controls": escalateOpen ? escalateFormId : void 0,
11717
+ onClick: () => setEscalateOpen(true),
11718
+ className: "rounded-sm underline underline-offset-2 hover:text-primary focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
11719
+ children: T.askHuman
11720
+ }
11721
+ )
11722
+ ) : (
11723
+ /* No conversation to hand over (a shared, read-only view). The old dead end
11724
+ is still better than a control whose submit could only fail. */
11725
+ /* @__PURE__ */ jsx(
11726
+ "a",
11727
+ {
11728
+ href: "/contact",
11729
+ className: "underline underline-offset-2 hover:text-primary",
11730
+ onClick: (event) => {
11731
+ if (!onNavigate) return;
11732
+ event.preventDefault();
11733
+ onNavigate("/contact");
11734
+ },
11735
+ children: T.askHuman
11736
+ }
11737
+ )
9392
11738
  ),
9393
11739
  "."
9394
11740
  ] })
9395
11741
  ]
9396
11742
  }
9397
11743
  ) : null,
9398
- body ? /* @__PURE__ */ jsxs("div", { className: "rounded-2xl rounded-tl-md border border-border bg-card px-4 py-3 shadow-sm", children: [
9399
- /* @__PURE__ */ jsx("div", { className: "boff-prose boff-prose-sm boff-explore-body min-w-0 text-card-foreground", children: /* @__PURE__ */ jsx(InlineImageScopeContext.Provider, { value: imageScope, children: /* @__PURE__ */ jsx(Markdown, { components: ANSWER_MARKDOWN_COMPONENTS, children: body }) }) }),
11744
+ visible ? /* @__PURE__ */ jsxs("div", { className: "rounded-2xl rounded-tl-md border border-border bg-card px-4 py-3 shadow-sm", children: [
11745
+ /* @__PURE__ */ jsx(
11746
+ ExploreAnswerBody,
11747
+ {
11748
+ strings: T,
11749
+ imageOrigins,
11750
+ enabled: completed,
11751
+ className: "boff-prose-sm text-card-foreground",
11752
+ children: visible
11753
+ }
11754
+ ),
9400
11755
  streaming ? /* @__PURE__ */ jsx("span", { className: "boff-explore-caret", "aria-hidden": "true" }) : null
9401
11756
  ] }) : null,
9402
11757
  grounded && provenance.total > 0 ? /* @__PURE__ */ jsx(ProvenanceChips, { strings: T, provenance }) : null,
@@ -9439,7 +11794,15 @@ function AssistantBubble({
9439
11794
  question
9440
11795
  )) })
9441
11796
  ] }) : null,
9442
- completed && copyText !== "" ? /* @__PURE__ */ jsx(AnswerActions, { strings: T, text: copyText }) : null,
11797
+ completed && copyText !== "" ? /* @__PURE__ */ jsx(
11798
+ AnswerActions,
11799
+ {
11800
+ strings: T,
11801
+ text: copyText,
11802
+ speechText,
11803
+ speechLang
11804
+ }
11805
+ ) : null,
9443
11806
  completed && onFeedback ? /* @__PURE__ */ jsx(
9444
11807
  AnswerFeedback,
9445
11808
  {
@@ -9448,6 +11811,30 @@ function AssistantBubble({
9448
11811
  feedback: message.feedback,
9449
11812
  onSubmit: onFeedback
9450
11813
  }
11814
+ ) : null,
11815
+ showQuietEscalate ? /* @__PURE__ */ jsx("div", { className: "pt-0.5", children: /* @__PURE__ */ jsx(
11816
+ "button",
11817
+ {
11818
+ ref: escalateTriggerRef,
11819
+ "data-boff-explore": "escalate-open",
11820
+ type: "button",
11821
+ "aria-expanded": escalateOpen,
11822
+ "aria-controls": escalateOpen ? escalateFormId : void 0,
11823
+ disabled: escalateBusy,
11824
+ onClick: () => setEscalateOpen((open) => !open),
11825
+ 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",
11826
+ children: T.escalateOpen
11827
+ }
11828
+ ) }) : null,
11829
+ escalateOpen && onEscalate ? /* @__PURE__ */ jsx(
11830
+ EscalateForm,
11831
+ {
11832
+ strings: T,
11833
+ formId: escalateFormId,
11834
+ onEscalate,
11835
+ onClose: closeEscalate,
11836
+ onBusyChange: handleEscalateBusy
11837
+ }
9451
11838
  ) : null
9452
11839
  ] })
9453
11840
  ]
@@ -9887,15 +12274,6 @@ function WelcomeState({
9887
12274
  }
9888
12275
  )
9889
12276
  ] }) : null,
9890
- /* @__PURE__ */ jsx(
9891
- ConceptStrip,
9892
- {
9893
- strings: T,
9894
- highlights: conceptHighlights,
9895
- onAsk: onPrompt,
9896
- disabled
9897
- }
9898
- ),
9899
12277
  products.length > 0 ? /* @__PURE__ */ jsxs("div", { className: "boff-explore-rise boff-explore-rise-3 mt-6", children: [
9900
12278
  /* @__PURE__ */ jsx("p", { className: "mb-2 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: T.focusProduct }),
9901
12279
  /* @__PURE__ */ jsx(
@@ -9907,7 +12285,16 @@ function WelcomeState({
9907
12285
  onFocus
9908
12286
  }
9909
12287
  )
9910
- ] }) : null
12288
+ ] }) : null,
12289
+ /* @__PURE__ */ jsx(
12290
+ ConceptStrip,
12291
+ {
12292
+ strings: T,
12293
+ highlights: conceptHighlights,
12294
+ onAsk: onPrompt,
12295
+ disabled
12296
+ }
12297
+ )
9911
12298
  ] });
9912
12299
  }
9913
12300
  function ExplorePage({
@@ -9933,6 +12320,7 @@ function ExplorePage({
9933
12320
  );
9934
12321
  const T = useMemo(() => exploreStrings(activeLocale), [activeLocale]);
9935
12322
  const rtl = isRtlLocale(activeLocale);
12323
+ const speechLang = speechLocaleOf(activeLocale);
9936
12324
  const {
9937
12325
  phase,
9938
12326
  catalog,
@@ -9953,6 +12341,8 @@ function ExplorePage({
9953
12341
  clearHistory,
9954
12342
  recordClick,
9955
12343
  submitFeedback,
12344
+ escalate,
12345
+ canEscalate,
9956
12346
  createShareLink,
9957
12347
  isSharedView
9958
12348
  } = useExploreChat({
@@ -10037,11 +12427,11 @@ function ExplorePage({
10037
12427
  const layoutHeight = window.innerHeight;
10038
12428
  if (layoutHeight === 0) return;
10039
12429
  const top = Math.round(
10040
- clamp(el.getBoundingClientRect().top, 0, layoutHeight)
12430
+ clamp2(el.getBoundingClientRect().top, 0, layoutHeight)
10041
12431
  );
10042
12432
  const viewport = window.visualViewport;
10043
12433
  const inset = viewport ? Math.round(
10044
- clamp(
12434
+ clamp2(
10045
12435
  layoutHeight - viewport.height - viewport.offsetTop,
10046
12436
  0,
10047
12437
  layoutHeight
@@ -10322,6 +12712,7 @@ function ExplorePage({
10322
12712
  const text = draft.trim();
10323
12713
  if (!text || overLimit || busy || !canSend) return;
10324
12714
  stopDictation();
12715
+ stopSpeaking();
10325
12716
  setDraft("");
10326
12717
  stickToBottomRef.current = true;
10327
12718
  void send(text, toPayload(stagedRef.current));
@@ -10332,6 +12723,7 @@ function ExplorePage({
10332
12723
  const sendPrompt = useCallback(
10333
12724
  (prompt) => {
10334
12725
  if (!canSend || busy) return;
12726
+ stopSpeaking();
10335
12727
  setDraft("");
10336
12728
  stickToBottomRef.current = true;
10337
12729
  void send(prompt, toPayload(stagedRef.current));
@@ -10394,6 +12786,7 @@ function ExplorePage({
10394
12786
  ),
10395
12787
  /* @__PURE__ */ jsx(ProseStyles, {}),
10396
12788
  /* @__PURE__ */ jsx(ExploreStyles, {}),
12789
+ /* @__PURE__ */ jsx(ExploreAnswerStyles, {}),
10397
12790
  !showWelcome ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2.5 border-b border-border px-4 py-2.5", children: [
10398
12791
  /* @__PURE__ */ jsx(
10399
12792
  "span",
@@ -10567,11 +12960,14 @@ function ExplorePage({
10567
12960
  activity,
10568
12961
  imageOrigins,
10569
12962
  productNames,
12963
+ speechLang,
10570
12964
  onNavigate,
10571
12965
  anchorRef: message.id === latestAssistantId ? latestAssistantRef : void 0,
10572
12966
  onFollow: (kind, url) => recordClick(message.id, kind, url),
10573
12967
  onFollowUp: sendPrompt,
10574
- onFeedback: isSharedView ? void 0 : (rating, detail) => submitFeedback(message.id, rating, detail)
12968
+ onFeedback: isSharedView ? void 0 : (rating, detail) => submitFeedback(message.id, rating, detail),
12969
+ onEscalate: canEscalate ? escalate : void 0,
12970
+ isLatestAnswer: message.id === latestAssistantId
10575
12971
  },
10576
12972
  message.id
10577
12973
  )
@@ -10678,10 +13074,19 @@ function ExplorePage({
10678
13074
  /* @__PURE__ */ jsxs(
10679
13075
  "div",
10680
13076
  {
13077
+ "data-boff-explore": "composer-field",
10681
13078
  className: cn(
10682
13079
  "flex min-w-0 items-end gap-2 rounded-2xl border bg-card p-2 shadow-sm transition-all",
10683
13080
  busy && "boff-explore-busy",
10684
- overLimit ? "border-destructive/60" : "border-border focus-within:border-primary/40 focus-within:ring-1 focus-within:ring-ring"
13081
+ overLimit ? "border-destructive/60" : "border-border focus-within:border-primary/40 focus-within:ring-1 focus-within:ring-ring",
13082
+ // The halo is an invitation, and an invitation is only useful before it has
13083
+ // been accepted: while the conversation is empty, the composer is usable, and
13084
+ // nothing has been typed. Once any of those stops being true the class goes
13085
+ // and the box is an ordinary card again. `-quiet` keeps the ring but stops the
13086
+ // movement the moment there are characters in the field, so it does not pulse
13087
+ // at someone who is mid-sentence.
13088
+ showWelcome && !composerDisabled && !overLimit && "boff-explore-invite",
13089
+ showWelcome && draft.length > 0 && "boff-explore-invite-quiet"
10685
13090
  ),
10686
13091
  children: [
10687
13092
  /* @__PURE__ */ jsx(
@@ -15528,6 +17933,6 @@ function StoreProductDetailPage({
15528
17933
  ] });
15529
17934
  }
15530
17935
 
15531
- export { BlogListPage, BlogPostPage, Button, CONCEPTS_PATH, CONCEPT_ILLUSTRATION_NOTICE, CONCEPT_PATH_PREFIX, CareersApplyForm, CareersSubmissionForm, CaseStudiesListPage, CaseStudyPage, ChangelogPage, ConceptDetailPage, ConceptsPage, ContactPage, ContentRenderer, ContractsPage, DEFAULT_CONTACT_CATEGORIES, DEFAULT_EXPLORE_EXAMPLE_PROMPTS, ECOSYSTEM_PRODUCTS, EXPLORE_CATALOG_QUERY, EXPLORE_CATALOG_QUERY_WITHOUT_HIGHLIGHTS, EXPLORE_LOCALES, EXPLORE_MESSAGE_QUERY, EXPLORE_RECAPTCHA_ACTION, ElectronDownloadLink, ExploreCta, ExplorePage, FALLBACK_EXPLORE_LIMITS, Input, Label, LaunchCountdown, Markdown, NewsletterForm, NewsletterPage, PageHead, PartnersPage, PressKitPage, PricingPage, PricingSection, ProblemsSolvedSection, ProductCard, ProductProvider, ResourceLinks, RybbitAnalytics, SEND_EXPLORE_MESSAGE_MUTATION, Select, SocialLinks, StarRating, StoreBrowsePage, StoreHomePage, StoreProductDetailPage, Textarea, TypeBadge, UnsubscribePage, WaitlistForm, WaitlistPage, WebSDKClient, WebSDKProvider, WebsiteSwitcher, buttonVariants, classifyExploreError, cn, conceptPath, detectElectronPlatform, fetchPublicJobPosting, fetchPublicJobPostings, fetchPublicJobPostingsForSubmission, formatDownloads, formatPrice2 as formatPrice, getConceptBySlug, getRecaptchaV3Token, isValidUrl, loadRecaptchaV3, useContentPage, useContentPages, useExploreChat, useProduct, useProductConfig, usePublicJobPosting, usePublicJobPostings, usePublicJobPostingsForSubmission, useWebSDK, useWebSDKConfig };
17936
+ export { ANSWERS_PATH, ANSWER_HEADING_SHIFT, ANSWER_PATH_PREFIX, AnswerDetailPage, AnswersPage, BlogListPage, BlogPostPage, Button, CONCEPTS_PATH, CONCEPT_ILLUSTRATION_NOTICE, CONCEPT_PATH_PREFIX, CareersApplyForm, CareersSubmissionForm, CaseStudiesListPage, CaseStudyPage, ChangelogPage, ConceptDetailPage, ConceptsPage, ContactPage, ContentRenderer, ContractsPage, DEFAULT_CONTACT_CATEGORIES, DEFAULT_EXPLORE_EXAMPLE_PROMPTS, ECOSYSTEM_PRODUCTS, ESCALATE_EXPLORE_CONVERSATION_MUTATION, EXPLORE_CATALOG_QUERY, EXPLORE_CATALOG_QUERY_WITHOUT_HIGHLIGHTS, EXPLORE_ESCALATION_NOTE_SOFT_MAX, EXPLORE_LOCALES, EXPLORE_MESSAGE_QUERY, EXPLORE_RECAPTCHA_ACTION, ElectronDownloadLink, ExploreAnswerBody, ExploreAnswerStyles, ExploreCta, ExplorePage, FALLBACK_EXPLORE_LIMITS, Input, Label, LaunchCountdown, Markdown, NewsletterForm, NewsletterPage, PUBLISHED_ANSWER_FIELDS, PageHead, PartnersPage, PressKitPage, PricingPage, PricingSection, ProblemsSolvedSection, ProductCard, ProductProvider, ResourceLinks, RybbitAnalytics, SEND_EXPLORE_MESSAGE_MUTATION, Select, SocialLinks, StarRating, StoreBrowsePage, StoreHomePage, StoreProductDetailPage, Textarea, TypeBadge, UnsubscribePage, WaitlistForm, WaitlistPage, WebSDKClient, WebSDKProvider, WebsiteSwitcher, answerPath, answerPlainText, answerSourceHost, answerSpeechText, answerStrings, buttonVariants, classifyExploreError, cn, conceptPath, detectElectronPlatform, fetchPublicJobPosting, fetchPublicJobPostings, fetchPublicJobPostingsForSubmission, formatAnswerDate, formatDownloads, formatPrice2 as formatPrice, getAnswerBySlug, getConceptBySlug, getRecaptchaV3Token, inlineImageOrigins, isInlineImageAllowed, isPublishedSourceUrl, isValidUrl, loadRecaptchaV3, looksLikeDeliverableEmail, speechLocaleOf, stopSpeaking, useContentPage, useContentPages, useExploreChat, useProduct, useProductConfig, useProgressiveReveal, usePublicJobPosting, usePublicJobPostings, usePublicJobPostingsForSubmission, useSpeechOutput, useWebSDK, useWebSDKConfig };
15532
17937
  //# sourceMappingURL=index.mjs.map
15533
17938
  //# sourceMappingURL=index.mjs.map