@burdenoff/website-sdk 2026.1102.3 → 2026.1104.2
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/README.md +46 -6
- package/dist/avatar-live/index.d.mts +2 -2
- package/dist/avatar-live/index.d.ts +2 -2
- package/dist/avatar-live/index.js +29 -4
- package/dist/avatar-live/index.js.map +1 -1
- package/dist/avatar-live/index.mjs +29 -4
- package/dist/avatar-live/index.mjs.map +1 -1
- package/dist/avatar-live-view/index.d.mts +19 -4
- package/dist/avatar-live-view/index.d.ts +19 -4
- package/dist/avatar-live-view/index.js +135 -28
- package/dist/avatar-live-view/index.js.map +1 -1
- package/dist/avatar-live-view/index.mjs +130 -23
- package/dist/avatar-live-view/index.mjs.map +1 -1
- package/dist/{chunk-DZLUZKOX.js → chunk-22OT6E26.js} +44 -12
- package/dist/chunk-22OT6E26.js.map +1 -0
- package/dist/{chunk-ZWEEBHXJ.mjs → chunk-5JQGE3XI.mjs} +44 -12
- package/dist/chunk-5JQGE3XI.mjs.map +1 -0
- package/dist/{chunk-K3QZGJEH.mjs → chunk-7MSB3EUI.mjs} +4 -3
- package/dist/chunk-7MSB3EUI.mjs.map +1 -0
- package/dist/{chunk-7O2I32ZN.js → chunk-WSEQ2I6I.js} +4 -3
- package/dist/chunk-WSEQ2I6I.js.map +1 -0
- package/dist/components/explore.d.mts +1 -1
- package/dist/components/explore.d.ts +1 -1
- package/dist/components/explore.js +13 -13
- package/dist/components/explore.mjs +1 -1
- package/dist/{explore-DtSPdlEy.d.ts → explore-BV4dRwoC.d.ts} +7 -0
- package/dist/{explore-DaSNdm4O.d.mts → explore-BgEeGPvY.d.mts} +7 -0
- package/dist/{explore-avatar-live-config-N4WhJzgS.d.mts → explore-avatar-live-config-B6_p0q1c.d.mts} +14 -1
- package/dist/{explore-avatar-live-config-CAfN5eAX.d.ts → explore-avatar-live-config-DRpS-mqQ.d.ts} +14 -1
- package/dist/index.d.mts +13 -7
- package/dist/index.d.ts +13 -7
- package/dist/index.js +59 -48
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +16 -5
- package/dist/index.mjs.map +1 -1
- package/dist/{types-CndbmBK-.d.mts → types-CXqaLlNB.d.mts} +14 -1
- package/dist/{types-CndbmBK-.d.ts → types-CXqaLlNB.d.ts} +14 -1
- package/package.json +1 -1
- package/dist/chunk-7O2I32ZN.js.map +0 -1
- package/dist/chunk-DZLUZKOX.js.map +0 -1
- package/dist/chunk-K3QZGJEH.mjs.map +0 -1
- package/dist/chunk-ZWEEBHXJ.mjs.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/explore-i18n.ts","../src/components/explore-video-dialog.tsx","../src/components/explore-answer.tsx","../src/components/explore-conversation.tsx","../src/components/explore-scope.ts","../src/hooks/use-swipe.ts","../src/utils/explore-attachments.ts","../src/components/explore.tsx"],"names":["useRef","useId","useState","useEffect","useCallback","createPortal","jsxs","jsx","Minimize","Maximize","X","VideoOff","createContext","useContext","MarkdownLink","Fragment","cn","Children","isValidElement","cloneElement","fill","Film","Play","useMemo","Markdown","useExploreChat","isSameProductSlug","productSlugVariants","BookOpenText","Layers","Link2","ExternalLink","Button","ThumbsUp","ThumbsDown","EXPLORE_FEEDBACK_COMMENT_SOFT_MAX","looksLikeDeliverableEmail","Textarea","EXPLORE_ESCALATION_NOTE_SOFT_MAX","useSpeechOutput","Volume2","Check","Copy","Paperclip","useProgressiveReveal","Sparkles","TriangleAlert","ArrowUp","ChevronLeft","ChevronRight","useSpeechInput","stopSpeaking","delta","serializeBakedCatalog","PageHead","ProseStyles","BAKED_CATALOG_ELEMENT_ID","bakedCatalogLocale","RotateCcw","HistoryIcon","Trash2","Mic","Square"],"mappings":"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","file":"chunk-22OT6E26.js","sourcesContent":["/**\n * Localisation for the `/explore` chat surface.\n *\n * ## Why this is self-contained\n *\n * The app shells localise through `useI18n()` from `@burdenoff/fe-libs`, which is mounted by\n * `AppShellProvider` and fetches translations at runtime from `global-i18n-svc`. None of that\n * exists on a marketing website: no provider, no dictionary, no locale routing, and no\n * translation files in any of the 39 site repos. Pulling that machinery in would mean adding\n * a runtime translation fetch to a static prerendered page — a network round-trip in front of\n * the first paint, on pages whose whole point is that they are prerendered.\n *\n * So the strings are bundled. There are few enough of them that the cost is bytes rather than\n * a request, and a prerendered page stays fully rendered.\n *\n * ## Locales\n *\n * The six the products actually ship, taken from `{product}-app/src/components/chrome/\n * languages.ts` (FALLBACK_LANGUAGES). Deliberately NOT the wider `Locale` union in fe-libs,\n * which also lists fr/de/ja that no product ships, and deliberately not the backend's BCP-47\n * set, which has fr/de/ja but lacks ta and ar.\n */\n\nexport const EXPLORE_LOCALES = [\"en\", \"zh\", \"hi\", \"es\", \"ar\", \"ta\"] as const;\nexport type ExploreLocale = (typeof EXPLORE_LOCALES)[number];\n\n/** Arabic is the one right-to-left locale in the product set. */\nconst RTL_LOCALES = new Set<ExploreLocale>([\"ar\"]);\n\nexport function isRtlLocale(locale: ExploreLocale): boolean {\n return RTL_LOCALES.has(locale);\n}\n\nexport interface ExploreStrings {\n badge: string;\n welcomeTitle: string;\n welcomeBody: string;\n /**\n * BOFF-9796: the welcome body of ONE product's own assistant (`scope=\"product\"`) when the host passes none. Takes\n * `{product}`. Problem-first like `welcomeBody`, and unlike the catalog's copy for a product site it offers nothing\n * beyond that product: no \"compare it with anything else we build\".\n */\n welcomeBodyProduct: string;\n /**\n * BOFF-9796: the product scope's welcome body when no product name is known (a slug no catalog lists, and no\n * `productName`). Like `welcomeBodyProduct` without the name, so it never falls back to the portfolio's invitation\n * to \"ask about a specific product or compare a few\".\n */\n welcomeBodyScoped: string;\n tryAsking: string;\n focusProduct: string;\n allProducts: string;\n showAll: string;\n showLess: string;\n sources: string;\n nextYouCouldAsk: string;\n placeholder: string;\n placeholderProduct: string;\n /**\n * BOFF-9796: the composer's placeholder on ONE product's own assistant (`scope=\"product\"`). Takes `{product}`.\n * Short on purpose, and the one thing about the composer that the product scope changes: the field is the published\n * one, one line tall on a phone, where a placeholder that wraps loses its second line. `placeholderProduct`\n * (\"Describe a problem, or ask about Healthy Bowl…\") wraps there at 390px and under; the English \"Ask about Healthy\n * Bowl…\" fits one line at 320px and wider. Spanish and Tamil, the longest here, may still wrap at 320px and\n * narrower: a follow-up (HealthyBowl, the site this was made for, is English-only). The welcome above the composer\n * already asks for the problem.\n */\n placeholderScoped: string;\n send: string;\n stop: string;\n newChat: string;\n history: string;\n clearHistory: string;\n share: string;\n copied: string;\n copying: string;\n shareUnavailable: string;\n disclaimer: string;\n disclaimerShort: string;\n dictate: string;\n stopDictating: string;\n attach: string;\n attachHint: string;\n removeAttachment: string;\n attachmentNameOnly: string;\n attachmentTooLarge: string;\n attachmentTooMany: string;\n noAnswer: string;\n answerDidNotArrive: string;\n /**\n * BOFF-9796: what a turn that ran out of searches (`TOOL_BUDGET`) says on ONE product's own assistant\n * (`scope=\"product\"`). The default message asks for \"two or three specific products\", an invitation to other\n * products that a product's own assistant must not make; here the narrowing offered is to one part of the question.\n */\n toolBudgetScoped: string;\n askHuman: string;\n feedbackPrompt: string;\n feedbackHelpful: string;\n feedbackNotHelpful: string;\n feedbackReasonTitle: string;\n feedbackReasonInaccurate: string;\n feedbackReasonIncomplete: string;\n feedbackReasonOffTopic: string;\n feedbackReasonHardToFollow: string;\n feedbackReasonOther: string;\n feedbackCommentPlaceholder: string;\n feedbackSend: string;\n feedbackDismiss: string;\n feedbackThanks: string;\n feedbackNotSent: string;\n // --- Handing the conversation to a person -------------------------------\n /**\n * The trigger, in its two homes: `escalateOpen` is the quiet one under an answer we DID\n * give, and the amber \"we could not find this\" banner reuses `askHuman` so that sentence\n * keeps reading as one sentence.\n */\n escalateOpen: string;\n escalateTitle: string;\n escalateBody: string;\n escalateEmailLabel: string;\n escalateEmailPlaceholder: string;\n escalateNoteLabel: string;\n escalateSubmit: string;\n escalateSending: string;\n escalateCancel: string;\n /**\n * Shown for BOTH the client's own pre-flight and the server's `INVALID_EMAIL`. The two\n * disagree about what is deliverable and the server is right, but the visitor's next\n * action is identical either way: check the address.\n */\n escalateInvalidEmail: string;\n /**\n * The success line. Takes `{email}` — and it is filled with the address the SERVER\n * returned, not the one in the box, because on a repeat handover the reply goes to\n * whichever address the first one used.\n *\n * Used for `created: false` as well: a visitor asking for help is not told \"you already\n * did that\".\n */\n escalateSent: string;\n escalateRateLimited: string;\n escalateCaptcha: string;\n escalateFailed: string;\n prevSuggestion: string;\n nextSuggestion: string;\n /**\n * The label every concept picture carries, wherever one is shown — inside an answer and on\n * the welcome strip alike.\n *\n * These images are published mockups, so the page has to say so; it says it in ONE wording,\n * because two phrasings for the same caveat read as two different caveats.\n */\n conceptIllustration: string;\n /** Rail arrows on the concept strip — pointer devices only. */\n conceptScrollPrev: string;\n conceptScrollNext: string;\n opensInNewTab: string;\n /** Heading over the concept strip on the welcome screen. */\n conceptStripTitle: string;\n /** Accessible name of the strip itself. */\n conceptStripLabel: string;\n /** Accessible name of one card. Takes `{title}` and `{product}`. */\n conceptAsk: string;\n /**\n * The question a card actually SENDS. Takes `{title}` and `{product}`.\n *\n * Localised because it becomes the visitor's own message in the transcript — an English\n * sentence appearing above an Arabic answer would read as the page talking to itself.\n */\n conceptAskQuestion: string;\n /** Label of the per-answer copy control, and its failure state. */\n copyAnswer: string;\n copyFailed: string;\n /**\n * Label of the per-answer read-aloud control, in its two states.\n *\n * A toggle, exactly like the composer's dictation button: one control whose label says\n * what pressing it does NOW, never a second button that appears while it is speaking.\n */\n readAloud: string;\n stopReading: string;\n /**\n * Accessible name of the scrollable box a table in an answer sits in.\n *\n * A scrollable region needs a name and a tab stop, or a keyboard visitor cannot reach the\n * columns that are off the edge. The `<table>` inside it keeps its own semantics.\n */\n answerTable: string;\n /**\n * The product-video card in an answer (CONTRACT.md §7) and the player it opens.\n *\n * `productVideo` is the card's badge — the video counterpart of `conceptIllustration` —\n * and names a video the answer gave no title. `productVideoTitle` names the video in this\n * language and takes `{product}`: the harness always writes the line's text as the English\n * \"<Name> product video\", so the card keeps only the name from it. `playVideo` is the\n * card's accessible name and takes `{title}`, which is that name. The last four belong to\n * the player: its Close button, the two states of its full-screen toggle, and the line\n * shown in place of a video that cannot be played.\n */\n productVideo: string;\n productVideoTitle: string;\n playVideo: string;\n closeVideo: string;\n enterFullScreen: string;\n exitFullScreen: string;\n /**\n * BOFF-9697: the site-wide assistant panel (`ExplorePanel`). The tab, view and avatar words are the ones the product\n * apps' assistant already ships in all six locales (Chat, Avatar, Live avatar, Assistant views).\n */\n panelTitle: string;\n /**\n * BOFF-9796: the panel's title on one product's own assistant (`scope=\"product\"`), \"{product} assistant\" in each\n * language's own word order. Takes `{product}`. `panelTitle` stays the title wherever no product name is known.\n */\n panelTitleProduct: string;\n panelViews: string;\n tabChat: string;\n tabAvatar: string;\n closePanel: string;\n liveAvatar: string;\n avatarComingSoon: string;\n continueInChat: string;\n videoUnavailable: string;\n /** Accessible name of the provenance row under an answer. */\n groundedIn: string;\n /** How many sources the answer cites. `sourceCountMany` takes `{count}`. */\n sourceCountOne: string;\n sourceCountMany: string;\n /** What KIND of page a source is, inferred from its URL. */\n sourceKindConcept: string;\n sourceKindDocs: string;\n sourceKindPricing: string;\n sourceKindUseCase: string;\n sourceKindPage: string;\n /**\n * The page's <title> and <meta description>.\n *\n * These are the surface a search result and a browser tab are built from, and they are\n * the LAST place the old product-first framing survived: all 38 sites hard-coded\n * \"Explore Burdenoff products with AI\" inline, so the tab announced our catalogue on a\n * page that asks the visitor about their problem — and named the wrong brand on 37 of\n * them. `seoTitle` carries no brand: PageHead appends \"| {productName}\" itself.\n */\n seoTitle: string;\n seoDescription: string;\n /** Used when the page belongs to a specific product's site. Takes `{product}`. */\n seoDescriptionProduct: string;\n /**\n * BOFF-9796: the meta description of ONE product's own `/explore` (`scope=\"product\"`). Takes `{product}`. Unlike\n * `seoDescriptionProduct`, it promises nothing beyond that product: no \"and every other product we build\".\n */\n seoDescriptionScoped: string;\n capabilities: [string, string, string];\n prompts: string[];\n}\n\n/**\n * BOFF-9796. The one built-in example prompt that asks the portfolio which of its products to use (\"Which of your\n * products fits a problem like mine?\"), in each locale: the last of that locale's `prompts`, a question on purpose so\n * that \"which product fits me\" stays discoverable on the portfolio's assistant.\n *\n * One product's own assistant (`scope=\"product\"`) leaves it out: there is no other product to choose there. Written\n * once, here, and referenced from each locale's `prompts`, so what the product scope leaves out is always exactly the\n * sentence the portfolio shows.\n */\nconst PORTFOLIO_PROMPT: Record<ExploreLocale, string> = {\n en: \"Which of your products fits a problem like mine?\",\n zh: \"哪个产品适合我这样的问题?\",\n hi: \"मेरी जैसी समस्या के लिए कौन सा उत्पाद सही है?\",\n es: \"¿Qué producto encaja con un problema como el mío?\",\n ar: \"أي منتج يناسب مشكلة مثل مشكلتي؟\",\n ta: \"என் பிரச்சினைக்கு எந்தத் தயாரிப்பு பொருந்தும்?\",\n};\n\nconst PORTFOLIO_PROMPTS: ReadonlySet<string> = new Set(\n Object.values(PORTFOLIO_PROMPT),\n);\n\n/**\n * BOFF-9796. Whether `prompt` is the SDK's built-in portfolio prompt ({@link PORTFOLIO_PROMPT}), in any of the six\n * locales. Any, not only the view's own: the conversation's fallback prompts are set up with a locale of their own (a\n * site-wide `ExploreChatProvider` and the panel showing it are each given one), so they need not be the view's.\n */\nexport function isPortfolioPrompt(prompt: string): boolean {\n return PORTFOLIO_PROMPTS.has(prompt);\n}\n\n/**\n * English is the source of truth. Every other locale is a full object rather than a partial,\n * so a missing key is a type error at build time instead of a raw key leaking onto a live\n * marketing page — the failure mode i18n usually has.\n */\nconst EN: ExploreStrings = {\n badge: \"AI answers, grounded in our documentation\",\n welcomeTitle: \"What problem are you trying to solve?\",\n welcomeBody:\n \"Describe the problem, in your own words. You can also ask about a specific product or compare a few. Every answer comes straight from our documentation.\",\n welcomeBodyProduct:\n \"Describe the problem in your own words, or ask what {product} does. Every answer comes straight from our documentation.\",\n welcomeBodyScoped:\n \"Describe the problem in your own words. Every answer comes straight from our documentation.\",\n tryAsking: \"Try asking\",\n focusProduct: \"Focus on a product\",\n allProducts: \"All products\",\n showAll: \"All\",\n showLess: \"Show less\",\n sources: \"Sources\",\n nextYouCouldAsk: \"Next you could ask\",\n placeholder: \"Describe the problem…\",\n placeholderProduct: \"Describe a problem, or ask about {product}…\",\n placeholderScoped: \"Ask about {product}…\",\n send: \"Send\",\n stop: \"Stop\",\n newChat: \"New chat\",\n history: \"History\",\n clearHistory: \"Clear history\",\n share: \"Share\",\n copied: \"Copied\",\n copying: \"Copying…\",\n shareUnavailable: \"Unavailable\",\n disclaimer: \"Disclaimer\",\n disclaimerShort: \"Grounded in our docs — check anything important.\",\n dictate: \"Dictate your question\",\n stopDictating: \"Stop dictating\",\n attach: \"Attach files\",\n attachHint: \"Up to {{max}} files, {{size}} MB each\",\n removeAttachment: \"Remove {{name}}\",\n attachmentNameOnly: \"name and type only\",\n attachmentTooLarge:\n \"{{name}} is larger than {{size}} MB and was not attached.\",\n attachmentTooMany:\n \"Only {{max}} files can be attached, so {{name}} was skipped.\",\n noAnswer:\n \"I couldn't find this in our documentation, so the answer below is not grounded in a source. Try rephrasing, or\",\n answerDidNotArrive: \"That answer didn't come through. Try asking again.\",\n toolBudgetScoped:\n \"That question covers more than I can look through in one go. Try asking about one part of it.\",\n askHuman: \"ask a human\",\n // An offer, not a demand: this row sits under every answer on 38 marketing sites, so the\n // wording has to be shruggable. \"Was this helpful?\" invites; \"Please rate this answer\"\n // conscripts.\n feedbackPrompt: \"Was this helpful?\",\n feedbackHelpful: \"Helpful\",\n feedbackNotHelpful: \"Not helpful\",\n feedbackReasonTitle: \"What was off?\",\n feedbackReasonInaccurate: \"Inaccurate\",\n feedbackReasonIncomplete: \"Incomplete\",\n feedbackReasonOffTopic: \"Off topic\",\n feedbackReasonHardToFollow: \"Hard to follow\",\n feedbackReasonOther: \"Something else\",\n feedbackCommentPlaceholder: \"Add a detail (optional)\",\n feedbackSend: \"Send\",\n feedbackDismiss: \"Dismiss\",\n feedbackThanks: \"Thanks — that helps.\",\n feedbackNotSent: \"That didn't send.\",\n escalateOpen: \"Talk to a person\",\n escalateTitle: \"Send this conversation to a person\",\n escalateBody:\n \"We'll pass the whole conversation on, so you don't have to type any of it again.\",\n escalateEmailLabel: \"Your email address\",\n escalateEmailPlaceholder: \"you@example.com\",\n escalateNoteLabel: \"Anything else a person should know? (optional)\",\n escalateSubmit: \"Send to a person\",\n escalateSending: \"Sending…\",\n escalateCancel: \"Cancel\",\n escalateInvalidEmail:\n \"That doesn't look like an address we can reply to. Please check it.\",\n escalateSent: \"A person now has this conversation. We'll reply to {email}.\",\n escalateRateLimited:\n \"That's a lot of requests in a short time. Please try again in a few minutes.\",\n escalateCaptcha:\n \"We couldn't verify that you're human. Please try that again.\",\n escalateFailed: \"We couldn't pass that on just now. Please try again.\",\n prevSuggestion: \"Previous suggestion\",\n nextSuggestion: \"Next suggestion\",\n conceptIllustration: \"Concept illustration\",\n conceptScrollPrev: \"Scroll concepts left\",\n conceptScrollNext: \"Scroll concepts right\",\n opensInNewTab: \"opens in a new tab\",\n conceptStripTitle: \"Or start from a concept\",\n conceptStripLabel: \"Concepts you can ask about\",\n conceptAsk: \"Ask about {title} in {product}\",\n conceptAskQuestion: \"How does {title} work in {product}?\",\n copyAnswer: \"Copy answer\",\n copyFailed: \"Couldn't copy\",\n readAloud: \"Read aloud\",\n stopReading: \"Stop reading\",\n answerTable: \"Table\",\n productVideo: \"Product video\",\n productVideoTitle: \"{product} product video\",\n playVideo: \"Play {title}\",\n closeVideo: \"Close video\",\n enterFullScreen: \"Full screen\",\n exitFullScreen: \"Exit full screen\",\n panelTitle: \"AI assistant\",\n panelTitleProduct: \"{product} assistant\",\n panelViews: \"Assistant views\",\n tabChat: \"Chat\",\n tabAvatar: \"Avatar\",\n closePanel: \"Close\",\n liveAvatar: \"Live avatar\",\n avatarComingSoon: \"Live avatar coming soon\",\n continueInChat: \"Continue in Chat\",\n videoUnavailable: \"This video can't be played right now.\",\n groundedIn: \"What this answer is based on\",\n sourceCountOne: \"1 source\",\n sourceCountMany: \"{count} sources\",\n sourceKindConcept: \"Concept\",\n sourceKindDocs: \"Documentation\",\n sourceKindPricing: \"Pricing\",\n sourceKindUseCase: \"Use case\",\n sourceKindPage: \"Product page\",\n seoTitle: \"Describe a problem, get an answer\",\n seoDescription:\n \"Describe the problem in your own words and get an answer drawn from our product documentation, with links to the exact pages it came from.\",\n seoDescriptionProduct:\n \"Describe the problem in your own words and get an answer drawn from {product}'s documentation — and every other product we build — with links to the exact pages it came from.\",\n seoDescriptionScoped:\n \"Answers about {product}, drawn from {product}'s documentation, with links to the exact pages they came from.\",\n capabilities: [\n \"Grounded in our own docs\",\n \"Compare across the ecosystem\",\n \"Straight to the right page\",\n ],\n prompts: [\n \"Every course we run lives in a different spreadsheet.\",\n \"We only hear a machine is down after the line has stopped.\",\n \"Members quietly stop showing up and we never know why.\",\n PORTFOLIO_PROMPT.en,\n ],\n};\n\nconst ZH: ExploreStrings = {\n badge: \"基于我们文档的 AI 回答\",\n welcomeTitle: \"你想解决什么问题?\",\n welcomeBody:\n \"用你自己的话描述问题。你也可以询问某一款产品,或比较几款产品。所有回答都直接来自我们的文档。\",\n welcomeBodyProduct:\n \"用你自己的话描述问题,或者问问 {product} 是做什么的。所有回答都直接来自我们的文档。\",\n welcomeBodyScoped: \"用你自己的话描述问题。所有回答都直接来自我们的文档。\",\n tryAsking: \"试着问\",\n focusProduct: \"聚焦某个产品\",\n allProducts: \"全部产品\",\n showAll: \"全部\",\n showLess: \"收起\",\n sources: \"来源\",\n nextYouCouldAsk: \"你还可以问\",\n placeholder: \"描述你的问题…\",\n placeholderProduct: \"描述问题,或询问 {product}…\",\n placeholderScoped: \"就 {product} 提问…\",\n send: \"发送\",\n stop: \"停止\",\n newChat: \"新对话\",\n history: \"历史\",\n clearHistory: \"清除历史\",\n share: \"分享\",\n copied: \"已复制\",\n copying: \"复制中…\",\n shareUnavailable: \"不可用\",\n disclaimer: \"免责声明\",\n disclaimerShort: \"内容基于我们的文档,重要信息请自行核对。\",\n dictate: \"语音输入\",\n stopDictating: \"停止语音输入\",\n attach: \"添加文件\",\n attachHint: \"最多 {{max}} 个文件,每个不超过 {{size}} MB\",\n removeAttachment: \"移除 {{name}}\",\n attachmentNameOnly: \"仅文件名和类型\",\n attachmentTooLarge: \"{{name}} 超过 {{size}} MB,未能添加。\",\n attachmentTooMany: \"最多只能添加 {{max}} 个文件,已跳过 {{name}}。\",\n noAnswer:\n \"我在文档中没有找到相关内容,下面的回答没有来源支持。请换个说法,或\",\n answerDidNotArrive: \"这条回答没有返回。请再问一次。\",\n toolBudgetScoped:\n \"这个问题涉及的内容太多,我没法一次查完。试着只问其中的一部分。\",\n askHuman: \"联系我们\",\n feedbackPrompt: \"这个回答有帮助吗?\",\n feedbackHelpful: \"有帮助\",\n feedbackNotHelpful: \"没有帮助\",\n feedbackReasonTitle: \"哪里不对?\",\n feedbackReasonInaccurate: \"不准确\",\n feedbackReasonIncomplete: \"不完整\",\n feedbackReasonOffTopic: \"答非所问\",\n feedbackReasonHardToFollow: \"看不太懂\",\n feedbackReasonOther: \"其他原因\",\n feedbackCommentPlaceholder: \"补充说明(可选)\",\n feedbackSend: \"提交\",\n feedbackDismiss: \"关闭\",\n feedbackThanks: \"谢谢,这对我们很有帮助。\",\n feedbackNotSent: \"没有提交成功。\",\n escalateOpen: \"联系真人\",\n escalateTitle: \"把这段对话转给真人\",\n escalateBody: \"我们会把整段对话一起转过去,您不用再重新打一遍。\",\n escalateEmailLabel: \"您的邮箱地址\",\n escalateEmailPlaceholder: \"you@example.com\",\n escalateNoteLabel: \"还有什么需要告诉我们的吗?(选填)\",\n escalateSubmit: \"转给真人\",\n escalateSending: \"正在发送…\",\n escalateCancel: \"取消\",\n escalateInvalidEmail: \"这似乎不是一个我们可以回复的邮箱地址,请检查一下。\",\n escalateSent: \"已有同事接手这段对话,我们会回复到 {email}。\",\n escalateRateLimited: \"短时间内请求过多,请几分钟后再试。\",\n escalateCaptcha: \"我们无法验证您是真人,请再试一次。\",\n escalateFailed: \"暂时无法转交,请再试一次。\",\n prevSuggestion: \"上一个建议\",\n nextSuggestion: \"下一个建议\",\n conceptIllustration: \"概念示意图\",\n conceptScrollPrev: \"向左滚动概念\",\n conceptScrollNext: \"向右滚动概念\",\n opensInNewTab: \"在新标签页中打开\",\n conceptStripTitle: \"或者从一个概念开始\",\n conceptStripLabel: \"你可以询问的概念\",\n conceptAsk: \"询问 {product} 中的 {title}\",\n conceptAskQuestion: \"{product} 的 {title} 是怎么运作的?\",\n copyAnswer: \"复制回答\",\n copyFailed: \"复制失败\",\n readAloud: \"朗读\",\n stopReading: \"停止朗读\",\n answerTable: \"表格\",\n productVideo: \"产品视频\",\n productVideoTitle: \"{product} 产品视频\",\n playVideo: \"播放 {title}\",\n closeVideo: \"关闭视频\",\n enterFullScreen: \"全屏\",\n exitFullScreen: \"退出全屏\",\n panelTitle: \"AI 助手\",\n panelTitleProduct: \"{product} 助手\",\n panelViews: \"助手视图\",\n tabChat: \"聊天\",\n tabAvatar: \"虚拟形象\",\n closePanel: \"关闭\",\n liveAvatar: \"实时虚拟形象\",\n avatarComingSoon: \"实时虚拟形象即将推出\",\n continueInChat: \"在聊天中继续\",\n videoUnavailable: \"暂时无法播放此视频。\",\n groundedIn: \"这个回答的依据\",\n sourceCountOne: \"1 个来源\",\n sourceCountMany: \"{count} 个来源\",\n sourceKindConcept: \"概念\",\n sourceKindDocs: \"文档\",\n sourceKindPricing: \"价格\",\n sourceKindUseCase: \"应用场景\",\n sourceKindPage: \"产品页面\",\n seoTitle: \"描述问题,获得答案\",\n seoDescription:\n \"用你自己的话描述问题,即可获得来自我们产品文档的回答,并附上答案出处的页面链接。\",\n seoDescriptionProduct:\n \"用你自己的话描述问题,即可获得来自 {product} 及我们其他产品文档的回答,并附上答案出处的页面链接。\",\n seoDescriptionScoped:\n \"有关 {product} 的回答,均来自 {product} 的文档,并附上答案出处的页面链接。\",\n capabilities: [\"基于我们自己的文档\", \"跨产品对比\", \"直达正确的页面\"],\n prompts: [\n \"每门课程都记在不同的表格里。\",\n \"机器停了,要等整条线停下来才知道。\",\n \"会员慢慢就不来了,我们也不知道为什么。\",\n PORTFOLIO_PROMPT.zh,\n ],\n};\n\nconst HI: ExploreStrings = {\n badge: \"हमारे दस्तावेज़ों पर आधारित AI उत्तर\",\n welcomeTitle: \"आप कौन सी समस्या हल करना चाहते हैं?\",\n welcomeBody:\n \"अपनी समस्या अपने शब्दों में बताएं। आप किसी एक उत्पाद के बारे में भी पूछ सकते हैं या कुछ की तुलना कर सकते हैं। हर उत्तर सीधे हमारे दस्तावेज़ से आता है।\",\n welcomeBodyProduct:\n \"अपनी समस्या अपने शब्दों में बताएं, या पूछें कि {product} क्या करता है। हर उत्तर सीधे हमारे दस्तावेज़ से आता है।\",\n welcomeBodyScoped:\n \"अपनी समस्या अपने शब्दों में बताएं। हर उत्तर सीधे हमारे दस्तावेज़ से आता है।\",\n tryAsking: \"यह पूछकर देखें\",\n focusProduct: \"किसी उत्पाद पर ध्यान दें\",\n allProducts: \"सभी उत्पाद\",\n showAll: \"सभी\",\n showLess: \"कम दिखाएँ\",\n sources: \"स्रोत\",\n nextYouCouldAsk: \"आगे आप पूछ सकते हैं\",\n placeholder: \"अपनी समस्या बताएं…\",\n placeholderProduct: \"समस्या बताएं, या {product} के बारे में पूछें…\",\n placeholderScoped: \"{product} के बारे में पूछें…\",\n send: \"भेजें\",\n stop: \"रोकें\",\n newChat: \"नई बातचीत\",\n history: \"इतिहास\",\n clearHistory: \"इतिहास मिटाएँ\",\n share: \"साझा करें\",\n copied: \"कॉपी हो गया\",\n copying: \"कॉपी हो रहा है…\",\n shareUnavailable: \"उपलब्ध नहीं\",\n disclaimer: \"अस्वीकरण\",\n disclaimerShort:\n \"यह हमारे दस्तावेज़ों पर आधारित है — महत्वपूर्ण बातें ज़रूर जाँच लें।\",\n dictate: \"बोलकर पूछें\",\n stopDictating: \"बोलना बंद करें\",\n attach: \"फ़ाइलें जोड़ें\",\n attachHint: \"अधिकतम {{max}} फ़ाइलें, प्रत्येक {{size}} MB तक\",\n removeAttachment: \"{{name}} हटाएँ\",\n attachmentNameOnly: \"केवल नाम और प्रकार\",\n attachmentTooLarge: \"{{name}} {{size}} MB से बड़ी है, इसलिए जोड़ी नहीं गई।\",\n attachmentTooMany:\n \"केवल {{max}} फ़ाइलें जोड़ी जा सकती हैं, इसलिए {{name}} छोड़ दी गई।\",\n noAnswer:\n \"यह मुझे हमारे दस्तावेज़ों में नहीं मिला, इसलिए नीचे दिया उत्तर किसी स्रोत पर आधारित नहीं है। दूसरे शब्दों में पूछें, या\",\n answerDidNotArrive: \"वह उत्तर नहीं आ सका। कृपया दोबारा पूछें।\",\n toolBudgetScoped:\n \"इस सवाल में इतना कुछ है कि एक बार में सब नहीं देखा जा सकता। इसके किसी एक हिस्से के बारे में पूछकर देखें।\",\n askHuman: \"हमसे संपर्क करें\",\n feedbackPrompt: \"क्या यह उत्तर मददगार था?\",\n feedbackHelpful: \"मददगार\",\n feedbackNotHelpful: \"मददगार नहीं\",\n feedbackReasonTitle: \"क्या ठीक नहीं था?\",\n feedbackReasonInaccurate: \"ग़लत जानकारी\",\n feedbackReasonIncomplete: \"अधूरा\",\n feedbackReasonOffTopic: \"विषय से हटकर\",\n feedbackReasonHardToFollow: \"समझने में मुश्किल\",\n feedbackReasonOther: \"कुछ और\",\n feedbackCommentPlaceholder: \"कुछ और बताएं (वैकल्पिक)\",\n feedbackSend: \"भेजें\",\n feedbackDismiss: \"बंद करें\",\n feedbackThanks: \"धन्यवाद, इससे मदद मिलती है।\",\n feedbackNotSent: \"यह भेजा नहीं जा सका।\",\n escalateOpen: \"किसी व्यक्ति से बात करें\",\n escalateTitle: \"यह बातचीत किसी व्यक्ति को भेजें\",\n escalateBody:\n \"हम पूरी बातचीत आगे भेज देंगे, ताकि आपको दोबारा कुछ लिखना न पड़े।\",\n escalateEmailLabel: \"आपका ईमेल पता\",\n escalateEmailPlaceholder: \"you@example.com\",\n escalateNoteLabel: \"क्या कुछ और बताना चाहेंगे? (वैकल्पिक)\",\n escalateSubmit: \"किसी व्यक्ति को भेजें\",\n escalateSending: \"भेजा जा रहा है…\",\n escalateCancel: \"रद्द करें\",\n escalateInvalidEmail:\n \"यह ऐसा ईमेल पता नहीं लगता जिस पर हम जवाब भेज सकें। कृपया जाँच लें।\",\n escalateSent: \"अब यह बातचीत एक व्यक्ति के पास है। हम {email} पर जवाब देंगे।\",\n escalateRateLimited:\n \"थोड़े समय में बहुत सारे अनुरोध हो गए। कृपया कुछ मिनट बाद कोशिश करें।\",\n escalateCaptcha:\n \"हम यह सत्यापित नहीं कर सके कि आप एक व्यक्ति हैं। कृपया फिर कोशिश करें।\",\n escalateFailed: \"अभी इसे आगे नहीं भेजा जा सका। कृपया फिर कोशिश करें।\",\n prevSuggestion: \"पिछला सुझाव\",\n nextSuggestion: \"अगला सुझाव\",\n conceptIllustration: \"अवधारणा चित्रण\",\n conceptScrollPrev: \"कॉन्सेप्ट बाएँ स्क्रॉल करें\",\n conceptScrollNext: \"कॉन्सेप्ट दाएँ स्क्रॉल करें\",\n opensInNewTab: \"नए टैब में खुलता है\",\n conceptStripTitle: \"या किसी अवधारणा से शुरू करें\",\n conceptStripLabel: \"जिन अवधारणाओं के बारे में आप पूछ सकते हैं\",\n conceptAsk: \"{product} में {title} के बारे में पूछें\",\n conceptAskQuestion: \"{product} में {title} कैसे काम करता है?\",\n copyAnswer: \"उत्तर कॉपी करें\",\n copyFailed: \"कॉपी नहीं हो सका\",\n readAloud: \"ज़ोर से पढ़ें\",\n stopReading: \"पढ़ना बंद करें\",\n answerTable: \"तालिका\",\n productVideo: \"उत्पाद वीडियो\",\n productVideoTitle: \"{product} उत्पाद वीडियो\",\n playVideo: \"{title} चलाएँ\",\n closeVideo: \"वीडियो बंद करें\",\n enterFullScreen: \"पूर्ण स्क्रीन\",\n exitFullScreen: \"पूर्ण स्क्रीन से बाहर निकलें\",\n panelTitle: \"AI सहायक\",\n panelTitleProduct: \"{product} सहायक\",\n panelViews: \"सहायक दृश्य\",\n tabChat: \"चैट\",\n tabAvatar: \"अवतार\",\n closePanel: \"बंद करें\",\n liveAvatar: \"लाइव अवतार\",\n avatarComingSoon: \"लाइव अवतार जल्द आ रहा है\",\n continueInChat: \"चैट में जारी रखें\",\n videoUnavailable: \"यह वीडियो अभी नहीं चल सकता।\",\n groundedIn: \"यह उत्तर किस पर आधारित है\",\n sourceCountOne: \"1 स्रोत\",\n sourceCountMany: \"{count} स्रोत\",\n sourceKindConcept: \"अवधारणा\",\n sourceKindDocs: \"दस्तावेज़\",\n sourceKindPricing: \"मूल्य\",\n sourceKindUseCase: \"उपयोग का उदाहरण\",\n sourceKindPage: \"उत्पाद पेज\",\n seoTitle: \"समस्या बताएं, जवाब पाएं\",\n seoDescription:\n \"अपनी समस्या अपने शब्दों में बताएं और हमारे उत्पाद दस्तावेज़ों से लिया गया जवाब पाएं, साथ में उन्हीं पन्नों के लिंक जहाँ से वह आया है।\",\n seoDescriptionProduct:\n \"अपनी समस्या अपने शब्दों में बताएं और {product} तथा हमारे बाकी उत्पादों के दस्तावेज़ों से लिया गया जवाब पाएं, साथ में उन्हीं पन्नों के लिंक जहाँ से वह आया है।\",\n seoDescriptionScoped:\n \"{product} के बारे में जवाब पाएं, जो {product} के दस्तावेज़ों से लिए गए हैं, साथ में उन्हीं पन्नों के लिंक जहाँ से वे आए हैं।\",\n capabilities: [\n \"हमारे अपने दस्तावेज़ों पर आधारित\",\n \"सभी उत्पादों की तुलना करें\",\n \"सीधे सही पेज पर\",\n ],\n prompts: [\n \"हर कोर्स का हिसाब अलग शीट में रखा जाता है।\",\n \"मशीन बंद होने का पता तभी चलता है जब लाइन रुक जाए।\",\n \"सदस्य धीरे-धीरे आना बंद कर देते हैं, वजह पता नहीं चलती।\",\n PORTFOLIO_PROMPT.hi,\n ],\n};\n\nconst ES: ExploreStrings = {\n badge: \"Respuestas de IA basadas en nuestra documentación\",\n welcomeTitle: \"¿Qué problema quieres resolver?\",\n welcomeBody:\n \"Describe el problema con tus propias palabras. También puedes preguntar por un producto concreto o comparar varios. Cada respuesta procede directamente de nuestra documentación.\",\n welcomeBodyProduct:\n \"Describe el problema con tus propias palabras o pregunta qué hace {product}. Cada respuesta procede directamente de nuestra documentación.\",\n welcomeBodyScoped:\n \"Describe el problema con tus propias palabras. Cada respuesta procede directamente de nuestra documentación.\",\n tryAsking: \"Prueba a preguntar\",\n focusProduct: \"Centrarse en un producto\",\n allProducts: \"Todos los productos\",\n showAll: \"Todos\",\n showLess: \"Ver menos\",\n sources: \"Fuentes\",\n nextYouCouldAsk: \"También puedes preguntar\",\n placeholder: \"Describe el problema…\",\n placeholderProduct: \"Describe un problema o pregunta por {product}…\",\n placeholderScoped: \"Pregunta sobre {product}…\",\n send: \"Enviar\",\n stop: \"Detener\",\n newChat: \"Nueva conversación\",\n history: \"Historial\",\n clearHistory: \"Borrar historial\",\n share: \"Compartir\",\n copied: \"Copiado\",\n copying: \"Copiando…\",\n shareUnavailable: \"No disponible\",\n disclaimer: \"Aviso\",\n disclaimerShort:\n \"Basado en nuestra documentación: comprueba cualquier dato importante.\",\n dictate: \"Dictar tu pregunta\",\n stopDictating: \"Dejar de dictar\",\n attach: \"Adjuntar archivos\",\n attachHint: \"Hasta {{max}} archivos, {{size}} MB cada uno\",\n removeAttachment: \"Quitar {{name}}\",\n attachmentNameOnly: \"solo nombre y tipo\",\n attachmentTooLarge: \"{{name}} supera los {{size}} MB y no se adjuntó.\",\n attachmentTooMany:\n \"Solo se pueden adjuntar {{max}} archivos, así que se omitió {{name}}.\",\n noAnswer:\n \"No he encontrado esto en nuestra documentación, así que la respuesta de abajo no se apoya en ninguna fuente. Prueba a reformularla, o\",\n answerDidNotArrive: \"Esa respuesta no llegó. Inténtalo de nuevo.\",\n toolBudgetScoped:\n \"Esa pregunta abarca más de lo que puedo revisar de una vez. Prueba a preguntar por una parte de ella.\",\n askHuman: \"habla con una persona\",\n feedbackPrompt: \"¿Te ha servido?\",\n feedbackHelpful: \"Me sirve\",\n feedbackNotHelpful: \"No me sirve\",\n feedbackReasonTitle: \"¿Qué ha fallado?\",\n feedbackReasonInaccurate: \"Es inexacta\",\n feedbackReasonIncomplete: \"Está incompleta\",\n feedbackReasonOffTopic: \"No viene al caso\",\n feedbackReasonHardToFollow: \"Cuesta seguirla\",\n feedbackReasonOther: \"Otra cosa\",\n feedbackCommentPlaceholder: \"Añade un detalle (opcional)\",\n feedbackSend: \"Enviar\",\n feedbackDismiss: \"Cerrar\",\n feedbackThanks: \"Gracias, nos sirve.\",\n feedbackNotSent: \"No se ha podido enviar.\",\n escalateOpen: \"Hablar con una persona\",\n escalateTitle: \"Envía esta conversación a una persona\",\n escalateBody:\n \"Le pasaremos la conversación entera, así no tienes que volver a escribirla.\",\n escalateEmailLabel: \"Tu dirección de correo\",\n escalateEmailPlaceholder: \"tu@ejemplo.com\",\n escalateNoteLabel: \"¿Algo más que deberíamos saber? (opcional)\",\n escalateSubmit: \"Enviar a una persona\",\n escalateSending: \"Enviando…\",\n escalateCancel: \"Cancelar\",\n escalateInvalidEmail:\n \"No parece una dirección a la que podamos responder. Revísala, por favor.\",\n escalateSent:\n \"Una persona ya tiene esta conversación. Te responderemos a {email}.\",\n escalateRateLimited:\n \"Han sido muchas peticiones en poco tiempo. Inténtalo de nuevo en unos minutos.\",\n escalateCaptcha:\n \"No hemos podido verificar que eres una persona. Inténtalo de nuevo.\",\n escalateFailed: \"No hemos podido pasarlo ahora mismo. Inténtalo de nuevo.\",\n prevSuggestion: \"Sugerencia anterior\",\n nextSuggestion: \"Sugerencia siguiente\",\n conceptIllustration: \"Ilustración del concepto\",\n conceptScrollPrev: \"Desplazar conceptos a la izquierda\",\n conceptScrollNext: \"Desplazar conceptos a la derecha\",\n opensInNewTab: \"se abre en una pestaña nueva\",\n conceptStripTitle: \"O empieza por un concepto\",\n conceptStripLabel: \"Conceptos sobre los que puedes preguntar\",\n conceptAsk: \"Preguntar por {title} en {product}\",\n conceptAskQuestion: \"¿Cómo funciona {title} en {product}?\",\n copyAnswer: \"Copiar respuesta\",\n copyFailed: \"No se pudo copiar\",\n readAloud: \"Leer en voz alta\",\n stopReading: \"Dejar de leer\",\n answerTable: \"Tabla\",\n productVideo: \"Vídeo del producto\",\n productVideoTitle: \"Vídeo de {product}\",\n playVideo: \"Reproducir {title}\",\n closeVideo: \"Cerrar vídeo\",\n enterFullScreen: \"Pantalla completa\",\n exitFullScreen: \"Salir de pantalla completa\",\n panelTitle: \"Asistente de IA\",\n panelTitleProduct: \"Asistente de {product}\",\n panelViews: \"Vistas del asistente\",\n tabChat: \"Chat\",\n tabAvatar: \"Avatar\",\n closePanel: \"Cerrar\",\n liveAvatar: \"Avatar en vivo\",\n avatarComingSoon: \"Avatar en vivo: próximamente\",\n continueInChat: \"Continuar en el chat\",\n videoUnavailable: \"Ahora mismo no se puede reproducir este vídeo.\",\n groundedIn: \"En qué se basa esta respuesta\",\n sourceCountOne: \"1 fuente\",\n sourceCountMany: \"{count} fuentes\",\n sourceKindConcept: \"Concepto\",\n sourceKindDocs: \"Documentación\",\n sourceKindPricing: \"Precios\",\n sourceKindUseCase: \"Caso de uso\",\n sourceKindPage: \"Página de producto\",\n seoTitle: \"Describe un problema y obtén una respuesta\",\n seoDescription:\n \"Describe el problema con tus palabras y recibe una respuesta extraída de la documentación de nuestros productos, con enlaces a las páginas exactas de las que procede.\",\n seoDescriptionProduct:\n \"Describe el problema con tus palabras y recibe una respuesta extraída de la documentación de {product} y del resto de nuestros productos, con enlaces a las páginas exactas de las que procede.\",\n seoDescriptionScoped:\n \"Respuestas sobre {product}, extraídas de la documentación de {product}, con enlaces a las páginas exactas de las que proceden.\",\n capabilities: [\n \"Basado en nuestra documentación\",\n \"Compara todo el ecosistema\",\n \"Directo a la página correcta\",\n ],\n prompts: [\n \"Cada curso que damos está en una hoja de cálculo distinta.\",\n \"Nos enteramos de que una máquina falla cuando para la línea.\",\n \"Los socios dejan de venir poco a poco y nunca sabemos por qué.\",\n PORTFOLIO_PROMPT.es,\n ],\n};\n\nconst AR: ExploreStrings = {\n badge: \"إجابات ذكاء اصطناعي مبنية على وثائقنا\",\n welcomeTitle: \"ما المشكلة التي تحاول حلها؟\",\n welcomeBody:\n \"صف المشكلة بكلماتك أنت. يمكنك أيضًا السؤال عن منتج بعينه أو المقارنة بين عدة منتجات. تأتي كل إجابة مباشرة من وثائقنا.\",\n welcomeBodyProduct:\n \"صف المشكلة بكلماتك أنت، أو اسأل عمّا يفعله {product}. تأتي كل إجابة مباشرة من وثائقنا.\",\n welcomeBodyScoped: \"صف المشكلة بكلماتك أنت. تأتي كل إجابة مباشرة من وثائقنا.\",\n tryAsking: \"جرّب أن تسأل\",\n focusProduct: \"التركيز على منتج\",\n allProducts: \"كل المنتجات\",\n showAll: \"الكل\",\n showLess: \"عرض أقل\",\n sources: \"المصادر\",\n nextYouCouldAsk: \"يمكنك أن تسأل بعد ذلك\",\n placeholder: \"صف المشكلة…\",\n placeholderProduct: \"صف مشكلتك أو اسأل عن {product}…\",\n placeholderScoped: \"اسأل عن {product}…\",\n send: \"إرسال\",\n stop: \"إيقاف\",\n newChat: \"محادثة جديدة\",\n history: \"السجل\",\n clearHistory: \"مسح السجل\",\n share: \"مشاركة\",\n copied: \"تم النسخ\",\n copying: \"جارٍ النسخ…\",\n shareUnavailable: \"غير متاح\",\n disclaimer: \"إخلاء مسؤولية\",\n disclaimerShort: \"مبني على وثائقنا — تحقّق من أي معلومة مهمة.\",\n dictate: \"أملِ سؤالك\",\n stopDictating: \"إيقاف الإملاء\",\n attach: \"إرفاق ملفات\",\n attachHint: \"حتى {{max}} ملفات، بحد أقصى {{size}} ميغابايت لكل ملف\",\n removeAttachment: \"إزالة {{name}}\",\n attachmentNameOnly: \"الاسم والنوع فقط\",\n attachmentTooLarge: \"{{name}} أكبر من {{size}} ميغابايت ولم يتم إرفاقه.\",\n attachmentTooMany: \"يمكن إرفاق {{max}} ملفات فقط، لذا تم تخطي {{name}}.\",\n noAnswer:\n \"لم أجد هذا في وثائقنا، لذا فالإجابة أدناه غير مستندة إلى مصدر. حاول إعادة الصياغة، أو\",\n answerDidNotArrive: \"لم تصل هذه الإجابة. يرجى المحاولة مرة أخرى.\",\n toolBudgetScoped:\n \"هذا السؤال يشمل أكثر مما أستطيع البحث فيه دفعة واحدة. جرّب أن تسأل عن جزء واحد منه.\",\n askHuman: \"تحدّث إلى شخص\",\n feedbackPrompt: \"هل كانت هذه الإجابة مفيدة؟\",\n feedbackHelpful: \"مفيدة\",\n feedbackNotHelpful: \"غير مفيدة\",\n feedbackReasonTitle: \"ما الخطأ فيها؟\",\n feedbackReasonInaccurate: \"غير دقيقة\",\n feedbackReasonIncomplete: \"ناقصة\",\n feedbackReasonOffTopic: \"خارج الموضوع\",\n feedbackReasonHardToFollow: \"صعبة الفهم\",\n feedbackReasonOther: \"شيء آخر\",\n feedbackCommentPlaceholder: \"أضف تفصيلاً (اختياري)\",\n feedbackSend: \"إرسال\",\n feedbackDismiss: \"إغلاق\",\n feedbackThanks: \"شكرًا، هذا يساعدنا.\",\n feedbackNotSent: \"لم يتم الإرسال.\",\n escalateOpen: \"تواصل مع شخص\",\n escalateTitle: \"أرسل هذه المحادثة إلى شخص\",\n escalateBody: \"سنمرّر المحادثة كاملة، حتى لا تضطر إلى كتابتها من جديد.\",\n escalateEmailLabel: \"بريدك الإلكتروني\",\n escalateEmailPlaceholder: \"you@example.com\",\n escalateNoteLabel: \"هل من شيء آخر ينبغي أن نعرفه؟ (اختياري)\",\n escalateSubmit: \"إرسال إلى شخص\",\n escalateSending: \"جارٍ الإرسال…\",\n escalateCancel: \"إلغاء\",\n escalateInvalidEmail:\n \"لا يبدو هذا عنوانًا يمكننا الرد عليه. يرجى التحقق منه.\",\n escalateSent: \"أصبحت هذه المحادثة لدى أحد الزملاء. سنرد على {email}.\",\n escalateRateLimited:\n \"طلبات كثيرة خلال وقت قصير. يرجى المحاولة بعد بضع دقائق.\",\n escalateCaptcha: \"تعذّر التحقق من أنك لست روبوتًا. يرجى المحاولة مرة أخرى.\",\n escalateFailed: \"تعذّر تمرير المحادثة الآن. يرجى المحاولة مرة أخرى.\",\n prevSuggestion: \"الاقتراح السابق\",\n nextSuggestion: \"الاقتراح التالي\",\n conceptIllustration: \"رسم توضيحي للمفهوم\",\n conceptScrollPrev: \"تمرير المفاهيم لليسار\",\n conceptScrollNext: \"تمرير المفاهيم لليمين\",\n opensInNewTab: \"يُفتح في علامة تبويب جديدة\",\n conceptStripTitle: \"أو ابدأ من مفهوم\",\n conceptStripLabel: \"مفاهيم يمكنك السؤال عنها\",\n conceptAsk: \"اسأل عن {title} في {product}\",\n conceptAskQuestion: \"كيف يعمل {title} في {product}؟\",\n copyAnswer: \"نسخ الإجابة\",\n copyFailed: \"تعذّر النسخ\",\n readAloud: \"اقرأ بصوت عالٍ\",\n stopReading: \"إيقاف القراءة\",\n answerTable: \"جدول\",\n productVideo: \"فيديو المنتج\",\n productVideoTitle: \"فيديو {product}\",\n playVideo: \"تشغيل {title}\",\n closeVideo: \"إغلاق الفيديو\",\n enterFullScreen: \"ملء الشاشة\",\n exitFullScreen: \"الخروج من ملء الشاشة\",\n panelTitle: \"مساعد الذكاء الاصطناعي\",\n panelTitleProduct: \"مساعد {product}\",\n panelViews: \"طرق عرض المساعد\",\n tabChat: \"دردشة\",\n tabAvatar: \"الأفاتار\",\n closePanel: \"إغلاق\",\n liveAvatar: \"الأفاتار المباشر\",\n avatarComingSoon: \"الأفاتار المباشر قريبًا\",\n continueInChat: \"المتابعة في الدردشة\",\n videoUnavailable: \"تعذّر تشغيل هذا الفيديو الآن.\",\n groundedIn: \"على ماذا تستند هذه الإجابة\",\n sourceCountOne: \"مصدر واحد\",\n sourceCountMany: \"{count} مصادر\",\n sourceKindConcept: \"مفهوم\",\n sourceKindDocs: \"التوثيق\",\n sourceKindPricing: \"الأسعار\",\n sourceKindUseCase: \"حالة استخدام\",\n sourceKindPage: \"صفحة المنتج\",\n seoTitle: \"صف مشكلتك واحصل على إجابة\",\n seoDescription:\n \"صف المشكلة بكلماتك واحصل على إجابة مستمدة من وثائق منتجاتنا، مع روابط إلى الصفحات التي جاءت منها.\",\n seoDescriptionProduct:\n \"صف المشكلة بكلماتك واحصل على إجابة مستمدة من وثائق {product} وبقية منتجاتنا، مع روابط إلى الصفحات التي جاءت منها.\",\n seoDescriptionScoped:\n \"إجابات عن {product} مستمدة من وثائق {product}، مع روابط إلى الصفحات التي جاءت منها.\",\n capabilities: [\n \"مبني على وثائقنا\",\n \"قارن عبر المنظومة\",\n \"مباشرةً إلى الصفحة الصحيحة\",\n ],\n prompts: [\n \"كل دورة تدريبية لدينا في جدول بيانات مختلف.\",\n \"لا نعلم بتعطل الماكينة إلا بعد توقف خط الإنتاج.\",\n \"أعضاؤنا يتوقفون عن الحضور تدريجيًا دون أن نعرف السبب.\",\n PORTFOLIO_PROMPT.ar,\n ],\n};\n\nconst TA: ExploreStrings = {\n badge: \"எங்கள் ஆவணங்களை அடிப்படையாகக் கொண்ட AI பதில்கள்\",\n welcomeTitle: \"நீங்கள் எந்தச் சிக்கலைத் தீர்க்க முயல்கிறீர்கள்?\",\n welcomeBody:\n \"சிக்கலை உங்கள் சொந்த வார்த்தைகளில் விவரியுங்கள். ஒரு குறிப்பிட்ட தயாரிப்பு பற்றியும் கேட்கலாம், சிலவற்றை ஒப்பிடவும் செய்யலாம். ஒவ்வொரு பதிலும் எங்கள் ஆவணப்படுத்தலிலிருந்து நேரடியாக வருகிறது.\",\n welcomeBodyProduct:\n \"சிக்கலை உங்கள் சொந்த வார்த்தைகளில் விவரியுங்கள், அல்லது {product} என்ன செய்கிறது என்று கேளுங்கள். ஒவ்வொரு பதிலும் எங்கள் ஆவணப்படுத்தலிலிருந்து நேரடியாக வருகிறது.\",\n welcomeBodyScoped:\n \"சிக்கலை உங்கள் சொந்த வார்த்தைகளில் விவரியுங்கள். ஒவ்வொரு பதிலும் எங்கள் ஆவணப்படுத்தலிலிருந்து நேரடியாக வருகிறது.\",\n tryAsking: \"இதைக் கேட்டுப் பாருங்கள்\",\n focusProduct: \"ஒரு தயாரிப்பில் கவனம்\",\n allProducts: \"அனைத்து தயாரிப்புகள்\",\n showAll: \"அனைத்தும்\",\n showLess: \"குறைவாகக் காட்டு\",\n sources: \"மூலங்கள்\",\n nextYouCouldAsk: \"அடுத்து நீங்கள் கேட்கலாம்\",\n placeholder: \"சிக்கலை விவரியுங்கள்…\",\n placeholderProduct:\n \"சிக்கலை விவரியுங்கள், அல்லது {product} பற்றிக் கேளுங்கள்…\",\n placeholderScoped: \"{product} பற்றிக் கேளுங்கள்…\",\n send: \"அனுப்பு\",\n stop: \"நிறுத்து\",\n newChat: \"புதிய உரையாடல்\",\n history: \"வரலாறு\",\n clearHistory: \"வரலாற்றை அழி\",\n share: \"பகிர்\",\n copied: \"நகலெடுக்கப்பட்டது\",\n copying: \"நகலெடுக்கிறது…\",\n shareUnavailable: \"கிடைக்கவில்லை\",\n disclaimer: \"பொறுப்புத் துறப்பு\",\n disclaimerShort:\n \"எங்கள் ஆவணங்களை அடிப்படையாகக் கொண்டது — முக்கியமானதைச் சரிபார்க்கவும்.\",\n dictate: \"உங்கள் கேள்வியைப் பேசுங்கள்\",\n stopDictating: \"பேசுவதை நிறுத்து\",\n attach: \"கோப்புகளை இணைக்க\",\n attachHint: \"அதிகபட்சம் {{max}} கோப்புகள், ஒவ்வொன்றும் {{size}} MB வரை\",\n removeAttachment: \"{{name}} அகற்று\",\n attachmentNameOnly: \"பெயரும் வகையும் மட்டும்\",\n attachmentTooLarge:\n \"{{name}} {{size}} MB-ஐ விட பெரியது, எனவே இணைக்கப்படவில்லை.\",\n attachmentTooMany:\n \"{{max}} கோப்புகள் மட்டுமே இணைக்க முடியும், எனவே {{name}} தவிர்க்கப்பட்டது.\",\n noAnswer:\n \"இது எங்கள் ஆவணங்களில் கிடைக்கவில்லை, எனவே கீழே உள்ள பதிலுக்கு மூலம் இல்லை. வேறு வகையில் கேளுங்கள், அல்லது\",\n answerDidNotArrive: \"அந்தப் பதில் வரவில்லை. மீண்டும் கேட்டுப் பாருங்கள்.\",\n toolBudgetScoped:\n \"இந்தக் கேள்வியில் ஒரே முறையில் என்னால் பார்க்க முடிவதை விட அதிகம் உள்ளது. அதன் ஒரு பகுதியைப் பற்றிக் கேட்டுப் பாருங்கள்.\",\n askHuman: \"எங்களைத் தொடர்பு கொள்ளுங்கள்\",\n feedbackPrompt: \"இந்தப் பதில் பயனுள்ளதாக இருந்ததா?\",\n feedbackHelpful: \"பயனுள்ளது\",\n feedbackNotHelpful: \"பயனில்லை\",\n feedbackReasonTitle: \"என்ன சரியாக இல்லை?\",\n feedbackReasonInaccurate: \"தவறான தகவல்\",\n feedbackReasonIncomplete: \"முழுமையற்றது\",\n feedbackReasonOffTopic: \"தலைப்புக்கு அப்பாற்பட்டது\",\n feedbackReasonHardToFollow: \"புரிந்துகொள்ள கடினம்\",\n feedbackReasonOther: \"வேறு ஏதோ\",\n feedbackCommentPlaceholder: \"மேலும் விவரம் (விருப்பம்)\",\n feedbackSend: \"அனுப்பு\",\n feedbackDismiss: \"மூடு\",\n feedbackThanks: \"நன்றி, இது எங்களுக்கு உதவுகிறது.\",\n feedbackNotSent: \"அனுப்ப முடியவில்லை.\",\n escalateOpen: \"ஒருவரிடம் பேசுங்கள்\",\n escalateTitle: \"இந்த உரையாடலை ஒருவருக்கு அனுப்புங்கள்\",\n escalateBody:\n \"முழு உரையாடலையும் நாங்கள் அனுப்பிவிடுவோம்; நீங்கள் மீண்டும் தட்டச்சு செய்ய வேண்டியதில்லை.\",\n escalateEmailLabel: \"உங்கள் மின்னஞ்சல் முகவரி\",\n escalateEmailPlaceholder: \"you@example.com\",\n escalateNoteLabel: \"வேறு ஏதேனும் சொல்ல விரும்புகிறீர்களா? (விருப்பம்)\",\n escalateSubmit: \"ஒருவருக்கு அனுப்பு\",\n escalateSending: \"அனுப்பப்படுகிறது…\",\n escalateCancel: \"ரத்து செய்\",\n escalateInvalidEmail:\n \"இது நாங்கள் பதிலளிக்கக்கூடிய மின்னஞ்சல் முகவரி போல் தெரியவில்லை. சரிபார்க்கவும்.\",\n escalateSent:\n \"இந்த உரையாடல் இப்போது ஒருவரிடம் உள்ளது. {email} முகவரிக்குப் பதிலளிப்போம்.\",\n escalateRateLimited:\n \"குறுகிய நேரத்தில் அதிக கோரிக்கைகள். சில நிமிடங்கள் கழித்து முயற்சிக்கவும்.\",\n escalateCaptcha:\n \"நீங்கள் மனிதர் என்பதை உறுதிசெய்ய முடியவில்லை. மீண்டும் முயற்சிக்கவும்.\",\n escalateFailed: \"இப்போது அனுப்ப முடியவில்லை. மீண்டும் முயற்சிக்கவும்.\",\n prevSuggestion: \"முந்தைய பரிந்துரை\",\n nextSuggestion: \"அடுத்த பரிந்துரை\",\n conceptIllustration: \"கருத்து விளக்கப்படம்\",\n conceptScrollPrev: \"கருத்துகளை இடதுபுறம் நகர்த்து\",\n conceptScrollNext: \"கருத்துகளை வலதுபுறம் நகர்த்து\",\n opensInNewTab: \"புதிய தாவலில் திறக்கும்\",\n conceptStripTitle: \"அல்லது ஒரு கருத்திலிருந்து தொடங்குங்கள்\",\n conceptStripLabel: \"நீங்கள் கேட்கக்கூடிய கருத்துகள்\",\n conceptAsk: \"{product} இல் {title} பற்றிக் கேளுங்கள்\",\n conceptAskQuestion: \"{product} இல் {title} எப்படி வேலை செய்கிறது?\",\n copyAnswer: \"பதிலை நகலெடு\",\n copyFailed: \"நகலெடுக்க முடியவில்லை\",\n readAloud: \"சத்தமாகப் படி\",\n stopReading: \"படிப்பதை நிறுத்து\",\n answerTable: \"அட்டவணை\",\n productVideo: \"தயாரிப்பு வீடியோ\",\n productVideoTitle: \"{product} தயாரிப்பு வீடியோ\",\n playVideo: \"{title} இயக்கு\",\n closeVideo: \"வீடியோவை மூடு\",\n enterFullScreen: \"முழுத் திரை\",\n exitFullScreen: \"முழுத் திரையிலிருந்து வெளியேறு\",\n panelTitle: \"AI உதவியாளர்\",\n panelTitleProduct: \"{product} உதவியாளர்\",\n panelViews: \"உதவியாளர் காட்சிகள்\",\n tabChat: \"அரட்டை\",\n tabAvatar: \"அவதார்\",\n closePanel: \"மூடு\",\n liveAvatar: \"நேரலை அவதார்\",\n avatarComingSoon: \"நேரலை அவதார் விரைவில்\",\n continueInChat: \"அரட்டையில் தொடரவும்\",\n videoUnavailable: \"இந்த வீடியோவை இப்போது இயக்க முடியவில்லை.\",\n groundedIn: \"இந்தப் பதில் எதை அடிப்படையாகக் கொண்டது\",\n sourceCountOne: \"1 மூலம்\",\n sourceCountMany: \"{count} மூலங்கள்\",\n sourceKindConcept: \"கருத்து\",\n sourceKindDocs: \"ஆவணம்\",\n sourceKindPricing: \"விலை\",\n sourceKindUseCase: \"பயன்பாட்டு நிலை\",\n sourceKindPage: \"தயாரிப்புப் பக்கம்\",\n seoTitle: \"சிக்கலை விவரியுங்கள், பதில் பெறுங்கள்\",\n seoDescription:\n \"சிக்கலை உங்கள் சொந்த வார்த்தைகளில் விவரியுங்கள்; எங்கள் தயாரிப்பு ஆவணங்களிலிருந்து பதில் கிடைக்கும், அது வந்த பக்கங்களுக்கான இணைப்புகளுடன்.\",\n seoDescriptionProduct:\n \"{product} மற்றும் எங்கள் பிற தயாரிப்புகளின் ஆவணங்களிலிருந்து பதில் பெற, சிக்கலை உங்கள் சொந்த வார்த்தைகளில் விவரியுங்கள் — அது வந்த பக்கங்களுக்கான இணைப்புகளுடன்.\",\n seoDescriptionScoped:\n \"{product} பற்றிய பதில்கள், {product} ஆவணங்களிலிருந்து, அவை வந்த பக்கங்களுக்கான இணைப்புகளுடன்.\",\n capabilities: [\n \"எங்கள் சொந்த ஆவணங்களின் அடிப்படையில்\",\n \"தயாரிப்புகளை ஒப்பிடுங்கள்\",\n \"நேராக சரியான பக்கத்திற்கு\",\n ],\n prompts: [\n \"ஒவ்வொரு பயிற்சி வகுப்பும் வெவ்வேறு விரிதாளில் உள்ளது.\",\n \"இயந்திரம் நின்றது லைன் நிற்கும்போதுதான் தெரிய வருகிறது.\",\n \"உறுப்பினர்கள் மெல்ல வருவதை நிறுத்துகிறார்கள், காரணம் தெரியாது.\",\n PORTFOLIO_PROMPT.ta,\n ],\n};\n\nconst STRINGS: Record<ExploreLocale, ExploreStrings> = {\n en: EN,\n zh: ZH,\n hi: HI,\n es: ES,\n ar: AR,\n ta: TA,\n};\n\n/**\n * The BCP-47 tag to ask the browser's speech synthesiser for.\n *\n * A region is required, not optional: `speechSynthesis` matches voices on the full tag, and\n * a bare `zh` or `ta` matches nothing on most platforms — the utterance then falls back to\n * the UI language and reads Tamil aloud in English phonetics. The regions here are the ones\n * the products' own locale pickers use, and a browser with no voice for the tag still gets\n * the right `lang` on the utterance, which is what the fallback voice reads it as.\n *\n * Not part of {@link ExploreStrings}: it is not copy, nothing renders it, and putting it\n * there would ask a translator to translate a language tag.\n */\nconst SPEECH_TAGS: Record<ExploreLocale, string> = {\n en: \"en-US\",\n zh: \"zh-CN\",\n hi: \"hi-IN\",\n es: \"es-ES\",\n ar: \"ar-SA\",\n ta: \"ta-IN\",\n};\n\nexport function speechLocaleOf(locale: ExploreLocale): string {\n return SPEECH_TAGS[locale];\n}\n\n/**\n * Resolve the locale to render in.\n *\n * Order: an explicit prop, then the document's own `lang` (which the host site controls and\n * which a prerendered page already carries), then the browser. Anything unrecognised falls\n * back to English rather than rendering keys.\n *\n * Matching is on the primary subtag, so `es-MX`, `zh-Hans-CN` and `ar-EG` all resolve.\n */\nexport function resolveExploreLocale(explicit?: string): ExploreLocale {\n const candidates = [\n explicit,\n typeof document === \"undefined\" ? undefined : document.documentElement.lang,\n typeof navigator === \"undefined\" ? undefined : navigator.language,\n ];\n\n for (const candidate of candidates) {\n if (!candidate) continue;\n const primary = candidate.toLowerCase().split(\"-\")[0];\n const match = EXPLORE_LOCALES.find((locale) => locale === primary);\n if (match) return match;\n }\n return \"en\";\n}\n\nexport function exploreStrings(locale: ExploreLocale): ExploreStrings {\n return STRINGS[locale] ?? EN;\n}\n\n// `fill` (substitute `{product}` and friends without pulling in a formatting library) is in a module of its own, so the\n// live avatar's view can use it without carrying these strings.\nexport { fill } from \"./explore-fill\";\n","/**\n * ExploreVideoDialog — the player behind a product-video card in an answer.\n *\n * CONTRACT.md §7 makes a product video ONE canonical line, `[](video)`,\n * which the answer renderer draws as a poster card (`InlineVideoCard` in `explore-answer.tsx`).\n * This is what that card opens. It is modelled on `ConceptLightbox`, for the same reasons:\n *\n * - A native `<dialog>` opened with `showModal()`: the browser supplies the top layer, the\n * inert page behind it, focus containment and Esc-to-close. Nothing here re-implements\n * those.\n * - Mounted ONLY while open — and it is the ONLY place a `<video>` element exists. A\n * transcript that carried one per answer would fetch video metadata for every conversation\n * anyone scrolled past; created on open, the file is requested only by a visitor who asked\n * to watch it.\n * - Portalled to `document.body`. The card sits inside a `<p>` in the answer, where a\n * `<dialog>` is not valid content, and inside `.boff-explore-body`, whose rules are written\n * for prose. The page's `dir` stays behind with the subtree that set it, so the card passes\n * it along.\n * - Returning focus to the card is the card's job — it owns the trigger.\n */\n\"use client\";\n\nimport { useCallback, useEffect, useId, useRef, useState } from \"react\";\nimport type { KeyboardEvent, MouseEvent, SyntheticEvent } from \"react\";\n\nimport { Maximize, Minimize, VideoOff, X } from \"lucide-react\";\nimport { createPortal } from \"react-dom\";\n\n/** The words the player needs. `AnswerRendererStrings`, and so `ExploreStrings`, carry them. */\nexport interface ExploreVideoStrings {\n /** Accessible name of the Close button. */\n closeVideo: string;\n /** The full-screen toggle's label in each state — it says what pressing it does NOW. */\n enterFullScreen: string;\n exitFullScreen: string;\n /** Shown in place of the player when the file cannot be played. */\n videoUnavailable: string;\n}\n\nexport interface ExploreVideoDialogProps {\n /** The video file. The card has already checked it against the catalog origins. */\n videoUrl: string;\n /** Its poster, shown until the first frame arrives. */\n posterUrl: string;\n /** \"<Name> product video\", as the answer wrote it. Names the dialog. */\n title: string;\n strings: ExploreVideoStrings;\n /** The direction of the page at the card. A portal does not inherit it. */\n dir?: \"ltr\" | \"rtl\";\n onClose: () => void;\n}\n\n/**\n * iOS Safari's own video full screen. An iPhone has no element Fullscreen API at all —\n * `requestFullscreen` is undefined there — and this is the only way to fill its screen.\n *\n * Declared as an extension of the DOM type rather than cast to: every member is optional, so\n * each one has to be checked before it is called, and a plain `HTMLVideoElement` is\n * assignable to it without an assertion.\n */\ninterface WebkitFullscreenVideo extends HTMLVideoElement {\n webkitEnterFullscreen?: () => void;\n webkitExitFullscreen?: () => void;\n webkitDisplayingFullscreen?: boolean;\n}\n\n/** Which full-screen mechanism the browser offers: the standard one, iOS's, or neither. */\ntype FullscreenSupport = \"element\" | \"video\" | null;\n\n/**\n * Read once, when the dialog mounts — which only ever happens in a browser, after a click.\n *\n * `fullscreenEnabled` as well as the method: an iframe without `allowfullscreen` has the\n * method and refuses every request, and a toggle that can never work must not be offered.\n */\nfunction fullscreenSupport(): FullscreenSupport {\n if (typeof document === \"undefined\") return null;\n if (\n document.fullscreenEnabled &&\n typeof document.documentElement.requestFullscreen === \"function\"\n ) {\n return \"element\";\n }\n if (\n typeof HTMLVideoElement !== \"undefined\" &&\n \"webkitEnterFullscreen\" in HTMLVideoElement.prototype\n ) {\n return \"video\";\n }\n return null;\n}\n\n/**\n * A full-screen request or exit the browser refuses — no user gesture, or already left —\n * has nothing to tell the visitor. Engines that predate the promise return nothing at all.\n */\nfunction ignoreRejection(result: Promise<void> | undefined): void {\n result?.catch(() => undefined);\n}\n\n/**\n * The rules the utilities cannot express: the panel in full screen fills the screen on the\n * page's own background — the header row across the top, the video letterboxed in the rest —\n * instead of keeping its card styling. (The browser already forces a full-screen element to\n * the viewport's size; these are what it leaves alone.) The column layout is stated here too,\n * rather than left to the panel's utility classes: the video's height is only bounded by the\n * screen because the frame is a flex item of a column exactly one screen tall.\n */\nconst VIDEO_DIALOG_CSS = `\n.boff-explore-video-panel:fullscreen {\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n padding: 1rem;\n background-color: hsl(var(--background));\n color: hsl(var(--foreground));\n}\n.boff-explore-video-panel:fullscreen .boff-explore-video-frame {\n display: flex;\n flex: 1 1 auto;\n min-height: 0;\n align-items: center;\n justify-content: center;\n border: 0;\n border-radius: 0;\n box-shadow: none;\n background-color: hsl(var(--background));\n}\n.boff-explore-video-panel:fullscreen video {\n width: 100%;\n height: 100%;\n max-height: none;\n}\n`;\n\nconst DIALOG_BUTTON =\n \"inline-flex h-10 w-10 shrink-0 items-center justify-center rounded-full border border-border bg-card text-foreground transition-colors hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\";\n\nexport function ExploreVideoDialog({\n videoUrl,\n posterUrl,\n title,\n strings: T,\n dir,\n onClose,\n}: ExploreVideoDialogProps) {\n const dialogRef = useRef<HTMLDialogElement>(null);\n /**\n * What goes full screen: the header row AND the video, so the toggle and Close stay on\n * screen and clickable. Full-screening the video's frame alone hid both — the only way back\n * was Esc, or the player's own control, which stacked a second full screen on the first.\n */\n const panelRef = useRef<HTMLDivElement>(null);\n const videoRef = useRef<HTMLVideoElement>(null);\n const closeRef = useRef<HTMLButtonElement>(null);\n /** False when the browser has no `showModal()` and Esc has to be handled here. */\n const nativeModalRef = useRef(false);\n const titleId = useId();\n const [support] = useState(fullscreenSupport);\n const [fullscreen, setFullscreen] = useState(false);\n const [failed, setFailed] = useState(false);\n\n useEffect(() => {\n const dialog = dialogRef.current;\n if (!dialog) return;\n if (typeof dialog.showModal === \"function\") {\n if (!dialog.open) dialog.showModal();\n nativeModalRef.current = true;\n } else {\n // No top layer in this engine: show it in place and handle Esc ourselves.\n dialog.setAttribute(\"open\", \"\");\n nativeModalRef.current = false;\n }\n closeRef.current?.focus();\n // \"Playing on open\" as a call, not only as `autoPlay`: WebKit honours the attribute for\n // unmuted media only when playback starts from a user gesture, and this effect still runs\n // inside the click that opened the player — React flushes a discrete update's effects\n // before the event returns. `autoPlay` stays as the fallback for an engine that refuses\n // the call.\n ignoreRejection(videoRef.current?.play());\n return () => {\n // No `pause()` here: StrictMode runs this on mount, and a pause before playback\n // clears the element's autoplay for good. A video removed from the document is paused\n // by the browser anyway; the close paths below pause it explicitly.\n if (dialog.open && typeof dialog.close === \"function\") dialog.close();\n };\n }, []);\n\n // The toggle reports what the browser DID, not what was asked: a request can be refused,\n // and Esc or the player's own control leaves full screen without touching this button.\n // Anything of this player's counts, not just the panel: where the native control is still\n // offered (`controlsList` is Chromium's), it puts the <video> itself full screen on top of\n // the panel, and the screen is no less full for it.\n useEffect(() => {\n const sync = (): void => {\n const current = document.fullscreenElement;\n setFullscreen(\n current !== null && dialogRef.current?.contains(current) === true,\n );\n };\n const enter = (): void => setFullscreen(true);\n const leave = (): void => setFullscreen(false);\n const video = videoRef.current;\n document.addEventListener(\"fullscreenchange\", sync);\n // iOS's video full screen announces itself on the element, not on the document.\n video?.addEventListener(\"webkitbeginfullscreen\", enter);\n video?.addEventListener(\"webkitendfullscreen\", leave);\n return () => {\n document.removeEventListener(\"fullscreenchange\", sync);\n video?.removeEventListener(\"webkitbeginfullscreen\", enter);\n video?.removeEventListener(\"webkitendfullscreen\", leave);\n };\n // Re-bound when the player is swapped for the \"unavailable\" message and back.\n }, [failed]);\n\n /** Leave full screen if — and only if — it is THIS player that is in it. */\n const leaveFullscreen = useCallback(() => {\n const current = document.fullscreenElement;\n if (\n current &&\n dialogRef.current?.contains(current) &&\n typeof document.exitFullscreen === \"function\"\n ) {\n ignoreRejection(document.exitFullscreen());\n }\n const video: WebkitFullscreenVideo | null = videoRef.current;\n if (video?.webkitDisplayingFullscreen) video.webkitExitFullscreen?.();\n }, []);\n\n /** Every way out goes through here: the button, Esc and the backdrop alike. */\n const requestClose = useCallback(() => {\n videoRef.current?.pause();\n leaveFullscreen();\n onClose();\n }, [leaveFullscreen, onClose]);\n\n const toggleFullscreen = useCallback(() => {\n if (fullscreen) {\n leaveFullscreen();\n return;\n }\n if (support === \"element\") {\n const panel = panelRef.current;\n if (panel) ignoreRejection(panel.requestFullscreen());\n return;\n }\n const video: WebkitFullscreenVideo | null = videoRef.current;\n video?.webkitEnterFullscreen?.();\n }, [fullscreen, leaveFullscreen, support]);\n\n // Esc closes the dialog natively and then fires `close`. StrictMode re-runs the mount\n // effect (close, then showModal again), so a `close` event can arrive for a dialog that is\n // already open again — that one must not tear the player down.\n const handleClose = useCallback(\n (event: SyntheticEvent<HTMLDialogElement>) => {\n if (event.currentTarget.open) return;\n requestClose();\n },\n [requestClose],\n );\n\n const handleKeyDown = useCallback(\n (event: KeyboardEvent<HTMLDialogElement>) => {\n if (event.key === \"Escape\" && !nativeModalRef.current) {\n event.preventDefault();\n requestClose();\n }\n },\n [requestClose],\n );\n\n // The stage is everything around the player, so a click that lands on it — and not on\n // anything inside it — is a click on the backdrop.\n const handleStageClick = useCallback(\n (event: MouseEvent<HTMLDivElement>) => {\n if (event.target === event.currentTarget) requestClose();\n },\n [requestClose],\n );\n\n if (typeof document === \"undefined\") return null;\n\n const fullscreenLabel = fullscreen ? T.exitFullScreen : T.enterFullScreen;\n\n return createPortal(\n <dialog\n ref={dialogRef}\n data-boff-explore=\"video-dialog\"\n aria-labelledby={titleId}\n dir={dir}\n onClose={handleClose}\n onKeyDown={handleKeyDown}\n // The dialog paints its own full-viewport scrim rather than styling `::backdrop`:\n // `::backdrop` only inherits custom properties since Chrome 122 / Safari 17.4, so a\n // token there resolves to nothing on older engines and the page would show through\n // undimmed. Same approach as ConceptLightbox.\n className=\"fixed inset-0 z-50 m-0 h-full max-h-none w-full max-w-none overflow-y-auto overscroll-contain border-0 bg-background/95 p-0 text-foreground backdrop-blur-sm\"\n >\n <style dangerouslySetInnerHTML={{ __html: VIDEO_DIALOG_CSS }} />\n <div\n onClick={handleStageClick}\n className=\"flex min-h-full items-center justify-center p-4 sm:p-6\"\n >\n <div\n ref={panelRef}\n className=\"boff-explore-video-panel flex w-full min-w-0 max-w-[960px] flex-col gap-3\"\n >\n <div className=\"flex items-center gap-2\">\n <h2\n id={titleId}\n className=\"min-w-0 flex-1 truncate text-sm font-semibold text-foreground sm:text-base\"\n >\n {title}\n </h2>\n {support !== null && !failed ? (\n // A plain button whose name says what pressing it does NOW, and no\n // `aria-pressed`: a toggle button's name must not change with its state, or it\n // announces \"Exit full screen, pressed\" — two answers to one question.\n <button\n type=\"button\"\n data-boff-explore=\"video-fullscreen\"\n aria-label={fullscreenLabel}\n title={fullscreenLabel}\n onClick={toggleFullscreen}\n className={DIALOG_BUTTON}\n >\n {fullscreen ? (\n <Minimize aria-hidden=\"true\" className=\"h-5 w-5\" />\n ) : (\n <Maximize aria-hidden=\"true\" className=\"h-5 w-5\" />\n )}\n </button>\n ) : null}\n <button\n ref={closeRef}\n type=\"button\"\n data-boff-explore=\"video-close\"\n aria-label={T.closeVideo}\n title={T.closeVideo}\n onClick={requestClose}\n className={DIALOG_BUTTON}\n >\n <X aria-hidden=\"true\" className=\"h-5 w-5\" />\n </button>\n </div>\n\n <div className=\"boff-explore-video-frame overflow-hidden rounded-xl border border-border bg-muted shadow-lg\">\n {failed ? (\n // A black box with a spinning control tells the visitor nothing; this says\n // what happened, in their language.\n <div\n role=\"alert\"\n className=\"flex aspect-video w-full flex-col items-center justify-center gap-2 p-6 text-center text-sm text-muted-foreground\"\n >\n <VideoOff aria-hidden=\"true\" className=\"h-6 w-6\" />\n <p>{T.videoUnavailable}</p>\n </div>\n ) : (\n <video\n ref={videoRef}\n data-boff-explore=\"video-player\"\n src={videoUrl}\n poster={posterUrl}\n controls\n // Where the toggle fills the screen, the player's own full-screen control\n // would only stack a second full screen on it, whose exit lands back in the\n // first. Chromium honours this; elsewhere `sync` above copes.\n controlsList={\n support === \"element\" ? \"nofullscreen\" : undefined\n }\n playsInline\n autoPlay\n preload=\"metadata\"\n onError={() => setFailed(true)}\n className=\"block max-h-[80vh] w-full bg-muted object-contain\"\n />\n )}\n </div>\n </div>\n </div>\n </dialog>,\n document.body,\n );\n}\n","/**\n * The answer renderer — ONE implementation, shared by every surface that shows an answer.\n *\n * `ExploreMessage.content` is GitHub-flavoured markdown written by the explore harness, and\n * the shape of it is part of the contract (`dev/platform/context/publishing/explore/CONTRACT.md` §7): a\n * comparison and a plan list come back as GFM tables, an answer may embed a concept\n * illustration, and every answer carries links. Rendering that correctly is a pile of\n * decisions — the table must not widen the document, it becomes one card per row on a phone,\n * an image may only load from a catalog origin, a product video is a poster card that opens\n * a player rather than a `<video>` in the transcript — and NONE of them may differ between the\n * chat at `/explore` and a published answer page. So they live here, once, and both surfaces\n * call `ExploreAnswerBody`.\n *\n * This module was split out of `explore.tsx` rather than copied from it. A second renderer\n * would pass review on the day it is written and drift the first time either half is fixed.\n *\n * Everything here is presentation of an answer the backend already produced. Nothing in it\n * reads, stores or displays anything a visitor typed.\n */\n\"use client\";\n\nimport {\n Children,\n cloneElement,\n createContext,\n isValidElement,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport type { ComponentProps, MouseEvent, ReactElement } from \"react\";\n\nimport { Film, Play } from \"lucide-react\";\n\nimport { fill } from \"./explore-i18n\";\nimport { ExploreVideoDialog } from \"./explore-video-dialog\";\nimport { Markdown, MarkdownLink } from \"../content/Markdown\";\nimport { cn } from \"../utils/cn\";\n\nimport type { ExploreProduct } from \"./explore-types\";\nimport type { ExploreVideoStrings } from \"./explore-video-dialog\";\nimport type { Components, ExtraProps, Options } from \"react-markdown\";\n\n// ============================================================================\n// Styles\n// ============================================================================\n\n/**\n * The stylesheet an answer body needs, wherever it is rendered. Everything is scoped under\n * `.boff-explore-body`, which `ExploreAnswerBody` puts on its wrapper, and every colour is a\n * semantic token so the same rules are correct in light and dark mode on all 38 palettes.\n */\nexport const EXPLORE_ANSWER_CSS = `\n/* Nothing inside an answer may widen the page. Model output carries long URLs, code and\n tables — each of those overflows a phone by default, and one overflowing child makes the\n WHOLE document horizontally scrollable, not just the bubble. */\n.boff-explore-body,\n.boff-explore-body p,\n.boff-explore-body li,\n.boff-explore-body a,\n.boff-explore-body h1,\n.boff-explore-body h2,\n.boff-explore-body h3,\n/* h4-h6 as well: a published answer page pushes the model's own headings down a level or\n two so they nest under the page's, and a long unbroken word is no narrower for it. */\n.boff-explore-body h4,\n.boff-explore-body h5,\n.boff-explore-body h6 {\n overflow-wrap: anywhere;\n word-break: break-word;\n}\n.boff-explore-body pre {\n overflow-x: auto;\n max-width: 100%;\n}\n.boff-explore-body table {\n display: block;\n overflow-x: auto;\n max-width: 100%;\n}\n.boff-explore-body img {\n max-width: 100%;\n height: auto;\n}\n/* A product-video poster fills the card's reserved 16:9 frame and is cropped to it. The\n blanket \\`img { height: auto }\\` above — and ProseStyles' own — outrank a height utility,\n and would size it by its own aspect ratio instead, leaving a band of the frame showing\n whenever a poster is not exactly 16:9. */\n.boff-explore-body .boff-explore-video-poster {\n height: 100%;\n max-width: none;\n}\n\n/* ---- Comparison and pricing tables ----------------------------------------------------\n The harness emits a comparison, and a set of plans, as a GFM table whose FIRST column is\n the subject — the product, or the plan (CONTRACT.md §7). Two things have to be true of it:\n the page must not scroll sideways because of it, and it has to be readable on a 320px\n phone, which a four-column grid of 1px borders is not.\n\n Wide: a contained scroller. \\`max-width: 100%\\` keeps the box inside the bubble and\n \\`overflow-x: auto\\` keeps the columns inside the box, so the widest possible table still\n cannot widen the document. \\`overscroll-behavior-x: contain\\` stops a swipe that runs out\n of table from chaining to the page — the same rule the transcript needed. */\n.boff-explore-body .boff-explore-table {\n max-width: 100%;\n overflow-x: auto;\n overscroll-behavior-x: contain;\n margin: 0.75rem 0;\n border: 1px solid hsl(var(--border));\n border-radius: 0.75rem;\n background-color: hsl(var(--card));\n}\n.boff-explore-body .boff-explore-table:focus-visible {\n outline: 2px solid hsl(var(--ring));\n outline-offset: 2px;\n}\n.boff-explore-body .boff-explore-table table {\n /* Beats the blanket \\`display: block\\` above, which is the unwrapped fallback. */\n display: table;\n width: 100%;\n max-width: none;\n margin: 0;\n border-collapse: collapse;\n font-size: 0.8125rem;\n}\n.boff-explore-body .boff-explore-table th,\n.boff-explore-body .boff-explore-table td {\n border: 0;\n border-top: 1px solid hsl(var(--border));\n padding: 0.5rem 0.75rem;\n /* \\`start\\`, never \\`left\\`: the page root carries dir=\"rtl\" in Arabic, and a left-aligned\n table there reads against the grain of every other line on the page. */\n text-align: start;\n vertical-align: top;\n overflow-wrap: anywhere;\n /* Prices in a column line up under each other instead of drifting by digit width. */\n font-variant-numeric: tabular-nums;\n min-width: 6rem;\n}\n.boff-explore-body .boff-explore-table thead th {\n border-top: 0;\n background-color: hsl(var(--muted));\n color: hsl(var(--foreground));\n font-weight: 600;\n white-space: nowrap;\n}\n/* The first column is what the row is ABOUT — the product, or the plan name. Reading it as\n the row's heading is what makes a price list scannable rather than a grid of strings. */\n.boff-explore-body .boff-explore-table tbody td:first-child {\n font-weight: 600;\n color: hsl(var(--card-foreground));\n}\n\n/* Narrow: one card per row. Each cell prints its own column heading, so a value is never\n stranded without the question it answers, and the subject cell becomes the card's title.\n A media query rather than a measured width — these pages are serialised post-hydration,\n so anything measured here would ship to every phone as static HTML. */\n@media (max-width: 30rem) {\n .boff-explore-body .boff-explore-table {\n overflow-x: visible;\n }\n .boff-explore-body .boff-explore-table table,\n .boff-explore-body .boff-explore-table tbody,\n .boff-explore-body .boff-explore-table tr,\n .boff-explore-body .boff-explore-table td {\n display: block;\n width: 100%;\n min-width: 0;\n }\n .boff-explore-body .boff-explore-table thead {\n display: none;\n }\n .boff-explore-body .boff-explore-table tr {\n border-top: 1px solid hsl(var(--border));\n padding: 0.5rem 0;\n }\n .boff-explore-body .boff-explore-table tr:first-child {\n border-top: 0;\n }\n .boff-explore-body .boff-explore-table td {\n border: 0;\n padding: 0.125rem 0.75rem;\n }\n .boff-explore-body .boff-explore-table td[data-label]::before {\n content: attr(data-label);\n display: block;\n font-size: 0.6875rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: hsl(var(--muted-foreground));\n }\n .boff-explore-body .boff-explore-table tbody td:first-child {\n font-size: 0.9375rem;\n padding-bottom: 0.25rem;\n }\n .boff-explore-body .boff-explore-table tbody td:first-child::before {\n /* The plan's own name is the heading here; repeating \"Plan\" over it says nothing. */\n display: none;\n }\n}\n`;\n\n/**\n * The answer stylesheet as an element. Safe to mount more than once — the rules are\n * idempotent — so a page that shows answers and nothing else still gets them.\n */\nexport function ExploreAnswerStyles() {\n return <style dangerouslySetInnerHTML={{ __html: EXPLORE_ANSWER_CSS }} />;\n}\n\n// ============================================================================\n// Inline concept images\n// ============================================================================\n\n/**\n * Origins an answer may embed images from: every catalog product's website, apex and\n * `www.` alike (BotManor ships on www.botmanor.com, everything else on the apex, and either can\n * appear in the corpus). https only.\n */\nexport function inlineImageOrigins(\n products: readonly Pick<ExploreProduct, \"website\">[],\n): Set<string> {\n const origins = new Set<string>();\n for (const product of products) {\n let url: URL;\n try {\n url = new URL(product.website);\n } catch {\n continue;\n }\n if (url.protocol !== \"https:\") continue;\n const apex = url.hostname.replace(/^www\\./, \"\");\n const port = url.port ? `:${url.port}` : \"\";\n origins.add(`https://${apex}${port}`);\n origins.add(`https://www.${apex}${port}`);\n }\n return origins;\n}\n\n/**\n * Every video or caption extension the contract names (§7). A file like this is never an\n * image, and a linked image that points at one is always a product-video line — whether or\n * not it passes the checks that would make it a card.\n *\n * Matched against a parsed URL's PATH, so the `?v=<hash>` cache-buster the harness keeps on\n * every video URL does not hide the extension, and one in a query or fragment is not the\n * file's.\n */\nconst VIDEO_FILE_PATH = /\\.(?:mp4|webm|m4v|mov|vtt)$/i;\n\n/** `value` parsed, when it is an https URL with no credentials on a catalog product site. */\nfunction catalogUrlOf(\n value: unknown,\n origins: ReadonlySet<string>,\n): URL | null {\n if (typeof value !== \"string\" || value === \"\") return null;\n let url: URL;\n try {\n url = new URL(value);\n } catch {\n return null;\n }\n if (url.protocol !== \"https:\" || url.username || url.password) return null;\n return origins.has(url.origin) ? url : null;\n}\n\n/**\n * True when `src` is an https URL on a catalog product site. The backend already strips\n * every image it did not put in the answer; this is the browser's own check, so a model\n * that slips an arbitrary URL past it still cannot make the visitor's browser fetch it.\n *\n * A video or caption file is refused even on a catalog site: as an `<img src>` it downloads\n * video bytes into a transcript that promises never to preload one (§7), and draws nothing.\n * That covers a product-video card's poster as well as a plain ``.\n */\nexport function isInlineImageAllowed(\n src: unknown,\n origins: ReadonlySet<string>,\n): src is string {\n const url = catalogUrlOf(src, origins);\n return url !== null && !VIDEO_FILE_PATH.test(url.pathname);\n}\n\n// ============================================================================\n// Product-video allow-list\n// ============================================================================\n\n/**\n * The containers a video card may point at — the two the canonical line is written with\n * (CONTRACT.md §7), and the two every browser the sites support plays natively. A video\n * line in any other container is removed rather than opening a player that may not play it.\n */\nconst INLINE_VIDEO_PATH = /\\.(?:mp4|webm)$/i;\n\n/**\n * True when `href` may become a product-video card: the SAME origin rule as an inline image\n * (https, no credentials, a catalog product site), and a path that is a playable video file.\n */\nexport function isInlineVideoAllowed(\n href: unknown,\n origins: ReadonlySet<string>,\n): href is string {\n const url = catalogUrlOf(href, origins);\n return url !== null && INLINE_VIDEO_PATH.test(url.pathname);\n}\n\n/** A URL's origin with any `www.` removed — how the catalog maps are keyed. */\nfunction apexOriginOf(url: URL): string {\n const apex = url.hostname.replace(/^www\\./, \"\");\n const port = url.port ? `:${url.port}` : \"\";\n return `https://${apex}${port}`;\n}\n\n/**\n * Apex origin → catalog slug, so a video card can say WHICH product it is (`data-product`).\n *\n * The file's host is not the answer on its own: HealthyBowl ships on gethealthybowl.com and\n * Workspaces on burdenoff.com, and an e2e selector written against the slug would miss both.\n * First entry wins, as in `productNamesByOrigin`.\n */\nexport function productSlugsByOrigin(\n products: readonly Pick<ExploreProduct, \"slug\" | \"website\">[],\n): Map<string, string> {\n const slugs = new Map<string, string>();\n for (const product of products) {\n let url: URL;\n try {\n url = new URL(product.website);\n } catch {\n continue;\n }\n if (url.protocol !== \"https:\") continue;\n const key = apexOriginOf(url);\n if (!slugs.has(key)) slugs.set(key, product.slug);\n }\n return slugs;\n}\n\n/**\n * The product a video belongs to: its catalog slug, else its bare host.\n *\n * Both surfaces pass a slug map — the chat from its catalog, a published answer page from\n * `ECOSYSTEM_PRODUCTS` — so the host only shows for a site neither of them lists.\n */\nfunction videoProductOf(\n href: string,\n slugs: ReadonlyMap<string, string>,\n): string {\n const url = new URL(href);\n return slugs.get(apexOriginOf(url)) ?? url.hostname.replace(/^www\\./, \"\");\n}\n\n/**\n * True when a link target is a video or caption file, wherever it is. Relative targets are\n * resolved against a placeholder base only so the PATH can be read; nothing is fetched.\n */\nfunction isVideoFileTarget(href: unknown): boolean {\n if (typeof href !== \"string\") return false;\n try {\n return VIDEO_FILE_PATH.test(\n new URL(href, \"https://answer.invalid\").pathname,\n );\n } catch {\n return false;\n }\n}\n\n// ============================================================================\n// Answer text\n// ============================================================================\n\n/** A ``` or ~~~ fence, which opens and closes a verbatim block. */\nconst CODE_FENCE = /^\\s*(?:```|~~~)/;\n/** A GFM table row. Every row the harness writes starts with a pipe (CONTRACT.md §7). */\nconst TABLE_ROW_LINE = /^\\s{0,3}\\|/;\n/** The `| --- | :-: |` row, without which the rows around it are not a table at all. */\nconst TABLE_DELIMITER_ROW = /^\\s{0,3}\\|[\\s:|-]*-[\\s:|-]*$/;\n\n/**\n * Who the stripped text is for. The two differ in exactly three places — links, tables and\n * the product-video line — and nowhere else, which is why they are one function and not two.\n */\ntype ReadableFor = \"clipboard\" | \"speech\";\n\n/*\n * The inline patterns below. Every bracketed part is `[^[\\]]`, not `[^\\]]`: excluding `[`\n * ends each attempt at the next bracket, where `[^\\]]` ran to the end of the line and back\n * for every `[` in it — quadratic on a line of unclosed `[![`. A label with nested brackets\n * matched neither class (its first `]` is not followed by `(`), and an unclosed `[` before a\n * link is now left as the literal bracket CommonMark renders it as, not folded into the label.\n */\n\n/**\n * A link whose whole label is an image: `[](target)` — the product-video line\n * (CONTRACT.md §7) when the target is a video file, a linked illustration otherwise. Captures\n * the alt text and the target.\n */\nconst LINKED_IMAGE =\n /\\[!\\[([^[\\]]*)\\]\\([^)\\s]*(?:\\s+\"[^\"]*\")?\\)\\]\\(([^)\\s]+)(?:\\s+\"[^\"]*\")?\\)/g;\n/** ``. */\nconst IMAGE = /!\\[[^[\\]]*\\]\\([^)\\s]*(?:\\s+\"[^\"]*\")?\\)/g;\n/** `[label](href)`. Captures both. */\nconst LINK = /\\[([^[\\]]+)\\]\\(([^)\\s]+)(?:\\s+\"[^\"]*\")?\\)/g;\n\n/** One line with its inline markup removed. A thematic break comes back as a blank line. */\nfunction readableLine(raw: string, mode: ReadableFor): string {\n let line = raw;\n // Every pattern here needs `](`. Most lines of an answer have none, and skipping them is\n // what keeps a long paragraph of brackets from costing a pass per pattern.\n if (line.includes(\"](\")) {\n // A linked image before images and links, because it is both: taken apart by the two\n // rules below, the image would go as images do and leave `[](https://…)` behind, which\n // no link pattern matches — and a voice would then spell the address out. What is left\n // is a link whose label is the image's alt text: `Planmagnet product video (https://…mp4)`\n // on the clipboard, and nothing in speech, where an image is never read.\n line = line.replace(LINKED_IMAGE, (_match, alt: string, href: string) => {\n if (mode === \"speech\") return \"\";\n return alt.trim() === \"\" ? href : `${alt.trim()} (${href})`;\n });\n // Images before links: `` also matches the link pattern.\n line = line.replace(IMAGE, \"\");\n line =\n mode === \"speech\"\n ? // A voice reading \"h-t-t-p-s colon slash slash…\" mid-sentence is noise, and the\n // prompt asks for two to five links in every answer. The label IS the words.\n line.replace(LINK, \"$1\")\n : line.replace(LINK, \"$1 ($2)\");\n }\n line =\n mode === \"speech\"\n ? line.replace(/<(https?:\\/\\/[^>\\s]+)>/g, \"\")\n : line.replace(/<(https?:\\/\\/[^>\\s]+)>/g, \"$1\");\n line = line.replace(/^\\s{0,3}#{1,6}\\s+/, \"\");\n line = line.replace(/^\\s{0,3}>\\s?/, \"\");\n // A thematic break is a horizontal rule; as text it is three hyphens meaning nothing.\n if (/^\\s{0,3}([-*_])[ \\t]*(?:\\1[ \\t]*){2,}$/.test(line)) return \"\";\n line = line.replace(/`([^`]+)`/g, \"$1\");\n line = line.replace(/\\*\\*([^*]+)\\*\\*/g, \"$1\");\n line = line.replace(/__([^_]+)__/g, \"$1\");\n // Single-delimiter emphasis only when it wraps a run, so a `* ` bullet and a\n // snake_case_identifier are both left alone.\n line = line.replace(/(^|[^*\\w])\\*([^*\\n]+)\\*(?![*\\w])/g, \"$1$2\");\n line = line.replace(/(^|[^_\\w])_([^_\\n]+)_(?![_\\w])/g, \"$1$2\");\n return line.replace(/[ \\t]+$/, \"\");\n}\n\n/**\n * The cells of one table row, in column order.\n *\n * Split by hand rather than with a lookbehind for `\\|`: a lookbehind is a parse error on\n * Safari before 16.4, and a regex literal cannot be caught — the whole bundle fails to load.\n */\nfunction tableCells(row: string): string[] {\n const trimmed = row.trim();\n const cells: string[] = [];\n let cell = \"\";\n for (let at = 0; at < trimmed.length; at += 1) {\n const char = trimmed[at] ?? \"\";\n if (char === \"\\\\\") {\n // An escaped pipe is a pipe in the cell's text, not a column break.\n cell += char + (trimmed[at + 1] ?? \"\");\n at += 1;\n continue;\n }\n if (char === \"|\") {\n cells.push(cell.trim());\n cell = \"\";\n continue;\n }\n cell += char;\n }\n cells.push(cell.trim());\n // `| a | b |` splits to an empty element outside each edge pipe. Only empty ones go: a\n // row whose FIRST cell is genuinely blank keeps it, and so keeps its columns aligned.\n if (trimmed.startsWith(\"|\") && cells[0] === \"\") cells.shift();\n if (trimmed.endsWith(\"|\") && cells[cells.length - 1] === \"\") cells.pop();\n return cells;\n}\n\n/** `a. b` reads as one thought; `a. b.` reads as two finished ones. */\nfunction asSentence(text: string): string {\n return /[.!?]$/.test(text) ? text : `${text}.`;\n}\n\n/**\n * A table as something a voice can say: one sentence per row, every cell under its own\n * column heading, exactly as the phone layout prints it (`AnswerTableRow`, `data-label`).\n * The header row itself is not spoken — it IS the labels — and neither is the `| --- |` row.\n *\n * Rows that are not a table (no delimiter row) are handed back untouched: they render as a\n * paragraph of pipes, and reading them as a table would be reading something nobody can see.\n */\nfunction spokenTable(rows: string[]): string[] {\n if (rows.length < 2 || !TABLE_DELIMITER_ROW.test(rows[1] ?? \"\")) return rows;\n const labels = tableCells(rows[0] ?? \"\");\n const spoken: string[] = [];\n for (const row of rows.slice(2)) {\n const parts: string[] = [];\n tableCells(row).forEach((value, column) => {\n if (value === \"\") return;\n // The first cell is what the row is ABOUT — the plan, or the product. Saying \"Plan:\"\n // in front of the plan's own name adds a word and no information, which is why the\n // card layout hides that label too.\n const label = column === 0 ? \"\" : (labels[column] ?? \"\");\n parts.push(label === \"\" ? value : `${label}: ${value}`);\n });\n if (parts.length > 0) spoken.push(asSentence(parts.join(\". \")));\n }\n return spoken;\n}\n\nfunction readableText(markdown: string, mode: ReadableFor): string {\n const lines: string[] = [];\n let inFence = false;\n let table: string[] = [];\n\n const flushTable = (): void => {\n if (table.length === 0) return;\n for (const line of spokenTable(table)) lines.push(readableLine(line, mode));\n table = [];\n };\n\n for (const raw of markdown.split(\"\\n\")) {\n if (CODE_FENCE.test(raw)) {\n flushTable();\n inFence = !inFence;\n continue;\n }\n if (inFence) {\n lines.push(raw);\n continue;\n }\n // A table has to be read as a block — a cell means nothing without its column heading,\n // which is on another line. Only speech needs that; the clipboard wants the table.\n if (mode === \"speech\" && TABLE_ROW_LINE.test(raw)) {\n table.push(raw);\n continue;\n }\n flushTable();\n lines.push(readableLine(raw, mode));\n }\n flushTable();\n\n return lines\n .join(\"\\n\")\n .replace(/\\n{3,}/g, \"\\n\\n\")\n .trim();\n}\n\n/**\n * An answer as READABLE TEXT, for the clipboard.\n *\n * What counts as \"our internal markup artefacts\", and why each choice:\n *\n * - **Image embeds go.** `` is a picture this\n * page injected into the answer; pasted into an email it is a URL and an alt string, and\n * neither is the answer. The caption line the backend writes under it is ordinary prose and\n * stays.\n * - **Links become `label (url)`.** The destination is information the reader may need; the\n * bracket-paren syntax is not. Dropping the URL would quietly strip the page it came from.\n * - **A linked image is a link like any other**, labelled by the image's alt text — so the\n * product video is `Planmagnet product video (https://…mp4)`. The image itself goes as\n * every image does; the link is kept because, unlike a bare illustration, it is somewhere\n * the reader can GO — and a pasted answer has no card to click.\n * - **Citation markers `[3]` stay.** They are the only attribution the copied text carries,\n * and they are the answer's own — not something the UI added. The sources they point at are\n * listed right next to the button that copied this.\n * - **Emphasis, headings, blockquote and rule markers go**, because `**` and `###` are\n * instructions to a renderer, not words.\n * - **A table keeps its pipes.** Pasted into a README, an issue or a chat it is a table\n * again; flattened into sentences it is not.\n * - **Fenced code is verbatim**, fences included, minus nothing but the fence lines\n * themselves: stripping `*` or `_` inside a code block would corrupt the code.\n *\n * Built from `message.content` rather than from the rendered DOM: `textContent` on the bubble\n * would fold every paragraph, list item and table cell into one run-on line.\n */\nexport function answerPlainText(markdown: string): string {\n return readableText(markdown, \"clipboard\");\n}\n\n/**\n * The same answer as something to SAY, for read-aloud.\n *\n * It shares every rule above but the three that are right for a paste and wrong for a voice:\n *\n * - **A link is its label.** The clipboard keeps `label (https://…)` because a pasted answer\n * loses the page otherwise. Spoken, that is a URL spelled out character by character in\n * the middle of a sentence — and the prompt asks for two to five links in every answer, so\n * it is not an edge case. The sources are listed under the answer either way.\n * - **A linked image is not read at all** — the product video included. Its label is a\n * picture, which is never read, and its link is an address; the card or illustration is\n * on screen for anyone who can click it.\n * - **A table is read as rows, not as pipes.** `| --- | --- |` is a line of punctuation and\n * the pipes are column rules, neither of which is a word. Each row is read with its cells\n * under their own column headings — the phone layout, out loud — so a plan list still says\n * which number is the price. Comparisons and plan lists are exactly the answers the\n * feature was built for (CONTRACT.md §7), which is what makes this worth a second mode.\n *\n * Everything else stays deliberately identical, including citation markers: they are the\n * answer's own attribution in both, and a listener hearing \"two\" after a claim is hearing\n * the same thing a reader sees.\n */\nexport function answerSpeechText(markdown: string): string {\n return readableText(markdown, \"speech\");\n}\n\n/**\n * The strings the markdown overrides render.\n *\n * Deliberately a handful of fields rather than the whole `ExploreStrings`: the chat and a\n * published answer page carry different chrome vocabularies, and these are the only words\n * the ANSWER itself needs — including the product-video card and the player it opens.\n * `ExploreStrings` satisfies this structurally, so the chat passes its own `T` unchanged.\n */\nexport interface AnswerRendererStrings extends ExploreVideoStrings {\n /** Accessible name of the scrollable box a table sits in. */\n answerTable: string;\n /** The badge laid over a concept illustration embedded in an answer. */\n conceptIllustration: string;\n /** Read out after a link that opens a new tab. */\n opensInNewTab: string;\n /** The badge on a product-video card, and its name when the answer gave the video none. */\n productVideo: string;\n /**\n * A product video's name, in the page's language. Takes `{product}`, read out of the\n * English `<Name> product video` alt text the canonical line always carries.\n */\n productVideoTitle: string;\n /** Accessible name of the card's play button. Takes `{title}`. */\n playVideo: string;\n}\n\n/**\n * What one answer's markdown overrides share. Provided by {@link ExploreAnswerBody}.\n *\n * The overrides are module-level components (see `ANSWER_MARKDOWN_COMPONENTS`), so this\n * context is the only way per-answer state reaches them.\n */\nexport interface AnswerScope {\n strings: AnswerRendererStrings;\n /**\n * True once the answer is COMPLETED. A streaming preview is cut mid-token, so an image URL\n * in it may be half-written (fetching it would request a truncated path), and the backend\n * has not yet dropped the images it does not allow.\n */\n enabled: boolean;\n /** Origins an image may come from — see `inlineImageOrigins`. */\n origins: ReadonlySet<string>;\n /** Apex origin → catalog slug, for a video card's `data-product`. May be empty. */\n productSlugs: ReadonlyMap<string, string>;\n /** Sources in this answer that failed to load. They stay hidden while it is on screen. */\n failed: ReadonlySet<string>;\n onFailed: (src: string) => void;\n}\n\nexport const AnswerScopeContext = createContext<AnswerScope | null>(null);\n\n/** True inside a markdown link, where an image must not open a second link of its own. */\nconst InsideLinkContext = createContext(false);\n\n/**\n * A link in an answer — or, when it is a product-video line, the video card or nothing.\n *\n * Which links are video lines was decided on the whole tree by {@link rehypeProductVideo}\n * before any of this renders; here that decision is only read. So the card appears once, for\n * the first paragraph-level video line whose file and poster are on one catalog site, and:\n *\n * - **Streaming renders nothing for it.** Both backends strip the line, and a half-written\n * tail of it, from partials, and the reveal holds a half-written link back at its opening\n * bracket while it is behind. A whole line that arrives anyway renders nothing here, so\n * the card mounts once, when the answer completes, rather than swapping in for text.\n * - **Every other video line renders nothing**: a second one, one that fails the allow-list,\n * and one in a table, a list or a heading. §7 has the sanitiser remove each of those; this\n * is the browser's own check, and a link to a raw video file — or an empty `<a>` around a\n * refused poster — is not a fallback worth drawing.\n * - **Every ordinary link is the link it always was.** Never a raw `<video>` in the\n * transcript.\n */\nfunction AnswerLink(props: ComponentProps<\"a\"> & ExtraProps) {\n const scope = useContext(AnswerScopeContext);\n const role = videoRoleOf(props.node);\n if (role !== undefined && scope !== null) {\n const video =\n role === \"card\" && scope.enabled ? productVideoOf(props.node) : null;\n if (video === null) return null;\n return (\n <InlineVideoCard\n href={video.href}\n poster={video.poster}\n alt={video.alt}\n scope={scope}\n />\n );\n }\n return (\n <InsideLinkContext.Provider value={true}>\n <MarkdownLink {...props} />\n </InsideLinkContext.Provider>\n );\n}\n\nconst INLINE_IMAGE_FRAME =\n \"relative inline-block max-w-full overflow-hidden rounded-xl border border-border bg-muted align-top shadow-sm\";\n\n/**\n * A concept illustration inside an answer — the markdown `img` override.\n *\n * It sits inside a `<p>` and may only use phrasing content, hence a block-level `<span>`, not\n * a `<div>` or `<figure>`. The picture links to the full-size file in a new tab, unless the\n * markdown already wraps it in a link (`[](page)`): an `<a>` inside an `<a>` is\n * invalid, and the inner one would swallow every click meant for the outer. The backend\n * writes the caption line under each image; nothing here repeats it. An image that fails to\n * load removes the whole block rather than leaving a broken frame in the answer.\n */\nfunction InlineConceptImage({ src, alt }: ComponentProps<\"img\"> & ExtraProps) {\n const scope = useContext(AnswerScopeContext);\n const insideLink = useContext(InsideLinkContext);\n if (\n !scope ||\n !scope.enabled ||\n !isInlineImageAllowed(src, scope.origins) ||\n scope.failed.has(src)\n ) {\n return null;\n }\n const { strings: T, onFailed } = scope;\n\n const picture = (\n <>\n <img\n src={src}\n alt={alt ?? \"\"}\n loading=\"lazy\"\n decoding=\"async\"\n onError={() => onFailed(src)}\n className=\"block h-auto max-h-80 w-auto max-w-full object-contain\"\n />\n <span\n aria-hidden=\"true\"\n 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\"\n >\n {T.conceptIllustration}\n </span>\n </>\n );\n\n return (\n <span data-boff-explore=\"inline-image\" className=\"my-3 block\">\n {insideLink ? (\n <span className={INLINE_IMAGE_FRAME}>{picture}</span>\n ) : (\n <a\n href={src}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className={cn(\n INLINE_IMAGE_FRAME,\n \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\",\n )}\n >\n {picture}\n <span className=\"sr-only\">({T.opensInNewTab})</span>\n </a>\n )}\n </span>\n );\n}\n\n// ============================================================================\n// Comparison and pricing tables\n// ============================================================================\n\n/**\n * The parts of a markdown (hast) node these overrides read.\n *\n * Declared structurally rather than imported from `hast`: `ElementContent` is a union whose\n * text and comment members have no `tagName`, so reading one off the imported type is an\n * error at every use site. Every hast node satisfies this by construction.\n */\ninterface MarkdownNode {\n tagName?: string;\n value?: string;\n properties?: Record<string, unknown>;\n children?: MarkdownNode[];\n /**\n * hast's slot for information that is never rendered — {@link rehypeProductVideo} writes\n * here. `unknown` because other plugins own the rest of it: read through `videoRoleOf`.\n */\n data?: unknown;\n}\n\n/** A node's text, for a column label. Cells carry inline markdown; the label is its words. */\nfunction markdownText(node: MarkdownNode | undefined): string {\n if (!node) return \"\";\n if (typeof node.value === \"string\") return node.value;\n return (node.children ?? []).map(markdownText).join(\"\");\n}\n\nfunction hasHeaderCells(node: MarkdownNode | undefined): boolean {\n return (node?.children ?? []).some((cell) => cell.tagName === \"th\");\n}\n\nfunction findHeaderRow(node: MarkdownNode | undefined): MarkdownNode | null {\n for (const child of node?.children ?? []) {\n if (child.tagName === \"tr\" && hasHeaderCells(child)) return child;\n const nested = findHeaderRow(child);\n if (nested !== null) return nested;\n }\n return null;\n}\n\n/** The table's column headings, in column order. Empty for a table that has none. */\nfunction tableColumnLabels(node: MarkdownNode | undefined): string[] {\n const row = findHeaderRow(node);\n if (row === null) return [];\n return (row.children ?? [])\n .filter((cell) => cell.tagName === \"th\")\n .map((cell) => markdownText(cell).trim());\n}\n\n/**\n * The column headings of the table currently being rendered, for the rows inside it.\n *\n * A cell has no way to know which column it is in — react-markdown hands each override its\n * own node and nothing else — so the table publishes the labels and the ROW, which does know\n * the order of its children, attaches one to each cell.\n */\nconst TableColumnsContext = createContext<readonly string[]>([]);\n\n/**\n * A comparison or pricing table inside an answer.\n *\n * A table is the one thing a model emits that can make a marketing page scroll SIDEWAYS —\n * one over-wide child makes the whole document horizontally scrollable, not just the bubble\n * — so it is wrapped in a box that is `max-width: 100%` and scrolls inside itself. The\n * wrapper is a labelled region with a tab stop because a scrollable box that only a mouse\n * can reach hides its off-screen columns from a keyboard visitor entirely.\n *\n * Under 30rem the stylesheet turns the same markup into one card per row, each cell labelled\n * with its column heading — see `data-label` below. A five-column comparison is unreadable\n * at 320px whichever way it scrolls.\n */\nfunction AnswerTable({ node, children }: ComponentProps<\"table\"> & ExtraProps) {\n const scope = useContext(AnswerScopeContext);\n const table = (\n <TableColumnsContext.Provider value={tableColumnLabels(node)}>\n <table>{children}</table>\n </TableColumnsContext.Provider>\n );\n // Rendered outside an answer there is nothing to name the region in the visitor's\n // language, and an unnamed region is worse than none — the table itself is unchanged.\n if (!scope) return table;\n return (\n <div\n data-boff-explore=\"table\"\n role=\"region\"\n aria-label={scope.strings.answerTable}\n tabIndex={0}\n className=\"boff-explore-table\"\n >\n {table}\n </div>\n );\n}\n\n/**\n * One row, with each of its cells told which column it is in.\n *\n * The label is what the stacked phone layout prints above the value; on a wide screen the\n * attribute is inert. The header row is left exactly as it is — it IS the labels.\n */\nfunction AnswerTableRow({\n node,\n children,\n ...props\n}: ComponentProps<\"tr\"> & ExtraProps) {\n const labels = useContext(TableColumnsContext);\n if (labels.length === 0 || hasHeaderCells(node)) {\n return <tr {...props}>{children}</tr>;\n }\n\n // Counted over ELEMENTS only: react-markdown puts the source's whitespace between cells\n // in as text children, and counting those would shift every label by a column.\n let column = 0;\n const cells = Children.map(children, (cell) => {\n if (!isValidElement(cell)) return cell;\n const label = labels[column] ?? \"\";\n column += 1;\n if (label === \"\") return cell;\n // The cast names the props bag we are adding to; `isValidElement` narrows to\n // `ReactElement<unknown>`, which cannot accept an extra attribute.\n return cloneElement(cell as ReactElement<Record<string, unknown>>, {\n \"data-label\": label,\n });\n });\n return <tr {...props}>{cells}</tr>;\n}\n\n// ============================================================================\n// Product-video cards\n// ============================================================================\n\n/**\n * \"card\" for the one video line in an answer that becomes a card; \"drop\" for every other\n * video line, which renders nothing.\n */\ntype ProductVideoRole = \"card\" | \"drop\";\n\n/** A link whose only content (whitespace aside) is an image — `[](href)`. */\nfunction linkedImageOf(\n node: MarkdownNode | undefined,\n): { href: unknown; src: unknown; alt: string } | null {\n if (node?.tagName !== \"a\") return null;\n const content = (node.children ?? []).filter(\n (child) => child.tagName !== undefined || (child.value ?? \"\").trim() !== \"\",\n );\n const image = content.length === 1 ? content[0] : undefined;\n if (image?.tagName !== \"img\") return null;\n const alt = image.properties?.alt;\n return {\n href: node.properties?.href,\n src: image.properties?.src,\n alt: typeof alt === \"string\" ? alt.trim() : \"\",\n };\n}\n\n/**\n * True when a video line may be the card: a playable file and an image poster, both on a\n * catalog site — and the SAME site. §7 puts both on the product's own origin, so a poster\n * borrowed from one product in front of another's video is not that product's line.\n */\nfunction isCardableVideo(\n embed: { href: unknown; src: unknown },\n origins: ReadonlySet<string>,\n): boolean {\n if (\n !isInlineVideoAllowed(embed.href, origins) ||\n !isInlineImageAllowed(embed.src, origins)\n ) {\n return false;\n }\n return apexOriginOf(new URL(embed.href)) === apexOriginOf(new URL(embed.src));\n}\n\n/**\n * Elements a video line may not become a card inside. §7 keeps a video out of every table,\n * and the canonical line is a paragraph of its own — a list item (tight or loose) is not.\n */\nconst NO_VIDEO_CONTAINERS: ReadonlySet<string> = new Set([\"li\", \"table\"]);\n\n/**\n * Marks the product-video lines in an answer, on the whole tree, in document order.\n *\n * A rehype pass rather than a check inside the `a` override, because \"at most ONE card per\n * answer\" is a question about the whole answer and an override only ever sees its own node.\n * Counting in the overrides instead would mean mutating shared state during render, which\n * StrictMode and concurrent rendering both replay.\n *\n * A video line is any linked image whose target is a video or caption file. The first one\n * that sits directly in a paragraph — not a table, a list item or a heading — and passes\n * {@link isCardableVideo} is marked \"card\"; every other one is marked \"drop\", whatever its\n * URL, since a second video is a second player for one question and a failed one has no\n * honest fallback. Only the mark decides: an unmarked link renders as a link.\n *\n * It runs after `rehype-sanitize` and only writes `data`, which is never rendered.\n */\nfunction rehypeProductVideo(options: { origins: ReadonlySet<string> }) {\n return (tree: MarkdownNode): void => {\n let claimed = false;\n const visit = (\n node: MarkdownNode,\n parent: MarkdownNode | null,\n contained: boolean,\n ): void => {\n const embed = linkedImageOf(node);\n if (embed !== null && isVideoFileTarget(embed.href)) {\n const card =\n !claimed &&\n !contained &&\n parent?.tagName === \"p\" &&\n isCardableVideo(embed, options.origins);\n if (card) claimed = true;\n const data = typeof node.data === \"object\" ? node.data : null;\n node.data = { ...data, boffVideo: card ? \"card\" : \"drop\" };\n return;\n }\n const inside =\n contained ||\n (node.tagName !== undefined && NO_VIDEO_CONTAINERS.has(node.tagName));\n for (const child of node.children ?? []) visit(child, node, inside);\n };\n visit(tree, null, false);\n };\n}\n\n/** The mark {@link rehypeProductVideo} left on a node, if any. */\nfunction videoRoleOf(\n node: MarkdownNode | undefined,\n): ProductVideoRole | undefined {\n const data = node?.data;\n if (typeof data !== \"object\" || data === null || !(\"boffVideo\" in data)) {\n return undefined;\n }\n return data.boffVideo === \"card\" || data.boffVideo === \"drop\"\n ? data.boffVideo\n : undefined;\n}\n\n/** What the `a` override needs to draw the video card, read off the node the pass marked. */\nfunction productVideoOf(node: MarkdownNode | undefined): {\n href: string;\n poster: string;\n alt: string;\n} | null {\n const embed = linkedImageOf(node);\n if (\n embed === null ||\n typeof embed.href !== \"string\" ||\n typeof embed.src !== \"string\"\n ) {\n return null;\n }\n return { href: embed.href, poster: embed.src, alt: embed.alt };\n}\n\n/**\n * The `<Name> product video` alt text the canonical line carries (§7). The harness writes it\n * in English whatever the page's language, so the card reads the name out of it and says the\n * rest in the visitor's.\n */\nconst CANONICAL_VIDEO_ALT = /^(.+?)\\s+product video$/i;\n\n/**\n * A video's name in the page's language: the product's name in `productVideoTitle` when the\n * alt is the canonical one, the alt as written when it is anything else, and the badge's\n * words when there is none.\n */\nfunction videoTitleOf(alt: string, T: AnswerRendererStrings): string {\n const product = CANONICAL_VIDEO_ALT.exec(alt)?.[1]?.trim();\n if (product) return fill(T.productVideoTitle, { product });\n return alt === \"\" ? T.productVideo : alt;\n}\n\n/** The 16:9 frame, reserved before the poster loads so the answer does not jump under it. */\nconst INLINE_VIDEO_FRAME =\n \"group relative block aspect-video w-full max-w-md overflow-hidden rounded-xl border border-border bg-muted shadow-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\";\n\n/**\n * A product video inside an answer: a poster card that opens the player.\n *\n * Phrasing content only — it sits in the `<p>` the canonical line is written as — so a block\n * `<span>` around a `<button>`. There is deliberately no `<video>` here: the player, and the\n * request for the file, exist only once the visitor asks for them (`ExploreVideoDialog`).\n *\n * A poster that fails to load turns into a plate with a film icon rather than removing the\n * card, unlike an illustration: the poster is decoration on a control, and the video behind\n * it may be perfectly playable.\n */\nfunction InlineVideoCard({\n href,\n poster,\n alt,\n scope,\n}: {\n href: string;\n poster: string;\n /** The line's alt text, as the harness wrote it — see {@link videoTitleOf}. */\n alt: string;\n scope: AnswerScope;\n}) {\n const { strings: T, failed, onFailed, productSlugs } = scope;\n /** The page's direction while the player is open; null while it is closed. */\n const [dialogDir, setDialogDir] = useState<\"ltr\" | \"rtl\" | null>(null);\n const buttonRef = useRef<HTMLButtonElement>(null);\n const returnFocusRef = useRef(false);\n const open = dialogDir !== null;\n\n // Focus goes back to the card that opened the player — not to the top of the page, which\n // would strand a keyboard visitor far from the answer they were reading.\n useEffect(() => {\n if (open || !returnFocusRef.current) return;\n returnFocusRef.current = false;\n const button = buttonRef.current;\n if (button?.isConnected) button.focus();\n }, [open]);\n\n const openPlayer = useCallback((event: MouseEvent<HTMLButtonElement>) => {\n // The player is portalled out of the subtree that set `dir=\"rtl\"` in Arabic, so it\n // takes the direction with it from here.\n const dir = event.currentTarget.closest(\"[dir]\")?.getAttribute(\"dir\");\n returnFocusRef.current = true;\n setDialogDir(dir === \"rtl\" ? \"rtl\" : \"ltr\");\n }, []);\n const closePlayer = useCallback(() => setDialogDir(null), []);\n\n const name = videoTitleOf(alt, T);\n const posterFailed = failed.has(poster);\n\n return (\n <span\n data-boff-explore=\"inline-video\"\n data-product={videoProductOf(href, productSlugs)}\n className=\"my-3 block\"\n >\n <button\n ref={buttonRef}\n type=\"button\"\n aria-haspopup=\"dialog\"\n aria-label={fill(T.playVideo, { title: name })}\n onClick={openPlayer}\n className={INLINE_VIDEO_FRAME}\n >\n {posterFailed ? (\n <span\n aria-hidden=\"true\"\n className=\"absolute inset-0 flex items-center justify-center bg-muted text-muted-foreground\"\n >\n <Film className=\"h-10 w-10\" />\n </span>\n ) : (\n <img\n src={poster}\n // The button's own name says what this is; an alt here would say it twice.\n alt=\"\"\n loading=\"lazy\"\n decoding=\"async\"\n onError={() => onFailed(poster)}\n className=\"boff-explore-video-poster absolute inset-0 h-full w-full object-cover\"\n />\n )}\n <span\n aria-hidden=\"true\"\n className=\"pointer-events-none absolute inset-0 flex items-center justify-center\"\n >\n <span className=\"flex h-14 w-14 items-center justify-center rounded-full border border-border bg-background/90 text-foreground shadow-md transition-transform group-hover:scale-105\">\n <Play className=\"h-6 w-6 fill-current\" />\n </span>\n </span>\n <span\n aria-hidden=\"true\"\n className=\"pointer-events-none absolute start-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\"\n >\n {T.productVideo}\n </span>\n </button>\n {open ? (\n <ExploreVideoDialog\n videoUrl={href}\n posterUrl={poster}\n title={name}\n strings={T}\n dir={dialogDir}\n onClose={closePlayer}\n />\n ) : null}\n </span>\n );\n}\n\n/**\n * Markdown overrides for answers. Module-level on purpose: react-markdown uses each override\n * as the element TYPE, so one re-created on render (in a memo on the catalog, say) is a new\n * component to React, and every image under it remounts — fetched again, and back on screen\n * after it had been hidden for failing to load. Per-answer state reaches the overrides\n * through `AnswerScopeContext` instead.\n */\nexport const ANSWER_MARKDOWN_COMPONENTS: Components = {\n a: AnswerLink,\n img: InlineConceptImage,\n table: AnswerTable,\n tr: AnswerTableRow,\n};\n\n// ============================================================================\n// The body\n// ============================================================================\n\n/** The default for `productSlugs`: one shared empty map, so the scope stays memoised. */\nconst NO_PRODUCT_SLUGS: ReadonlyMap<string, string> = new Map();\n\nexport interface ExploreAnswerBodyProps {\n /** The answer, exactly as the harness wrote it: GitHub-flavoured markdown. */\n children: string;\n /** The strings the overrides render. `ExploreStrings` satisfies this. */\n strings: AnswerRendererStrings;\n /** Origins an inline image may come from — see {@link inlineImageOrigins}. */\n imageOrigins: ReadonlySet<string>;\n /**\n * Origins a product video and its poster may come from. Defaults to `imageOrigins`, which\n * in the chat is already every catalog site. A published answer page allows fewer images\n * than that and passes the whole catalog here: the video is the product's own file, and is\n * never one of the sources the page's image list is built from. Pass a stable set.\n */\n videoOrigins?: ReadonlySet<string>;\n /**\n * Apex origin → catalog slug (see {@link productSlugsByOrigin}), so a video card can name\n * its product in `data-product`. Without it the card names the file's host instead. Pass a\n * stable map.\n */\n productSlugs?: ReadonlyMap<string, string>;\n /**\n * False while the answer is still streaming, which suppresses its images and its video\n * card: a partial is cut mid-token, so a URL in it may be half-written, and the backend has\n * not yet dropped what it does not allow. A settled answer — every published one — is\n * `true`.\n */\n enabled?: boolean;\n /**\n * Extra markdown overrides, merged OVER the shared ones.\n *\n * Pass a module-level constant, never an object built during render: react-markdown uses an\n * override as the element TYPE, so a component re-created on every render remounts\n * everything under it — an image would be fetched again, and one that had been hidden for\n * failing to load would come back.\n */\n components?: Components;\n /** Extra classes for the prose wrapper. */\n className?: string;\n}\n\n/**\n * An answer, rendered.\n *\n * The wrapper carries `boff-prose` and `boff-explore-body`: the first styles ordinary\n * markdown, the second is what every rule in {@link EXPLORE_ANSWER_CSS} is scoped to. A page\n * that renders this must also mount `<ProseStyles />` and `<ExploreAnswerStyles />`, or a\n * wide table has nothing holding it inside the page.\n *\n * The set of images that failed to load is held HERE rather than in each image, so a source\n * that 404s stays hidden even when the markdown re-renders from scratch underneath it.\n */\nexport function ExploreAnswerBody({\n children,\n strings,\n imageOrigins,\n videoOrigins = imageOrigins,\n productSlugs = NO_PRODUCT_SLUGS,\n enabled = true,\n components,\n className,\n}: ExploreAnswerBodyProps) {\n const [failed, setFailed] = useState<ReadonlySet<string>>(() => new Set());\n const onFailed = useCallback((src: string) => {\n setFailed((current) =>\n current.has(src) ? current : new Set(current).add(src),\n );\n }, []);\n\n const scope = useMemo<AnswerScope>(\n () => ({\n strings,\n enabled,\n origins: imageOrigins,\n productSlugs,\n failed,\n onFailed,\n }),\n [strings, enabled, imageOrigins, productSlugs, failed, onFailed],\n );\n\n // Plugins are not element types, so a new list does not remount anything; memoised only\n // so an unrelated re-render does not rebuild it.\n const rehypePlugins = useMemo<Options[\"rehypePlugins\"]>(\n () => [[rehypeProductVideo, { origins: videoOrigins }]],\n [videoOrigins],\n );\n\n const overrides = useMemo(\n () =>\n components\n ? { ...ANSWER_MARKDOWN_COMPONENTS, ...components }\n : ANSWER_MARKDOWN_COMPONENTS,\n [components],\n );\n\n return (\n <div className={cn(\"boff-prose boff-explore-body min-w-0\", className)}>\n <AnswerScopeContext.Provider value={scope}>\n <Markdown components={overrides} rehypePlugins={rehypePlugins}>\n {children}\n </Markdown>\n </AnswerScopeContext.Provider>\n </div>\n );\n}\n","/**\n * One Explore conversation, shareable between the `/explore` page and the site-wide assistant panel (BOFF-9697).\n *\n * `ExplorePage` has always owned its conversation: it calls `useExploreChat` and keeps the composer's draft and\n * staged attachments in its own state, so the conversation lives exactly as long as the page is mounted. A site that\n * also offers the compact panel needs ONE conversation for both, or the panel and the page would each poll, persist\n * and lose a running answer on their own. `ExploreChatProvider` lifts that same setup (`useExploreConversation`) above\n * the site's routes; under it, every `ExplorePage` and the `ExplorePanel` use the provider's conversation instead of\n * their own. Without a provider nothing changes: `ExplorePage` sets up its own conversation exactly as before.\n *\n * Import from the package ROOT, like `ExplorePage`: tsup's `splitting: false` gives each entry its own copy of a\n * module, and a context created twice is two contexts.\n */\n\"use client\";\n\nimport {\n createContext,\n useCallback,\n useMemo,\n useState,\n type Dispatch,\n type ReactNode,\n type SetStateAction,\n} from \"react\";\n\nimport { exploreStrings, resolveExploreLocale } from \"./explore-i18n\";\nimport {\n useExploreChat,\n type UseExploreChatResult,\n} from \"../hooks/use-explore-chat\";\n\nimport type { ExploreProduct } from \"./explore-types\";\nimport type { StagedAttachment } from \"../utils/explore-attachments\";\n\n/** One conversation and the composer state that belongs to it: what a page and a panel share. */\nexport interface ExploreConversationState extends UseExploreChatResult {\n /** The composer's text, kept with the conversation so it survives Expand, Restore and a route change. */\n readonly draft: string;\n readonly setDraft: Dispatch<SetStateAction<string>>;\n /** Files staged for the next question, kept the same way. */\n readonly staged: StagedAttachment[];\n readonly setStaged: Dispatch<SetStateAction<StagedAttachment[]>>;\n}\n\nexport interface ExploreConversationOptions {\n /** Slug of the product site — a soft hint to the harness. */\n productSlug?: string;\n /** BCP-47 locale for the fallback welcome and example prompts (the six product locales). */\n locale?: string;\n /** Example prompts when `exploreCatalog` supplies none. */\n examplePrompts?: string[];\n /** Fired with the message text every time a send is accepted. */\n onSend?: (message: string) => void;\n /**\n * The page the visitor is on, forwarded with each question. Default: the URL when the conversation was set up\n * (what `ExplorePage` has always sent). A site-wide provider passes the current one.\n */\n pageUrl?: string;\n /** See `UseExploreChatOptions.enabled`. Default `true`. */\n enabled?: boolean;\n /**\n * See `UseExploreChatOptions.shareToken`. Unset: read from the URL, as `ExplorePage` always has. A site-wide\n * provider passes the `?c=` token of the route showing `/explore` (`null` elsewhere), and is given that token as its\n * `key`, so a different shared link starts its own conversation.\n */\n shareToken?: string | null;\n}\n\n/** The provider's conversation, or null when there is none (then each `ExplorePage` keeps its own). */\nexport const ExploreConversationContext =\n createContext<ExploreConversationState | null>(null);\n\n/**\n * The provider's catalog products alone, or null without a provider (BOFF-9796): what `ExplorePanel` names its product\n * from in the product scope. A context of its own because the conversation's value changes with every keystroke and\n * every streamed answer, and the panel, which only needs a name, must not re-render with them. This one changes only\n * when the catalog does.\n */\nexport const ExploreCatalogProductsContext = createContext<\n readonly ExploreProduct[] | null\n>(null);\n\n/**\n * BOFF-9797. Starts the provider's conversation (the same latch as its `enabled`), or null when there is no provider.\n * What `SiteAssistantDock` calls on the visitor's first opening, so a host using the dock passes `enabled` for its\n * `/explore` route only. A context of its own, like the one above, because its value never changes: a component that\n * only needs to start the conversation must not re-render with every keystroke and every streamed answer. Internal:\n * not exported from any entry.\n */\nexport const ExploreConversationStartContext = createContext<\n (() => void) | null\n>(null);\n\n/**\n * The conversation exactly as `ExplorePage` sets it up for itself: the same `useExploreChat` options (the locale's\n * fallback welcome and prompts, the URL at mount), plus the composer's draft and staged files.\n */\nexport function useExploreConversation(\n options: ExploreConversationOptions = {},\n): ExploreConversationState {\n const {\n productSlug,\n locale,\n examplePrompts,\n onSend,\n pageUrl,\n enabled,\n shareToken,\n } = options;\n const urlAtMount = useMemo(\n () => (typeof window === \"undefined\" ? undefined : window.location.href),\n [],\n );\n const T = useMemo(\n () => exploreStrings(resolveExploreLocale(locale)),\n [locale],\n );\n const chat = useExploreChat({\n productSlug,\n pageUrl: pageUrl ?? urlAtMount,\n onSend,\n // Locale-aware, so a catalog outage degrades to a translated welcome rather than an English one.\n examplePrompts: examplePrompts ?? T.prompts,\n fallbackWelcome: { title: T.welcomeTitle, body: T.welcomeBody },\n ...(enabled === undefined ? {} : { enabled }),\n ...(shareToken === undefined ? {} : { shareToken }),\n });\n const [draft, setDraft] = useState(\"\");\n const [staged, setStaged] = useState<StagedAttachment[]>([]);\n return useMemo(\n () => ({ ...chat, draft, setDraft, staged, setStaged }),\n [chat, draft, staged],\n );\n}\n\nexport interface ExploreChatProviderProps extends Omit<\n ExploreConversationOptions,\n \"enabled\" | \"shareToken\"\n> {\n /**\n * Start the conversation. Pass `true` from the visitor's first opening of the assistant, or while the `/explore`\n * route is shown; until then the provider asks nothing (no catalog request, no restore). Latched: once it has been\n * `true` the conversation stays live, so a running answer is never cut by the host flipping it back. Under a\n * `SiteAssistantDock` the dock starts it on its first opening (BOFF-9797): pass `true` on the `/explore` route only.\n */\n enabled: boolean;\n /**\n * The `?c=` share token of the route showing `/explore`, from the host's router, and `null` on every other route.\n * Required: the provider outlives every page, so reading `?c=` from whatever page it first mounted on would turn an\n * unrelated `?c=` into a \"shared conversation not found\", and keep a real one for the rest of the visit.\n */\n shareToken: string | null;\n children?: ReactNode;\n}\n\n/**\n * ONE conversation for the whole site (BOFF-9697). Mount it once, above the routes (inside the router, so the host\n * can pass the current `pageUrl` and `shareToken`), and put the `ExplorePanel` and every `ExplorePage` under it.\n * Key it by `shareToken`: a shared link is its own read-only conversation, and leaving it returns to the visitor's.\n */\nexport function ExploreChatProvider({\n enabled,\n children,\n ...options\n}: ExploreChatProviderProps) {\n const [started, setStarted] = useState(enabled);\n // Latch during render (React's documented pattern for state derived from a prop), so the first enabled render is\n // already live: on `/explore` the conversation starts with the page, as it always has.\n if (enabled && !started) setStarted(true);\n const conversation = useExploreConversation({\n ...options,\n // `enabled` as well as `started`: on the render that first sees `enabled`, the latch above has only been queued.\n enabled: enabled || started,\n });\n // BOFF-9797: the same latch, for `SiteAssistantDock`'s first opening. Stable for the provider's life.\n const start = useCallback(() => setStarted(true), []);\n return (\n <ExploreConversationStartContext.Provider value={start}>\n <ExploreConversationContext.Provider value={conversation}>\n <ExploreCatalogProductsContext.Provider\n value={conversation.catalog.products}\n >\n {children}\n </ExploreCatalogProductsContext.Provider>\n </ExploreConversationContext.Provider>\n </ExploreConversationStartContext.Provider>\n );\n}\n","/**\n * The product scope of the Explore assistant (BOFF-9796).\n *\n * Every site's assistant has been the PORTFOLIO's: the whole catalogue in a \"Focus on a product\" picker, every\n * product's concept illustrations, and the catalog's copy, which is written for all the sites at once (\"compare it\n * with anything else we build\", \"Compare Bigconsole and Fluidgrids\"). A product site can make it that product's own\n * instead, with `scope=\"product\"` on `ExplorePage` and `ExplorePanel`: the focus pinned to its `productSlug`, and\n * nothing the SDK renders around the conversation naming another product.\n *\n * These are the rules both components share, in one place so the panel's title and the chat view under it cannot\n * disagree about which product they belong to. The default scope never reaches any of them.\n *\n * Answers are the backend's and are rendered as they come: an answer, and the sources listed under it, may name\n * another product when the visitor asks about one.\n */\nimport { isPortfolioPrompt } from \"./explore-i18n\";\nimport { isSameProductSlug, productSlugVariants } from \"../utils/product-slug\";\n\nimport type { ExploreConceptHighlight, ExploreProduct } from \"./explore-types\";\nimport type { ExploreChatError } from \"../hooks/use-explore-chat\";\n\n/** Whose assistant this is: the portfolio's (the default, on every site), or one product's own. */\nexport type ExploreScope = \"portfolio\" | \"product\";\n\n/** What the scope rules read from a catalog product. `website` is optional: the SDK's own list names it otherwise. */\nexport type ExploreScopeProduct = Pick<ExploreProduct, \"slug\" | \"name\"> & {\n website?: string | null;\n};\n\n/**\n * The product a view is pinned to: its `productSlug`, in the product scope. Null for the portfolio, and for a product\n * scope given no slug, which has no product to pin to and stays the portfolio (see `warnProductScopeWithoutSlug`).\n * The slug is returned as given, so a question carries exactly the `productSlug` it always has.\n */\nexport function pinnedProductSlug(\n scope: ExploreScope | undefined,\n productSlug: string | undefined,\n): string | null {\n if (scope !== \"product\" || productSlug === undefined) return null;\n return productSlug.trim() === \"\" ? null : productSlug;\n}\n\n/** The product's display name: the host's own, else the catalog's for that slug. Null when neither knows it. */\nexport function productNameFor(\n products: readonly ExploreScopeProduct[],\n slug: string,\n given?: string,\n): string | null {\n const own = given?.trim();\n if (own) return own;\n return (\n products.find((product) => isSameProductSlug(product.slug, slug))?.name ??\n null\n );\n}\n\n/**\n * Product names are written in the Latin script in all six locales, so a spelling is a whole word when the characters\n * either side of it are not Latin letters or digits. A space, punctuation, or Chinese or Arabic text beside it all\n * count as a boundary: `比较Bigconsole和Fluidgrids` names both.\n */\nconst NAME_CHARACTER = /[a-z0-9]/;\n\n/** Shorter than this, a spelling would match ordinary words; no product has a name that short. */\nconst MIN_SPELLING_LENGTH = 3;\n\n/** `burdenoff` for https://burdenoff.com, `fluidgrids` for https://www.fluidgrids.ai: the name a sentence uses. */\nfunction siteNameOf(website: string | null | undefined): string {\n if (!website) return \"\";\n try {\n const labels = new URL(website).hostname.split(\".\");\n return labels.length >= 2 ? (labels[labels.length - 2] ?? \"\") : \"\";\n } catch {\n return \"\";\n }\n}\n\n/**\n * Every spelling free text uses for a product, lower-cased: its name, the same run together (\"healthybowl\"), its slug\n * and a renamed product's other slug (botlit and botmanor), and its site's own name (burdenoff for Workspaces).\n */\nfunction spellingsOf(product: ExploreScopeProduct): string[] {\n const spellings = [\n product.name,\n product.name.replace(/\\s+/g, \"\"),\n ...productSlugVariants(product.slug),\n siteNameOf(product.website),\n ]\n .map((spelling) => spelling.trim().toLowerCase())\n .filter((spelling) => spelling.length >= MIN_SPELLING_LENGTH);\n return [...new Set(spellings)];\n}\n\n/** Where `spelling` occurs in `text` as a whole word, from `from` on; -1 when it does not. Both lower-case. */\nfunction wordAt(text: string, spelling: string, from = 0): number {\n for (\n let at = text.indexOf(spelling, from);\n at !== -1;\n at = text.indexOf(spelling, at + 1)\n ) {\n const before = text[at - 1];\n const after = text[at + spelling.length];\n const bounded =\n (before === undefined || !NAME_CHARACTER.test(before)) &&\n (after === undefined || !NAME_CHARACTER.test(after));\n if (bounded) return at;\n }\n return -1;\n}\n\n/** `text` with every whole-word `spelling` in it blanked out. Both lower-case. */\nfunction withoutWord(text: string, spelling: string): string {\n let result = text;\n for (\n let at = wordAt(result, spelling);\n at !== -1;\n at = wordAt(result, spelling, at + spelling.length)\n ) {\n result = `${result.slice(0, at)}${\" \".repeat(spelling.length)}${result.slice(at + spelling.length)}`;\n }\n return result;\n}\n\n/**\n * The test the product scope puts the catalog's own copy through: true when `text` names a product other than the\n * pinned one, as a whole word, in any case. Built once per catalog and product.\n *\n * The pinned product's own spellings are taken out of the text first, so a name that contains another product's\n * (\"Healthy Bowl\", beside a product called \"Bowl\") is never mistaken for it. The pinned slug counts as its own even\n * when the catalog does not list the product.\n */\nexport function anotherProductMatcher(\n products: readonly ExploreScopeProduct[],\n pinnedSlug: string,\n): (text: string) => boolean {\n const own = productSlugVariants(pinnedSlug).map((slug) => slug.toLowerCase());\n const others: string[] = [];\n for (const product of products) {\n if (isSameProductSlug(product.slug, pinnedSlug)) {\n own.push(...spellingsOf(product));\n } else {\n others.push(...spellingsOf(product));\n }\n }\n // Longest first, so a longer spelling is taken out before a shorter one inside it.\n const ownSpellings = [...new Set(own)].sort((a, b) => b.length - a.length);\n const otherSpellings = [...new Set(others)].filter(\n (spelling) => !ownSpellings.includes(spelling),\n );\n return (text) => {\n let rest = text.toLowerCase();\n for (const spelling of ownSpellings) rest = withoutWord(rest, spelling);\n return otherSpellings.some((spelling) => wordAt(rest, spelling) !== -1);\n };\n}\n\n/** `prompts` in their order, each once, blanks dropped. */\nfunction distinctPrompts(prompts: readonly string[]): string[] {\n return [...new Set(prompts.filter((prompt) => prompt.trim() !== \"\"))];\n}\n\n/**\n * A product-scoped view's example prompts.\n *\n * When the host passes any, its own and nothing else, each once, blanks dropped. They are never filtered (what a site\n * passes is its choice), and none of the catalog's are added: those are written for every site at once, so even the\n * ones that name no product describe another site's problem (\"Every course we run lives in a different\n * spreadsheet.\", reported on the HealthyBowl site's assistant).\n *\n * Only when the host passes none (no list, an empty one, or blanks alone), the catalog's: less any that name another\n * product, and less the SDK's built-in portfolio prompt (\"Which of your products fits a problem like mine?\", in any\n * locale), which asks which product to choose.\n */\nexport function productScopedPrompts(\n hostPrompts: readonly string[] | undefined,\n catalogPrompts: readonly string[],\n namesAnotherProduct: (text: string) => boolean,\n): string[] {\n const own = distinctPrompts(hostPrompts ?? []);\n if (own.length > 0) return own;\n return distinctPrompts(\n catalogPrompts.filter(\n (prompt) => !isPortfolioPrompt(prompt) && !namesAnotherProduct(prompt),\n ),\n );\n}\n\n/**\n * A product-scoped view's concept illustrations: the pinned product's alone, less any whose title or picture text\n * names another product. None at all is ordinary: the strip then renders nothing, heading included.\n */\nexport function productScopedHighlights(\n highlights: readonly ExploreConceptHighlight[],\n pinnedSlug: string,\n namesAnotherProduct: (text: string) => boolean,\n): ExploreConceptHighlight[] {\n return highlights.filter(\n (highlight) =>\n isSameProductSlug(highlight.product, pinnedSlug) &&\n !namesAnotherProduct(`${highlight.title}\\n${highlight.alt}`),\n );\n}\n\n/**\n * A product-scoped view's error, as its banner shows it: the same error, except that a turn which ran out of searches\n * (`TOOL_BUDGET`) gets `toolBudgetMessage` (the view's `toolBudgetScoped`, in its language). The default message asks\n * for \"two or three specific products\", which invites other products onto one product's own assistant. Every other\n * error is returned as it is, the very object, so its banner renders exactly what it always has.\n */\nexport function productScopedError(\n error: ExploreChatError,\n toolBudgetMessage: string,\n): ExploreChatError {\n return error.code === \"TOOL_BUDGET\"\n ? { ...error, message: toolBudgetMessage }\n : error;\n}\n\n/**\n * A development build, as the host's bundler sees it: bundlers replace `process.env.NODE_ENV` in this package at the\n * host's build, so a production bundle has the warning below compiled to nothing that runs. A page loaded without a\n * bundler has no `process` at all, and counts as production.\n */\nexport function isDevelopmentBuild(): boolean {\n try {\n return process.env.NODE_ENV !== \"production\";\n } catch {\n return false;\n }\n}\n\nlet warnedWithoutSlug = false;\n\n/** Once per page load, in a development build only: a product scope was given no `productSlug` to pin to. */\nexport function warnProductScopeWithoutSlug(): void {\n if (warnedWithoutSlug || !isDevelopmentBuild()) return;\n warnedWithoutSlug = true;\n console.warn(\n '[WebSDK] Explore scope=\"product\" needs a productSlug. Without one the assistant stays the portfolio\\'s: every product, and a product picker.',\n );\n}\n","\"use client\";\n\nimport { useCallback, useRef } from \"react\";\n\n/**\n * Horizontal swipe detection for the explore strips.\n *\n * Pointer Events rather than touch events, so the same handler covers finger, pen and a\n * mouse drag without three code paths. No dependency and no listener on `window` — every\n * handler is attached to the element that owns the gesture.\n *\n * Deliberately does NOT call `preventDefault`. A horizontal strip sits inside a vertically\n * scrolling page, and swallowing the gesture would trap the page scroll whenever a finger\n * lands on the strip. Instead the drag is only treated as a swipe when it is clearly\n * horizontal — past a distance threshold AND more horizontal than vertical — so a diagonal\n * or vertical drag falls through to the browser and scrolls the page as the visitor expects.\n */\n\n/** Distance in px before a drag counts as a swipe rather than a tap or a jitter. */\nconst SWIPE_THRESHOLD = 40;\n\nexport interface UseSwipeOptions {\n onSwipeLeft?: () => void;\n onSwipeRight?: () => void;\n /** Disable while a strip is expanded/scrollable and owns its own gesture. */\n enabled?: boolean;\n}\n\nexport interface SwipeHandlers {\n onPointerDown: (event: React.PointerEvent) => void;\n onPointerUp: (event: React.PointerEvent) => void;\n onPointerCancel: () => void;\n}\n\nexport function useSwipe({\n onSwipeLeft,\n onSwipeRight,\n enabled = true,\n}: UseSwipeOptions): SwipeHandlers {\n const start = useRef<{ x: number; y: number } | null>(null);\n\n const onPointerDown = useCallback(\n (event: React.PointerEvent) => {\n if (!enabled) return;\n start.current = { x: event.clientX, y: event.clientY };\n },\n [enabled],\n );\n\n const onPointerUp = useCallback(\n (event: React.PointerEvent) => {\n const from = start.current;\n start.current = null;\n if (!enabled || !from) return;\n\n const dx = event.clientX - from.x;\n const dy = event.clientY - from.y;\n\n // Mostly-vertical drags belong to the page, not to us.\n if (Math.abs(dx) < SWIPE_THRESHOLD || Math.abs(dx) <= Math.abs(dy))\n return;\n\n // Swiping left (negative dx) moves FORWARD, matching how a carousel behaves everywhere\n // else: the content follows the finger.\n if (dx < 0) onSwipeLeft?.();\n else onSwipeRight?.();\n },\n [enabled, onSwipeLeft, onSwipeRight],\n );\n\n const onPointerCancel = useCallback(() => {\n start.current = null;\n }, []);\n\n return { onPointerDown, onPointerUp, onPointerCancel };\n}\n","/**\n * File attachments for the explore chat.\n *\n * ## Why the browser extracts the text and not the server\n *\n * The grounding harness is text-only by design — no webfetch, no file tools, no object store\n * — so the bytes of a file could not be used even if they arrived. Shipping them anyway would\n * mean base64-inflating a 10 MB file to ~13 MB through a public GraphQL mutation to produce\n * nothing the model can read.\n *\n * So the browser reads what it can as text and sends that. A format it cannot decode (a PDF,\n * an image, a zip) still travels as its NAME and TYPE, and the UI says \"name and type only\"\n * rather than implying the contents were read. Being honest about that is the whole point: a\n * visitor who attaches a PDF and gets an answer must not be left thinking the PDF was read.\n *\n * ## The limits are advisory here\n *\n * Everything below is re-validated in `global-support-svc`. These checks exist so the visitor\n * finds out immediately, in the composer, rather than after a network round-trip — they are\n * not the enforcement boundary, and must never be described as one.\n */\n\n/** Matches the server's `MAX_ATTACHMENTS`. */\nexport const MAX_ATTACHMENTS = 5;\n/** Matches the server's `MAX_ATTACHMENT_BYTES`. */\nexport const MAX_ATTACHMENT_BYTES = 10 * 1024 * 1024;\n/** Matches the server's `MAX_TEXT_PER_ATTACHMENT`; truncating here saves the upload. */\nexport const MAX_TEXT_PER_ATTACHMENT = 20_000;\n\n/** What travels on the wire — mirrors `ExploreAttachmentInput`. */\nexport interface ExploreAttachmentPayload {\n name: string;\n mimeType: string;\n size: number;\n textContent: string | null;\n}\n\n/** A file staged in the composer, before it is sent. */\nexport interface StagedAttachment extends ExploreAttachmentPayload {\n /** Stable across re-renders so React keys and the remove button behave. */\n id: string;\n /** False when only the name and type could be used. Drives the UI's honesty. */\n textExtracted: boolean;\n}\n\nexport type AttachmentRejectionReason = \"too-large\" | \"too-many\";\n\nexport interface AttachmentRejection {\n name: string;\n reason: AttachmentRejectionReason;\n}\n\nexport interface StageFilesResult {\n accepted: StagedAttachment[];\n rejected: AttachmentRejection[];\n}\n\n/**\n * Extensions that are text but whose `File.type` the browser routinely leaves blank or wrong.\n *\n * Sniffing by MIME type alone loses most of what a visitor would actually attach to a\n * product question: Chrome reports `\"\"` for `.md`, `.yaml`, `.log` and `.env`, and\n * `application/octet-stream` for `.ts`. Those are exactly the files worth reading.\n */\nconst TEXT_EXTENSIONS = new Set([\n \"txt\",\n \"md\",\n \"markdown\",\n \"csv\",\n \"tsv\",\n \"json\",\n \"jsonl\",\n \"yaml\",\n \"yml\",\n \"toml\",\n \"ini\",\n \"cfg\",\n \"conf\",\n \"env\",\n \"log\",\n \"sql\",\n \"graphql\",\n \"gql\",\n \"html\",\n \"htm\",\n \"xml\",\n \"svg\",\n \"css\",\n \"scss\",\n \"js\",\n \"jsx\",\n \"mjs\",\n \"cjs\",\n \"ts\",\n \"tsx\",\n \"py\",\n \"rb\",\n \"go\",\n \"rs\",\n \"java\",\n \"kt\",\n \"c\",\n \"h\",\n \"cpp\",\n \"cs\",\n \"php\",\n \"sh\",\n \"bash\",\n \"zsh\",\n \"ps1\",\n \"dockerfile\",\n \"tf\",\n \"tfvars\",\n]);\n\n/** MIME types that are text regardless of extension. */\nfunction isTextualMimeType(mimeType: string): boolean {\n if (mimeType.startsWith(\"text/\")) return true;\n return (\n mimeType === \"application/json\" ||\n mimeType === \"application/xml\" ||\n mimeType === \"application/yaml\" ||\n mimeType === \"application/x-yaml\" ||\n mimeType === \"application/javascript\" ||\n mimeType === \"application/graphql\" ||\n mimeType.endsWith(\"+json\") ||\n mimeType.endsWith(\"+xml\")\n );\n}\n\nfunction extensionOf(name: string): string {\n const dot = name.lastIndexOf(\".\");\n if (dot <= 0 || dot === name.length - 1) return \"\";\n return name.slice(dot + 1).toLowerCase();\n}\n\n/** Whether we should even attempt to read this file as text. */\nexport function looksTextual(name: string, mimeType: string): boolean {\n if (isTextualMimeType(mimeType)) return true;\n return TEXT_EXTENSIONS.has(extensionOf(name));\n}\n\n/**\n * A decoded string is only usable if it is actually text.\n *\n * `TextDecoder` never throws on binary — it substitutes U+FFFD — so a PDF read as UTF-8\n * comes back as a long string of replacement characters that would sail through a\n * `length > 0` check and reach the model as noise. The NUL byte and a replacement-character\n * ratio are the two cheap signals that separate real text from a mis-decoded binary.\n */\nexport function isDecodedTextUsable(decoded: string): boolean {\n if (decoded.length === 0) return false;\n // A NUL byte does not occur in real text and is the cheapest binary tell.\n if (decoded.includes(\"\\u0000\")) return false;\n\n let replacements = 0;\n for (const char of decoded) if (char === \"\\uFFFD\") replacements += 1;\n return replacements / decoded.length < 0.1;\n}\n\n/** Human-readable size for the chip. Bytes are unhelpful above a KB. */\nexport function formatBytes(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${Math.round(bytes / 1024)} KB`;\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n}\n\nlet counter = 0;\nfunction nextId(): string {\n counter += 1;\n return `att-${counter}`;\n}\n\n/**\n * Read one file, truncated to the per-file budget.\n *\n * Only the first `MAX_TEXT_PER_ATTACHMENT` **bytes** are decoded — `File.slice` avoids\n * pulling a 10 MB log into memory to throw away 99.8% of it. Slicing on a byte boundary can\n * cut a multi-byte character in half; the trailing partial character decodes to a single\n * U+FFFD, which is well under the ratio `isDecodedTextUsable` tolerates.\n */\nasync function readArrayBuffer(blob: Blob): Promise<ArrayBuffer> {\n if (typeof blob.arrayBuffer === \"function\") return blob.arrayBuffer();\n // `Blob.arrayBuffer` is Safari 14+. On anything older it is simply absent, and calling it\n // throws a TypeError that the caller's catch would quietly turn into \"this file is not\n // text\" — a readable document silently downgraded to name-and-type with no way for the\n // visitor to tell. `FileReader` has been universal for a decade, so fall back to it.\n return new Promise<ArrayBuffer>((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = () => resolve(reader.result as ArrayBuffer);\n reader.onerror = () =>\n reject(reader.error ?? new Error(\"file read failed\"));\n reader.readAsArrayBuffer(blob);\n });\n}\n\nasync function readTextPrefix(file: File): Promise<string | null> {\n try {\n const slice = file.slice(0, MAX_TEXT_PER_ATTACHMENT);\n const buffer = await readArrayBuffer(slice);\n const decoded = new TextDecoder(\"utf-8\").decode(buffer);\n return isDecodedTextUsable(decoded) ? decoded : null;\n } catch {\n // A file the OS revoked access to between picking and reading. Not fatal: the name and\n // type still reach the model.\n return null;\n }\n}\n\n/**\n * Validate and read a batch of picked files against what is already staged.\n *\n * Over-limit files are reported as rejections rather than throwing: attaching a sixth file\n * should tell the visitor which one was skipped, not discard the five that were fine.\n */\nexport async function stageFiles(\n files: readonly File[],\n alreadyStaged: readonly StagedAttachment[],\n): Promise<StageFilesResult> {\n const accepted: StagedAttachment[] = [];\n const rejected: AttachmentRejection[] = [];\n let slots = MAX_ATTACHMENTS - alreadyStaged.length;\n\n for (const file of files) {\n if (slots <= 0) {\n rejected.push({ name: file.name, reason: \"too-many\" });\n continue;\n }\n if (file.size > MAX_ATTACHMENT_BYTES) {\n rejected.push({ name: file.name, reason: \"too-large\" });\n continue;\n }\n\n const mimeType = file.type || \"application/octet-stream\";\n const textContent = looksTextual(file.name, mimeType)\n ? await readTextPrefix(file)\n : null;\n\n accepted.push({\n id: nextId(),\n name: file.name,\n mimeType,\n size: file.size,\n textContent,\n textExtracted: textContent !== null,\n });\n slots -= 1;\n }\n\n return { accepted, rejected };\n}\n\n/** Strip the UI-only fields before sending. */\nexport function toPayload(\n staged: readonly StagedAttachment[],\n): ExploreAttachmentPayload[] {\n return staged.map(({ name, mimeType, size, textContent }) => ({\n name,\n mimeType,\n size,\n textContent,\n }));\n}\n","/**\n * ExplorePage — the public `/explore` AI chat surface.\n *\n * Ships on 38 marketing sites, so it is written as a *marketing* page that\n * happens to be a chat, not a chat widget dropped onto a marketing site:\n *\n * - The welcome state discloses what the assistant can do **before** the\n * visitor types — a real `<h1>`, a one-line pitch, three capability bullets,\n * clickable example prompts and product-focus chips.\n * - That `<h1>` renders on the FIRST render, from props or the hook's built-in\n * fallback catalog, never from the catalog fetch. The websites' prerender\n * waits for an `h1`; a heading behind a network round-trip would bake 38\n * blank static pages.\n * - Colours are semantic tokens only (`bg-card`, `text-muted-foreground`,\n * `border-border`, …) so the page is correct in light AND dark mode on every\n * product's palette. No raw hex/rgb/hsl anywhere.\n *\n * Import from the package ROOT — `@burdenoff/website-sdk` — never from\n * `@burdenoff/website-sdk/components/explore`. tsup builds with\n * `splitting: false`, so a sub-path bundle carries its own copy of the React\n * context and cannot see the app's `WebSDKProvider`.\n *\n * @example\n * ```tsx\n * import { ExplorePage } from '@burdenoff/website-sdk'\n *\n * <ExplorePage\n * productSlug=\"vibecontrols\"\n * heightMode=\"viewport\"\n * viewportOffset=\"4rem\" // site header height\n * onNavigate={(path) => navigate(path)}\n * seo={{ url: 'https://vibecontrols.com/explore' }}\n * />\n * ```\n */\n\"use client\";\n\nimport {\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport type { CSSProperties } from \"react\";\n\nimport {\n ArrowUp,\n BookOpenText,\n Check,\n ChevronLeft,\n ChevronRight,\n Copy,\n ExternalLink,\n Layers,\n Link2,\n Paperclip,\n RotateCcw,\n Sparkles,\n History as HistoryIcon,\n Mic,\n Square,\n ThumbsDown,\n ThumbsUp,\n Trash2,\n TriangleAlert,\n Volume2,\n X,\n} from \"lucide-react\";\n\nimport {\n ExploreAnswerBody,\n ExploreAnswerStyles,\n answerPlainText,\n answerSpeechText,\n inlineImageOrigins,\n isInlineImageAllowed,\n isInlineVideoAllowed,\n productSlugsByOrigin,\n} from \"./explore-answer\";\nimport {\n ExploreConversationContext,\n useExploreConversation,\n type ExploreConversationState,\n} from \"./explore-conversation\";\nimport {\n type ExploreLocale,\n type ExploreStrings,\n exploreStrings,\n fill,\n isRtlLocale,\n resolveExploreLocale,\n speechLocaleOf,\n} from \"./explore-i18n\";\nimport {\n anotherProductMatcher,\n pinnedProductSlug,\n productNameFor,\n productScopedError,\n productScopedHighlights,\n productScopedPrompts,\n warnProductScopeWithoutSlug,\n type ExploreScope,\n} from \"./explore-scope\";\nimport {\n EXPLORE_ESCALATION_NOTE_SOFT_MAX,\n EXPLORE_FEEDBACK_COMMENT_SOFT_MAX,\n EXPLORE_FEEDBACK_REASONS,\n looksLikeDeliverableEmail,\n} from \"./explore-types\";\nimport { ProseStyles } from \"../content/prose-styles\";\nimport {\n BAKED_CATALOG_ELEMENT_ID,\n bakedCatalogLocale,\n serializeBakedCatalog,\n} from \"../hooks/use-explore-chat\";\nimport { useProgressiveReveal } from \"../hooks/use-progressive-reveal\";\nimport { useSpeechInput } from \"../hooks/use-speech-input\";\nimport { stopSpeaking, useSpeechOutput } from \"../hooks/use-speech-output\";\nimport { useSwipe } from \"../hooks/use-swipe\";\nimport { PageHead } from \"../seo/page-head\";\nimport { Button } from \"../ui/button\";\nimport { Textarea } from \"../ui/textarea\";\nimport { cn } from \"../utils/cn\";\nimport {\n MAX_ATTACHMENTS,\n MAX_ATTACHMENT_BYTES,\n type StagedAttachment,\n formatBytes,\n stageFiles,\n toPayload,\n} from \"../utils/explore-attachments\";\nimport { isSameProductSlug } from \"../utils/product-slug\";\n\nimport type {\n ExploreConceptHighlight,\n ExploreCtaLink,\n ExploreFeedback,\n ExploreFeedbackRating,\n ExploreFeedbackReason,\n ExploreMessage,\n ExploreProduct,\n ExploreReference,\n} from \"./explore-types\";\nimport type {\n ExploreChatError,\n ExploreEscalateResult,\n} from \"../hooks/use-explore-chat\";\n\n/**\n * Re-exported from where they now live.\n *\n * The answer renderer moved to `./explore-answer` so the published answer pages can use the\n * SAME one rather than a second copy that would drift. These four were part of this module's\n * public surface before that split, so they stay importable from here — and the video\n * allow-list sits beside the image one it extends.\n */\nexport {\n answerPlainText,\n answerSpeechText,\n inlineImageOrigins,\n isInlineImageAllowed,\n isInlineVideoAllowed,\n};\n\n// ============================================================================\n// Props\n// ============================================================================\n\nexport interface ExplorePageProps {\n /**\n * SEO metadata. Every field is optional and each one falls back to a default\n * derived from {@link ExplorePageProps.productSlug}, so a site that passes\n * nothing still gets a correct head — see `defaultExploreSeo`.\n *\n * Pass this only to say something the default cannot. All 38 sites used to\n * hard-code the same two sentences here, which is how every one of them ended\n * up announcing \"Explore Burdenoff products with AI\" — product-first on a page\n * whose whole purpose is to ask the visitor about their problem, and simply\n * the wrong brand on 37 of them.\n */\n seo?: {\n title?: string;\n description?: string;\n keywords?: string;\n image?: string;\n url?: string;\n };\n /** Slug of the product site this page lives on — a soft hint to the harness. */\n productSlug?: string;\n /**\n * Example prompts shown when `exploreCatalog` supplies none. Resolution\n * order: catalog → this prop → the SDK's built-in list.\n *\n * BOFF-9796: with `scope=\"product\"` these are the ONLY prompts shown (each once, blanks dropped), whatever the\n * catalog has, under an `ExploreChatProvider` too. Only when none are passed does the view fall back to the\n * catalog's, less any that name another product and the SDK's \"Which of your products fits a problem like mine?\".\n * A product-scoped site should pass its own: the catalog's are written for every site at once, and even those that\n * name no product describe other sites' problems.\n */\n examplePrompts?: string[];\n /** Extra classes for the page root. */\n className?: string;\n /**\n * `viewport` (default) pins the chat to the viewport with an internally\n * scrolling transcript — the right feel for a dedicated `/explore` route.\n * `auto` lets the page grow, for embedding inside a longer page.\n *\n * `viewport` also means \"this component IS the page\": only in that mode does it take over\n * `history.scrollRestoration` and correct a restored scroll offset that has parked the\n * page in the site footer. An `auto` embed never touches its host page's scrolling.\n */\n heightMode?: \"viewport\" | \"auto\";\n /**\n * Chrome to subtract in `viewport` mode — the site header height. A number is treated as\n * pixels. Default `0`.\n *\n * Pre-measurement fallback ONLY. Once mounted the pane measures its own top, so an\n * approximate value is fine and the keyboard case is handled; see `measurePane` in\n * `ExplorePage`.\n */\n viewportOffset?: string | number;\n /** SPA navigation for internal CTA paths. Falls back to a plain link. */\n onNavigate?: (path: string) => void;\n /** Fired with the message text every time a send is accepted. */\n onSend?: (message: string) => void;\n /** Overrides `exploreCatalog.welcomeTitle` — also the page `<h1>`. */\n welcomeTitle?: string;\n /** Overrides `exploreCatalog.welcomeBody`. */\n welcomeBody?: string;\n /**\n * BCP-47 locale to render in. Defaults to the document's own `lang`, then the browser.\n * Only the six the products ship are recognised (en, zh, hi, es, ar, ta); anything else\n * falls back to English.\n */\n locale?: string;\n /**\n * BOFF-9697. `page` (default) is the dedicated `/explore` route, exactly as before: it owns the document head\n * (PageHead), the `<h1>`, the baked catalog and, in `viewport` mode, the page's scrolling. `panel` is the same\n * conversation inside the site-wide assistant panel (`ExplorePanel`): it is a guest on whatever page is showing,\n * so it writes nothing to the head, uses an `<h2>`, bakes nothing, fills its container and leaves the page's\n * scrolling alone. Share links point at `/explore` (`explorePath`), not at the page the panel is on.\n */\n presentation?: \"page\" | \"panel\";\n /**\n * BOFF-9697. Whether the view is showing (default `true`). The panel passes `false` while it is closed or on its\n * Avatar tab: dictation and read-aloud stop then, and the conversation itself is untouched.\n */\n active?: boolean;\n /**\n * BOFF-9797. Set by `ExplorePanel` while its live avatar's voice is the page's (a session being created, joined or\n * played): the avatar's own status line, else null (the default). Chat's read-aloud and dictation are held then, so\n * the page never speaks in two voices and the microphone never takes down the avatar's: a reading under way stops, and\n * both controls stay where they are, `aria-disabled`, with this line as their title, until the session ends.\n */\n voiceHold?: string | null;\n /** BOFF-9697. The site's Explore route, for share links made from the panel. Default `/explore`. */\n explorePath?: string;\n /**\n * BOFF-9796. Whose assistant this is. `portfolio` (default) is the assistant every site has had, unchanged: every\n * product in a \"Focus on a product\" picker, every product's concept illustrations, the catalog's welcome copy.\n *\n * `product` makes it ONE product's own, for a product site that wants no other product in it. It needs\n * `productSlug` (without one it stays `portfolio`, and a development build warns once). Then:\n *\n * - the focus is pinned to `productSlug`: there is no product picker, and every new question is asked about this\n * product (`productSlug` on the request, as always), also in a conversation stored or shared with another focus;\n * - only this product's concept illustrations show, and no strip at all when it has none;\n * - the example prompts are `examplePrompts` alone; only without any, the catalog's, less any that name another\n * product and the SDK's built-in \"Which of your products fits a problem like mine?\";\n * - the welcome body, unless `welcomeBody` is passed, invites a problem or a question about this product, never\n * the catalog's invitation to compare it with other products; a catalog title naming another product is\n * replaced by the built-in one;\n * - the welcome has no capability tile that invites other products (\"Compare across the ecosystem\");\n * - the composer's placeholder, a shorter \"Ask about {product}…\", and the conversation's header name this product.\n * The composer itself is the published one, unchanged (its classes, and its fit to the draft alone), so on a phone\n * its field stays one line tall: the English placeholder fits that line at 320px and wider, and a longer\n * locale's (Spanish, Tamil) may still wrap at 320px and narrower and lose its second line;\n * - the page head's description promises this product's answers alone, never \"and every other product we build\";\n * - a question that needs more searches than a turn allows (`TOOL_BUDGET`) is asked to be narrowed to one part of\n * it, not to \"two or three specific products\".\n *\n * Answers come from the backend and are shown as they come: an answer, and the sources under it, can still name\n * another product when the visitor asks about one.\n */\n scope?: ExploreScope;\n /**\n * BOFF-9796. The product's display name in the `product` scope (\"Healthy Bowl\"): the welcome body, the placeholder\n * and, on `ExplorePanel`, the title. Default: the catalog's name for `productSlug`. Pass it to show the name the way\n * the site writes it, before the catalog has loaded too. Unused in the `portfolio` scope.\n */\n productName?: string;\n}\n\n// ============================================================================\n// Local styling (scoped, token-driven)\n// ============================================================================\n\n/**\n * Viewport height (px) at or below which a one-screen pane is worse than no pane at all: a\n * landscape phone is 320–430px tall, and a pane that size leaves a ~124px transcript under\n * ~610px of chrome and content. Below this the pane grows with its content and the page\n * scrolls instead.\n *\n * Compared against the VIEWPORT's own height, never against the height left over after the\n * site header — a 568px portrait phone under 80px of chrome has 454px of room and is not a\n * landscape phone. It is spent in a media query rather than in JavaScript for the same\n * reason: a media query reads the layout viewport, which the on-screen keyboard does not\n * shrink, so opening the keyboard cannot flip a portrait phone into this mode.\n */\nconst SHORT_VIEWPORT_PX = 420;\n\n/**\n * The welcome screen must fit the pane it is actually given, not the one it was tuned at.\n *\n * The pane is the viewport minus the site header, the composer, and whatever foreign chrome\n * the composer has to clear — 12 of the 39 host sites show a consent banner on a first visit\n * (73–173px wide-screen), and the composer reserves all of it. Inner heights real screens\n * leave after browser chrome, and the pane each gives (no banner / 73px banner):\n *\n * 1920x1080 monitor ~950 -> 746 / 690\n * 1440x900 laptop ~790 -> 586 / 530\n * 1536x864 (1080p @125%) ~730 -> 526 / 470\n * 1366x768 laptop ~650 -> 446 / 390\n *\n * One fixed layout cannot fit all of those, so the welcome steps down a ladder as the pane\n * shrinks. Each step engages from the welcome's measured height at the step above it, in the\n * LONGEST locale (es and ta run 23px taller than en), plus a 20px margin:\n *\n * step what changes worst-case height\n * 0 full layout 680\n * 1 capability tiles hidden 529\n * 2 concept thumbnails cropped to 4:1 485\n * 3 concept cards title-only, tighter spacing 402\n * 4 hero badge hidden 368\n *\n * The ORDER is the point. What goes is only ever something the page says twice. The tiles\n * go first because every one of them repeats the page — the badge, the intro and the composer\n * footer all state that answers come from our documentation, and the intro already invites\n * comparing products. The badge goes last, for the same reason: it is the third statement of\n * that sentence. The concept strip is never hidden: it was asked for, by name, on this page.\n * Below step 4 the pane scrolls rather than hiding anything, so no content becomes\n * unreachable at any zoom level (an earlier ladder hid the strip at 150% zoom — WCAG 1.4.4).\n *\n * In rem, not px: the welcome's text is rem-sized, so a visitor with a larger default font\n * gets a taller welcome, and px thresholds would engage too late for them. rem in a\n * container query tracks the root font size, so both scale together.\n *\n * Container queries rather than JavaScript: a measured density would be written into the\n * prerendered HTML at the prerender machine's viewport and served to every visitor until the\n * bundle executes — what the pane-height block below exists to prevent. A container query is\n * evaluated on the visitor's own screen, live.\n *\n * Wide panes only. A phone's welcome is far taller than any phone and scrolls by design; a\n * height query alone would pin every phone at the last step.\n */\nconst WELCOME_FIT_MIN_WIDTH_PX = 640;\n/** Pane heights (px at a 16px root) below which steps 1–4 engage. */\nconst WELCOME_FIT_STEP_PX = [700, 549, 505, 422] as const;\n/** Emitted in rem so the ladder scales with the visitor's default font size. */\nconst toRem = (px: number): string => `${px / 16}rem`;\n\nconst EXPLORE_CSS = `\n@keyframes boff-explore-pulse {\n 0%, 80%, 100% { opacity: 0.25; transform: translateY(0); }\n 40% { opacity: 1; transform: translateY(-2px); }\n}\n.boff-explore-dot {\n display: inline-block;\n width: 5px;\n height: 5px;\n border-radius: 9999px;\n background-color: hsl(var(--muted-foreground));\n animation: boff-explore-pulse 1.2s ease-in-out infinite;\n}\n@keyframes boff-explore-caret {\n 0%, 45% { opacity: 1; }\n 50%, 100% { opacity: 0; }\n}\n.boff-explore-caret {\n display: inline-block;\n width: 2px;\n height: 1em;\n margin-left: 2px;\n vertical-align: text-bottom;\n background-color: hsl(var(--primary));\n animation: boff-explore-caret 1s step-end infinite;\n}\n@media (prefers-reduced-motion: reduce) {\n .boff-explore-dot,\n .boff-explore-caret { animation: none; }\n .boff-explore-dot { opacity: 0.6; }\n}\n.boff-explore-scroll {\n scrollbar-width: thin;\n scrollbar-color: hsl(var(--border)) transparent;\n /* Stop the transcript handing its scroll to the page. Without this, the first\n swipe that exhausts the transcript chains to the document — and on a host site\n that is 65-70% footer, which is how a phone ends up showing nothing but the\n footer. Engines that do not support this property ignore the line and keep\n today's behaviour; the scroll correction above covers them. */\n overscroll-behavior: contain;\n}\n.boff-explore-scroll::-webkit-scrollbar { width: 10px; }\n.boff-explore-scroll::-webkit-scrollbar-track { background: transparent; }\n.boff-explore-scroll::-webkit-scrollbar-thumb {\n background-color: hsl(var(--border));\n border: 3px solid transparent;\n border-radius: 9999px;\n background-clip: content-box;\n}\n\n/* The product strip scrolls inside itself; a visible scrollbar would read as a broken\n layout rather than an affordance, and reserving its gutter shifts the chips. */\n.boff-explore-strip {\n scrollbar-width: none;\n -ms-overflow-style: none;\n}\n.boff-explore-strip::-webkit-scrollbar { display: none; }\n\n/* The product chips run past the edge of their row (there are 38). A hard edge sliced the\n last visible chip mid-word (\"Bi\", \"BigC\") right beside \"All 38\"; a short fade says \"there\n is more this way\" instead. A mask carries only alpha, so the gradient's colour is a token\n that never shows. Mirrored for right-to-left locales, whose row runs the other way. */\n.boff-explore-chips-fade {\n /* Focus scrolling honours scroll-padding, so a tabbed-to chip is brought clear of the fade\n rather than left half-hidden under it. */\n scroll-padding-inline-end: 2rem;\n -webkit-mask-image: linear-gradient(to right, hsl(var(--foreground)) calc(100% - 2rem), hsl(var(--foreground) / 0));\n mask-image: linear-gradient(to right, hsl(var(--foreground)) calc(100% - 2rem), hsl(var(--foreground) / 0));\n}\n/* A fade over a fixed edge would leave the LAST chip under it once the row is scrolled to\n the end — the visitor could never read it. A trailing spacer the width of the fade lets\n the final chip scroll clear of it. A pseudo-element rather than padding: trailing padding\n on a flex scroll container is not reliably part of its scrollable overflow. */\n.boff-explore-chips-fade::after {\n content: \"\";\n flex: 0 0 2rem;\n}\n[dir=\"rtl\"] .boff-explore-chips-fade {\n -webkit-mask-image: linear-gradient(to left, hsl(var(--foreground)) calc(100% - 2rem), hsl(var(--foreground) / 0));\n mask-image: linear-gradient(to left, hsl(var(--foreground)) calc(100% - 2rem), hsl(var(--foreground) / 0));\n}\n\n/* The concept rail had the chip row's problem: the card at its edge was cut hard mid-word\n (\"Apparatus Rig\", \"CONCEPT ILLUST\") on a dozen sites. It fades an edge only while there are\n more cards beyond it — the same state that lights the arrow on that side — so a rail\n scrolled to its end shows its last card whole. Physical edges, because that state is\n physical: it is measured from the left in either reading direction. */\n.boff-explore-rail-fade-left {\n -webkit-mask-image: linear-gradient(to right, hsl(var(--foreground) / 0), hsl(var(--foreground)) 3rem);\n mask-image: linear-gradient(to right, hsl(var(--foreground) / 0), hsl(var(--foreground)) 3rem);\n}\n.boff-explore-rail-fade-right {\n -webkit-mask-image: linear-gradient(to right, hsl(var(--foreground)) calc(100% - 3rem), hsl(var(--foreground) / 0));\n mask-image: linear-gradient(to right, hsl(var(--foreground)) calc(100% - 3rem), hsl(var(--foreground) / 0));\n}\n.boff-explore-rail-fade-left.boff-explore-rail-fade-right {\n -webkit-mask-image: linear-gradient(to right, hsl(var(--foreground) / 0), hsl(var(--foreground)) 3rem, hsl(var(--foreground)) calc(100% - 3rem), hsl(var(--foreground) / 0));\n mask-image: linear-gradient(to right, hsl(var(--foreground) / 0), hsl(var(--foreground)) 3rem, hsl(var(--foreground)) calc(100% - 3rem), hsl(var(--foreground) / 0));\n}\n\n@keyframes boff-explore-fade-in {\n from { opacity: 0; transform: translateY(2px); }\n to { opacity: 1; transform: none; }\n}\n.boff-explore-fade { animation: boff-explore-fade-in 220ms ease-out; }\n@media (prefers-reduced-motion: reduce) {\n .boff-explore-fade { animation: none; }\n}\n\n/* ---- Ambient backdrop -----------------------------------------------------------------\n Two very low-opacity radial washes behind the welcome state, drifting slowly. Painted on\n a pseudo-element with pointer-events:none so it can never intercept a click — a\n decorative overlay that swallows clicks is a bug we have shipped before.\n Colours come from the product's own --primary token, so this picks up each site's palette\n instead of introducing one. */\n.boff-explore-aura {\n position: relative;\n isolation: isolate;\n}\n.boff-explore-aura::before {\n content: \"\";\n position: absolute;\n inset: -10% -20% auto -20%;\n height: 60%;\n z-index: -1;\n pointer-events: none;\n background:\n radial-gradient(38% 55% at 22% 30%, hsl(var(--primary) / 0.10), transparent 70%),\n radial-gradient(32% 48% at 78% 18%, hsl(var(--primary) / 0.07), transparent 72%);\n filter: blur(6px);\n animation: boff-explore-drift 26s ease-in-out infinite alternate;\n}\n@keyframes boff-explore-drift {\n from { transform: translate3d(-1.5%, -1%, 0) scale(1); }\n to { transform: translate3d(1.5%, 1.5%, 0) scale(1.06); }\n}\n\n/* Entrance: content settles rather than snapping in. Short, and only once. */\n@keyframes boff-explore-rise {\n from { opacity: 0; transform: translateY(6px); }\n to { opacity: 1; transform: none; }\n}\n.boff-explore-rise {\n animation: boff-explore-rise 380ms cubic-bezier(0.22, 1, 0.36, 1) both;\n}\n.boff-explore-rise-1 { animation-delay: 40ms; }\n.boff-explore-rise-2 { animation-delay: 90ms; }\n.boff-explore-rise-3 { animation-delay: 140ms; }\n\n/* A soft sheen that crosses the send button while a turn is in flight — enough to say\n \"working\" without another spinner competing with the thinking dots. */\n@keyframes boff-explore-sheen {\n from { transform: translateX(-120%); }\n to { transform: translateX(220%); }\n}\n.boff-explore-busy { position: relative; overflow: hidden; }\n.boff-explore-busy::after {\n content: \"\";\n position: absolute;\n inset: 0;\n pointer-events: none;\n background: linear-gradient(100deg, transparent 20%, hsl(var(--primary) / 0.22) 50%, transparent 80%);\n animation: boff-explore-sheen 1.5s ease-in-out infinite;\n}\n\n/* ---- The composer, before anyone has typed -----------------------------------------\n On the welcome screen the box IS the page: everything above it is a way of explaining\n what to put in it. Unhighlighted it reads as a search bar at the bottom of a landing\n page, which people scroll past — so while the conversation is empty it gets a soft halo\n in the site's own --primary and one slow breath of it, and the moment there is a\n transcript, or the visitor focuses or types, it drops back to the ordinary card it was.\n An input that keeps pulsing while you are using it is nagging, not inviting.\n\n Colour comes from the product's --primary token, so it is whatever that site's palette\n already is, never a colour chosen here. */\n.boff-explore-invite {\n border-color: hsl(var(--primary) / 0.6);\n box-shadow:\n 0 0 0 4px hsl(var(--primary) / 0.12),\n 0 8px 24px -12px hsl(var(--primary) / 0.55);\n animation: boff-explore-breathe 3.2s ease-in-out infinite;\n}\n/* Focus and typing both mean \"I have found it\", and the hint has done its job. */\n.boff-explore-invite:focus-within,\n.boff-explore-invite.boff-explore-invite-quiet {\n animation: none;\n box-shadow: 0 0 0 4px hsl(var(--primary) / 0.10);\n}\n@keyframes boff-explore-breathe {\n 0%, 100% { box-shadow: 0 0 0 4px hsl(var(--primary) / 0.10), 0 8px 24px -12px hsl(var(--primary) / 0.50); }\n 50% { box-shadow: 0 0 0 7px hsl(var(--primary) / 0.18), 0 8px 28px -12px hsl(var(--primary) / 0.65); }\n}\n\n/* Every one of the above is decoration. Reduced motion removes the movement and keeps the\n final state, rather than leaving content mid-animation and invisible. */\n@media (prefers-reduced-motion: reduce) {\n .boff-explore-aura::before,\n .boff-explore-busy::after,\n .boff-explore-invite { animation: none; }\n .boff-explore-rise { animation: none; opacity: 1; transform: none; }\n}\n\n/* ---- Pane height ----------------------------------------------------------------------\n This used to be one inline declaration, \\`height: calc(100dvh - 64px)\\`, and it carried two\n defects. An inline style cannot carry a fallback, so every engine without \\`dvh\\` (iOS\n Safari < 15.4, Chrome/WebView < 108, Samsung Internet < 21, Firefox < 101) dropped it\n whole; and the 64px came from a prop hard-coded to 64 on all 41 host pages that matches\n none of them — the burdenoff/algoshred chrome is 80px, the sticky-header sites are 65.\n\n A class plus custom properties lets the cascade do the work: \\`vh\\` is the floor and \\`dvh\\`\n an upgrade where it exists, while the two measured values stay *lengths*, never a height.\n That distinction is the whole prerender contract. The host sites snapshot \\`/explore\\` by\n loading the built SPA in headless Chromium and writing the POST-HYDRATION DOM to\n dist/explore/index.html, so every attribute and inline value this component sets after\n mount IS the static HTML CloudFront serves. A measured pixel *height* would therefore\n hand every phone the prerender viewport's height until the bundle executes; a measured\n *offset* is a site-header height, which is the same on every device to within a few\n pixels, and the height built from it stays viewport-relative on the visitor's own screen.\n\n --boff-explore-offset chrome above the pane (measured root top; the prop pre-measure)\n --boff-explore-inset the slice of the layout viewport hidden below the visible area —\n the on-screen keyboard, which \\`dvh\\` does not track. Zero unless\n something is actually covering the bottom, so a snapshot taken\n with no keyboard open never carries it. */\n.boff-explore-viewport {\n height: calc(100vh - var(--boff-explore-offset, 0px) - var(--boff-explore-inset, 0px));\n}\n@supports (height: 100dvh) {\n .boff-explore-viewport {\n height: calc(100dvh - var(--boff-explore-offset, 0px) - var(--boff-explore-inset, 0px));\n }\n}\n\n/* Landscape phones and other short viewports: a one-screen pane leaves a ~124px transcript\n sliver under ~610px of chrome and content. At or below the threshold the pane stops\n pretending to be a window and lets the page's own scrolling carry the transcript. The\n min-height is the available height rather than a fixed rem value, so the fallback can\n never be taller than the screen it is rescuing. */\n@media (max-height: ${SHORT_VIEWPORT_PX}px) {\n .boff-explore-viewport {\n height: auto;\n min-height: calc(100vh - var(--boff-explore-offset, 0px));\n }\n}\n@supports (height: 100dvh) {\n @media (max-height: ${SHORT_VIEWPORT_PX}px) {\n .boff-explore-viewport {\n min-height: calc(100dvh - var(--boff-explore-offset, 0px));\n }\n }\n}\n\n/* ---- Welcome fit ----------------------------------------------------------------------\n The ladder is documented at WELCOME_FIT_STEP_PX. The pane becomes a query container only\n in viewport mode and above the short-viewport threshold, because size containment sizes\n an element as if it had no content. That is safe exactly while the pane's height comes\n from its flex parent. In \\`auto\\` mode, and in the short-viewport fallback above, the pane\n grows WITH its content — and containment there would collapse it to zero height.\n\n Selectors are two classes deep on purpose. The host sites' Tailwind puts \\`py-5\\`, \\`mt-4\\`\n and \\`aspect-[2/1]\\` on these same elements; unlayered SDK CSS already outranks a v4\n \\`@layer utilities\\` rule, and the extra class makes it outrank a v3 one too, whichever\n stylesheet happens to load last.\n\n Nothing here hides the concept strip, and nothing here hides content the page does not\n also say elsewhere. Below the last step the pane scrolls, so every control stays\n reachable at every zoom level. */\n@media (min-height: ${SHORT_VIEWPORT_PX + 1}px) {\n .boff-explore-viewport .boff-explore-scroll {\n container: boff-explore-pane / size;\n }\n}\n@container boff-explore-pane (min-width: ${toRem(WELCOME_FIT_MIN_WIDTH_PX)}) and (max-height: ${toRem(WELCOME_FIT_STEP_PX[0])}) {\n /* Step 1. Each tile restates something the page already says in the badge, the intro or\n the composer footer, so this is the one block whose absence loses nothing. */\n .boff-explore-scroll .boff-explore-capabilities { display: none; }\n}\n@container boff-explore-pane (min-width: ${toRem(WELCOME_FIT_MIN_WIDTH_PX)}) and (max-height: ${toRem(WELCOME_FIT_STEP_PX[1])}) {\n /* Step 2. At a 4:1 crop the picture is ~44px tall, and the full-size caveat badge covered\n half of it — on ten sites, every card, whenever the consent banner was up. It stays (the\n picture is still a mockup), just smaller and tucked into the corner. */\n .boff-explore-scroll .boff-explore-concept-media { aspect-ratio: 4 / 1; }\n .boff-explore-scroll .boff-explore-concept-badge {\n top: 0.25rem;\n left: 0.25rem;\n padding: 0 0.3125rem;\n font-size: 0.5rem;\n line-height: 0.75rem;\n letter-spacing: 0.02em;\n }\n}\n@container boff-explore-pane (min-width: ${toRem(WELCOME_FIT_MIN_WIDTH_PX)}) and (max-height: ${toRem(WELCOME_FIT_STEP_PX[2])}) {\n /* Step 3. Title-only cards. The \"concept illustration\" caveat lives on the picture, so it\n goes with it; the button's accessible name never depended on the image. Lazy images\n inside a display:none box are not fetched until there is room to show them. */\n .boff-explore-scroll .boff-explore-concept-media { display: none; }\n .boff-explore-scroll .boff-explore-aura { padding-top: 0.75rem; padding-bottom: 0.75rem; }\n .boff-explore-scroll .boff-explore-aura > :not(:first-child) { margin-top: 0.5rem; }\n}\n@container boff-explore-pane (min-width: ${toRem(WELCOME_FIT_MIN_WIDTH_PX)}) and (max-height: ${toRem(WELCOME_FIT_STEP_PX[3])}) {\n /* Step 4. The badge is the third statement on this screen that answers come from our\n documentation. The heading beneath it loses its top margin so the hero starts flush. */\n .boff-explore-scroll .boff-explore-hero-badge { display: none; }\n .boff-explore-scroll .boff-explore-hero-badge + h1 { margin-top: 0; }\n}\n\n/* ---- Composer dock --------------------------------------------------------------------\n Three declarations, each the fallback for the one after it: a plain 1rem where \\`max()\\`\n is unknown, then the measured overlap of any FOREIGN fixed chrome sitting over the\n composer (the host sites' cookie banner is 229px tall and lands exactly there), then the\n same plus the home-indicator inset. \\`--boff-explore-chrome\\` is set on the root only once\n an overlap has actually been measured, so everywhere else this collapses to 1rem. */\n.boff-explore-composer {\n padding-bottom: 1rem;\n padding-bottom: max(1rem, var(--boff-explore-chrome, 0px));\n padding-bottom: max(1rem, env(safe-area-inset-bottom), var(--boff-explore-chrome, 0px));\n}\n`;\n\nfunction ExploreStyles() {\n return <style dangerouslySetInnerHTML={{ __html: EXPLORE_CSS }} />;\n}\n\n// ============================================================================\n// Constants\n// ============================================================================\n\n/**\n * The welcome's capability tiles. `invitesOtherProducts` marks a tile that points the visitor at OTHER products, which\n * one product's own assistant (`scope=\"product\"`, BOFF-9796) leaves out: only the comparison tile does. The other two\n * describe this assistant's answers (grounded in the docs; the sources and next steps), whichever product it is for.\n */\nconst CAPABILITIES = [\n {\n icon: BookOpenText,\n title: \"Grounded in our own docs\",\n body: \"Every answer comes from published product pages and documentation — never invented.\",\n invitesOtherProducts: false,\n },\n {\n icon: Layers,\n title: \"Compare across the ecosystem\",\n body: \"Ask which product fits your team, or how two of them work together.\",\n invitesOtherProducts: true,\n },\n {\n icon: Link2,\n title: \"Straight to the right page\",\n body: \"Get the sources and next steps — pricing, docs, a demo — without hunting.\",\n invitesOtherProducts: false,\n },\n] as const;\n\n/**\n * How much of the explore root has to be on screen for a restored scroll offset to count as\n * \"the visitor is looking at it\". `/explore` is one viewport of app inside a marketing page\n * whose mobile footer is 1096–1332px tall, so any restored offset past ~600px shows a full\n * screen of footer and 0px of explore.\n *\n * The fraction is of whatever CAN be on screen — the lesser of the root's height and the\n * viewport's — not of the root's own height, which a long conversation makes several screens\n * tall and would put the bar above anything the viewport can ever show.\n */\nconst MIN_VISIBLE_FRACTION = 0.25;\n\n/**\n * The marker every element this SDK renders carries, wherever it ends up in the tree.\n * Nothing in explore portals out of its own subtree today — the disclaimer dialog is\n * hand-rolled inside it precisely because `@radix-ui/react-dialog` is not a peer dependency\n * — so `root.contains()` already covers everything and this only keeps that true for\n * anything portalled later. It deliberately does NOT list the host page's overlay markers:\n * a site's own consent banner or popper menu over the composer is foreign chrome, which is\n * the entire case the composer padding exists for.\n */\nconst SDK_OVERLAY_SELECTOR = \"[data-boff-explore]\";\n\n/** What a product-scoped welcome lists in its product picker (BOFF-9796): nothing, so it renders none. */\nconst NO_PRODUCTS: ExploreProduct[] = [];\n\n/** CTA kind → button styling. Unknown kinds fall through to the outline look. */\nconst CTA_VARIANTS: Record<string, \"default\" | \"secondary\" | \"outline\"> = {\n CONTACT: \"default\",\n WAITLIST: \"default\",\n APP: \"default\",\n PRICING: \"secondary\",\n STORE: \"secondary\",\n PARTNERS: \"secondary\",\n DOCS: \"outline\",\n SERVICES: \"outline\",\n OTHER: \"outline\",\n};\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\nfunction normalizeOffset(offset: string | number | undefined): string {\n if (offset === undefined) return \"0px\";\n return typeof offset === \"number\" ? `${offset}px` : offset;\n}\n\n/**\n * React's `CSSProperties` has no room for custom properties, and the pane's whole sizing\n * contract rides on three of them. Declared rather than cast, so the values stay typed.\n */\ntype CssVars = Record<`--${string}`, string>;\n\n/**\n * True when `el` belongs to this SDK rather than to the host page. `contains` covers the\n * component's own subtree; the selector covers anything the SDK may portal out of it later.\n */\nfunction isOwnElement(el: Element, root: HTMLElement): boolean {\n // Hitting the page background means nothing is painted over that point at all.\n if (el === document.body || el === document.documentElement) return true;\n if (root.contains(el)) return true;\n return el.closest(SDK_OVERLAY_SELECTOR) !== null;\n}\n\n/** The viewport the visitor actually sees — the keyboard shrinks this one, `innerHeight` not. */\nfunction visualViewportHeight(): number {\n return window.visualViewport?.height ?? window.innerHeight;\n}\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.min(Math.max(value, min), max);\n}\n\n/**\n * True when the BROWSER, not the visitor, put the page where it is. Only a reload or a\n * history traversal carries a scroll offset over; a fresh navigation starts at the top, so\n * any offset on one is the visitor's own and must be left alone.\n *\n * Engines with no navigation entry keep the correction rather than lose it — the reported\n * bug is a blank screenful of footer, which is worse than an unwanted scroll to the top.\n */\nfunction isRestoredNavigation(): boolean {\n const entries = window.performance?.getEntriesByType?.(\"navigation\");\n const entry = entries?.[0];\n if (!entry) return true;\n // `PerformanceNavigationTiming` is the only entry published under this name; the cast is\n // how the DOM lib exposes its `type` field, which the base `PerformanceEntry` lacks.\n const navigation = entry as PerformanceNavigationTiming;\n return navigation.type === \"reload\" || navigation.type === \"back_forward\";\n}\n\n/**\n * True when the PAGE, not the transcript, is what scrolls: the short-viewport fallback has\n * made the pane auto-height (see `SHORT_VIEWPORT_PX`), so the scroller has no overflow of\n * its own and writing `scrollTop` on it does nothing at all.\n *\n * Both halves are load-bearing. \"The scroller has nothing left to scroll\" is on its own\n * also true of the welcome screen and of every conversation's first turn on a roomy\n * screen — and moving the host PAGE for those drags the marketing page, and its\n * 1100–1330px footer, up over a pane the visitor is looking straight at. Measured with the\n * height test missing: one message sent at 1280×800 scrolled the window down 138px.\n *\n * That test mirrors the stylesheet's `max-height: ${SHORT_VIEWPORT_PX}px` off the same\n * constant and reads the LAYOUT viewport, which is what a media query resolves against and\n * what the on-screen keyboard leaves alone — a mode that flipped when the keyboard opened\n * would carry the composer hundreds of pixels below the fold mid-sentence.\n */\nfunction pageOwnsScrolling(el: HTMLElement): boolean {\n if (window.innerHeight > SHORT_VIEWPORT_PX) return false;\n return el.scrollHeight - el.clientHeight <= 1;\n}\n\n/** A same-origin path the host router can handle, as opposed to `https://…`. */\nfunction isInternalPath(url: string): boolean {\n return url.startsWith(\"/\") && !url.startsWith(\"//\");\n}\n\nfunction hostnameOf(url: string): string {\n try {\n return new URL(url).hostname.replace(/^www\\./, \"\");\n } catch {\n /* relative or malformed URL — the label is decorative, so degrade quietly */\n return \"\";\n }\n}\n\nfunction initialOf(value: string | null | undefined, fallback: string): string {\n const source = (value || fallback).trim();\n return source ? source.slice(0, 1).toUpperCase() : \"?\";\n}\n\n/**\n * The product's own logo, derived from the reference's origin.\n *\n * Every Burdenoff product site serves `/favicon.svg`, so the logo needs no registry and no\n * bundled assets — the reference URL already names the product. Deliberately NOT\n * `/favicon-512.png`: that path returns 200 with `text/html` because the SPA fallback\n * answers unknown paths, so it would render as a broken image rather than 404 into the\n * fallback below.\n */\nexport function logoUrlOf(url: string): string | null {\n try {\n const { origin, protocol } = new URL(url);\n if (protocol !== \"https:\" && protocol !== \"http:\") return null;\n return `${origin}/favicon.svg`;\n } catch {\n return null;\n }\n}\n\n// ============================================================================\n// Provenance\n// ============================================================================\n\n/**\n * The kinds of page an answer can cite.\n *\n * `PAGE` is the catch-all for a catalog site's own marketing pages, so the list is total for\n * anything on one of our origins; a reference that is NOT on a catalog origin gets no kind at\n * all (see `referenceKindOf`).\n */\nexport type ExploreReferenceKind =\n \"CONCEPT\" | \"DOCS\" | \"PRICING\" | \"USE_CASE\" | \"PAGE\";\n\n/**\n * Presentation order for the kind chips.\n *\n * Fixed, and deliberately not the order the answer happened to cite them in: the row exists\n * to be *glanced* at, and a summary whose chips move between two answers is read as two\n * different summaries. It is also the tie-break that keeps the row identical across renders.\n */\nconst REFERENCE_KIND_ORDER: readonly ExploreReferenceKind[] = [\n \"CONCEPT\",\n \"DOCS\",\n \"PRICING\",\n \"USE_CASE\",\n \"PAGE\",\n];\n\n/**\n * Hostname prefixes a product site publishes under, longest first so `alphadocs.` is never\n * mistaken for `alpha.` + `docs`.\n *\n * `docs.`/`alphadocs.` are the two that carry meaning — that host IS the documentation. The\n * rest resolve to the same product and are stripped so the origin check below is against the\n * apex the catalog actually lists.\n */\nconst PRODUCT_SUBDOMAINS = [\n \"alphadocs.\",\n \"alphaapp.\",\n \"docs.\",\n \"alpha.\",\n \"app.\",\n \"www.\",\n] as const;\n\n/** One reference URL, reduced to the pieces both readers below need. */\ninterface CatalogUrl {\n /** The APEX origin, spelled the way `inlineImageOrigins` spells it. */\n origin: string;\n /** The hostname prefix that was stripped, if any. `docs.` is the meaningful one. */\n prefix?: string;\n pathname: string;\n}\n\n/**\n * Reduce a reference URL to its apex origin, so `https://docs.vibecontrols.com/agents` and\n * `https://www.vibecontrols.com/pricing` both land on the `https://vibecontrols.com` the\n * catalog lists.\n *\n * One function for both readers on purpose. They used to normalise separately, and the row\n * then labelled a `docs.` reference's KIND correctly while failing to recognise its product\n * — so one answer citing a product's site and its docs listed that product twice, once as\n * \"VibeControls\" and once as the raw slug.\n */\nfunction readCatalogUrl(raw: string): CatalogUrl | null {\n let parsed: URL;\n try {\n parsed = new URL(raw);\n } catch {\n return null;\n }\n if (parsed.protocol !== \"https:\") return null;\n\n const host = parsed.hostname.toLowerCase();\n const prefix = PRODUCT_SUBDOMAINS.find((candidate) =>\n host.startsWith(candidate),\n );\n const apex = prefix === undefined ? host : host.slice(prefix.length);\n const port = parsed.port ? `:${parsed.port}` : \"\";\n return {\n origin: `https://${apex}${port}`,\n prefix,\n pathname: parsed.pathname,\n };\n}\n\n/**\n * What KIND of page a reference points at, decided from its URL alone.\n *\n * Deliberately not from the title: titles are model-written prose in six languages, so\n * \"Pricing\" in one answer is \"Precios\" in the next and \"Plans and pricing\" in the one after.\n * The URL is the only part of a reference nobody paraphrases.\n *\n * Reasoned against the catalog origins exactly as `isInlineImageAllowed` is: a URL that is\n * not on a product site we list gets `null` rather than a guessed label, because the whole\n * value of the row is that it says what the evidence IS.\n */\nexport function referenceKindOf(\n url: string,\n origins: ReadonlySet<string>,\n): ExploreReferenceKind | null {\n const parsed = readCatalogUrl(url);\n if (parsed === null || !origins.has(parsed.origin)) return null;\n\n if (parsed.prefix === \"docs.\" || parsed.prefix === \"alphadocs.\")\n return \"DOCS\";\n\n const segment =\n parsed.pathname.toLowerCase().split(\"/\").filter(Boolean)[0] ?? \"\";\n if (segment === \"concept\" || segment === \"concepts\") return \"CONCEPT\";\n if (segment === \"docs\") return \"DOCS\";\n if (segment === \"pricing\" || segment === \"plans\") return \"PRICING\";\n if (\n segment === \"use-case\" ||\n segment === \"use-cases\" ||\n segment === \"solutions\"\n ) {\n return \"USE_CASE\";\n }\n return \"PAGE\";\n}\n\n/**\n * Apex origin → the product's display name, built from the catalog the same way\n * `inlineImageOrigins` builds its allow-list.\n *\n * The display name matters: `ExploreReference.product` carries the slug, so a row built from\n * it says \"vibecontrols\" next to a page that calls itself VibeControls everywhere else.\n */\nexport function productNamesByOrigin(\n products: readonly Pick<ExploreProduct, \"name\" | \"website\">[],\n): Map<string, string> {\n const names = new Map<string, string>();\n for (const product of products) {\n let url: URL;\n try {\n url = new URL(product.website);\n } catch {\n continue;\n }\n if (url.protocol !== \"https:\") continue;\n const apex = url.hostname.replace(/^www\\./, \"\");\n const port = url.port ? `:${url.port}` : \"\";\n const key = `https://${apex}${port}`;\n // First entry wins. Two catalog rows on one domain would otherwise rename each other\n // depending on the order the server happened to list them in.\n if (!names.has(key)) names.set(key, product.name);\n }\n return names;\n}\n\n/** The shape of one answer's evidence, as the chips render it. */\nexport interface ExploreProvenance {\n /** Every reference the answer cites, including any we could not classify. */\n total: number;\n /** Kinds present, in `REFERENCE_KIND_ORDER`, with how many sources each covers. */\n kinds: Array<{ kind: ExploreReferenceKind; count: number }>;\n /** Product names, in the order the answer first cited them. */\n products: string[];\n}\n\n/**\n * Summarise what an answer is grounded in. Pure, and derived entirely from `references` —\n * there is no backend field behind this row.\n */\nexport function summariseReferences(\n references: readonly ExploreReference[],\n origins: ReadonlySet<string>,\n productNames: ReadonlyMap<string, string>,\n): ExploreProvenance {\n const counts = new Map<ExploreReferenceKind, number>();\n const products: string[] = [];\n\n for (const reference of references) {\n const kind = referenceKindOf(reference.url, origins);\n if (kind !== null) counts.set(kind, (counts.get(kind) ?? 0) + 1);\n\n // The catalog's display name when the URL is on a site we know — resolved through the\n // same apex normalisation the kind uses, so a product's docs host and its marketing host\n // are one product and not two. The reference's own `product` otherwise: it is the slug,\n // but a slug beats dropping the attribution.\n const parsed = readCatalogUrl(reference.url);\n const name =\n (parsed === null ? undefined : productNames.get(parsed.origin)) ??\n (reference.product || null);\n if (name != null && !products.includes(name)) products.push(name);\n }\n\n return {\n total: references.length,\n kinds: REFERENCE_KIND_ORDER.filter((kind) => counts.has(kind)).map(\n (kind) => ({ kind, count: counts.get(kind) ?? 0 }),\n ),\n products,\n };\n}\n\n// ============================================================================\n// Reference card\n// ============================================================================\n\nfunction ReferenceCard({\n reference,\n onFollow,\n}: {\n reference: ExploreReference;\n onFollow?: (url: string) => void;\n}) {\n const [imageFailed, setImageFailed] = useState(false);\n const [logoFailed, setLogoFailed] = useState(false);\n const host = hostnameOf(reference.url);\n const logoUrl = logoUrlOf(reference.url);\n const showImage = Boolean(reference.imageUrl) && !imageFailed;\n const showLogo = Boolean(logoUrl) && !logoFailed;\n\n // The letter plate is the last resort only. Every product's first letter collides with\n // several others (A for AdapterCloud and AssetHandler, B for BrainyRich and BuildMyIQ …),\n // so it identifies nothing — it exists purely so a card is never a blank hole.\n const letterPlate = (\n <div className=\"flex h-full w-full items-center justify-center bg-gradient-to-br from-primary/25 via-primary/5 to-secondary\">\n <span className=\"text-sm font-semibold text-primary/70 sm:text-2xl\">\n {initialOf(reference.product, reference.title || host)}\n </span>\n </div>\n );\n\n const logoImg = showLogo ? (\n <img\n src={logoUrl ?? \"\"}\n alt=\"\"\n loading=\"lazy\"\n onError={() => setLogoFailed(true)}\n className=\"h-full w-full object-contain p-1.5 sm:p-0\"\n />\n ) : (\n letterPlate\n );\n\n return (\n <a\n data-boff-explore=\"reference\"\n data-index={reference.index ?? undefined}\n href={reference.url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n onClick={() => onFollow?.(reference.url)}\n /* Mobile is a compact row, not a 16:9 card. Stacked preview cards pushed the answer\n itself off the top of a phone screen — five sources were taller than the response. */\n className=\"group flex flex-row items-center gap-3 overflow-hidden rounded-xl border border-border bg-card p-2 transition-colors hover:border-primary/40 hover:bg-accent/40 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring sm:flex-col sm:items-stretch sm:gap-0 sm:p-0\"\n >\n {/* Mobile: a small square logo. An og:image is a wide banner and is unreadable at 44px,\n so the phone layout always shows the product mark instead. */}\n <div className=\"relative h-11 w-11 shrink-0 overflow-hidden rounded-lg bg-muted sm:hidden\">\n {logoImg}\n </div>\n\n {/* sm+: the preview card, falling back to the product logo on a tinted plate. */}\n <div className=\"relative hidden aspect-[16/9] w-full overflow-hidden bg-muted sm:block\">\n {showImage ? (\n <img\n src={reference.imageUrl ?? \"\"}\n alt=\"\"\n loading=\"lazy\"\n onError={() => setImageFailed(true)}\n className=\"h-full w-full object-cover transition-transform duration-300 group-hover:scale-105\"\n />\n ) : showLogo ? (\n <div className=\"flex h-full w-full items-center justify-center bg-gradient-to-br from-primary/15 via-transparent to-secondary/60 p-6\">\n <img\n src={logoUrl ?? \"\"}\n alt=\"\"\n loading=\"lazy\"\n onError={() => setLogoFailed(true)}\n className=\"max-h-full max-w-full object-contain\"\n />\n </div>\n ) : (\n letterPlate\n )}\n </div>\n\n <div className=\"flex min-w-0 flex-1 flex-col gap-0.5 sm:gap-1.5 sm:p-3\">\n <p className=\"line-clamp-2 text-sm font-semibold leading-snug text-card-foreground\">\n {reference.index ? (\n <span className=\"mr-1.5 inline-flex h-4 min-w-4 items-center justify-center rounded bg-primary/10 px-1 text-[10px] font-bold text-primary\">\n {reference.index}\n </span>\n ) : null}\n {reference.title || host || reference.url}\n </p>\n {reference.description ? (\n <p className=\"line-clamp-2 text-xs leading-relaxed text-muted-foreground max-sm:hidden\">\n {reference.description}\n </p>\n ) : null}\n <div className=\"flex items-center gap-2 sm:mt-auto sm:pt-2\">\n {reference.product ? (\n <span className=\"rounded-full bg-secondary px-2 py-0.5 text-xs font-medium text-secondary-foreground max-sm:hidden\">\n {reference.product}\n </span>\n ) : null}\n <span className=\"inline-flex min-w-0 items-center gap-1 text-xs text-muted-foreground sm:ml-auto\">\n <ExternalLink className=\"h-3 w-3 shrink-0\" />\n <span className=\"truncate\">{host}</span>\n </span>\n </div>\n </div>\n </a>\n );\n}\n\n// ============================================================================\n// CTA button\n// ============================================================================\n\nfunction CtaButton({\n cta,\n onNavigate,\n onFollow,\n}: {\n cta: ExploreCtaLink;\n onNavigate?: (path: string) => void;\n onFollow?: (url: string) => void;\n}) {\n const variant = CTA_VARIANTS[cta.kind] ?? \"outline\";\n const internal = isInternalPath(cta.url);\n\n // Internal path + a router from the host: keep it an SPA navigation.\n if (internal && onNavigate) {\n return (\n <Button\n data-boff-explore=\"cta\"\n data-kind={cta.kind}\n type=\"button\"\n size=\"sm\"\n variant={variant}\n onClick={() => {\n onFollow?.(cta.url);\n onNavigate(cta.url);\n }}\n >\n {cta.label}\n </Button>\n );\n }\n\n return (\n <Button asChild size=\"sm\" variant={variant}>\n <a\n data-boff-explore=\"cta\"\n data-kind={cta.kind}\n href={cta.url}\n onClick={() => onFollow?.(cta.url)}\n {...(internal\n ? {}\n : { target: \"_blank\", rel: \"noopener noreferrer\" as const })}\n >\n {cta.label}\n {internal ? null : <ExternalLink className=\"ml-1 h-3 w-3\" />}\n </a>\n </Button>\n );\n}\n\n// ============================================================================\n// Thinking indicator\n// ============================================================================\n\nfunction ThinkingIndicator({ activity }: { activity: string | null }) {\n return (\n <div\n data-boff-explore=\"thinking\"\n className=\"flex items-center gap-2.5 rounded-2xl border border-border bg-muted/60 px-3.5 py-2.5 text-sm text-muted-foreground\"\n >\n <span className=\"flex items-center gap-1\" aria-hidden=\"true\">\n <span className=\"boff-explore-dot\" />\n <span\n className=\"boff-explore-dot\"\n style={{ animationDelay: \"150ms\" }}\n />\n <span\n className=\"boff-explore-dot\"\n style={{ animationDelay: \"300ms\" }}\n />\n </span>\n <span className=\"truncate\">{activity || \"Thinking…\"}</span>\n </div>\n );\n}\n\n// ============================================================================\n// Answer feedback\n// ============================================================================\n\n/**\n * What the visitor asked us to record, as opposed to what we have asked the server for.\n *\n * `null` means \"this browser has submitted nothing\", which is what makes the row hydrate:\n * with nothing local to show it falls through to `message.feedback`, so a polled, restored\n * or shared transcript comes back already rated. A failed submit puts this back to `null`\n * rather than to a rating of its own, so the fall-through re-exposes whatever the server\n * still holds — which, after a failed RE-rating, is the older rating and is the truth.\n */\ntype LocalRating = ExploreFeedbackRating | null;\n\n/**\n * The quiet row under a completed answer: a prompt, a thumbs-up and a thumbs-down.\n *\n * Layout rules this row lives under (see the pane-height and prerender notes in\n * `EXPLORE_CSS`): it is ordinary in-flow content inside the scroll pane, so it cannot move\n * the root's measured top and cannot change what `measurePane` reads. Nothing here is\n * fixed or sticky, and nothing carries a measured pixel value — these pages are serialised\n * post-hydration, so a number measured on the prerender box would ship to every phone as\n * static HTML. The reason chooser therefore expands IN FLOW rather than as a popover.\n */\nfunction AnswerFeedback({\n strings: T,\n messageId,\n feedback,\n onSubmit,\n}: {\n strings: ExploreStrings;\n messageId: string;\n /** What the server holds for this answer, or null/undefined for an unrated one. */\n feedback?: ExploreFeedback | null;\n /** Resolves false when nothing was recorded — a transport failure or `recorded: false`. */\n onSubmit: (\n rating: ExploreFeedbackRating,\n detail?: { reason?: ExploreFeedbackReason | null; comment?: string },\n ) => Promise<boolean>;\n}) {\n const [local, setLocal] = useState<LocalRating>(null);\n const [failed, setFailed] = useState(false);\n const [sending, setSending] = useState(false);\n const [chooserOpen, setChooserOpen] = useState(false);\n const [reason, setReason] = useState<ExploreFeedbackReason | null>(null);\n const [comment, setComment] = useState(\"\");\n\n const downRef = useRef<HTMLButtonElement>(null);\n const firstReasonRef = useRef<HTMLButtonElement>(null);\n /** Guards a double-click: `sending` state is one render behind the second click. */\n const inFlightRef = useRef(false);\n\n // Unique per answer, so several rated answers in one transcript never share an id.\n const panelId = `boff-explore-feedback-${messageId}`;\n\n const rating: LocalRating = local ?? feedback?.rating ?? null;\n const rated = rating !== null;\n\n // Explicit per-reason keys rather than an indexed tuple: the order of the five reasons and\n // the order of five translated strings are two different things, and a tuple silently\n // mislabels every chip the day one of them moves.\n const reasonLabels: Record<ExploreFeedbackReason, string> = {\n INACCURATE: T.feedbackReasonInaccurate,\n INCOMPLETE: T.feedbackReasonIncomplete,\n OFF_TOPIC: T.feedbackReasonOffTopic,\n HARD_TO_FOLLOW: T.feedbackReasonHardToFollow,\n OTHER: T.feedbackReasonOther,\n };\n\n const closeChooser = useCallback(() => {\n setChooserOpen(false);\n // Focus goes back where it came from, or a keyboard visitor is dropped at the top of the\n // document with the panel gone from under them.\n downRef.current?.focus();\n }, []);\n\n const submit = useCallback(\n async (\n next: ExploreFeedbackRating,\n detail?: { reason?: ExploreFeedbackReason | null; comment?: string },\n ) => {\n if (inFlightRef.current) return;\n inFlightRef.current = true;\n setSending(true);\n // Optimistic: the thumb reflects the press before the round-trip, which is the whole\n // difference between a control that feels alive and one that feels broken.\n setFailed(false);\n setLocal(next);\n\n const recorded = await onSubmit(next, detail);\n\n inFlightRef.current = false;\n setSending(false);\n if (recorded) return;\n\n // Nothing was recorded, so the row must stop claiming otherwise: the thumb reverts and\n // one short line says so.\n //\n // Why this much and no more. Leaving the thumb lit would be a lie the visitor acts on\n // (\"I already told them\"), and that is the one outcome worth avoiding — so silence is\n // not an option. But this is OUR analytics, not their task: a toast, a red alert or a\n // retry prompt would interrupt a marketing visitor over a thing they were doing us a\n // favour by touching at all. So it is muted body text in the slot the prompt already\n // occupied — no colour change, no new row, no height change, nothing to dismiss — and\n // it does not time out, because a notice that clears itself before it is read is\n // exactly the \"they think it was sent\" failure again. The next rating clears it.\n setLocal(null);\n setFailed(true);\n },\n [onSubmit],\n );\n\n const onThumbUp = useCallback(() => {\n setChooserOpen(false);\n // Always sent, even when HELPFUL is already showing: the server upserts, so a second\n // submit is never an error, and this is what makes clicking the same thumb again a retry\n // after a failure rather than a dead control.\n void submit(\"HELPFUL\");\n }, [submit]);\n\n const onThumbDown = useCallback(() => {\n // Thumbs-down is a disclosure, not a submit — nothing leaves the browser until the\n // reason step is confirmed.\n setChooserOpen((open) => !open);\n }, []);\n\n const onSendReason = useCallback(() => {\n // The chooser closes on send and the draft is KEPT. If the submit fails, pressing\n // thumbs-down again reopens it with the reason and comment still filled, one click from\n // retrying — where clearing them would have thrown away work the visitor did for us.\n setChooserOpen(false);\n void submit(\"NOT_HELPFUL\", { reason, comment });\n }, [comment, reason, submit]);\n\n // Open by mouse or by keyboard, the first reason is where the visitor continues from.\n useEffect(() => {\n if (!chooserOpen) return;\n firstReasonRef.current?.focus();\n }, [chooserOpen]);\n\n const thumbClass = (active: boolean) =>\n cn(\n \"inline-flex h-7 w-7 shrink-0 items-center justify-center rounded-full border transition-colors\",\n \"focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\",\n \"disabled:pointer-events-none disabled:opacity-50\",\n active\n ? \"border-primary/40 bg-accent text-primary\"\n : \"border-border bg-card text-muted-foreground hover:border-primary/40 hover:bg-accent hover:text-foreground\",\n );\n\n return (\n <div\n data-boff-explore=\"feedback\"\n data-rating={rating ?? \"none\"}\n className=\"pt-0.5\"\n >\n {/* No auto-margins anywhere in this row: `dir=\"rtl\"` is set on the page root for\n Arabic, and a `ml-auto` would pin the controls to the wrong edge there. Flow order\n plus a gap flips on its own. */}\n <div className=\"flex flex-wrap items-center gap-x-2 gap-y-1\">\n <p\n data-boff-explore=\"feedback-status\"\n /* The same slot carries the prompt, the acknowledgement and the failure notice, so\n a screen reader hears the outcome without a second region appearing from\n nowhere. Live regions announce CHANGES, so the initial prompt stays silent. */\n role=\"status\"\n className=\"text-xs text-muted-foreground\"\n >\n {failed\n ? T.feedbackNotSent\n : rated\n ? T.feedbackThanks\n : T.feedbackPrompt}\n </p>\n <div className=\"flex items-center gap-1\">\n <button\n data-boff-explore=\"feedback-up\"\n type=\"button\"\n disabled={sending}\n aria-label={T.feedbackHelpful}\n title={T.feedbackHelpful}\n aria-pressed={rating === \"HELPFUL\"}\n onClick={onThumbUp}\n className={thumbClass(rating === \"HELPFUL\")}\n >\n <ThumbsUp className=\"h-3.5 w-3.5\" aria-hidden=\"true\" />\n </button>\n <button\n ref={downRef}\n data-boff-explore=\"feedback-down\"\n type=\"button\"\n disabled={sending}\n aria-label={T.feedbackNotHelpful}\n title={T.feedbackNotHelpful}\n aria-pressed={rating === \"NOT_HELPFUL\"}\n aria-expanded={chooserOpen}\n aria-controls={chooserOpen ? panelId : undefined}\n onClick={onThumbDown}\n className={thumbClass(rating === \"NOT_HELPFUL\" || chooserOpen)}\n >\n <ThumbsDown className=\"h-3.5 w-3.5\" aria-hidden=\"true\" />\n </button>\n </div>\n </div>\n\n {chooserOpen ? (\n <div\n id={panelId}\n data-boff-explore=\"feedback-reasons\"\n role=\"group\"\n aria-label={T.feedbackReasonTitle}\n /* Escape anywhere inside the panel closes it, which is what makes it dismissible\n without reaching for the Dismiss control. Stopped here so it cannot travel on to\n a host page listening for Escape on the document. */\n onKeyDown={(event) => {\n if (event.key !== \"Escape\") return;\n event.stopPropagation();\n closeChooser();\n }}\n className=\"boff-explore-fade mt-2 rounded-xl border border-border bg-card p-3\"\n >\n <p className=\"mb-2 text-xs font-medium text-card-foreground\">\n {T.feedbackReasonTitle}\n </p>\n <div className=\"flex flex-wrap gap-1.5\">\n {EXPLORE_FEEDBACK_REASONS.map((code, index) => (\n <button\n key={code}\n ref={index === 0 ? firstReasonRef : undefined}\n data-boff-explore=\"feedback-reason\"\n data-reason={code}\n type=\"button\"\n aria-pressed={reason === code}\n onClick={() =>\n setReason((current) => (current === code ? null : code))\n }\n className={cn(\n \"inline-flex max-w-full items-center rounded-full border px-3 py-1 text-xs transition-colors\",\n \"focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\",\n reason === code\n ? \"border-primary/40 bg-accent text-primary\"\n : \"border-border bg-background text-muted-foreground hover:border-primary/40 hover:bg-accent hover:text-foreground\",\n )}\n >\n <span className=\"truncate\">{reasonLabels[code]}</span>\n </button>\n ))}\n </div>\n\n <div className=\"mt-2 flex flex-wrap items-center gap-2\">\n <input\n data-boff-explore=\"feedback-comment\"\n type=\"text\"\n value={comment}\n onChange={(event) => setComment(event.target.value)}\n onKeyDown={(event) => {\n if (event.key !== \"Enter\") return;\n // Not inside a <form> — the composer's form is elsewhere in the tree — so\n // Enter would otherwise do nothing at all in a one-line field.\n event.preventDefault();\n onSendReason();\n }}\n /* A placeholder is not an accessible name; the same string does both jobs\n rather than shipping a seventh reason-step key that says the same thing. */\n aria-label={T.feedbackCommentPlaceholder}\n placeholder={T.feedbackCommentPlaceholder}\n maxLength={EXPLORE_FEEDBACK_COMMENT_SOFT_MAX}\n /* text-base on mobile is load-bearing, not styling: iOS Safari auto-zooms a\n focused input under 16px, and that zoom is what scaled the viewport and\n created a horizontal scroll last time. Same rule as the composer. */\n className=\"min-w-0 flex-1 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\"\n />\n <Button\n data-boff-explore=\"feedback-send\"\n type=\"button\"\n size=\"sm\"\n disabled={sending}\n onClick={onSendReason}\n >\n {T.feedbackSend}\n </Button>\n <Button\n data-boff-explore=\"feedback-dismiss\"\n type=\"button\"\n size=\"sm\"\n variant=\"ghost\"\n className=\"text-muted-foreground\"\n onClick={closeChooser}\n >\n {T.feedbackDismiss}\n </Button>\n </div>\n </div>\n ) : null}\n </div>\n );\n}\n\n// ============================================================================\n// Hand the conversation to a person\n// ============================================================================\n\n/**\n * The inline hand-off form: an email address, an optional note, and a send.\n *\n * ## Why this exists where it does\n *\n * When the corpus cannot answer, the banner used to offer a link to `/contact` — which is a\n * dead end dressed as help. The visitor arrives at an empty form and has to retype, from\n * memory, everything the conversation on screen already says; most simply leave. The server\n * now takes the conversation itself (`escalateExploreConversation`), so a person picks it up\n * with the transcript attached and the visitor types one line at most.\n *\n * ## Layout rules\n *\n * Ordinary in-flow content inside the scroll pane, exactly like `AnswerFeedback`: nothing\n * fixed, nothing sticky, no measured pixel value anywhere in the markup. These pages are\n * serialised from the POST-HYDRATION DOM, so a number measured on the prerender box would\n * ship to every phone as static HTML. The form expands in flow rather than as a popover for\n * the same reason.\n *\n * ## The address is personal data\n *\n * `email` lives in this component's state and goes to the mutation. It goes NOWHERE else:\n * not to `localStorage` (the hook persists `messages`, and the address is deliberately not\n * one), not into the transcript, not to `onSend`, not into an analytics call. There is no\n * product question a stored visitor address answers, and every place it were copied to is a\n * place nothing ever deletes it from.\n */\nfunction EscalateForm({\n strings: T,\n formId,\n onEscalate,\n onClose,\n onBusyChange,\n}: {\n strings: ExploreStrings;\n /** Stable id, so several answers in one transcript never share one. */\n formId: string;\n onEscalate: (email: string, note?: string) => Promise<ExploreEscalateResult>;\n onClose: () => void;\n /**\n * Raised while a handover is in flight, so the OTHER control that can unmount this\n * form — the quiet trigger, which toggles — can refuse for as long as the request is\n * out. The two closers this form owns (Cancel, Escape) guard themselves; the trigger\n * lives outside it and cannot see `sending`. Must be referentially stable.\n */\n onBusyChange?: (busy: boolean) => void;\n}) {\n const [email, setEmail] = useState(\"\");\n const [note, setNote] = useState(\"\");\n const [error, setError] = useState<string | null>(null);\n const [sending, setSending] = useState(false);\n /** The address the SERVER confirmed, once there is one. Non-null ⇒ handed over. */\n const [sentTo, setSentTo] = useState<string | null>(null);\n\n const emailRef = useRef<HTMLInputElement>(null);\n /** Guards the double-click: `sending` state is one render behind the second press. */\n const inFlightRef = useRef(false);\n\n const titleId = `${formId}-title`;\n const emailId = `${formId}-email`;\n const noteId = `${formId}-note`;\n const errorId = `${formId}-error`;\n\n // Opening the form and then hunting for the field it opened is not an interaction. The\n // visitor asked for a person; put them in the box that gets them one.\n useEffect(() => {\n emailRef.current?.focus();\n }, []);\n\n // Tell the parent while the request is out. The cleanup runs on every change AND on\n // unmount, so a form that disappears for a reason outside its control (the transcript\n // resetting under it) can never leave the trigger disabled forever.\n useEffect(() => {\n onBusyChange?.(sending);\n return () => onBusyChange?.(false);\n }, [sending, onBusyChange]);\n\n const handleSubmit = useCallback(\n async (event: React.FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n if (inFlightRef.current) return;\n\n const address = email.trim();\n // Caught here, so a typo never costs a round-trip and never reaches the mutation. This\n // check is deliberately a SUBSET of the server's: an address it accepts can still come\n // back INVALID_EMAIL, and that verdict is surfaced too (below) because the server is\n // the one that has to deliver.\n if (!looksLikeDeliverableEmail(address)) {\n setError(T.escalateInvalidEmail);\n emailRef.current?.focus();\n return;\n }\n\n inFlightRef.current = true;\n setSending(true);\n setError(null);\n\n const result = await onEscalate(address, note);\n\n inFlightRef.current = false;\n setSending(false);\n\n switch (result.outcome) {\n case \"sent\":\n case \"already-handed-over\":\n // BOTH are success. `already-handed-over` is the double-clicked button, the\n // retried request and the reloaded page — the conversation is with a person\n // either way, and telling a worried visitor \"you already did that\" is a graceless\n // answer to the one thing they got right.\n //\n // The address shown is the SERVER's: on a repeat handover it is the address the\n // FIRST one used, which is where the reply is actually going. Falling back to what\n // was typed only covers a server that sent no address at all, which the contract\n // says cannot happen.\n setSentTo(result.email ?? address);\n return;\n case \"invalid-email\":\n setError(T.escalateInvalidEmail);\n emailRef.current?.focus();\n return;\n case \"rate-limited\":\n setError(T.escalateRateLimited);\n return;\n case \"captcha\":\n setError(T.escalateCaptcha);\n return;\n // `no-conversation` included: the form should not have been offered at all, and the\n // honest thing to show is that nothing was passed on.\n default:\n setError(T.escalateFailed);\n return;\n }\n },\n [T, email, note, onEscalate],\n );\n\n if (sentTo !== null) {\n return (\n <p\n id={formId}\n data-boff-explore=\"escalate-sent\"\n /* A live region, so the outcome is announced rather than only appearing where the\n form used to be — the control that triggered it has just been unmounted. */\n role=\"status\"\n className=\"boff-explore-fade mt-2 rounded-xl border border-border bg-card px-3 py-2 text-xs leading-relaxed text-card-foreground\"\n >\n {fill(T.escalateSent, { email: sentTo })}\n </p>\n );\n }\n\n return (\n <form\n id={formId}\n data-boff-explore=\"escalate-form\"\n aria-labelledby={titleId}\n /* Our own check runs instead of the browser's: a native validation bubble is not\n reliably announced, cannot be styled to this page, and would pre-empt the server's\n INVALID_EMAIL with a different rule. `type=\"email\"` stays, for the keyboard. */\n noValidate\n onSubmit={handleSubmit}\n onKeyDown={(event) => {\n if (event.key !== \"Escape\") return;\n // Stopped here so it cannot travel on to a host page listening on the document —\n // including while the request is out, where a host closing the panel would unmount\n // this form just as surely as we would.\n event.stopPropagation();\n // Nothing closes over a request that is already with the server. The mutation is\n // not cancellable: it files the ticket and sends the mail whatever this component\n // does next, so unmounting here would hand the visitor's address to support while\n // leaving them looking at a page that says a handover never happened. Same rule as\n // the send button, which is disabled for exactly this window.\n if (sending) return;\n onClose();\n }}\n className=\"boff-explore-fade mt-2 space-y-2 rounded-xl border border-border bg-card p-3\"\n >\n <p id={titleId} className=\"text-xs font-medium text-card-foreground\">\n {T.escalateTitle}\n </p>\n <p className=\"text-xs leading-relaxed text-muted-foreground\">\n {T.escalateBody}\n </p>\n\n <div className=\"space-y-1\">\n <label\n htmlFor={emailId}\n className=\"block text-xs font-medium text-card-foreground\"\n >\n {T.escalateEmailLabel}\n </label>\n <input\n ref={emailRef}\n id={emailId}\n name=\"email\"\n data-boff-explore=\"escalate-email\"\n type=\"email\"\n inputMode=\"email\"\n autoComplete=\"email\"\n required\n value={email}\n onChange={(event) => {\n setEmail(event.target.value);\n // The message described the value that was submitted; it stops describing the\n // one being typed the moment it changes.\n if (error) setError(null);\n }}\n aria-invalid={error ? \"true\" : undefined}\n aria-describedby={error ? errorId : undefined}\n placeholder={T.escalateEmailPlaceholder}\n /* text-base on mobile is load-bearing, not styling: iOS Safari auto-zooms a\n focused input under 16px, and that zoom is what creates a horizontal scroll.\n Same rule as the composer and the feedback comment. */\n 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\"\n />\n </div>\n\n <div className=\"space-y-1\">\n <label\n htmlFor={noteId}\n className=\"block text-xs font-medium text-card-foreground\"\n >\n {T.escalateNoteLabel}\n </label>\n <Textarea\n id={noteId}\n name=\"note\"\n data-boff-explore=\"escalate-note\"\n rows={2}\n value={note}\n onChange={(event) => setNote(event.target.value)}\n /* The server's own cap, so the box does not invite text it would truncate. It\n truncates rather than rejects, so this can never lose the whole note. */\n maxLength={EXPLORE_ESCALATION_NOTE_SOFT_MAX}\n className=\"min-h-0 border-border bg-background\"\n />\n </div>\n\n {error ? (\n <p\n id={errorId}\n data-boff-explore=\"escalate-error\"\n /* Announced, not merely coloured: `role=\"alert\"` is what reaches a visitor who\n cannot see that the field turned red. `aria-describedby` on the input ties the\n two together for anyone who tabs back to it. */\n role=\"alert\"\n className=\"text-xs leading-relaxed text-destructive\"\n >\n {error}\n </p>\n ) : null}\n\n <div className=\"flex flex-wrap items-center gap-2\">\n <Button\n data-boff-explore=\"escalate-send\"\n type=\"submit\"\n size=\"sm\"\n disabled={sending}\n >\n {sending ? T.escalateSending : T.escalateSubmit}\n </Button>\n <Button\n data-boff-explore=\"escalate-cancel\"\n type=\"button\"\n size=\"sm\"\n variant=\"ghost\"\n className=\"text-muted-foreground\"\n /* Busy for the same window as the send button, and for the same reason: there is\n no cancelling a mutation the server is already acting on, so the only thing\n this press could achieve is hiding the outcome of it. */\n disabled={sending}\n onClick={onClose}\n >\n {T.escalateCancel}\n </Button>\n </div>\n </form>\n );\n}\n\n// ============================================================================\n// Provenance chips\n// ============================================================================\n\n/**\n * One informational chip. Not a control — nothing here is clickable, and the full source\n * cards with their links are directly below — so these are list items rather than buttons.\n */\nconst PROVENANCE_CHIP =\n \"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\";\n\n/**\n * The evidence, at a glance: how many sources, what kind they are, and whose pages they are.\n *\n * Everything on this row is derived from `message.references` in the browser; no field was\n * added to the contract for it. It renders under answers that actually cite something, which\n * is why it can never contradict the \"I could not find this\" banner — that state is defined\n * by `answered === false`, and its caller withholds the row there (see `AssistantBubble`).\n *\n * Layout rules, same as the feedback row: ordinary in-flow content inside the scroll pane,\n * nothing fixed or sticky, no measured pixel value in the markup. These pages are serialised\n * post-hydration, so anything measured here would ship to every phone as static HTML.\n */\nfunction ProvenanceChips({\n strings: T,\n provenance,\n}: {\n strings: ExploreStrings;\n provenance: ExploreProvenance;\n}) {\n if (provenance.total === 0) return null;\n\n // Explicit per-kind keys rather than an indexed tuple — the order of the kinds and the\n // order of five translated strings are two different things.\n const kindLabels: Record<ExploreReferenceKind, string> = {\n CONCEPT: T.sourceKindConcept,\n DOCS: T.sourceKindDocs,\n PRICING: T.sourceKindPricing,\n USE_CASE: T.sourceKindUseCase,\n PAGE: T.sourceKindPage,\n };\n\n return (\n <ul\n data-boff-explore=\"provenance\"\n aria-label={T.groundedIn}\n className=\"flex flex-wrap items-center gap-1.5\"\n >\n <li data-boff-explore=\"provenance-count\" className={PROVENANCE_CHIP}>\n <BookOpenText className=\"h-3 w-3 shrink-0\" aria-hidden=\"true\" />\n <span className=\"truncate\">\n {provenance.total === 1\n ? T.sourceCountOne\n : fill(T.sourceCountMany, { count: String(provenance.total) })}\n </span>\n </li>\n {provenance.kinds.map(({ kind, count }) => (\n <li\n key={kind}\n data-boff-explore=\"provenance-kind\"\n data-kind={kind}\n data-count={count}\n className={PROVENANCE_CHIP}\n >\n <span className=\"truncate\">\n {count > 1 ? `${kindLabels[kind]} · ${count}` : kindLabels[kind]}\n </span>\n </li>\n ))}\n {provenance.products.map((name) => (\n <li\n key={name}\n data-boff-explore=\"provenance-product\"\n className={PROVENANCE_CHIP}\n >\n <span className=\"truncate\">{name}</span>\n </li>\n ))}\n </ul>\n );\n}\n\n// ============================================================================\n// Copy answer, and read it aloud\n// ============================================================================\n\n/** How long the copy control shows its outcome before going back to offering the action. */\nconst COPY_FEEDBACK_MS = 2500;\n\n/** Shared by the two controls in the row, so neither can drift into its own look. */\nconst ANSWER_ACTION_PILL =\n \"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\";\nconst ANSWER_ACTION_IDLE =\n \"border-border bg-card text-muted-foreground hover:border-primary/40 hover:bg-accent hover:text-foreground\";\nconst ANSWER_ACTION_ACTIVE = \"border-primary/40 bg-accent text-primary\";\n\n/**\n * Read this answer aloud, on the browser's own voice.\n *\n * The composer has dictation; this is the other half of it, and it deliberately mirrors that\n * control: one button, `aria-pressed` for the state, a label that says what pressing it does\n * NOW, and — the part that matters — it is not rendered at all when the browser cannot do\n * it. `useSpeechOutput` reports `supported: false` both for a browser with no synthesiser\n * and for one that accepted a press and then said nothing, so a dead control cannot survive\n * on the page.\n *\n * It speaks {@link answerSpeechText}: the same stripper as the copy button, in its speech\n * mode. One stripper with two modes rather than two strippers — a second one would\n * eventually disagree, and the disagreement would be a voice reading \"asterisk asterisk\n * Settings asterisk asterisk\" out loud.\n */\nfunction ReadAloudButton({\n strings: T,\n text,\n lang,\n hold,\n}: {\n strings: ExploreStrings;\n /** The answer as something to say — see `answerSpeechText`. */\n text: string;\n /** BCP-47 tag for the page's locale, so the right voice reads it. */\n lang: string;\n /**\n * BOFF-9797: the live avatar is speaking (its status line), or null. Held, the control stays where it is but starts\n * nothing (`aria-disabled`, the line as its title): a second voice would talk over the avatar.\n */\n hold: string | null;\n}) {\n const speech = useSpeechOutput({ lang });\n if (!speech.supported) return null;\n\n const label = speech.speaking ? T.stopReading : T.readAloud;\n // A reading under way when the hold began was stopped by it; one still speaking can always be stopped.\n const held = hold !== null && !speech.speaking;\n return (\n <button\n data-boff-explore=\"read-aloud\"\n data-speaking={speech.speaking ? \"true\" : \"false\"}\n type=\"button\"\n title={held ? hold : label}\n aria-pressed={speech.speaking}\n aria-disabled={held ? \"true\" : undefined}\n onClick={() => {\n if (!held) speech.toggle(text);\n }}\n className={cn(\n ANSWER_ACTION_PILL,\n speech.speaking ? ANSWER_ACTION_ACTIVE : ANSWER_ACTION_IDLE,\n held && \"cursor-not-allowed opacity-50\",\n )}\n >\n <Volume2 className=\"h-3 w-3 shrink-0\" aria-hidden=\"true\" />\n <span className=\"truncate\">{label}</span>\n </button>\n );\n}\n\n/**\n * The quiet row under a completed answer that copies it.\n *\n * Same idiom as the header's share control, deliberately: the acknowledgement is the\n * button's OWN label for a couple of seconds, because no host site is guaranteed to have a\n * toast renderer mounted — `showToast` with nothing listening is a no-op, which is exactly\n * the \"it looked like it worked\" failure this control must not have.\n *\n * `navigator.clipboard` does not exist outside a secure context and `writeText` can be\n * refused by permission policy, so the lookup AND the call are guarded: this never throws,\n * and it never claims success it did not get. There is no hand-copy fallback the way share\n * has one — share puts a short URL in an input to select, and an entire answer will not fit\n * in one — but the answer itself is selectable text a few pixels above the button, so the\n * failure state points at something the visitor can still do.\n */\nfunction AnswerActions({\n strings: T,\n text,\n speechText,\n speechLang,\n voiceHold,\n}: {\n strings: ExploreStrings;\n /** The readable answer — see `answerPlainText`. */\n text: string;\n /** The same answer as something to say — see `answerSpeechText`. */\n speechText: string;\n /** BCP-47 tag for the page's locale, handed to the read-aloud control. */\n speechLang: string;\n /** BOFF-9797: the live avatar is speaking, and read-aloud is held (see `ExplorePageProps.voiceHold`). */\n voiceHold: string | null;\n}) {\n const [outcome, setOutcome] = useState<\"idle\" | \"copied\" | \"failed\">(\"idle\");\n const resetRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n useEffect(\n () => () => {\n if (resetRef.current !== null) clearTimeout(resetRef.current);\n },\n [],\n );\n\n const copy = useCallback(async () => {\n let copied = false;\n try {\n const clipboard =\n typeof navigator === \"undefined\" ? undefined : navigator.clipboard;\n if (typeof clipboard?.writeText === \"function\") {\n await clipboard.writeText(text);\n copied = true;\n }\n } catch {\n /* Refused, or no permission. Reported below rather than swallowed. */\n copied = false;\n }\n setOutcome(copied ? \"copied\" : \"failed\");\n if (resetRef.current !== null) clearTimeout(resetRef.current);\n resetRef.current = setTimeout(() => setOutcome(\"idle\"), COPY_FEEDBACK_MS);\n }, [text]);\n\n const label =\n outcome === \"copied\"\n ? T.copied\n : outcome === \"failed\"\n ? T.copyFailed\n : T.copyAnswer;\n\n return (\n <div\n data-boff-explore=\"answer-actions\"\n className=\"flex flex-wrap items-center gap-2 pt-0.5\"\n >\n <button\n data-boff-explore=\"copy-answer\"\n data-outcome={outcome}\n type=\"button\"\n title={label}\n onClick={() => {\n void copy();\n }}\n className={cn(\n ANSWER_ACTION_PILL,\n outcome === \"failed\"\n ? \"border-destructive/40 bg-card text-destructive\"\n : ANSWER_ACTION_IDLE,\n )}\n >\n {outcome === \"copied\" ? (\n <Check className=\"h-3 w-3 shrink-0\" aria-hidden=\"true\" />\n ) : (\n <Copy className=\"h-3 w-3 shrink-0\" aria-hidden=\"true\" />\n )}\n <span className=\"truncate\">{label}</span>\n </button>\n <ReadAloudButton\n strings={T}\n text={speechText}\n lang={speechLang}\n hold={voiceHold}\n />\n {/* The button's own label is the acknowledgement, and a label that changes under a\n screen reader is not announced. This is the announcement; it is empty at rest, so\n nothing is said until something has actually happened. */}\n <span data-boff-explore=\"copy-status\" role=\"status\" className=\"sr-only\">\n {outcome === \"idle\" ? \"\" : label}\n </span>\n </div>\n );\n}\n\n// ============================================================================\n// Message bubbles\n// ============================================================================\n\nfunction UserBubble({\n strings: T,\n message,\n}: {\n strings: ExploreStrings;\n message: ExploreMessage;\n}) {\n // The server echoes back what it ACCEPTED, not what the browser sent — a file dropped by a\n // server-side limit simply does not appear here, which is the honest record of the turn.\n const attachments = message.attachments ?? [];\n\n return (\n <div className=\"flex flex-col items-end gap-1.5\">\n <div\n data-boff-explore=\"user\"\n className=\"max-w-[85%] whitespace-pre-wrap break-words rounded-2xl rounded-br-md bg-primary px-4 py-2.5 text-sm leading-relaxed text-primary-foreground shadow-sm\"\n >\n {message.content}\n </div>\n {attachments.length > 0 ? (\n <ul\n data-boff-explore=\"user-attachments\"\n className=\"flex max-w-[85%] flex-wrap justify-end gap-1.5\"\n >\n {attachments.map((attachment) => (\n <li\n key={`${attachment.name}-${attachment.size}`}\n data-boff-explore=\"user-attachment\"\n data-text-extracted={attachment.textExtracted ? \"true\" : \"false\"}\n className=\"flex max-w-full items-center gap-1.5 rounded-full border border-border bg-muted/60 px-2.5 py-1 text-xs text-muted-foreground\"\n >\n <Paperclip className=\"h-3 w-3 shrink-0\" />\n <span className=\"truncate\" title={attachment.name}>\n {attachment.name}\n </span>\n {attachment.textExtracted ? null : (\n <span className=\"shrink-0\">· {T.attachmentNameOnly}</span>\n )}\n </li>\n ))}\n </ul>\n ) : null}\n </div>\n );\n}\n\nfunction AssistantBubble({\n strings: T,\n message,\n activity,\n imageOrigins,\n productSlugs,\n productNames,\n speechLang,\n voiceHold,\n onNavigate,\n anchorRef,\n onFollow,\n onFollowUp,\n onFeedback,\n onEscalate,\n isLatestAnswer = false,\n}: {\n strings: ExploreStrings;\n message: ExploreMessage;\n activity: string | null;\n /** Origins an inline image may come from — see `inlineImageOrigins`. */\n imageOrigins: ReadonlySet<string>;\n /** Catalog origin → product slug, for a video card's `data-product`. */\n productSlugs: ReadonlyMap<string, string>;\n /** Catalog origin → product display name, for the provenance row. */\n productNames: ReadonlyMap<string, string>;\n /** BCP-47 tag for the page's locale — which voice reads this answer aloud. */\n speechLang: string;\n /** BOFF-9797: the live avatar is speaking, and read-aloud is held (see `ExplorePageProps.voiceHold`). */\n voiceHold: string | null;\n onNavigate?: (path: string) => void;\n /** Set on the newest assistant turn so the transcript can align its top. */\n anchorRef?: React.Ref<HTMLDivElement>;\n onFollow?: (kind: \"CTA\" | \"REFERENCE\", url: string) => void;\n onFollowUp?: (question: string) => void;\n /**\n * Rate this answer. Omitted when there is nobody to rate on behalf of — a read-only\n * shared view — and the row then does not render at all, rather than offering a control\n * the server can only answer `recorded: false` to.\n */\n onFeedback?: (\n rating: ExploreFeedbackRating,\n detail?: { reason?: ExploreFeedbackReason | null; comment?: string },\n ) => Promise<boolean>;\n /**\n * Hand this conversation to a person.\n *\n * Omitted when there is no conversation token to hand over — a read-only shared view, or\n * a page where nothing has been asked yet — and the form is then not offered at all,\n * because the submit could only fail. The \"we could not find this\" banner falls back to\n * its old `/contact` link in that case: a dead end is still better than a control that\n * cannot work.\n */\n onEscalate?: (email: string, note?: string) => Promise<ExploreEscalateResult>;\n /**\n * Whether this is the newest assistant turn.\n *\n * Decides whether the quiet \"talk to a person\" trigger renders under an answer we DID\n * give. It renders on the last turn only. The visitor's need for a person is about where\n * the conversation has GOT to, not about one turn in the middle of it — and a transcript\n * that repeats the offer under every answer stops reading as an escape hatch and starts\n * reading as us giving up on our own answers.\n */\n isLatestAnswer?: boolean;\n}) {\n const streaming =\n message.status === \"PENDING\" || message.status === \"RUNNING\";\n const body = message.content || message.partialContent || \"\";\n const failed = message.status === \"FAILED\";\n const completed = message.status === \"COMPLETED\";\n\n /**\n * The answer as it is being read, rather than as it was last polled.\n *\n * `partialContent` is replaced wholesale every ~1.5s, so painting it as it arrives made\n * the answer land in blocks — a reader watched text snap rather than arrive. This reveals\n * the SAME characters at a readable pace and asks for nothing extra to do it: no request,\n * no shorter poll, no socket. Once the turn is settled the hook returns the whole answer\n * on the render that says so, so nobody ever waits on an animation for text we already\n * have.\n */\n const visible = useProgressiveReveal(body, !streaming);\n\n const provenance = useMemo(\n () => summariseReferences(message.references, imageOrigins, productNames),\n [message.references, imageOrigins, productNames],\n );\n /**\n * `message.content`, never `body`: `body` falls back to `partialContent`, which is cut\n * mid-token, and the control only exists on a COMPLETED answer anyway.\n */\n const copyText = useMemo(\n () => answerPlainText(message.content),\n [message.content],\n );\n /** The same answer, said rather than pasted — see `answerSpeechText`. */\n const speechText = useMemo(\n () => answerSpeechText(message.content),\n [message.content],\n );\n\n /**\n * The corpus found nothing, so there is nothing to summarise. A chip row reading\n * \"2 sources\" under a banner that says the answer is not grounded in a source would be the\n * page contradicting itself in two adjacent lines.\n */\n const grounded = completed && message.answered !== false;\n\n /**\n * The hand-off, and where the visitor reaches it.\n *\n * TWO entry points, and the second one is a decision worth writing down. The obvious\n * placement is the unanswered turn alone — that is the dead end the wave is about. But\n * the corpus is product documentation: it can answer a question about the product\n * perfectly and still have nothing to say about the visitor's own situation (their\n * contract, their invoice, their outage). Offering a person only after the assistant has\n * admitted defeat means the route to a human runs through getting an unanswerable answer\n * first, which is both slower and a worse experience than the /contact link it replaced.\n *\n * So: in the banner when we could not answer, and as a quiet line under the newest answer\n * when we could. Never both on one turn, and never on turns further up the transcript —\n * see `isLatestAnswer`.\n */\n const [escalateOpen, setEscalateOpen] = useState(false);\n /**\n * True while the form has a handover with the server. The quiet trigger TOGGLES, so it is\n * a third way to unmount the form mid-request — and the form, which owns `sending`, is\n * below it in the tree and cannot disable it from there.\n */\n const [escalateBusy, setEscalateBusy] = useState(false);\n const escalateTriggerRef = useRef<HTMLButtonElement>(null);\n const escalateFormId = `boff-explore-escalate-${message.id}`;\n const unanswered = completed && message.answered === false;\n const offerEscalate = Boolean(onEscalate) && completed;\n const showQuietEscalate = offerEscalate && !unanswered && isLatestAnswer;\n\n const closeEscalate = useCallback(() => {\n setEscalateOpen(false);\n // Focus goes back where it came from, or a keyboard visitor is dropped at the top of the\n // document with the form gone from under them.\n escalateTriggerRef.current?.focus();\n }, []);\n\n /** Stable: it is an effect dependency inside the form. */\n const handleEscalateBusy = useCallback((busy: boolean) => {\n setEscalateBusy(busy);\n }, []);\n\n return (\n <div\n ref={anchorRef}\n data-boff-explore=\"assistant\"\n data-status={message.status}\n className=\"boff-explore-rise flex scroll-mt-4 gap-3\"\n >\n <span\n aria-hidden=\"true\"\n className=\"mt-0.5 flex h-7 w-7 shrink-0 items-center justify-center rounded-lg bg-primary/10 text-primary\"\n >\n <Sparkles className=\"h-4 w-4\" />\n </span>\n\n <div className=\"min-w-0 flex-1 space-y-3\">\n {/* The corpus had nothing. Saying so outright is more credible than a hedged\n paragraph that reads like an answer — and it points somewhere useful. */}\n {unanswered ? (\n <div\n data-boff-explore=\"no-answer\"\n className=\"flex items-start gap-2 rounded-xl border border-amber-500/30 bg-amber-500/10 px-3 py-2 text-xs leading-relaxed text-foreground\"\n >\n <TriangleAlert className=\"mt-0.5 h-3.5 w-3.5 shrink-0 text-amber-600 dark:text-amber-400\" />\n <span>\n {T.noAnswer}{\" \"}\n {offerEscalate ? (\n /* The point of the wave: the same words, but they now open a form that\n sends the conversation we are both looking at, instead of a link to a\n blank contact page that asks the visitor to type it all again. */\n <button\n ref={escalateTriggerRef}\n data-boff-explore=\"escalate-open\"\n type=\"button\"\n aria-expanded={escalateOpen}\n aria-controls={escalateOpen ? escalateFormId : undefined}\n onClick={() => setEscalateOpen(true)}\n className=\"rounded-sm underline underline-offset-2 hover:text-primary focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\"\n >\n {T.askHuman}\n </button>\n ) : (\n /* No conversation to hand over (a shared, read-only view). The old dead end\n is still better than a control whose submit could only fail. */\n <a\n href=\"/contact\"\n className=\"underline underline-offset-2 hover:text-primary\"\n onClick={(event) => {\n if (!onNavigate) return;\n event.preventDefault();\n onNavigate(\"/contact\");\n }}\n >\n {T.askHuman}\n </a>\n )}\n .\n </span>\n </div>\n ) : null}\n\n {visible ? (\n <div className=\"rounded-2xl rounded-tl-md border border-border bg-card px-4 py-3 shadow-sm\">\n {/* The shared renderer — the same one a published answer page uses, so a table\n or an illustration cannot look one way in the chat and another on a page. */}\n <ExploreAnswerBody\n strings={T}\n imageOrigins={imageOrigins}\n productSlugs={productSlugs}\n enabled={completed}\n className=\"boff-prose-sm text-card-foreground\"\n >\n {visible}\n </ExploreAnswerBody>\n {streaming ? (\n <span className=\"boff-explore-caret\" aria-hidden=\"true\" />\n ) : null}\n </div>\n ) : null}\n\n {/* Directly under the answer: the shape of the evidence first, the source cards\n themselves below it. */}\n {grounded && provenance.total > 0 ? (\n <ProvenanceChips strings={T} provenance={provenance} />\n ) : null}\n\n {streaming ? <ThinkingIndicator activity={activity} /> : null}\n\n {failed && !body ? (\n <div className=\"rounded-2xl rounded-tl-md border border-border bg-muted px-4 py-3 text-sm text-muted-foreground\">\n {T.answerDidNotArrive}\n </div>\n ) : null}\n\n {message.references.length > 0 ? (\n <div>\n <p className=\"mb-2 text-xs font-semibold uppercase tracking-wide text-muted-foreground\">\n {T.sources}\n </p>\n <div className=\"grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-3\">\n {message.references.map((reference) => (\n <ReferenceCard\n key={reference.url}\n reference={reference}\n onFollow={(url) => onFollow?.(\"REFERENCE\", url)}\n />\n ))}\n </div>\n </div>\n ) : null}\n\n {message.ctas.length > 0 ? (\n <div className=\"flex flex-wrap gap-2 pt-0.5\">\n {message.ctas.map((cta) => (\n <CtaButton\n key={`${cta.kind}-${cta.url}`}\n cta={cta}\n onNavigate={onNavigate}\n onFollow={(url) => onFollow?.(\"CTA\", url)}\n />\n ))}\n </div>\n ) : null}\n\n {/* One question is a lookup; a second is a conversation. These are derived from\n what the answer actually cited, so they are always answerable. */}\n {message.status === \"COMPLETED\" &&\n (message.followUps?.length ?? 0) > 0 ? (\n <div className=\"space-y-1.5 pt-0.5\">\n <p className=\"text-xs font-medium text-muted-foreground\">\n {T.nextYouCouldAsk}\n </p>\n <div className=\"flex flex-wrap gap-1.5\">\n {(message.followUps ?? []).map((question) => (\n <button\n key={question}\n data-boff-explore=\"follow-up\"\n type=\"button\"\n onClick={() => onFollowUp?.(question)}\n className=\"group inline-flex max-w-full items-center gap-1.5 rounded-full border border-border bg-card px-3 py-1 text-left text-xs text-card-foreground transition-colors hover:border-primary/40 hover:bg-accent focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\"\n >\n <span className=\"truncate\">{question}</span>\n <ArrowUp className=\"h-3 w-3 shrink-0 rotate-45 text-muted-foreground transition-colors group-hover:text-primary\" />\n </button>\n ))}\n </div>\n </div>\n ) : null}\n\n {/* An answer worth reading is an answer somebody wants to keep — in a ticket, a\n message to a colleague, their own notes. Only on a COMPLETED turn, and only when\n there is text: a failed turn has nothing to copy. */}\n {completed && copyText !== \"\" ? (\n <AnswerActions\n strings={T}\n text={copyText}\n speechText={speechText}\n speechLang={speechLang}\n voiceHold={voiceHold}\n />\n ) : null}\n\n {/* Last, under the sources and the follow-ups: every answer ends with no way to say\n \"that was wrong\" or \"that helped\", and the visitor's only other options are to\n rephrase or leave — from which we learn nothing either way. Only on a COMPLETED\n answer, because a streaming or failed one is not a thing anybody can rate. */}\n {completed && onFeedback ? (\n <AnswerFeedback\n strings={T}\n messageId={message.id}\n feedback={message.feedback}\n onSubmit={onFeedback}\n />\n ) : null}\n\n {/* The quiet way to a person after an answer we DID give — see the note on\n `escalateOpen`. Deliberately understated: it is an escape hatch, not a call to\n action, and it must not read as the page doubting the answer above it. */}\n {showQuietEscalate ? (\n <div className=\"pt-0.5\">\n <button\n ref={escalateTriggerRef}\n data-boff-explore=\"escalate-open\"\n type=\"button\"\n aria-expanded={escalateOpen}\n aria-controls={escalateOpen ? escalateFormId : undefined}\n /* This one toggles, so while a handover is in flight it is a close button —\n and closing would unmount the form the answer is about to land in. The\n request cannot be recalled, so the only outcome of that press is a visitor\n who never learns their conversation was handed over. */\n disabled={escalateBusy}\n onClick={() => setEscalateOpen((open) => !open)}\n 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\"\n >\n {T.escalateOpen}\n </button>\n </div>\n ) : null}\n\n {/* ONE render site for the form, at the end of the bubble, whichever trigger opened\n it: an unanswered turn is a banner and little else, so \"below the banner\" and\n \"at the end\" are the same place there, and on an answered turn the form belongs\n under the trigger rather than above the answer. */}\n {escalateOpen && onEscalate ? (\n <EscalateForm\n strings={T}\n formId={escalateFormId}\n onEscalate={onEscalate}\n onClose={closeEscalate}\n onBusyChange={handleEscalateBusy}\n />\n ) : null}\n </div>\n </div>\n );\n}\n\n// ============================================================================\n// Error banner\n// ============================================================================\n\nfunction ErrorBanner({\n error,\n onRetry,\n onReset,\n}: {\n error: ExploreChatError;\n onRetry: () => void;\n onReset: () => void;\n}) {\n const showRetry = error.retryable;\n const showReset = error.code === \"CONVERSATION_LIMIT\";\n\n return (\n <div\n data-boff-explore=\"error\"\n data-error-kind={error.kind}\n role=\"alert\"\n className=\"mb-3 flex items-start gap-3 rounded-xl border border-destructive/40 bg-destructive/10 px-3 py-2.5\"\n >\n {/* Solid destructive chip for the icon: `text-destructive` alone loses\n contrast against a dark background in dark mode. */}\n <span\n aria-hidden=\"true\"\n className=\"mt-0.5 flex h-5 w-5 shrink-0 items-center justify-center rounded-full bg-destructive text-destructive-foreground\"\n >\n <TriangleAlert className=\"h-3 w-3\" />\n </span>\n <p className=\"flex-1 text-sm leading-relaxed text-foreground\">\n {error.message}\n </p>\n {showRetry ? (\n <Button\n data-boff-explore=\"retry\"\n type=\"button\"\n size=\"sm\"\n variant=\"outline\"\n onClick={onRetry}\n >\n Retry\n </Button>\n ) : null}\n {showReset ? (\n <Button type=\"button\" size=\"sm\" variant=\"outline\" onClick={onReset}>\n New chat\n </Button>\n ) : null}\n </div>\n );\n}\n\n// ============================================================================\n// Welcome / capability disclosure\n// ============================================================================\n\n/**\n * Example prompts as a single auto-advancing line.\n *\n * They used to wrap into a block several rows tall, which on a phone pushed everything below\n * it — including the composer — off the screen. One line costs a fixed ~40px no matter how\n * many prompts there are, and rotating through them keeps every prompt reachable without a\n * \"show more\".\n *\n * Autoplay pauses on hover and on keyboard focus, and never starts at all for visitors who\n * asked for reduced motion — for them the arrows are the whole interaction.\n */\nfunction PromptCarousel({\n strings: T,\n label,\n prompts,\n onPrompt,\n disabled,\n}: {\n strings: ExploreStrings;\n label: string;\n prompts: string[];\n onPrompt: (prompt: string) => void;\n disabled: boolean;\n}) {\n const [index, setIndex] = useState(0);\n const [paused, setPaused] = useState(false);\n\n const count = prompts.length;\n const current = prompts[index % count] ?? prompts[0] ?? \"\";\n\n const go = useCallback(\n (delta: number) => {\n setIndex((i) => (i + delta + count) % count);\n },\n [count],\n );\n\n // Swiping is the gesture people actually reach for on a phone; the arrows stay for\n // pointer and keyboard users.\n const swipe = useSwipe({\n onSwipeLeft: () => go(1),\n onSwipeRight: () => go(-1),\n enabled: count > 1,\n });\n\n useEffect(() => {\n if (paused || disabled || count < 2) return;\n if (\n typeof window !== \"undefined\" &&\n window.matchMedia?.(\"(prefers-reduced-motion: reduce)\").matches\n ) {\n return;\n }\n const timer = setInterval(() => setIndex((i) => (i + 1) % count), 4500);\n return () => clearInterval(timer);\n }, [paused, disabled, count]);\n\n if (count === 0) return null;\n\n // One grid, two arrangements, and one set of buttons (so a screen reader never meets the\n // arrows twice). From `sm` up it is the familiar row: the label above, `‹ pill ›` below. On\n // a phone the arrows move up beside the label and the pill takes the full width. Flanked by\n // the arrows, the pill's text had ~200px at 390px wide: measured in Chrome, four of the six\n // live example prompts needed three lines there (five needed four at 320px), so the\n // two-line clamp still cut most of them mid-sentence.\n return (\n <div\n className=\"grid min-w-0 touch-pan-y grid-cols-[minmax(0,1fr)_auto_auto] items-center gap-x-1.5 gap-y-1.5 sm:grid-cols-[auto_minmax(0,1fr)_auto]\"\n role=\"group\"\n aria-roledescription=\"carousel\"\n aria-label=\"Example questions\"\n onMouseEnter={() => setPaused(true)}\n onMouseLeave={() => setPaused(false)}\n onFocusCapture={() => setPaused(true)}\n onBlurCapture={() => setPaused(false)}\n {...swipe}\n >\n <p className=\"col-start-1 row-start-1 text-xs font-semibold uppercase tracking-wide text-muted-foreground sm:col-span-3\">\n {label}\n </p>\n {count > 1 ? (\n <button\n type=\"button\"\n aria-label={T.prevSuggestion}\n onClick={() => go(-1)}\n /* Visible on mobile too. It was sm:inline-flex, which left a phone with a forward\n arrow only and no way to step back to a prompt that had just rotated away. */\n className=\"col-start-2 row-start-1 inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-full text-muted-foreground transition-colors hover:bg-accent hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring sm:col-start-1 sm:row-start-2\"\n >\n <ChevronLeft className=\"h-4 w-4\" />\n </button>\n ) : null}\n\n <button\n data-boff-explore=\"chip\"\n data-chip-kind=\"prompt\"\n type=\"button\"\n disabled={disabled}\n aria-label={`Ask: ${current}`}\n aria-live={paused ? \"polite\" : \"off\"}\n onClick={() => onPrompt(current)}\n /* min-w-0 + truncate is what keeps a long prompt from widening the page. The pill\n itself is NOT re-keyed per prompt: re-mounting it made the whole pill — border and\n background — fade in from nothing every 4.5s, so for a moment the row showed two\n arrows around an empty gap. Only the text below changes and fades now. */\n className={cn(\n \"group col-span-3 row-start-2 flex min-w-0 items-center gap-2 rounded-full border border-border bg-card px-4 py-2 max-sm:min-h-[3.625rem] max-sm:rounded-2xl text-left text-sm text-card-foreground shadow-sm transition-colors hover:border-primary/50 hover:bg-accent disabled:cursor-not-allowed disabled:opacity-50 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\",\n count > 1 ? \"sm:col-span-1 sm:col-start-2\" : \"sm:col-span-3\",\n )}\n >\n <Sparkles className=\"h-3.5 w-3.5 shrink-0 text-primary\" />\n {/* A phone shows the whole example: truncated, the example problem was cut off\n before it said what the problem was — and the examples are what tell a visitor the\n page takes problems, not product names. Full width, every live prompt fits two\n lines at 390px; three is the backstop for a narrower phone or a longer prompt. */}\n <span\n key={current}\n className=\"boff-explore-fade min-w-0 max-sm:line-clamp-3 sm:truncate\"\n >\n {current}\n </span>\n {/* Decorative: the whole pill is the control. On a phone its width goes to the text. */}\n <ArrowUp className=\"ml-auto h-3.5 w-3.5 shrink-0 rotate-45 text-muted-foreground transition-colors group-hover:text-primary max-sm:hidden\" />\n </button>\n\n {count > 1 ? (\n <button\n type=\"button\"\n aria-label={T.nextSuggestion}\n onClick={() => go(1)}\n className=\"col-start-3 row-start-1 inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-full text-muted-foreground transition-colors hover:bg-accent hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring sm:row-start-2\"\n >\n <ChevronRight className=\"h-4 w-4\" />\n </button>\n ) : null}\n </div>\n );\n}\n\n/**\n * Product focus chips on one line, expandable.\n *\n * Collapsed is a single clipped row; expanded wraps to the full set. The row scrolls inside\n * itself rather than pushing the page wide — `overflow-x-auto` on a `min-w-0` flex child is\n * contained, and the scrollbar is hidden so it reads as a strip, not a scroller.\n */\nfunction ProductStrip({\n strings: T,\n products,\n focusProduct,\n onFocus,\n}: {\n strings: ExploreStrings;\n products: Array<{ slug: string; name: string; tagline?: string | null }>;\n focusProduct: string | null;\n onFocus: (slug: string | null) => void;\n}) {\n const [expanded, setExpanded] = useState(false);\n\n const chipClass = (active: boolean) =>\n cn(\n \"shrink-0 rounded-full border px-3 py-1 text-xs font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\",\n active\n ? \"border-primary bg-primary text-primary-foreground\"\n : \"border-border bg-card text-muted-foreground hover:bg-accent hover:text-accent-foreground\",\n );\n\n return (\n <div\n className=\"flex min-w-0 items-center gap-2\"\n role=\"group\"\n aria-label=\"Focus the assistant on one product\"\n >\n <div\n className={cn(\n \"boff-explore-strip flex min-w-0 flex-1 gap-2\",\n expanded\n ? \"flex-wrap\"\n : \"boff-explore-chips-fade flex-nowrap overflow-x-auto\",\n )}\n >\n <button\n data-boff-explore=\"chip\"\n data-chip-kind=\"product\"\n data-product=\"all\"\n type=\"button\"\n aria-pressed={focusProduct === null}\n onClick={() => onFocus(null)}\n className={chipClass(focusProduct === null)}\n >\n {T.allProducts}\n </button>\n {products.map((product) => {\n // A focus restored under a product's old slug (botlit) still marks its chip.\n const focused = isSameProductSlug(focusProduct, product.slug);\n return (\n <button\n key={product.slug}\n data-boff-explore=\"chip\"\n data-chip-kind=\"product\"\n data-product={product.slug}\n type=\"button\"\n aria-pressed={focused}\n title={product.tagline ?? product.name}\n onClick={() => onFocus(focused ? null : product.slug)}\n className={chipClass(focused)}\n >\n {product.name}\n </button>\n );\n })}\n </div>\n {products.length > 0 ? (\n <button\n type=\"button\"\n data-boff-explore=\"products-toggle\"\n aria-expanded={expanded}\n onClick={() => setExpanded((v) => !v)}\n className=\"shrink-0 whitespace-nowrap rounded-full px-2 py-1 text-xs font-medium text-primary underline-offset-4 hover:underline focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\"\n >\n {expanded ? T.showLess : `${T.showAll} ${products.length}`}\n </button>\n ) : null}\n </div>\n );\n}\n\n/**\n * How many concept cards the strip shows at most.\n *\n * The catalog sends up to 8; six is what fits before the strip stops reading as a row of\n * suggestions and starts reading as a gallery the visitor is expected to browse. The rest of\n * the catalogue is one question away, which is the point of the page.\n */\nconst MAX_CONCEPT_CARDS = 6;\n\n/**\n * Concept illustrations on the welcome screen — the visual half of \"what can I ask?\".\n *\n * Pressing a card ASKS about that concept and stays here. It deliberately does not link to\n * the concept page: the entire value of `/explore` is that a visitor does not have to go and\n * read a site, and a strip of outbound links would be a navigation menu wearing pictures.\n *\n * Three rules this component exists to keep:\n *\n * - **It disappears cleanly.** No highlights, or every image failed, and it renders nothing\n * at all — heading included. A section title over an empty rail is a hole; no section is a\n * decision.\n * - **A broken picture takes its own card with it**, rather than leaving a grey frame in a\n * row that is otherwise all pictures. Same rule the inline concept images follow.\n * - **It changes no geometry.** Ordinary in-flow content inside the scroll pane: nothing\n * fixed, nothing sticky, no measured value in the markup, and no effect that reads a box.\n * The pane's height is built from the root's measured TOP, which content inside the\n * transcript cannot move, and the composer lives outside the scroller so nothing added\n * here can push it off a phone. These pages are serialised post-hydration, so the strip\n * this bakes is the one every phone paints until the bundle runs — which is why the\n * fallback catalog ships no highlights at all rather than invented ones.\n *\n * Keyboard: every card is a real button, so Tab reaches them and the browser scrolls each\n * one into view as it goes. The rail itself takes no `tabIndex` and installs no key handler,\n * so nothing here adds a tab stop that is not a control, and nothing swallows a key.\n */\nfunction ConceptStrip({\n strings: T,\n highlights,\n onAsk,\n disabled,\n}: {\n strings: ExploreStrings;\n highlights: readonly ExploreConceptHighlight[];\n /** Sends the question. The strip composes it, so the wording stays with the copy. */\n onAsk: (question: string) => void;\n disabled: boolean;\n}) {\n const [failed, setFailed] = useState<ReadonlySet<string>>(() => new Set());\n const markFailed = useCallback((src: string) => {\n setFailed((current) =>\n current.has(src) ? current : new Set(current).add(src),\n );\n }, []);\n\n /**\n * Arrow affordances for the rail, on pointer devices only.\n *\n * A touch visitor swipes and needs no arrows; a mouse visitor gets no\n * scrollbar on a `overflow-x-auto` rail until they hover it, so on desktop the\n * rail reads as a row that simply ends. `canLeft`/`canRight` are measured from\n * the element rather than assumed from the card count, because how many cards\n * fit depends on the viewport.\n */\n const railRef = useRef<HTMLUListElement | null>(null);\n const [canLeft, setCanLeft] = useState(false);\n const [canRight, setCanRight] = useState(false);\n\n const measureRail = useCallback(() => {\n const el = railRef.current;\n if (!el) return;\n const max = el.scrollWidth - el.clientWidth;\n // How far the rail sits from its LEFT edge, in either direction. Right-to-left, scrollLeft\n // is 0 at the start (the right edge) and runs negative towards the left — the model every\n // current engine follows — so reading it as a left-to-right offset left both arrows dark\n // on a right-to-left page however many cards were hidden.\n const rtl =\n typeof getComputedStyle === \"function\" &&\n getComputedStyle(el).direction === \"rtl\";\n const fromLeft = rtl ? max + el.scrollLeft : el.scrollLeft;\n // 1px of slack: fractional widths make scrollLeft land a hair short of the\n // true end, which would leave the arrow lit with nowhere to go.\n setCanLeft(fromLeft > 1);\n setCanRight(fromLeft < max - 1);\n }, []);\n\n useEffect(() => {\n const el = railRef.current;\n if (!el) return;\n measureRail();\n const onResize = () => measureRail();\n window.addEventListener(\"resize\", onResize);\n // The rail's own box changes with no window resize: the pane gains or loses its scrollbar\n // (which narrows the rail), and the welcome-fit ladder re-lays the cards as a consent\n // banner appears or is dismissed, or the composer grows as someone types. Measured only on\n // window resize, the arrows keep whatever the rail looked like at mount. An earlier\n // version of the ladder hid the whole strip, and with this listener alone a strip hidden\n // at mount came back with \"next\" dark — reproduced in Chrome: four cards, and no control\n // to reach the rest. A ResizeObserver fires on exactly these changes; the window listener\n // stays for engines without one.\n const observer =\n typeof ResizeObserver === \"function\"\n ? new ResizeObserver(onResize)\n : null;\n observer?.observe(el);\n return () => {\n window.removeEventListener(\"resize\", onResize);\n observer?.disconnect();\n };\n // `failed` and the highlight count both change what is in the rail, and both\n // are in scope here; `visible` is derived below, so depending on it would be\n // a use-before-declaration.\n }, [measureRail, highlights.length, failed]);\n\n const scrollRail = useCallback((direction: -1 | 1) => {\n const el = railRef.current;\n if (!el) return;\n // A little less than a full viewport of the rail, so the card you were\n // looking at stays partly visible and the movement reads as continuous.\n el.scrollBy({ left: direction * el.clientWidth * 0.8, behavior: \"smooth\" });\n }, []);\n\n // Filtered BEFORE the cap, so a card that drops out is replaced by the next highlight\n // rather than leaving a gap. An entry with no image is not a highlight at all.\n const visible = highlights\n .filter(\n (highlight) =>\n highlight.imageUrl !== \"\" && !failed.has(highlight.imageUrl),\n )\n .slice(0, MAX_CONCEPT_CARDS);\n\n if (visible.length === 0) return null;\n\n // `concept-strip-block` marks the block root, not just the rail. The wrapper and the\n // heading are what carry layout here, so the welcome screen's \"nothing fixed, sticky, or\n // measured\" guard has to be able to reach them; querying the <ul> alone walks past both.\n return (\n <div\n data-boff-explore=\"concept-strip-block\"\n /* rise-3: the delays stagger what the eye meets first, so this tracks the block's\n place in the order. It is last on the welcome screen, so it fades in last. */\n className=\"boff-explore-rise boff-explore-rise-3 mt-4\"\n >\n <p className=\"mb-1.5 text-xs font-semibold uppercase tracking-wide text-muted-foreground\">\n {T.conceptStripTitle}\n </p>\n <div className=\"relative\">\n {/* Pointer devices only: a touch visitor swipes, and an arrow floating over\n a card they are trying to tap is in the way. `hidden sm:flex` rather than a\n media query in JS, so it is right during the static prerender too. */}\n <button\n type=\"button\"\n data-boff-explore=\"concept-prev\"\n aria-label={T.conceptScrollPrev}\n tabIndex={-1}\n onClick={() => scrollRail(-1)}\n className={cn(\n \"absolute left-0 top-1/2 z-10 hidden h-8 w-8 -translate-y-1/2 items-center justify-center rounded-full border border-border bg-background/90 text-muted-foreground shadow-sm backdrop-blur transition-opacity hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring sm:flex\",\n canLeft ? \"opacity-100\" : \"pointer-events-none opacity-0\",\n )}\n >\n <ChevronLeft className=\"h-4 w-4\" />\n </button>\n <button\n type=\"button\"\n data-boff-explore=\"concept-next\"\n aria-label={T.conceptScrollNext}\n tabIndex={-1}\n onClick={() => scrollRail(1)}\n className={cn(\n \"absolute right-0 top-1/2 z-10 hidden h-8 w-8 -translate-y-1/2 items-center justify-center rounded-full border border-border bg-background/90 text-muted-foreground shadow-sm backdrop-blur transition-opacity hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring sm:flex\",\n canRight ? \"opacity-100\" : \"pointer-events-none opacity-0\",\n )}\n >\n <ChevronRight className=\"h-4 w-4\" />\n </button>\n <ul\n ref={railRef}\n onScroll={measureRail}\n data-boff-explore=\"concept-strip\"\n aria-label={T.conceptStripLabel}\n /* sm:mx-10 puts the scroller between the arrows instead of under them. Centred on\n the rail, an arrow sat on the picture of a full card but on the TITLE of a cropped\n or title-only one — on ~9 sites once the welcome-fit ladder engaged.\n The fades mark an edge with more cards beyond it; see .boff-explore-rail-fade-*. */\n className={cn(\n \"boff-explore-strip flex min-w-0 snap-x gap-3 overflow-x-auto pb-1 sm:mx-10\",\n canLeft && \"boff-explore-rail-fade-left\",\n canRight && \"boff-explore-rail-fade-right\",\n )}\n >\n {visible.map((highlight) => (\n <li\n key={`${highlight.product}:${highlight.url}`}\n /* flex so the card fills the row's height: a one-line title otherwise left\n that card ~16px shorter than its neighbours. */\n className=\"flex shrink-0 snap-start\"\n >\n <button\n data-boff-explore=\"concept-card\"\n data-product={highlight.product}\n type=\"button\"\n disabled={disabled}\n /* The accessible name says what PRESSING it does, because that — not the\n picture — is what the control is. The image keeps its own alt so the markup\n is still honest if this label ever goes. */\n aria-label={fill(T.conceptAsk, {\n title: highlight.title,\n product: highlight.productName,\n })}\n onClick={() =>\n onAsk(\n fill(T.conceptAskQuestion, {\n title: highlight.title,\n product: highlight.productName,\n }),\n )\n }\n className=\"group flex w-40 flex-col overflow-hidden rounded-xl border border-border bg-card text-left shadow-sm transition-colors hover:border-primary/50 hover:bg-accent disabled:cursor-not-allowed disabled:opacity-50 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring sm:w-44\"\n >\n <span className=\"boff-explore-concept-media relative block aspect-[2/1] w-full overflow-hidden bg-muted\">\n <img\n src={highlight.imageUrl}\n alt={highlight.alt}\n loading=\"lazy\"\n decoding=\"async\"\n onError={() => markFailed(highlight.imageUrl)}\n className=\"h-full w-full object-cover transition-transform duration-300 group-hover:scale-105\"\n />\n {/* The same label the inline concept images carry, from the same string:\n these are published mockups, and two wordings for one caveat read as two\n different caveats. */}\n <span\n aria-hidden=\"true\"\n className=\"boff-explore-concept-badge pointer-events-none absolute left-1.5 top-1.5 rounded-full border border-border bg-background/90 px-1.5 py-0.5 text-[9px] font-semibold uppercase tracking-wide text-foreground\"\n >\n {T.conceptIllustration}\n </span>\n </span>\n <span className=\"flex min-w-0 flex-1 flex-col gap-0.5 p-2.5\">\n <span className=\"line-clamp-2 text-xs font-semibold leading-snug text-card-foreground\">\n {highlight.title}\n </span>\n <span className=\"mt-auto truncate text-[11px] text-muted-foreground\">\n {highlight.productName}\n </span>\n </span>\n </button>\n </li>\n ))}\n </ul>\n </div>\n </div>\n );\n}\n\n/**\n * The storage notice, behind a link.\n *\n * It has to be said — conversations really are kept — but as three permanent sentences under\n * the composer it was the largest thing on a phone screen. A link plus a dialog says the same\n * thing and costs one line.\n *\n * Hand-rolled rather than a Radix dialog: `@radix-ui/react-dialog` is not among the SDK's peer\n * dependencies, and adding one would mean an install across all 39 consuming sites for a\n * single popup.\n */\nfunction DisclaimerDialog({\n open,\n onClose,\n captchaOn,\n}: {\n open: boolean;\n onClose: () => void;\n captchaOn: boolean;\n}) {\n const panelRef = useRef<HTMLDivElement>(null);\n const closeRef = useRef<HTMLButtonElement>(null);\n const titleId = \"boff-explore-disclaimer-title\";\n\n useEffect(() => {\n if (!open) return;\n\n // Remember where focus came from so it can be handed back — a dialog that dumps focus\n // at the top of the document strands a keyboard or screen-reader user.\n const opener =\n document.activeElement instanceof HTMLElement\n ? document.activeElement\n : null;\n\n // Deliberately NOT filtered by `offsetParent !== null`. That is the usual visibility\n // test, but offsetParent is null for elements inside a `position: fixed` container —\n // which this dialog is — so the filter silently emptied the list and the trap never\n // engaged. The panel only exists while open and holds nothing hidden, so every match\n // here is focusable by construction.\n const focusable = () =>\n Array.from(\n panelRef.current?.querySelectorAll<HTMLElement>(\n 'a[href], button:not([disabled]), textarea, input, select, [tabindex]:not([tabindex=\"-1\"])',\n ) ?? [],\n );\n\n const onKey = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") {\n onClose();\n return;\n }\n // Focus trap. Without it Tab walks straight out of the dialog and onto the page\n // behind the overlay, where the visitor cannot see what is focused.\n if (event.key !== \"Tab\") return;\n const items = focusable();\n if (items.length === 0) return;\n const first = items[0];\n const last = items[items.length - 1];\n const active = document.activeElement;\n if (\n event.shiftKey &&\n (active === first || !panelRef.current?.contains(active))\n ) {\n event.preventDefault();\n last?.focus();\n } else if (!event.shiftKey && active === last) {\n event.preventDefault();\n first?.focus();\n }\n };\n\n document.addEventListener(\"keydown\", onKey);\n closeRef.current?.focus();\n return () => {\n document.removeEventListener(\"keydown\", onKey);\n opener?.focus();\n };\n }, [open, onClose]);\n\n if (!open) return null;\n\n return (\n <div\n data-boff-explore=\"disclaimer-dialog\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={titleId}\n className=\"fixed inset-0 z-50 flex items-end justify-center bg-foreground/40 p-4 backdrop-blur-sm sm:items-center\"\n onClick={onClose}\n >\n <div\n ref={panelRef}\n className=\"w-full max-w-md rounded-2xl border border-border bg-card p-5 shadow-xl\"\n onClick={(event) => event.stopPropagation()}\n >\n <div className=\"flex items-start gap-3\">\n <span\n aria-hidden=\"true\"\n className=\"flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-primary/10 text-primary\"\n >\n <TriangleAlert className=\"h-4 w-4\" />\n </span>\n <div className=\"min-w-0\">\n <p\n id={titleId}\n className=\"text-sm font-semibold text-card-foreground\"\n >\n How this assistant works\n </p>\n <div className=\"mt-2 space-y-2 text-xs leading-relaxed text-muted-foreground\">\n <p>\n Answers are generated from our public documentation and can be\n imperfect — check anything important against the linked sources.\n </p>\n {/* Conversations are recorded server-side, so say so plainly. */}\n <p>\n Conversations are saved in this browser so you can come back to\n them, and are also stored on our servers to help us improve\n these answers. Please don't share personal or confidential\n information.\n </p>\n {captchaOn ? (\n <p>\n Protected by reCAPTCHA — the Google Privacy Policy and Terms\n of Service apply.\n </p>\n ) : null}\n </div>\n </div>\n </div>\n <div className=\"mt-4 flex justify-end\">\n <Button\n ref={closeRef}\n size=\"sm\"\n variant=\"secondary\"\n onClick={onClose}\n >\n Got it\n </Button>\n </div>\n </div>\n </div>\n );\n}\n\nfunction WelcomeState({\n strings: T,\n title,\n body,\n prompts,\n products,\n conceptHighlights,\n focusProduct,\n onPrompt,\n onFocus,\n disabled,\n heading = \"h1\",\n productScoped = false,\n}: {\n strings: ExploreStrings;\n title: string;\n body: string;\n prompts: string[];\n products: Array<{ slug: string; name: string; tagline?: string | null }>;\n /** Concept illustrations to offer as a way in. Empty renders no strip at all. */\n conceptHighlights: readonly ExploreConceptHighlight[];\n focusProduct: string | null;\n onPrompt: (prompt: string) => void;\n onFocus: (slug: string | null) => void;\n disabled: boolean;\n /** `h2` in the panel (BOFF-9697): the page it sits on owns the one `<h1>`. */\n heading?: \"h1\" | \"h2\";\n /**\n * One product's own assistant (`scope=\"product\"`, BOFF-9796): no capability tile that invites other products, so\n * the comparison tile goes and the other two sit two across. False (the portfolio) renders all three, as always.\n */\n productScoped?: boolean;\n}) {\n const Heading = heading;\n // Centred in the available height rather than pinned to the top: on a tall desktop the\n // block used to sit under a large band of empty space with the composer far below it.\n // `my-auto` inside the flex scroll area lets it sit in the middle when there is room and\n // scroll normally when there is not.\n return (\n <div className=\"boff-explore-aura mx-auto my-auto w-full max-w-3xl px-4 py-4 sm:py-5\">\n <div className=\"boff-explore-rise text-center\">\n <span className=\"boff-explore-hero-badge inline-flex items-center gap-1.5 rounded-full border border-border bg-muted px-3 py-1 text-xs font-medium text-muted-foreground\">\n <Sparkles className=\"h-3.5 w-3.5\" />\n {T.badge}\n </span>\n {/* Rendered synchronously on the first paint — the static prerender\n waits for an <h1> and must never capture a blank page. */}\n <Heading className=\"mt-2 text-balance break-words text-2xl font-bold tracking-tight sm:text-3xl\">\n {title}\n </Heading>\n {/* Deliberately stays at `text-sm` on desktop. It used to step up to\n `sm:text-base`, which read as the loudest thing on the screen after the\n heading and pushed the composer below the fold on a 900px-tall window. The\n heading asks the question; this line only has to be legible. */}\n <p className=\"mx-auto mt-2 max-w-2xl text-pretty text-sm leading-relaxed text-muted-foreground\">\n {body}\n </p>\n </div>\n\n {/* Three across even on a phone: as full-width cards these were three scroll-lengths\n of the fold before the visitor reached the thing they came to use. The body copy\n is the part that costs the height, so it goes at small sizes and the icon plus\n title carry the meaning. One product's own assistant (BOFF-9796) shows two, two\n across: the class list is spelled out whole rather than built with `cn`, so the\n portfolio's stays exactly what it was. */}\n <ul\n className={`boff-explore-capabilities boff-explore-rise boff-explore-rise-1 mt-4 grid ${productScoped ? \"grid-cols-2\" : \"grid-cols-3\"} gap-2 sm:gap-2.5`}\n >\n {CAPABILITIES.map(\n ({ icon: Icon, body: capBody, invitesOtherProducts }, i) =>\n productScoped && invitesOtherProducts ? null : (\n <li\n key={i}\n className=\"rounded-xl border border-border/70 bg-card/60 p-2.5 text-center transition-colors hover:border-border sm:p-2.5 sm:text-left\"\n >\n <span className=\"mx-auto mb-1.5 flex h-7 w-7 items-center justify-center rounded-lg bg-primary/10 text-primary sm:mx-0 sm:mb-2 sm:h-8 sm:w-8\">\n <Icon className=\"h-3.5 w-3.5 sm:h-4 sm:w-4\" />\n </span>\n <p className=\"text-[11px] font-semibold leading-tight text-card-foreground sm:text-sm sm:leading-snug\">\n {T.capabilities[i] ?? \"\"}\n </p>\n <p className=\"mt-1 hidden text-xs leading-snug text-muted-foreground lg:block\">\n {capBody}\n </p>\n </li>\n ),\n )}\n </ul>\n\n {prompts.length > 0 ? (\n <div className=\"boff-explore-rise boff-explore-rise-2 mt-4\">\n <PromptCarousel\n strings={T}\n label={T.tryAsking}\n prompts={prompts}\n onPrompt={onPrompt}\n disabled={disabled}\n />\n </div>\n ) : null}\n\n {products.length > 0 ? (\n <div className=\"boff-explore-rise boff-explore-rise-3 mt-4\">\n <p className=\"mb-1.5 text-xs font-semibold uppercase tracking-wide text-muted-foreground\">\n {T.focusProduct}\n </p>\n <ProductStrip\n strings={T}\n products={products}\n focusProduct={focusProduct}\n onFocus={onFocus}\n />\n </div>\n ) : null}\n\n {/* LAST on the welcome screen, after the product filter. The composer is what this\n page is for, and everything above is a way into it; the illustrations are the\n furthest thing from \"type your problem here\", so they sit at the end for a\n visitor who would rather browse than ask.\n\n Renders nothing — heading included — when there is nothing to show, so the welcome\n screen is the same shape it was before this existed. */}\n <ConceptStrip\n strings={T}\n highlights={conceptHighlights}\n onAsk={onPrompt}\n disabled={disabled}\n />\n </div>\n );\n}\n\n// ============================================================================\n// Main component\n// ============================================================================\n\n/**\n * Longest question a `?q=` link may pre-fill. Links are written by us (industry-solution\n * pages, product sites), so this only guards against a pasted or crafted URL flooding the\n * composer; the catalog's own message limit still applies when the visitor sends.\n */\nexport const EXPLORE_PREFILL_MAX_LENGTH = 500;\n\n/**\n * Link to `/explore` with a starter question in the composer (see `?q=` in `ExplorePage`).\n * `base` is the explore page's path or absolute URL.\n */\nexport function exploreQuestionHref(\n question: string,\n base = \"/explore\",\n): string {\n const trimmed = question.trim().slice(0, EXPLORE_PREFILL_MAX_LENGTH);\n if (!trimmed) return base;\n const joiner = base.includes(\"?\") ? \"&\" : \"?\";\n return `${base}${joiner}q=${encodeURIComponent(trimmed)}`;\n}\n\n/**\n * The Explore page. Under an `ExploreChatProvider` it shows the provider's conversation (one for the whole site, shared\n * with `ExplorePanel`); otherwise it sets up its own, exactly as it always has (BOFF-9697).\n */\nexport function ExplorePage(props: ExplorePageProps) {\n const shared = useContext(ExploreConversationContext);\n return shared ? (\n <ExploreView {...props} conversation={shared} />\n ) : (\n <StandaloneExplorePage {...props} />\n );\n}\n\n/** The page with a conversation of its own: the setup `ExplorePage` always had. */\nfunction StandaloneExplorePage(props: ExplorePageProps) {\n const conversation = useExploreConversation({\n productSlug: props.productSlug,\n locale: props.locale,\n examplePrompts: props.examplePrompts,\n onSend: props.onSend,\n });\n return <ExploreView {...props} conversation={conversation} />;\n}\n\nfunction ExploreView({\n seo,\n productSlug,\n className,\n heightMode = \"viewport\",\n viewportOffset,\n onNavigate,\n welcomeTitle,\n welcomeBody,\n locale,\n presentation = \"page\",\n active = true,\n voiceHold = null,\n explorePath = \"/explore\",\n examplePrompts,\n scope,\n productName,\n conversation,\n}: ExplorePageProps & { conversation: ExploreConversationState }) {\n const panel = presentation === \"panel\";\n /** The dedicated route in `viewport` mode: the only case that sizes itself to the window and handles its scrolling. */\n const viewportPage = !panel && heightMode === \"viewport\";\n const pageUrl = useMemo(\n () => (typeof window === \"undefined\" ? undefined : window.location.href),\n [],\n );\n\n // Resolved BEFORE the hook: its localised strings seed the hook's fallback catalog, so a\n // catalog outage shows a translated welcome instead of an English one. Depends only on the\n // `locale` prop, so hoisting it changes nothing else.\n const activeLocale: ExploreLocale = useMemo(\n () => resolveExploreLocale(locale),\n [locale],\n );\n const T = useMemo(() => exploreStrings(activeLocale), [activeLocale]);\n const rtl = isRtlLocale(activeLocale);\n /** Which voice reads an answer aloud. A lookup, not copy — see `speechLocaleOf`. */\n const speechLang = speechLocaleOf(activeLocale);\n\n const {\n phase,\n catalog,\n serverCatalogRaw,\n messages,\n activity,\n remainingToday,\n error,\n focusProduct,\n setFocusProduct,\n send,\n stop,\n retry,\n reset,\n canSend,\n history,\n openConversation,\n deleteConversation,\n clearHistory,\n recordClick,\n submitFeedback,\n escalate,\n canEscalate,\n createShareLink,\n isSharedView,\n draft,\n setDraft,\n staged,\n setStaged,\n } = conversation;\n\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n\n // `?q=` pre-fills the composer — and only pre-fills it: other pages (an industry-solution\n // page on burdenoff.com, a product page) link here with a starter question the visitor can\n // edit before sending, so nothing is asked on their behalf and no turn is spent on a link\n // click. A shared conversation (`?c=`) is a read-only view and takes precedence. Read once\n // on mount, client-side only, so the prerendered page stays identical for every URL.\n useEffect(() => {\n // The panel never reads the URL: `?q=` belongs to the page it was linked to (BOFF-9697).\n if (typeof window === \"undefined\" || panel) return;\n const params = new URLSearchParams(window.location.search);\n if (params.has(\"c\")) return;\n const question = params.get(\"q\")?.trim();\n if (!question) return;\n setDraft(question.slice(0, EXPLORE_PREFILL_MAX_LENGTH));\n }, [panel, setDraft]);\n\n // Dictation, on the browser's own recogniser. Settled speech is appended to whatever is\n // already typed, so a visitor can mix typing and talking in one message.\n const [historyOpen, setHistoryOpen] = useState(false);\n\n const speechStopRef = useRef<() => void>(() => undefined);\n const stopDictation = useCallback(() => {\n speechStopRef.current();\n }, []);\n\n const speech = useSpeechInput({\n onFinalTranscript: (text) => {\n setDraft((current) => {\n const joined =\n current.trim() === \"\"\n ? text.trimStart()\n : `${current.trimEnd()} ${text.trim()}`;\n return joined;\n });\n textareaRef.current?.focus();\n },\n });\n speechStopRef.current = speech.stop;\n\n // BOFF-9697: the panel closed, or its Avatar tab opened: stop listening and stop reading aloud. The conversation\n // itself (and an answer still on its way) is untouched.\n useEffect(() => {\n if (active) return;\n stopDictation();\n stopSpeaking();\n }, [active, stopDictation]);\n // BOFF-9797: the panel's live avatar is connecting or speaking. One voice at a time, and no microphone over it: a\n // reading or dictation under way stops (both are already stopped when the visitor opens the Avatar tab to start one),\n // and both controls are held until the session ends. Dictation is held rather than allowed to end the avatar: no\n // Chat control ends a session the visitor started (only their Stop, closing the panel or leaving the page do), and\n // it ends by itself within its minute.\n const voiceHeld = voiceHold !== null;\n useEffect(() => {\n if (!voiceHeld) return;\n stopDictation();\n stopSpeaking();\n }, [voiceHeld, stopDictation]);\n // Resolved once: the document lang and navigator do not change under us, and re-resolving\n // on every render would make the strings object a new identity each time.\n\n const [disclaimerOpen, setDisclaimerOpen] = useState(false);\n const [attachmentNotice, setAttachmentNotice] = useState<string | null>(null);\n const fileInputRef = useRef<HTMLInputElement>(null);\n /* Read through a ref, not the state value: the picker resolves asynchronously (each file is\n read off disk), so a second pick that starts before the first finishes would otherwise\n count slots against a stale list and overshoot the five-file cap. */\n const stagedRef = useRef<StagedAttachment[]>([]);\n stagedRef.current = staged;\n /** Serialises overlapping picks — see `handleFilesPicked`. */\n const pickQueueRef = useRef<Promise<void>>(Promise.resolve());\n const [shareLabel, setShareLabel] = useState(T.share);\n const [shareUrl, setShareUrl] = useState<string | null>(null);\n const rootRef = useRef<HTMLDivElement>(null);\n const composerRef = useRef<HTMLDivElement>(null);\n const scrollRef = useRef<HTMLDivElement>(null);\n const latestAssistantRef = useRef<HTMLDivElement>(null);\n /** id of the answer whose top has already been aligned, so it happens once per turn. */\n const alignedForRef = useRef<string | null>(null);\n const stickToBottomRef = useRef(true);\n const composingRef = useRef(false);\n\n const busy = phase === \"sending\" || phase === \"streaming\";\n const showWelcome = messages.length === 0;\n const maxLength = catalog.limits.maxMessageLength;\n const overLimit = draft.length > maxLength;\n const canSubmit = canSend && draft.trim().length > 0 && !overLimit && !busy;\n\n // BOFF-9796: the product a `scope=\"product\"` view is pinned to, its name, and the test the catalog's own copy has to\n // pass there. All three are null in the portfolio scope, which is every view that does not ask for the product\n // scope, and then everything below is exactly what it always was.\n const pinnedSlug = pinnedProductSlug(scope, productSlug);\n useEffect(() => {\n if (scope === \"product\" && pinnedSlug === null) {\n warnProductScopeWithoutSlug();\n }\n }, [pinnedSlug, scope]);\n const pinnedName = useMemo(\n () =>\n pinnedSlug === null\n ? null\n : productNameFor(catalog.products, pinnedSlug, productName),\n [catalog.products, pinnedSlug, productName],\n );\n // The catalog's copy is written for every site at once (\"Compare Bigconsole and Fluidgrids\"): in the product scope,\n // what names another product does not show.\n const namesAnotherProduct = useMemo(\n () =>\n pinnedSlug === null\n ? null\n : anotherProductMatcher(catalog.products, pinnedSlug),\n [catalog.products, pinnedSlug],\n );\n\n const resolvedTitle =\n welcomeTitle ??\n (namesAnotherProduct?.(catalog.welcomeTitle)\n ? T.welcomeTitle\n : catalog.welcomeTitle);\n // In the product scope, never the catalog's body: for a product site it invites comparing the product \"with anything\n // else we build\". Without a name to put in ours (a slug no catalog lists, and no `productName`), the product scope's\n // name-free body, never the portfolio's built-in one, which invites asking about other products.\n const resolvedBody =\n welcomeBody ??\n (pinnedSlug === null\n ? catalog.welcomeBody\n : pinnedName === null\n ? T.welcomeBodyScoped\n : fill(T.welcomeBodyProduct, { product: pinnedName }));\n // Resolution order (catalog → prop → SDK built-in) lives in the hook, which\n // seeds its fallback catalog from the `examplePrompts` prop. The product scope\n // does not use that order: it shows the site's own prompts alone, whatever the\n // catalog has, and only when the site passes none, the catalog's, less any that\n // name another product and the SDK's portfolio prompt (`productScopedPrompts`).\n const prompts = useMemo(\n () =>\n namesAnotherProduct === null\n ? catalog.examplePrompts\n : productScopedPrompts(\n examplePrompts,\n catalog.examplePrompts,\n namesAnotherProduct,\n ),\n [catalog.examplePrompts, examplePrompts, namesAnotherProduct],\n );\n const conceptHighlights = useMemo(\n () =>\n pinnedSlug === null || namesAnotherProduct === null\n ? catalog.conceptHighlights\n : productScopedHighlights(\n catalog.conceptHighlights,\n pinnedSlug,\n namesAnotherProduct,\n ),\n [catalog.conceptHighlights, namesAnotherProduct, pinnedSlug],\n );\n\n // The product the conversation is about, for its header and the composer's placeholder: in the product scope always\n // the pinned one, whatever focus a stored or shared conversation came back with.\n const focusedProductName = useMemo(\n () =>\n pinnedSlug !== null\n ? pinnedName\n : (catalog.products.find((p) => isSameProductSlug(p.slug, focusProduct))\n ?.name ?? null),\n [catalog.products, focusProduct, pinnedName, pinnedSlug],\n );\n\n // The product whose SITE this is, for the page head — not `focusProduct`, which is a\n // filter the visitor can change mid-conversation and which must never rewrite the title\n // a search engine indexed. Resolved through the catalog rather than a local table so the\n // displayed casing is the one product page itself uses (\"VibeControls\", not the slug);\n // the catalog is seeded synchronously from ECOSYSTEM_PRODUCTS, so this is correct on the\n // very first render, which is the one the 38 prerenders capture. In the product scope it is the\n // pinned product's name, the one the rest of the page shows (BOFF-9796).\n const headProductName = useMemo(\n () =>\n pinnedSlug !== null\n ? pinnedName\n : productSlug\n ? (catalog.products.find((p) =>\n isSameProductSlug(p.slug, productSlug),\n )?.name ?? null)\n : null,\n [catalog.products, pinnedName, pinnedSlug, productSlug],\n );\n // The fallback catalog lists every product site on the same origins as the server catalog\n // (`ECOSYSTEM_PRODUCTS`), so inline images work before — and without — the catalog fetch.\n // The image overrides are stable components, so a new origin set once the fetch lands\n // re-renders them in place; it never remounts them.\n const imageOrigins = useMemo(\n () => inlineImageOrigins(catalog.products),\n [catalog.products],\n );\n // Same source, same seeding story: the provenance row can name products from the very\n // first render, and re-labels in place when the server catalog lands.\n const productNames = useMemo(\n () => productNamesByOrigin(catalog.products),\n [catalog.products],\n );\n // And again for the slug a product-video card names itself by (`data-product`), so the\n // card on gethealthybowl.com's video says \"healthybowl\" from the first render.\n const productSlugs = useMemo(\n () => productSlugsByOrigin(catalog.products),\n [catalog.products],\n );\n\n // --- auto-grow the composer -------------------------------------------\n useEffect(() => {\n const el = textareaRef.current;\n if (!el) return;\n el.style.height = \"auto\";\n el.style.height = `${Math.min(el.scrollHeight, 200)}px`;\n }, [draft]);\n\n // --- pane geometry, measured rather than declared -----------------------\n //\n // `viewportOffset` is hard-coded to 64 on all 41 host pages and matches none of them — the\n // burdenoff/algoshred chrome is 80px, the sticky-header sites are 65 — so the pane always\n // overflowed the fold, which is what made the page scrollable at rest and fed the\n // footer-parking below. Two numbers replace it, both measured after mount:\n //\n // paneOffset the root's own top, i.e. how much site chrome sits above the pane.\n // bottomInset the slice of the layout viewport hidden below the visible area. `dvh`\n // tracks browser UI but NOT the on-screen keyboard, so without this the\n // keyboard covers the composer — the one control this page exists for.\n //\n // Both are fed to the stylesheet as lengths and never as a height, because these pages are\n // snapshotted post-hydration by a headless browser: a measured pixel *height* would be\n // served to every phone as static HTML until the bundle runs, while a measured *offset* is\n // a site-header height that is the same on any device and the height built from it stays\n // viewport-relative. `bottomInset` is zero unless something is genuinely covering the\n // bottom, so a snapshot never carries it at all.\n const [paneOffset, setPaneOffset] = useState<number | null>(null);\n const [bottomInset, setBottomInset] = useState(0);\n // Mirrored for the transcript effects, which need the chrome allowance without taking a\n // render-triggering dependency on it.\n const paneOffsetRef = useRef(0);\n\n const measurePane = useCallback(() => {\n if (!viewportPage) return;\n const el = rootRef.current;\n if (!el) return;\n // The LAYOUT viewport, deliberately: `visualViewport.height` is what the keyboard\n // shrinks, and a threshold or an offset taken from it would move when the keyboard\n // opens. The keyboard belongs in `bottomInset` and nowhere else.\n const layoutHeight = window.innerHeight;\n if (layoutHeight === 0) return;\n\n const top = Math.round(\n clamp(el.getBoundingClientRect().top, 0, layoutHeight),\n );\n const viewport = window.visualViewport;\n const inset = viewport\n ? Math.round(\n clamp(\n layoutHeight - viewport.height - viewport.offsetTop,\n 0,\n layoutHeight,\n ),\n )\n : 0;\n\n paneOffsetRef.current = top;\n setPaneOffset((current) => (current === top ? current : top));\n setBottomInset((current) => (current === inset ? current : inset));\n }, [viewportPage]);\n\n // --- keep foreign fixed chrome off the composer -------------------------\n //\n // The host sites put a `fixed bottom-0` cookie banner up to 229px tall across the bottom\n // of the viewport, which is exactly where the composer lives: on a 640px-tall phone a\n // first-time visitor cannot reach the only control on the page. Measured here so one SDK\n // release covers all 41 sites.\n const [chromeOverlap, setChromeOverlap] = useState(0);\n\n const measureChrome = useCallback(() => {\n const root = rootRef.current;\n const dock = composerRef.current;\n if (!root || !dock) return;\n if (typeof document.elementFromPoint !== \"function\") return;\n\n const viewportHeight = visualViewportHeight();\n const rect = dock.getBoundingClientRect();\n if (rect.width === 0 || viewportHeight === 0) return;\n // Nothing to defend while the composer is off screen, and a probe outside the viewport\n // returns null — which would drop the padding and re-open the overlap.\n if (rect.bottom <= 0 || rect.top >= viewportHeight) return;\n\n // The lower of the composer's own bottom edge and the viewport's. In `auto` height the\n // composer can sit below the fold, and measuring against the fold keeps the result\n // stable instead of oscillating as the new padding pushes that edge further down.\n const edge = Math.min(rect.bottom, viewportHeight);\n const hit = document.elementFromPoint(rect.left + rect.width / 2, edge - 1);\n if (!hit || isOwnElement(hit, root)) {\n setChromeOverlap(0);\n return;\n }\n const overlap = Math.round(edge - hit.getBoundingClientRect().top);\n setChromeOverlap(overlap > 0 && overlap < viewportHeight ? overlap : 0);\n }, []);\n\n const remeasure = useCallback(() => {\n measurePane();\n measureChrome();\n }, [measurePane, measureChrome]);\n\n useEffect(() => {\n // The panel sits above any host chrome by design (ExplorePanel bottomOffset): nothing here to measure.\n if (typeof window === \"undefined\" || panel) return;\n\n let frame = 0;\n const run = () => {\n frame = 0;\n remeasure();\n };\n const schedule = () => {\n if (frame) return;\n if (typeof window.requestAnimationFrame !== \"function\") {\n remeasure();\n return;\n }\n frame = window.requestAnimationFrame(run);\n };\n\n remeasure();\n const viewport = window.visualViewport;\n window.addEventListener(\"resize\", schedule);\n window.addEventListener(\"orientationchange\", schedule);\n viewport?.addEventListener(\"resize\", schedule);\n viewport?.addEventListener(\"scroll\", schedule);\n\n // A consent banner appears once the page has settled and there is no event for it. On\n // every host site it is a React child of `#root` — 10 of the 13 behind `lazy()`, so it\n // mounts commits after this one — which means body's own child list never changes and a\n // non-subtree observer would see nothing at all. It is also what notices the banner\n // going away again when the visitor accepts.\n //\n // Mutations inside the explore root are dropped: the transcript re-renders on every\n // streamed token, and re-probing the chrome for those would force a layout per frame\n // for a change that cannot possibly be site chrome.\n const observer =\n typeof MutationObserver === \"function\"\n ? new MutationObserver((records) => {\n const el = rootRef.current;\n if (el && records.every((record) => el.contains(record.target)))\n return;\n schedule();\n })\n : null;\n observer?.observe(document.body, { childList: true, subtree: true });\n\n return () => {\n if (frame) window.cancelAnimationFrame(frame);\n window.removeEventListener(\"resize\", schedule);\n window.removeEventListener(\"orientationchange\", schedule);\n viewport?.removeEventListener(\"resize\", schedule);\n viewport?.removeEventListener(\"scroll\", schedule);\n observer?.disconnect();\n // Cleared rather than left behind: a remount must re-measure, never re-apply the\n // geometry of whatever viewport the last mount happened to see.\n setPaneOffset(null);\n setBottomInset(0);\n setChromeOverlap(0);\n };\n }, [remeasure, panel]);\n\n // A pane that just changed height has moved the composer's bottom edge, and with it\n // whatever is painted there.\n useEffect(() => {\n measureChrome();\n }, [measureChrome, paneOffset, bottomInset]);\n\n // --- the page may not be parked in the site footer ----------------------\n //\n // This is the \"explore shows nothing but the footer on my phone\" report, and it is a\n // scroll-position problem rather than a render one. Browsers restore the previous scroll\n // offset on reload, pull-to-refresh, back/forward, bfcache and tab discard-and-restore —\n // routine on a phone under memory pressure, nearly absent on desktop, which is why it read\n // as \"only some mobiles\". With a 1100–1330px mobile footer under a one-viewport pane, any\n // restored offset past ~600px leaves 0px of explore on screen.\n //\n // The host sites' own `ScrollToTop` cannot help: it runs on mount, and the restore lands\n // after it.\n //\n // Scoped to `viewport` mode. In `auto` mode the component is documented as an embeddable\n // block that lets the page grow, and an embed below the fold that scrolls its host page to\n // itself on load — and seizes `history.scrollRestoration` for the whole document while it\n // is mounted — is a different product.\n useEffect(() => {\n if (!viewportPage || typeof window === \"undefined\") return;\n\n const { history: browserHistory } = window;\n const previousRestoration =\n \"scrollRestoration\" in browserHistory\n ? browserHistory.scrollRestoration\n : null;\n if (previousRestoration !== null)\n browserHistory.scrollRestoration = \"manual\";\n\n let frame = 0;\n // A visitor who moves the page themselves keeps their place, forever. The flag is fed by\n // input events rather than by `scroll`, because `align` scrolls the window itself and a\n // `scroll` listener would let it disarm the very passes that exist to beat a late\n // restore.\n let visitorMoved = false;\n const onVisitorMove = () => {\n visitorMoved = true;\n };\n\n const align = () => {\n if (visitorMoved) return;\n const el = rootRef.current;\n if (!el) return;\n const viewportHeight = visualViewportHeight();\n const rect = el.getBoundingClientRect();\n if (rect.height === 0 || viewportHeight === 0) return;\n\n // Only a root that is essentially off screen gets corrected, and only here — never on\n // every scroll. The fraction is of whatever can actually BE on screen: a long\n // conversation on a short viewport makes the root several screens tall, and a quarter\n // of that is more than the viewport can ever show, which would turn the guard into an\n // unconditional scroll-to-top on a visitor reading mid-transcript.\n const visible =\n Math.min(rect.bottom, viewportHeight) - Math.max(rect.top, 0);\n const reachable = Math.min(rect.height, viewportHeight);\n if (visible >= reachable * MIN_VISIBLE_FRACTION) return;\n\n // Instant, and on the window only. `scrollIntoView` scrolls every scrollable ancestor\n // as well — including the transcript — which drags the composer off screen.\n window.scrollTo({\n top: Math.max(0, window.scrollY + rect.top),\n left: window.scrollX,\n behavior: \"auto\",\n });\n\n // The root now starts at y=0, where a sticky site header paints over it even though\n // the root sits below that header in the document. Probe what is actually painted\n // there and give those rows back, rather than trusting `viewportOffset` — which is\n // wrong on every site (see `measurePane`).\n if (typeof document.elementFromPoint === \"function\") {\n const probe = document.elementFromPoint(\n Math.max(0, rect.left + rect.width / 2),\n 1,\n );\n if (probe && !isOwnElement(probe, el)) {\n const chrome = probe.getBoundingClientRect().bottom;\n if (chrome > 0 && chrome < viewportHeight / 2) {\n window.scrollBy({ top: -chrome, left: 0, behavior: \"auto\" });\n }\n }\n }\n\n // The pane's height is measured from the root's top, and the root has just moved. Left\n // alone it would keep the height computed for the position the page was parked in —\n // a full-viewport pane starting under the site header, i.e. the overhang this whole\n // effect exists to remove — until the next resize.\n remeasure();\n };\n\n // Only an offset the BROWSER restored is corrected. On a fresh navigation the page\n // starts at the top, so a visitor who has scrolled down (which, on a slow connection,\n // they can do for seconds against the prerendered HTML before this ever mounts) is left\n // exactly where they are.\n const alignIfRestored = () => {\n if (!isRestoredNavigation()) return;\n align();\n };\n\n // Two passes on mount: the restore can land after this effect runs.\n alignIfRestored();\n if (typeof window.requestAnimationFrame === \"function\") {\n frame = window.requestAnimationFrame(alignIfRestored);\n }\n\n // A bfcache restore replays the page with NO mount at all, so the passes above never run\n // for it and `pageshow` is the only hook. It is also a fresh arrival, which re-arms the\n // correction. An ordinary load fires `pageshow` too, after scroll restoration has\n // landed — exactly when the mount pass is too early — so that case runs through the same\n // navigation-type filter as the mount passes.\n const onPageShow = (event: PageTransitionEvent) => {\n if (!event.persisted) {\n alignIfRestored();\n return;\n }\n visitorMoved = false;\n align();\n };\n window.addEventListener(\"pageshow\", onPageShow);\n window.addEventListener(\"wheel\", onVisitorMove, { passive: true });\n window.addEventListener(\"touchmove\", onVisitorMove, { passive: true });\n window.addEventListener(\"keydown\", onVisitorMove, { passive: true });\n\n return () => {\n if (frame) window.cancelAnimationFrame(frame);\n window.removeEventListener(\"pageshow\", onPageShow);\n window.removeEventListener(\"wheel\", onVisitorMove);\n window.removeEventListener(\"touchmove\", onVisitorMove);\n window.removeEventListener(\"keydown\", onVisitorMove);\n if (previousRestoration !== null)\n browserHistory.scrollRestoration = previousRestoration;\n };\n }, [viewportPage, remeasure]);\n\n // --- transcript positioning --------------------------------------------\n //\n // An answer plus its sources is routinely taller than a phone screen, so pinning the\n // transcript to the BOTTOM landed the visitor below the sources and made them scroll up\n // to find the response they had just asked for. Instead each new answer is anchored by\n // its TOP: the reply starts where the eye already is and grows downward.\n //\n // Bottom-sticking is kept only for the pre-answer phase, so the \"thinking\" indicator\n // stays visible while the turn is still running.\n //\n // On a short viewport none of that can go through `scrollTop`: the pane is auto-height,\n // the transcript has no overflow of its own and the PAGE is the scroller, so every\n // movement below has a window-level twin. Without it the composer walks further down the\n // document with each answer and nothing ever brings it back.\n const handleScroll = useCallback(() => {\n const el = scrollRef.current;\n if (!el) return;\n stickToBottomRef.current =\n el.scrollHeight - el.scrollTop - el.clientHeight < 80;\n }, []);\n\n // The window's twin of `handleScroll`. It is the composer's bottom edge that has to stay\n // near the fold, not the transcript's, because in this mode the composer is the last thing\n // in the document flow.\n //\n // Never in the panel (BOFF-9697): its pane takes its height from the panel, so the pane is\n // always the scroller there, and the window is the HOST page's, which the panel must never\n // move. Without this, a short phone screen (landscape) let a new answer in the panel scroll\n // the page behind it.\n useEffect(() => {\n if (typeof window === \"undefined\" || panel) return;\n\n let frame = 0;\n const run = () => {\n frame = 0;\n const el = scrollRef.current;\n const dock = composerRef.current;\n if (!el || !dock) return;\n if (!pageOwnsScrolling(el)) return;\n stickToBottomRef.current =\n dock.getBoundingClientRect().bottom - visualViewportHeight() < 80;\n };\n const schedule = () => {\n if (frame) return;\n if (typeof window.requestAnimationFrame !== \"function\") {\n run();\n return;\n }\n frame = window.requestAnimationFrame(run);\n };\n\n window.addEventListener(\"scroll\", schedule, { passive: true });\n return () => {\n if (frame) window.cancelAnimationFrame(frame);\n window.removeEventListener(\"scroll\", schedule);\n };\n }, [panel]);\n\n const latestAssistantId = useMemo(() => {\n for (let i = messages.length - 1; i >= 0; i -= 1) {\n const message = messages[i];\n if (message && message.role === \"ASSISTANT\") return message.id;\n }\n return null;\n }, [messages]);\n\n useEffect(() => {\n const el = scrollRef.current;\n const anchor = latestAssistantRef.current;\n if (!el || !anchor || !latestAssistantId) return;\n\n // Only align once per answer, and never against a visitor who has scrolled away to\n // read something else — yanking the viewport out from under them is worse than the\n // problem this solves.\n if (alignedForRef.current === latestAssistantId) return;\n if (!stickToBottomRef.current) return;\n\n // Wait for the answer to actually have height; aligning an empty bubble puts the top\n // of a zero-height element at the top of an otherwise blank transcript.\n if (anchor.offsetHeight === 0) return;\n\n alignedForRef.current = latestAssistantId;\n // Measured as a rect delta rather than via `offsetTop`: offsetTop is relative to the\n // nearest POSITIONED ancestor, and this scroll container is not positioned, so it would\n // resolve against something further up the page and land in the wrong place.\n // `scrollIntoView` is also wrong here — on mobile it scrolls the page as well as the\n // container, dragging the composer off-screen. The panel's pane is always its own\n // scroller (see the window twin above).\n if (panel || !pageOwnsScrolling(el)) {\n const delta =\n anchor.getBoundingClientRect().top - el.getBoundingClientRect().top;\n el.scrollTop = Math.max(0, el.scrollTop + delta - 12);\n return;\n }\n // Short viewport: the same movement on the window, measured against the fold rather\n // than the scroller's top, with the measured site chrome given back so a sticky header\n // does not land on the first line of the answer.\n const delta = Math.round(\n anchor.getBoundingClientRect().top - paneOffsetRef.current - 12,\n );\n if (delta !== 0) window.scrollBy({ top: delta, left: 0, behavior: \"auto\" });\n }, [latestAssistantId, messages, panel]);\n\n // While the turn is still running there is no answer to anchor yet, so keep the thinking\n // indicator in view the old way.\n useEffect(() => {\n // …but never on the welcome screen. `stickToBottomRef` starts true, so on first paint\n // this ran against a transcript whose only content is the marketing block, scrolling the\n // <h1> and the intro away before the visitor had read a word of them: 160px of 183 gone\n // at 375×553, 411 of 440 in landscape. There is nothing to follow until a message\n // exists; live answers are unchanged.\n if (messages.length === 0) return;\n if (!stickToBottomRef.current) return;\n if (latestAssistantId && alignedForRef.current === latestAssistantId)\n return;\n const el = scrollRef.current;\n if (!el) return;\n if (panel || !pageOwnsScrolling(el)) {\n el.scrollTop = el.scrollHeight;\n return;\n }\n // Short viewport: follow the bottom of the pane on the window instead, and only ever\n // downwards — pulling the page UP would fight a visitor who has scrolled back to read.\n const dock = composerRef.current ?? el;\n const delta = Math.round(\n dock.getBoundingClientRect().bottom - visualViewportHeight(),\n );\n if (delta > 0) window.scrollBy({ top: delta, left: 0, behavior: \"auto\" });\n }, [activity, latestAssistantId, messages, panel]);\n\n /**\n * Copy a read-only link to this conversation.\n *\n * The URL carries a share secret, never the conversation token — that one also authorises\n * posting, so a forwarded link built from it would let the recipient continue someone\n * else's thread. Feedback is the button label itself, because a toast renderer is not\n * guaranteed to be mounted on every host site.\n */\n const handleShare = useCallback(async () => {\n setShareLabel(T.copying);\n setShareUrl(null);\n const token = await createShareLink();\n if (!token) {\n setShareLabel(T.shareUnavailable);\n setTimeout(() => setShareLabel(T.share), 2500);\n return;\n }\n // `pageUrl` is undefined during SSR/prerender, but this only runs from a click, so\n // window is present; fall back rather than assert.\n //\n // Built through `URL`, not by splitting on \"?\": the href can carry a fragment, and\n // `\"/explore#top\".split(\"?\")[0]` keeps it, so appending `?c=` would produce\n // `/explore#top?c=<token>` — where the token sits INSIDE the fragment and\n // `searchParams.get(\"c\")` reads null. That is the dead-link bug again, one layer down.\n // Clearing `search` also drops a stale `?c=` when sharing from a shared view.\n // From the panel the conversation belongs to the Explore route, not to the page the panel is on (BOFF-9697).\n const url = panel\n ? new URL(explorePath, window.location.href)\n : new URL(pageUrl ?? window.location.href);\n url.search = \"\";\n url.hash = \"\";\n url.searchParams.set(\"c\", token);\n const shareable = url.toString();\n try {\n await navigator.clipboard.writeText(shareable);\n setShareLabel(T.copied);\n setTimeout(() => setShareLabel(T.share), 2500);\n } catch {\n // The clipboard needs a secure context and a live gesture, and can simply be refused.\n // Show the link so the visitor can copy it by hand — a click that appears to do\n // nothing is worse than one extra step.\n setShareUrl(shareable);\n setShareLabel(T.share);\n }\n }, [\n createShareLink,\n pageUrl,\n panel,\n explorePath,\n T.copied,\n T.copying,\n T.share,\n T.shareUnavailable,\n ]);\n\n // --- attachments -------------------------------------------------------\n const handleFilesPicked = useCallback(\n (picked: FileList | null) => {\n if (!picked || picked.length === 0) return pickQueueRef.current;\n\n // Serialised. Reading a file is asynchronous, so a second pick that starts before the\n // first finishes would count its slots against a `stagedRef` that has not re-rendered\n // yet and let six files past a five-file cap. Chaining means each pick sees the\n // committed result of the one before it.\n const files = Array.from(picked);\n pickQueueRef.current = pickQueueRef.current.then(async () => {\n const { accepted, rejected } = await stageFiles(\n files,\n stagedRef.current,\n );\n setStaged((prev) => [...prev, ...accepted]);\n\n // Report only the FIRST rejection: a list of five identical complaints buries the\n // one thing the visitor needs to know, and the reason is the same for all of them.\n const first = rejected[0];\n setAttachmentNotice(\n first\n ? first.reason === \"too-large\"\n ? fill(T.attachmentTooLarge, {\n name: first.name,\n size: String(MAX_ATTACHMENT_BYTES / (1024 * 1024)),\n })\n : fill(T.attachmentTooMany, {\n name: first.name,\n max: String(MAX_ATTACHMENTS),\n })\n : null,\n );\n });\n return pickQueueRef.current;\n },\n [T, setStaged],\n );\n\n const removeAttachment = useCallback(\n (id: string) => {\n setStaged((prev) => prev.filter((entry) => entry.id !== id));\n setAttachmentNotice(null);\n },\n [setStaged],\n );\n\n // --- send --------------------------------------------------------------\n /**\n * BOFF-9796: in the product scope every question is asked about the pinned product, whatever focus the conversation\n * holds: one restored from storage or the history list, or the provider's, shared with an `/explore` page where the\n * visitor picked another product. Set on each send rather than once, so the view never fights such a page over it,\n * and it is what the next question goes out with. Nothing at all in the portfolio scope.\n */\n const pinFocus = useCallback(() => {\n if (pinnedSlug !== null) setFocusProduct(pinnedSlug);\n }, [pinnedSlug, setFocusProduct]);\n\n const retryTurn = useCallback(() => {\n pinFocus();\n retry();\n }, [pinFocus, retry]);\n\n // BOFF-9796: the error as the banner shows it. One product's own assistant never answers a turn that ran out of\n // searches with the default \"Try asking about two or three specific products\". Any other error, and every error in\n // the portfolio scope, is the conversation's own object, unchanged.\n const shownError = useMemo(\n () =>\n error !== null && pinnedSlug !== null\n ? productScopedError(error, T.toolBudgetScoped)\n : error,\n [T, error, pinnedSlug],\n );\n\n const submitDraft = useCallback(() => {\n const text = draft.trim();\n if (!text || overLimit || busy || !canSend) return;\n // Close the microphone on send — leaving it hot would keep dictating into the next message.\n stopDictation();\n // …and stop reading the last answer out loud. A voice still working through the previous\n // reply while the next question is on its way is the thing people actually complain\n // about; the control that started it is about to scroll away, too.\n stopSpeaking();\n setDraft(\"\");\n stickToBottomRef.current = true;\n pinFocus();\n void send(text, toPayload(stagedRef.current));\n // Clear the staging tray on send, not on completion: the files belong to the turn that\n // was just sent, and leaving them would silently re-attach them to the next question.\n setStaged([]);\n setAttachmentNotice(null);\n textareaRef.current?.focus();\n }, [\n busy,\n canSend,\n draft,\n overLimit,\n pinFocus,\n send,\n setDraft,\n setStaged,\n stopDictation,\n ]);\n\n const sendPrompt = useCallback(\n (prompt: string) => {\n if (!canSend || busy) return;\n // Same rule as `submitDraft`: a suggestion chip is a new question too.\n stopSpeaking();\n setDraft(\"\");\n stickToBottomRef.current = true;\n pinFocus();\n // Staged files travel with a suggestion chip too — leaving them behind would drop\n // context the visitor deliberately attached, with nothing on screen saying so.\n void send(prompt, toPayload(stagedRef.current));\n setStaged([]);\n setAttachmentNotice(null);\n },\n [busy, canSend, pinFocus, send, setDraft, setStaged],\n );\n\n const handleKeyDown = useCallback(\n (event: React.KeyboardEvent<HTMLTextAreaElement>) => {\n if (event.key !== \"Enter\" || event.shiftKey) return;\n // IME safety: while a CJK/other candidate window is open, Enter commits\n // the candidate and must not send the message.\n if (composingRef.current || event.nativeEvent.isComposing) return;\n event.preventDefault();\n submitDraft();\n },\n [submitDraft],\n );\n\n const composerDisabled =\n phase === \"limited\" ||\n phase === \"disabled\" ||\n !catalog.enabled ||\n // A share token grants read access only — the server would reject a send anyway, so\n // disable it here rather than letting the visitor type into a dead composer.\n isSharedView;\n const captchaOn = Boolean(\n catalog.captchaRequired && catalog.recaptchaSiteKey,\n );\n\n // What the page bakes for the next prerender (see the <script> below). Never a disabled\n // catalog: the server answers enabled:false whenever its agent is unreachable, and a site\n // prerendered during that outage would otherwise start every visit switched off. Memoised,\n // because it is the whole catalog and ExplorePage re-renders on every streamed token.\n const bakedCatalogJson = useMemo(\n () =>\n serverCatalogRaw && serverCatalogRaw.enabled !== false\n ? serializeBakedCatalog(serverCatalogRaw)\n : null,\n [serverCatalogRaw],\n );\n\n // Lengths only — every rule they feed lives in `ExploreStyles`, where it can carry a\n // fallback, and every one of them is a custom property, which is valid in every engine, so\n // nothing here can be dropped whole the way the old inline `calc(100dvh - …)` was. Nothing\n // here is a HEIGHT either: this markup is what the sites' prerender serialises, and a\n // height is the one value that cannot survive being written at one viewport and served at\n // another. See the pane-height block in `EXPLORE_CSS`.\n const rootStyle: CSSProperties & CssVars = {};\n if (viewportPage) {\n rootStyle[\"--boff-explore-offset\"] =\n paneOffset === null ? normalizeOffset(viewportOffset) : `${paneOffset}px`;\n if (bottomInset > 0) {\n rootStyle[\"--boff-explore-inset\"] = `${bottomInset}px`;\n }\n }\n if (chromeOverlap > 0) {\n rootStyle[\"--boff-explore-chrome\"] = `${chromeOverlap}px`;\n }\n\n return (\n <div\n ref={rootRef}\n data-boff-explore={panel ? \"panel\" : \"page\"}\n data-phase={phase}\n data-locale={activeLocale}\n /* Arabic is the one RTL locale in the product set. Scoped to this subtree rather than\n set on <html>, because the SDK is a guest on someone else's page. */\n dir={rtl ? \"rtl\" : undefined}\n className={cn(\n panel\n ? \"boff-explore-panel flex h-full min-h-0 w-full min-w-0 flex-col overflow-hidden bg-background text-foreground\"\n : \"flex w-full min-w-0 flex-col overflow-x-hidden bg-background text-foreground\",\n viewportPage && \"boff-explore-viewport\",\n !panel && heightMode === \"auto\" && \"min-h-[70vh]\",\n className,\n )}\n style={panel ? undefined : rootStyle}\n >\n {/* Rendered unconditionally, unlike before. A page with no <title> and no description\n is not a neutral outcome — it is the one surface a search result and a browser tab\n are built from — so the default has to come from here rather than from whether the\n host site remembered to pass a prop. `productName` lets PageHead append \"| Name\",\n so the title itself stays about the visitor's problem and the brand still appears. */}\n {/* The panel is a guest on whatever page is showing: the head stays that page's (BOFF-9697). */}\n {panel ? null : (\n <PageHead\n title={seo?.title ?? T.seoTitle}\n description={\n seo?.description ??\n (headProductName\n ? fill(\n // BOFF-9796: one product's own page promises that product's answers alone, never \"and every\n // other product we build\". The title (\"Describe a problem, get an answer | {product}\") and the\n // site name already name this product only, and the og:/twitter: tags repeat these two.\n pinnedSlug === null\n ? T.seoDescriptionProduct\n : T.seoDescriptionScoped,\n { product: headProductName },\n )\n : T.seoDescription)\n }\n productName={seo?.title ? undefined : (headProductName ?? undefined)}\n keywords={seo?.keywords}\n image={seo?.image}\n url={seo?.url}\n />\n )}\n\n <ProseStyles />\n <ExploreStyles />\n {/* BOFF-9697: the panel's pane height always comes from the panel, never from its content, so it is always safe\n as a query container, and the welcome fit ladder applies to the expanded panel as it does to the page.\n Narrower than the ladder's floor (the compact panel, a phone's sheet) the capability tiles go at once: they\n restate the badge, the intro and the composer footer, and there they push the suggested questions below the\n fold. Rendered by the panel only and scoped to it, so a page renders exactly what it did before, even with a\n panel mounted beside it. */}\n {panel ? (\n <style>{`.boff-explore-panel .boff-explore-scroll { container: boff-explore-pane / size; }\n@container boff-explore-pane (width < ${toRem(WELCOME_FIT_MIN_WIDTH_PX)}) {\n .boff-explore-panel .boff-explore-scroll .boff-explore-capabilities { display: none; }\n}`}</style>\n ) : null}\n {/* The catalog this page is showing, for the site's prerender to capture. Every host\n site mounts with createRoot, which replaces the static page; without this the first\n client render started from the fallback catalog and tore down the concept strip and\n the product's own intro that the static page was already showing, on every load.\n The hook reads it back before that first commit (readBakedCatalog). Written only\n once the SERVER has answered: a fallback baked during a catalog outage would pin\n every visitor to it. Same data for every visitor, so baking it keeps the prerender\n contract — unlike a measured height, it does not depend on the prerender machine. */}\n {!panel && bakedCatalogJson ? (\n <script\n id={BAKED_CATALOG_ELEMENT_ID}\n type=\"application/json\"\n data-product={productSlug ?? \"\"}\n data-locale={bakedCatalogLocale()}\n dangerouslySetInnerHTML={{ __html: bakedCatalogJson }}\n />\n ) : null}\n <ExploreAnswerStyles />\n\n {/* Compact header in conversation mode — keeps exactly one <h1> on the\n page whichever state we are in. */}\n {!showWelcome ? (\n <div className=\"flex items-center gap-2.5 border-b border-border px-4 py-2.5\">\n <span\n aria-hidden=\"true\"\n className=\"flex h-7 w-7 shrink-0 items-center justify-center rounded-lg bg-primary/10 text-primary\"\n >\n <Sparkles className=\"h-4 w-4\" />\n </span>\n {panel ? (\n <h2 className=\"truncate text-sm font-semibold\">{resolvedTitle}</h2>\n ) : (\n <h1 className=\"truncate text-sm font-semibold\">{resolvedTitle}</h1>\n )}\n {focusedProductName ? (\n <span className=\"hidden shrink-0 rounded-full bg-secondary px-2 py-0.5 text-xs font-medium text-secondary-foreground sm:inline\">\n {focusedProductName}\n </span>\n ) : null}\n <Button\n data-boff-explore=\"new-chat\"\n type=\"button\"\n size=\"sm\"\n variant=\"ghost\"\n className=\"ml-auto shrink-0 text-muted-foreground\"\n onClick={reset}\n >\n <RotateCcw className=\"h-3.5 w-3.5\" />\n <span className=\"hidden sm:inline\">{T.newChat}</span>\n </Button>\n {messages.length > 0 ? (\n <Button\n data-boff-explore=\"share\"\n type=\"button\"\n size=\"sm\"\n variant=\"ghost\"\n className=\"shrink-0 text-muted-foreground\"\n title=\"Copy a read-only link to this conversation\"\n onClick={() => {\n void handleShare();\n }}\n >\n <Link2 className=\"h-3.5 w-3.5\" />\n <span className=\"hidden sm:inline\">{shareLabel}</span>\n </Button>\n ) : null}\n {history.length > 0 ? (\n <Button\n data-boff-explore=\"history-toggle\"\n type=\"button\"\n size=\"sm\"\n variant=\"ghost\"\n className=\"shrink-0 text-muted-foreground\"\n aria-expanded={historyOpen}\n onClick={() => {\n setHistoryOpen((open) => !open);\n }}\n >\n <HistoryIcon className=\"h-3.5 w-3.5\" />\n <span className=\"hidden sm:inline\">\n {T.history} ({history.length})\n </span>\n </Button>\n ) : null}\n </div>\n ) : null}\n\n {/* Past conversations, held in this browser only. */}\n {historyOpen && history.length > 0 ? (\n <div\n data-boff-explore=\"history-panel\"\n className=\"border-b border-border bg-muted/30 px-4 py-3\"\n >\n <div className=\"mx-auto w-full max-w-3xl\">\n <div className=\"mb-2 flex items-center justify-between gap-2\">\n <p className=\"text-xs font-semibold uppercase tracking-wide text-muted-foreground\">\n Your recent conversations\n </p>\n <Button\n data-boff-explore=\"history-clear\"\n type=\"button\"\n size=\"sm\"\n variant=\"ghost\"\n className=\"h-7 shrink-0 text-xs text-muted-foreground hover:text-destructive\"\n onClick={() => {\n clearHistory();\n setHistoryOpen(false);\n }}\n >\n <Trash2 className=\"h-3.5 w-3.5\" />\n {T.clearHistory}\n </Button>\n </div>\n <ul className=\"space-y-1\">\n {history.map((entry) => (\n <li key={entry.token} className=\"flex items-center gap-1\">\n <button\n data-boff-explore=\"history-item\"\n type=\"button\"\n className=\"flex-1 truncate rounded-md px-2 py-1.5 text-left text-sm text-foreground transition-colors hover:bg-accent hover:text-accent-foreground\"\n onClick={() => {\n openConversation(entry.token);\n setHistoryOpen(false);\n }}\n >\n <span className=\"truncate\">{entry.title}</span>\n <span className=\"ml-2 text-xs text-muted-foreground\">\n {entry.messageCount} message\n {entry.messageCount === 1 ? \"\" : \"s\"}\n </span>\n </button>\n <Button\n type=\"button\"\n size=\"icon\"\n variant=\"ghost\"\n className=\"h-7 w-7 shrink-0 text-muted-foreground hover:text-destructive\"\n aria-label={`Delete conversation: ${entry.title}`}\n onClick={() => {\n deleteConversation(entry.token);\n }}\n >\n <Trash2 className=\"h-3.5 w-3.5\" />\n </Button>\n </li>\n ))}\n </ul>\n </div>\n </div>\n ) : null}\n\n {/* Transcript */}\n <div\n ref={scrollRef}\n onScroll={handleScroll}\n data-boff-explore=\"messages\"\n role=\"log\"\n aria-live=\"polite\"\n aria-label=\"Explore conversation\"\n className={cn(\n \"boff-explore-scroll min-h-0 min-w-0 flex-1 overflow-y-auto overflow-x-hidden\",\n // Only while the welcome state is showing: a flex column is what lets its\n // `my-auto` centre the block on a tall screen. The transcript must NOT be a flex\n // column — that would fight the natural top-down flow of messages.\n showWelcome && \"flex flex-col\",\n )}\n >\n {showWelcome ? (\n <WelcomeState\n heading={panel ? \"h2\" : \"h1\"}\n strings={T}\n title={resolvedTitle}\n body={resolvedBody}\n prompts={prompts}\n /* BOFF-9796: one product's own assistant has no product picker (its focus is pinned), so none of\n the catalogue's names, and no \"All N\" either. */\n products={pinnedSlug === null ? catalog.products : NO_PRODUCTS}\n conceptHighlights={conceptHighlights}\n focusProduct={focusProduct}\n onPrompt={sendPrompt}\n onFocus={setFocusProduct}\n disabled={!canSend || busy}\n productScoped={pinnedSlug !== null}\n />\n ) : (\n <div className=\"mx-auto w-full min-w-0 max-w-3xl space-y-6 px-4 py-6\">\n {messages.map((message) =>\n message.role === \"USER\" ? (\n <UserBubble key={message.id} strings={T} message={message} />\n ) : (\n <AssistantBubble\n key={message.id}\n strings={T}\n message={message}\n activity={activity}\n imageOrigins={imageOrigins}\n productSlugs={productSlugs}\n productNames={productNames}\n speechLang={speechLang}\n voiceHold={voiceHold}\n onNavigate={onNavigate}\n anchorRef={\n message.id === latestAssistantId\n ? latestAssistantRef\n : undefined\n }\n onFollow={(kind, url) => recordClick(message.id, kind, url)}\n onFollowUp={sendPrompt}\n /* A shared view is somebody else's thread opened read-only: the `?c=`\n secret is not a conversation token, so a rating from here could only\n come back `recorded: false`. Offer nothing rather than a control that\n cannot work. */\n onFeedback={\n isSharedView\n ? undefined\n : (rating, detail) =>\n submitFeedback(message.id, rating, detail)\n }\n /* `canEscalate`, not `!isSharedView`: the hand-off needs a conversation\n TOKEN, and a shared view is only one of the ways there isn't one. The\n hook owns the token, so it owns this answer. */\n onEscalate={canEscalate ? escalate : undefined}\n isLatestAnswer={message.id === latestAssistantId}\n />\n ),\n )}\n </div>\n )}\n </div>\n\n <DisclaimerDialog\n open={disclaimerOpen}\n onClose={() => setDisclaimerOpen(false)}\n captchaOn={captchaOn}\n />\n\n {/* A shared conversation is someone else's thread, opened read-only. Say so plainly:\n without it the visitor sees a chat they cannot send in and no reason why. */}\n {isSharedView ? (\n <div\n data-boff-explore=\"shared-banner\"\n className=\"mx-auto flex w-full max-w-3xl items-center gap-2 px-4 pb-2 text-xs text-muted-foreground\"\n >\n <Link2 className=\"h-3.5 w-3.5 shrink-0\" />\n <span className=\"min-w-0 flex-1\">\n You are viewing a shared conversation. Start your own to ask a\n question.\n </span>\n <button\n type=\"button\"\n data-boff-explore=\"shared-start-own\"\n onClick={() => {\n // Drop the ?c= so a refresh does not reopen the shared thread.\n if (typeof window !== \"undefined\") {\n const url = new URL(window.location.href);\n url.searchParams.delete(\"c\");\n window.location.href = url.toString();\n }\n }}\n className=\"shrink-0 underline underline-offset-2 hover:text-foreground\"\n >\n New chat\n </button>\n </div>\n ) : null}\n\n {/* Composer. The bottom padding is a stylesheet rule rather than an arbitrary Tailwind\n value because it has to fold in the measured overlap of any foreign fixed chrome\n (see `measureChrome`) on top of the safe-area inset, with a fallback for engines\n that have neither `max()` nor `env()`. */}\n <div\n ref={composerRef}\n data-boff-explore=\"composer-dock\"\n className=\"boff-explore-composer border-t border-border bg-background/85 px-4 pt-3 backdrop-blur-md\"\n >\n <form\n data-boff-explore=\"composer\"\n className=\"mx-auto w-full max-w-3xl\"\n onSubmit={(event) => {\n event.preventDefault();\n submitDraft();\n }}\n >\n {shownError ? (\n <ErrorBanner\n error={shownError}\n onRetry={retryTurn}\n onReset={reset}\n />\n ) : null}\n\n {staged.length > 0 ? (\n <ul\n data-boff-explore=\"attachments\"\n className=\"mb-2 flex flex-wrap gap-1.5\"\n aria-label={T.attach}\n >\n {staged.map((entry) => (\n <li\n key={entry.id}\n data-boff-explore=\"attachment\"\n data-text-extracted={entry.textExtracted ? \"true\" : \"false\"}\n className=\"flex max-w-full items-center gap-1.5 rounded-full border border-border bg-muted/60 py-1 pl-2.5 pr-1 text-xs\"\n >\n <Paperclip className=\"h-3 w-3 shrink-0 text-muted-foreground\" />\n <span className=\"truncate font-medium\" title={entry.name}>\n {entry.name}\n </span>\n <span className=\"shrink-0 text-muted-foreground\">\n {formatBytes(entry.size)}\n {/* Said plainly rather than implied: a PDF contributes its name and type,\n and the visitor must not be left thinking we read it. */}\n {entry.textExtracted ? \"\" : ` · ${T.attachmentNameOnly}`}\n </span>\n <button\n type=\"button\"\n data-boff-explore=\"attachment-remove\"\n onClick={() => removeAttachment(entry.id)}\n aria-label={fill(T.removeAttachment, { name: entry.name })}\n className=\"ml-0.5 flex h-5 w-5 shrink-0 items-center justify-center rounded-full text-muted-foreground transition-colors hover:bg-background hover:text-foreground\"\n >\n <X className=\"h-3 w-3\" />\n </button>\n </li>\n ))}\n </ul>\n ) : null}\n\n {attachmentNotice !== null ? (\n <p\n data-boff-explore=\"attachment-notice\"\n role=\"status\"\n className=\"mb-2 text-xs text-destructive\"\n >\n {attachmentNotice}\n </p>\n ) : null}\n\n <div\n data-boff-explore=\"composer-field\"\n className={cn(\n // Stacked on a phone, one row from `sm` up. Three 36px icon buttons beside\n // the field left it 138px wide at 320px — about seventeen characters — so on\n // the narrowest screens the field takes the full width and the buttons get\n // their own row beneath it. The buttons' wrapper is `sm:contents`, so from\n // `sm` up it stops being a box and the buttons are direct flex children of\n // this row again: the desktop layout is byte-for-byte what it was.\n \"flex min-w-0 flex-col items-stretch gap-1 rounded-2xl border bg-card p-2 shadow-sm transition-all sm:flex-row sm:items-end sm:gap-2\",\n busy && \"boff-explore-busy\",\n overLimit\n ? \"border-destructive/60\"\n : \"border-border focus-within:border-primary/40 focus-within:ring-1 focus-within:ring-ring\",\n // The halo is an invitation, and an invitation is only useful before it has\n // been accepted: while the conversation is empty, the composer is usable, and\n // nothing has been typed. Once any of those stops being true the class goes\n // and the box is an ordinary card again. `-quiet` keeps the ring but stops the\n // movement the moment there are characters in the field, so it does not pulse\n // at someone who is mid-sentence.\n showWelcome &&\n !composerDisabled &&\n !overLimit &&\n \"boff-explore-invite\",\n showWelcome && draft.length > 0 && \"boff-explore-invite-quiet\",\n )}\n >\n <Textarea\n ref={textareaRef}\n value={draft}\n rows={1}\n disabled={composerDisabled}\n onChange={(event) => setDraft(event.target.value)}\n onKeyDown={handleKeyDown}\n onCompositionStart={() => {\n composingRef.current = true;\n }}\n onCompositionEnd={() => {\n composingRef.current = false;\n }}\n aria-label=\"Ask a question\"\n placeholder={\n composerDisabled\n ? phase === \"limited\"\n ? \"Message limit reached — please try again later\"\n : \"Explore is unavailable right now\"\n : focusedProductName\n ? fill(\n // BOFF-9796: one product's own assistant keeps this field exactly as every site has it, its\n // classes and its fit to the draft alone; only its placeholder says less. On a phone the\n // field is one line tall and cuts off a placeholder that wraps: in English, \"Ask about\n // {product}…\" fits that line at 320px and wider.\n pinnedSlug === null\n ? T.placeholderProduct\n : T.placeholderScoped,\n { product: focusedProductName },\n )\n : T.placeholder\n }\n /* text-base (16px) on mobile is load-bearing, not styling: iOS Safari auto-zooms any\n focused input under 16px, and that zoom is what scaled the viewport, created the\n horizontal scroll and pushed the send button off-screen. Fixed here rather than\n with maximum-scale=1 in the viewport meta, which would disable pinch-zoom for\n everyone. */\n className=\"max-h-[200px] min-h-[44px] w-full min-w-0 flex-1 resize-none border-0 bg-transparent px-2 py-2.5 text-base shadow-none focus-visible:ring-0 sm:text-sm\"\n />\n <input\n ref={fileInputRef}\n type=\"file\"\n multiple\n className=\"hidden\"\n /* No `accept` filter: the visitor may attach anything, and a format we cannot\n read still contributes its name and type. Filtering here would hide files the\n picker should offer and tell them nothing about why. */\n onChange={(event) => {\n void handleFilesPicked(event.target.files);\n // Reset so picking the SAME file again still fires a change event.\n event.target.value = \"\";\n }}\n />\n {/* `sm:contents` is the whole trick: this box exists only below `sm`, to put\n the buttons on their own row under a full-width field. From `sm` up it\n stops generating a box, so each button is a direct flex child of the\n composer row exactly as before and the desktop layout is untouched. */}\n <div className=\"flex items-center justify-end gap-1 sm:contents\">\n <Button\n data-boff-explore=\"attach\"\n type=\"button\"\n size=\"icon\"\n variant=\"ghost\"\n disabled={composerDisabled || staged.length >= MAX_ATTACHMENTS}\n aria-label={T.attach}\n title={`${T.attach} — ${fill(T.attachHint, {\n max: String(MAX_ATTACHMENTS),\n size: String(MAX_ATTACHMENT_BYTES / (1024 * 1024)),\n })}`}\n onClick={() => fileInputRef.current?.click()}\n >\n <Paperclip className=\"h-4 w-4\" />\n </Button>\n {speech.supported ? (\n <Button\n data-boff-explore=\"mic\"\n data-listening={speech.listening ? \"true\" : \"false\"}\n type=\"button\"\n size=\"icon\"\n variant={speech.listening ? \"default\" : \"ghost\"}\n disabled={composerDisabled}\n aria-label={speech.listening ? T.stopDictating : T.dictate}\n aria-pressed={speech.listening}\n /* BOFF-9797: held while the live avatar speaks, focusable and explained (the avatar's own status line\n as its title), never `disabled`. A dictation still listening can always be stopped. */\n aria-disabled={\n voiceHeld && !speech.listening ? \"true\" : undefined\n }\n title={\n speech.listening\n ? T.stopDictating\n : (voiceHold ?? T.dictate)\n }\n onClick={() => {\n if (voiceHeld && !speech.listening) return;\n speech.toggle();\n }}\n className={cn(\n speech.listening && \"animate-pulse\",\n voiceHeld &&\n !speech.listening &&\n \"cursor-not-allowed opacity-50\",\n )}\n >\n <Mic className=\"h-4 w-4\" />\n </Button>\n ) : null}\n {busy ? (\n <Button\n data-boff-explore=\"stop\"\n type=\"button\"\n size=\"icon\"\n variant=\"secondary\"\n aria-label={T.stop}\n onClick={stop}\n >\n <Square className=\"h-4 w-4\" />\n </Button>\n ) : (\n <Button\n data-boff-explore=\"send\"\n type=\"submit\"\n size=\"icon\"\n disabled={!canSubmit}\n aria-label={T.send}\n >\n <ArrowUp className=\"h-4 w-4\" />\n </Button>\n )}\n </div>\n </div>\n\n {speech.listening || speech.interim !== \"\" ? (\n <p\n data-boff-explore=\"dictation\"\n className=\"mt-2 flex items-center gap-2 text-xs text-muted-foreground\"\n aria-live=\"polite\"\n >\n <span className=\"relative flex h-2 w-2 shrink-0\">\n <span className=\"absolute inline-flex h-full w-full animate-ping rounded-full bg-primary opacity-75\" />\n <span className=\"relative inline-flex h-2 w-2 rounded-full bg-primary\" />\n </span>\n <span className=\"italic\">\n {speech.interim !== \"\" ? speech.interim : \"Listening…\"}\n </span>\n </p>\n ) : null}\n {speech.error !== null ? (\n <p\n data-boff-explore=\"dictation-error\"\n className=\"mt-2 text-xs text-destructive\"\n >\n {speech.error}\n </p>\n ) : null}\n\n <div className=\"mt-2 flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-muted-foreground\">\n <span className=\"hidden sm:inline\">\n Enter to send · Shift + Enter for a new line\n </span>\n {remainingToday !== null ? (\n <span data-boff-explore=\"remaining\">\n {remainingToday} message{remainingToday === 1 ? \"\" : \"s\"} left\n today\n </span>\n ) : null}\n <span\n className={cn(\n \"ml-auto tabular-nums\",\n overLimit && \"font-medium text-destructive\",\n )}\n >\n {draft.length.toLocaleString()} / {maxLength.toLocaleString()}\n </span>\n </div>\n\n {/* One line instead of three sentences. The notice still has to be said — the\n conversation really is stored — but as permanent body copy it was the tallest\n thing on a phone screen, directly under the control people came here to use. */}\n {shareUrl ? (\n <div className=\"mt-2 flex items-center gap-2\">\n <input\n data-boff-explore=\"share-url\"\n readOnly\n value={shareUrl}\n aria-label=\"Read-only link to this conversation\"\n onFocus={(event) => event.currentTarget.select()}\n className=\"min-w-0 flex-1 rounded-md border border-border bg-muted px-2 py-1 text-xs text-muted-foreground\"\n />\n <button\n type=\"button\"\n className=\"shrink-0 text-xs underline underline-offset-2\"\n onClick={() => setShareUrl(null)}\n >\n Done\n </button>\n </div>\n ) : null}\n\n <div className=\"mt-2 flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-muted-foreground\">\n <span className=\"min-w-0 sm:truncate\">{T.disclaimerShort}</span>\n <button\n type=\"button\"\n data-boff-explore=\"disclaimer\"\n onClick={() => setDisclaimerOpen(true)}\n className=\"shrink-0 underline underline-offset-2 transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\"\n >\n {T.disclaimer}\n </button>\n </div>\n </form>\n </div>\n </div>\n );\n}\n"]}
|