@burdenoff/website-sdk 2026.924.1 → 2026.924.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/dist/components/explore.d.mts +1 -1
- package/dist/components/explore.d.ts +1 -1
- package/dist/components/explore.js +17 -0
- package/dist/components/explore.js.map +1 -1
- package/dist/components/explore.mjs +17 -2
- package/dist/components/explore.mjs.map +1 -1
- package/dist/{explore-I4QnY4J9.d.ts → explore-C3SEP5K6.d.ts} +12 -1
- package/dist/{explore-D25zoXy9.d.mts → explore-Crc41y0j.d.mts} +12 -1
- package/dist/index.d.mts +36 -4
- package/dist/index.d.ts +36 -4
- package/dist/index.js +292 -140
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +291 -142
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/content/Markdown.tsx","../../src/utils/cn.ts","../../src/components/explore-answer.tsx","../../src/components/explore-i18n.ts","../../src/components/explore-types.ts","../../src/content/prose-styles.tsx","../../src/client/security.ts","../../src/client/graphql-client.ts","../../src/client/provider.tsx","../../src/data/products.ts","../../src/utils/recaptcha-v3.ts","../../src/hooks/use-explore-chat.ts","../../src/hooks/use-progressive-reveal.ts","../../src/hooks/use-speech-input.ts","../../src/hooks/use-speech-output.ts","../../src/hooks/use-swipe.ts","../../src/seo/page-head.tsx","../../src/ui/button.tsx","../../src/ui/textarea.tsx","../../src/utils/explore-attachments.ts","../../src/components/explore.tsx"],"names":["jsx","createContext","useContext","useMemo","useState","useCallback","open","useRef","useEffect","id","jsxs","React2","clamp","delta","HistoryIcon"],"mappings":"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","file":"explore.mjs","sourcesContent":["import type { ComponentProps, ReactNode } from \"react\";\n\nimport ReactMarkdown from \"react-markdown\";\nimport rehypeSanitize from \"rehype-sanitize\";\nimport remarkGfm from \"remark-gfm\";\n\nimport type { Components, ExtraProps } from \"react-markdown\";\n\nexport interface MarkdownProps {\n /** Markdown source to render. */\n children: string;\n /** Additional classes for the wrapper element. */\n className?: string;\n /** Render without a wrapping block element, suitable for inline content. */\n inline?: boolean;\n /** Optional react-markdown component overrides. */\n components?: Components;\n}\n\n/**\n * The default markdown link: external links open in a new tab, every link gets safe `rel`\n * attributes. Exported so a caller overriding `a` (to add context around links, say) can\n * still render the same element.\n */\nexport function MarkdownLink({\n href,\n children,\n // react-markdown passes the hast node to every override; it is not a DOM attribute.\n node: _node,\n ...props\n}: ComponentProps<\"a\"> & ExtraProps) {\n const isExternal =\n typeof href === \"string\" &&\n (href.startsWith(\"http://\") || href.startsWith(\"https://\"));\n return (\n <a\n href={href}\n {...props}\n {...(isExternal\n ? { target: \"_blank\", rel: \"noopener noreferrer\" }\n : { rel: \"noopener noreferrer\" })}\n >\n {children}\n </a>\n );\n}\n\nconst defaultComponents: Components = {\n a: MarkdownLink,\n};\n\n/**\n * Shared markdown renderer for website content.\n *\n * - Uses `react-markdown` for standards-compliant parsing.\n * - Enables GitHub Flavored Markdown (tables, task lists, strikethrough, autolinks).\n * - Sanitizes HTML via `rehype-sanitize` so raw markup in markdown is stripped.\n * - External links open in a new tab with safe rel attributes.\n */\nexport function Markdown({\n children,\n className,\n inline,\n components,\n}: MarkdownProps): ReactNode {\n const content = (\n <ReactMarkdown\n remarkPlugins={[remarkGfm]}\n rehypePlugins={[rehypeSanitize]}\n components={{ ...defaultComponents, ...components }}\n {...(inline ? { disallowedElements: [\"p\"], unwrapDisallowed: true } : {})}\n >\n {children}\n </ReactMarkdown>\n );\n\n if (inline) {\n return <span className={className}>{content}</span>;\n }\n\n return <div className={className}>{content}</div>;\n}\n","/**\n * Utility function to merge Tailwind CSS classes\n * Combines clsx and tailwind-merge for optimal class handling\n */\n\nimport { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Merge multiple class names intelligently\n * - Handles conditional classes via clsx\n * - Deduplicates and resolves Tailwind conflicts via tailwind-merge\n *\n * @example\n * ```ts\n * cn('px-4 py-2', 'bg-blue-500', { 'text-white': isActive })\n * // => 'px-4 py-2 bg-blue-500 text-white' (if isActive is true)\n * ```\n */\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\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/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 — 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 useMemo,\n useState,\n} from \"react\";\nimport type { ComponentProps, ReactElement } from \"react\";\n\nimport { Markdown, MarkdownLink } from \"../content/Markdown\";\nimport { cn } from \"../utils/cn\";\n\nimport type { ExploreProduct } from \"./explore-types\";\nimport type { Components, ExtraProps } 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\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 (Botlit ships on www.botlit.ai, 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 * 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 */\nexport function isInlineImageAllowed(\n src: unknown,\n origins: ReadonlySet<string>,\n): src is string {\n if (typeof src !== \"string\" || src === \"\") return false;\n let url: URL;\n try {\n url = new URL(src);\n } catch {\n return false;\n }\n if (url.protocol !== \"https:\" || url.username || url.password) return false;\n return origins.has(url.origin);\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 two places — links and tables —\n * and nowhere else, which is why they are one function and not two.\n */\ntype ReadableFor = \"clipboard\" | \"speech\";\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 // Images before links: `` also matches the link pattern.\n line = line.replace(/!\\[[^\\]]*\\]\\([^)\\s]*(?:\\s+\"[^\"]*\")?\\)/g, \"\");\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(/\\[([^\\]]+)\\]\\(([^)\\s]+)(?:\\s+\"[^\"]*\")?\\)/g, \"$1\")\n : line.replace(/\\[([^\\]]+)\\]\\(([^)\\s]+)(?:\\s+\"[^\"]*\")?\\)/g, \"$1 ($2)\");\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 * - **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 two 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 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 three fields rather than the whole `ExploreStrings`: the chat and a published\n * answer page carry different chrome vocabularies, and these three are the only words the\n * ANSWER itself needs. `ExploreStrings` satisfies this structurally, so the chat passes its\n * own `T` unchanged.\n */\nexport interface AnswerRendererStrings {\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}\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 /** 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\nfunction AnswerLink(props: ComponentProps<\"a\"> & ExtraProps) {\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 children?: MarkdownNode[];\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 * 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\nexport interface ExploreAnswerBodyProps {\n /** The answer, exactly as the harness wrote it: GitHub-flavoured markdown. */\n children: string;\n /** The three 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 * False while the answer is still streaming, which suppresses its images: a partial is cut\n * mid-token, so an image URL in it may be half-written, and the backend has not yet dropped\n * the images it does not allow. A settled answer — every published one — is `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 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 failed,\n onFailed,\n }),\n [strings, enabled, imageOrigins, failed, onFailed],\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}>{children}</Markdown>\n </AnswerScopeContext.Provider>\n </div>\n );\n}\n","/**\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 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 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 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 /** 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 capabilities: [string, string, string];\n prompts: string[];\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 you're facing, in your own words. You can also ask about a specific product or compare a few. 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 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 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 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 you're facing 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 you're facing 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 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 \"Which of your products fits a problem like mine?\",\n ],\n};\n\nconst ZH: ExploreStrings = {\n badge: \"基于我们文档的 AI 回答\",\n welcomeTitle: \"你想解决什么问题?\",\n welcomeBody:\n \"用你自己的话描述你遇到的问题。你也可以询问某一款产品,或比较几款产品。所有回答都直接来自我们的文档。\",\n tryAsking: \"试着问\",\n focusProduct: \"聚焦某个产品\",\n allProducts: \"全部产品\",\n showAll: \"全部\",\n showLess: \"收起\",\n sources: \"来源\",\n nextYouCouldAsk: \"你还可以问\",\n placeholder: \"描述你的问题…\",\n placeholderProduct: \"描述问题,或询问 {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 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 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 capabilities: [\"基于我们自己的文档\", \"跨产品对比\", \"直达正确的页面\"],\n prompts: [\n \"每门课程都记在不同的表格里。\",\n \"机器停了,要等整条线停下来才知道。\",\n \"会员慢慢就不来了,我们也不知道为什么。\",\n \"哪个产品适合我这样的问题?\",\n ],\n};\n\nconst HI: ExploreStrings = {\n badge: \"हमारे दस्तावेज़ों पर आधारित AI उत्तर\",\n welcomeTitle: \"आप कौन सी समस्या हल करना चाहते हैं?\",\n welcomeBody:\n \"अपनी समस्या अपने शब्दों में बताएं। आप किसी एक उत्पाद के बारे में भी पूछ सकते हैं या कुछ की तुलना कर सकते हैं। हर उत्तर सीधे हमारे दस्तावेज़ से आता है।\",\n tryAsking: \"यह पूछकर देखें\",\n focusProduct: \"किसी उत्पाद पर ध्यान दें\",\n allProducts: \"सभी उत्पाद\",\n showAll: \"सभी\",\n showLess: \"कम दिखाएँ\",\n sources: \"स्रोत\",\n nextYouCouldAsk: \"आगे आप पूछ सकते हैं\",\n placeholder: \"अपनी समस्या बताएं…\",\n placeholderProduct: \"समस्या बताएं, या {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 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 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 capabilities: [\n \"हमारे अपने दस्तावेज़ों पर आधारित\",\n \"सभी उत्पादों की तुलना करें\",\n \"सीधे सही पेज पर\",\n ],\n prompts: [\n \"हर कोर्स का हिसाब अलग शीट में रखा जाता है।\",\n \"मशीन बंद होने का पता तभी चलता है जब लाइन रुक जाए।\",\n \"सदस्य धीरे-धीरे आना बंद कर देते हैं, वजह पता नहीं चलती।\",\n \"मेरी जैसी समस्या के लिए कौन सा उत्पाद सही है?\",\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 que tienes con tus propias palabras. También puedes preguntar por un producto concreto o comparar varios. 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 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 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 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 con tus palabras el problema que tienes 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 con tus palabras el problema que tienes 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 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 \"¿Qué producto encaja con un problema como el mío?\",\n ],\n};\n\nconst AR: ExploreStrings = {\n badge: \"إجابات ذكاء اصطناعي مبنية على وثائقنا\",\n welcomeTitle: \"ما المشكلة التي تحاول حلها؟\",\n welcomeBody:\n \"صف المشكلة التي تواجهها بكلماتك أنت. يمكنك أيضًا السؤال عن منتج بعينه أو المقارنة بين عدة منتجات. تأتي كل إجابة مباشرة من وثائقنا.\",\n tryAsking: \"جرّب أن تسأل\",\n focusProduct: \"التركيز على منتج\",\n allProducts: \"كل المنتجات\",\n showAll: \"الكل\",\n showLess: \"عرض أقل\",\n sources: \"المصادر\",\n nextYouCouldAsk: \"يمكنك أن تسأل بعد ذلك\",\n placeholder: \"صف المشكلة…\",\n placeholderProduct: \"صف مشكلتك أو اسأل عن {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 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 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 capabilities: [\n \"مبني على وثائقنا\",\n \"قارن عبر المنظومة\",\n \"مباشرةً إلى الصفحة الصحيحة\",\n ],\n prompts: [\n \"كل دورة تدريبية لدينا في جدول بيانات مختلف.\",\n \"لا نعلم بتعطل الماكينة إلا بعد توقف خط الإنتاج.\",\n \"أعضاؤنا يتوقفون عن الحضور تدريجيًا دون أن نعرف السبب.\",\n \"أي منتج يناسب مشكلة مثل مشكلتي؟\",\n ],\n};\n\nconst TA: ExploreStrings = {\n badge: \"எங்கள் ஆவணங்களை அடிப்படையாகக் கொண்ட AI பதில்கள்\",\n welcomeTitle: \"நீங்கள் எந்தச் சிக்கலைத் தீர்க்க முயல்கிறீர்கள்?\",\n welcomeBody:\n \"நீங்கள் எதிர்கொள்ளும் சிக்கலை உங்கள் சொந்த வார்த்தைகளில் விவரியுங்கள். ஒரு குறிப்பிட்ட தயாரிப்பு பற்றியும் கேட்கலாம், சிலவற்றை ஒப்பிடவும் செய்யலாம். ஒவ்வொரு பதிலும் எங்கள் ஆவணப்படுத்தலிலிருந்து நேரடியாக வருகிறது.\",\n tryAsking: \"இதைக் கேட்டுப் பாருங்கள்\",\n focusProduct: \"ஒரு தயாரிப்பில் கவனம்\",\n allProducts: \"அனைத்து தயாரிப்புகள்\",\n showAll: \"அனைத்தும்\",\n showLess: \"குறைவாகக் காட்டு\",\n sources: \"மூலங்கள்\",\n nextYouCouldAsk: \"அடுத்து நீங்கள் கேட்கலாம்\",\n placeholder: \"சிக்கலை விவரியுங்கள்…\",\n placeholderProduct:\n \"சிக்கலை விவரியுங்கள், அல்லது {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 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 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 capabilities: [\n \"எங்கள் சொந்த ஆவணங்களின் அடிப்படையில்\",\n \"தயாரிப்புகளை ஒப்பிடுங்கள்\",\n \"நேராக சரியான பக்கத்திற்கு\",\n ],\n prompts: [\n \"ஒவ்வொரு பயிற்சி வகுப்பும் வெவ்வேறு விரிதாளில் உள்ளது.\",\n \"இயந்திரம் நின்றது லைன் நிற்கும்போதுதான் தெரிய வருகிறது.\",\n \"உறுப்பினர்கள் மெல்ல வருவதை நிறுத்துகிறார்கள், காரணம் தெரியாது.\",\n \"என் பிரச்சினைக்கு எந்தத் தயாரிப்பு பொருந்தும்?\",\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/** Substitute `{product}` and friends without pulling in a formatting library. */\nexport function fill(template: string, values: Record<string, string>): string {\n return template.replace(/\\{(\\w+)\\}/g, (match, key) => values[key] ?? match);\n}\n","/**\n * Explore chat — TypeScript mirror of the public `/explore` GraphQL contract.\n *\n * Canonical source: `~/products/dev/platform/context/explore/CONTRACT.md` §1\n * (global-support-svc, served through the global PUBLIC gateway with\n * `@rbac(public: true, scopeType: \"global\")`).\n *\n * Nothing in this file may drift from that document. If a shape here looks\n * wrong, fix CONTRACT.md first and tell the backend workstreams — never patch\n * it locally.\n *\n * Nullability note: the contract marks `title`, `description`, `product`,\n * `imageUrl`, `partialContent`, `errorCode`, `completedAt`, `productSlug`,\n * `recaptchaSiteKey` and `remainingToday` as nullable, so every one of them is\n * `?: T | null` here — a GraphQL `null` and an omitted selection both have to\n * be representable.\n */\n\n// ============================================================================\n// Enums (string unions — the wire format is the enum name)\n// ============================================================================\n\nexport type ExploreMessageRole = \"USER\" | \"ASSISTANT\";\n\nexport type ExploreMessageStatus =\n \"PENDING\" | \"RUNNING\" | \"COMPLETED\" | \"FAILED\";\n\n/** `enum ExploreFeedbackRating` — the visitor's verdict on one answer. */\nexport type ExploreFeedbackRating = \"HELPFUL\" | \"NOT_HELPFUL\";\n\n/**\n * The reasons offered alongside `NOT_HELPFUL`, in the order the chooser shows them.\n *\n * `reason` is `String` on the wire, not an enum, so this list is the SDK's half of the\n * agreement rather than something the schema enforces — the same treatment\n * {@link ExploreCtaKind} gets. Use the union when you are *producing* a reason; read one\n * back as a plain string.\n */\nexport const EXPLORE_FEEDBACK_REASONS = [\n \"INACCURATE\",\n \"INCOMPLETE\",\n \"OFF_TOPIC\",\n \"HARD_TO_FOLLOW\",\n \"OTHER\",\n] as const;\n\nexport type ExploreFeedbackReason = (typeof EXPLORE_FEEDBACK_REASONS)[number];\n\n/**\n * The `ExploreCta.kind` values enumerated in CONTRACT.md §1.\n *\n * `ExploreCtaLink.kind` is deliberately typed `string`, not this union: the\n * field is `String!` on the wire, and a kind added server-side must render\n * (falling back to the neutral CTA style) rather than break the build of 38\n * websites. Use this union when you are *producing* a kind.\n */\nexport type ExploreCtaKind =\n | \"CONTACT\"\n | \"PARTNERS\"\n | \"PRICING\"\n | \"SERVICES\"\n | \"WAITLIST\"\n | \"STORE\"\n | \"APP\"\n | \"DOCS\"\n | \"OTHER\";\n\n/**\n * Error codes surfaced through `extensions.code`. `HTTP_429` is what the\n * gateway emits when it rate-limits at the edge; the SDK client also produces\n * `TIMEOUT` / `NETWORK_ERROR` for transport failures.\n */\nexport type ExploreErrorCode =\n | \"EXPLORE_DISABLED\"\n | \"RATE_LIMITED\"\n | \"EXPLORE_GLOBAL_LIMIT\"\n | \"CAPTCHA_REQUIRED\"\n | \"CAPTCHA_FAILED\"\n | \"MESSAGE_TOO_LONG\"\n | \"MESSAGE_EMPTY\"\n | \"CONVERSATION_LIMIT\"\n | \"CONVERSATION_BUSY\"\n | \"UPSTREAM_UNAVAILABLE\"\n | \"NOT_FOUND\"\n // Handover-only. `INVALID_EMAIL` is the server's verdict on an address the client's own\n // pre-flight let through, and has to be shown rather than folded into a generic failure.\n | \"INVALID_EMAIL\"\n | \"ESCALATION_FAILED\"\n | \"HTTP_429\"\n | \"TIMEOUT\"\n | \"NETWORK_ERROR\";\n\n// ============================================================================\n// Object types\n// ============================================================================\n\n/** `type ExploreReference` — a cited source page for an answer. */\nexport interface ExploreReference {\n url: string;\n title?: string | null;\n description?: string | null;\n product?: string | null;\n imageUrl?: string | null;\n /** 1-based citation number; the answer text carries a matching `[n]` marker. */\n index?: number | null;\n}\n\n/**\n * `type ExploreCta` — a suggested next step attached to an answer.\n *\n * Named `ExploreCtaLink` in the SDK because `ExploreCta` is taken by the\n * exported nav component (`<ExploreCta variant=\"header\" />`). Same shape,\n * different name; the GraphQL type is unchanged.\n */\nexport interface ExploreCtaLink {\n /** One of {@link ExploreCtaKind}; unknown values render with the neutral style. */\n kind: string;\n label: string;\n url: string;\n product?: string | null;\n}\n\n/**\n * `type ExploreFeedback` — what is on record for one answer, as the server holds it.\n *\n * A rating REPLACES the previous one (the server upserts on `messageId`), so this is the\n * visitor's current opinion and never a history. `reason` is null for `HELPFUL` by\n * definition, and typed `string` rather than the union because it is `String` on the wire —\n * a reason added server-side must read back, not break the build of 38 websites.\n */\nexport interface ExploreFeedback {\n rating: ExploreFeedbackRating;\n /** One of {@link EXPLORE_FEEDBACK_REASONS}. Null for `HELPFUL`. */\n reason?: string | null;\n comment?: string | null;\n createdAt: string;\n}\n\n/** `type ExploreMessage`. `content` is `\"\"` while the turn is PENDING. */\nexport interface ExploreMessage {\n id: string;\n conversationId: string;\n role: ExploreMessageRole;\n status: ExploreMessageStatus;\n /** Final answer, markdown. Empty string until the turn completes. */\n content: string;\n /** Streaming preview while PENDING/RUNNING. */\n partialContent?: string | null;\n /** Human-readable progress lines, e.g. \"Searching vibecontrols…\". */\n activity: string[];\n references: ExploreReference[];\n ctas: ExploreCtaLink[];\n /** Up to three suggested next questions, derived from what the answer covered. */\n followUps?: string[] | null;\n /**\n * False when the corpus could not answer. A grounded answer always cites, so an answer\n * with no source is the honest \"we do not have this\" signal rather than a hedge.\n */\n answered?: boolean | null;\n /** Files the visitor attached to this turn. Present on USER messages only. */\n attachments?: ExploreAttachment[] | null;\n /**\n * The rating this visitor already gave this answer, or null for an unrated one.\n *\n * Selected only by the reads scoped to a `conversationToken`, so a polled or restored\n * transcript shows what was already rated instead of offering the row again. It is always\n * null on a SHARED transcript — that read is performed by someone else, and the rater's\n * verdict and free-text note are not theirs to receive. See\n * `EXPLORE_OWN_MESSAGE_FIELDS`.\n */\n feedback?: ExploreFeedback | null;\n errorCode?: string | null;\n createdAt: string;\n completedAt?: string | null;\n}\n\n/** `type ExploreConversation`. `token` is the client's only handle. */\nexport interface ExploreConversation {\n id: string;\n token: string;\n productSlug?: string | null;\n turnCount: number;\n createdAt: string;\n}\n\n/** `type ExploreProduct` — one product the harness can answer about. */\nexport interface ExploreProduct {\n slug: string;\n name: string;\n tagline?: string | null;\n website: string;\n}\n\n/** `type ExploreLimits` — server-owned caps the composer enforces locally. */\nexport interface ExploreLimits {\n maxMessageLength: number;\n maxTurnsPerConversation: number;\n messagesPerDay: number;\n historyTurns: number;\n}\n\n/**\n * `type ExploreConceptHighlight` — one published concept illustration, offered\n * as a way into the conversation before the visitor has typed anything.\n *\n * Every field is non-null on the wire: a highlight with no picture or no\n * destination is not a highlight, so the server drops it rather than sending a\n * half-built one. `product` is the slug, `productName` the display casing the\n * product's own pages use.\n *\n * The pictures are the published concept mockups — illustrations of an idea,\n * not screenshots of shipping software — which is why every surface that shows\n * one also labels it (`ExploreStrings.conceptIllustration`).\n */\nexport interface ExploreConceptHighlight {\n product: string;\n productName: string;\n title: string;\n url: string;\n imageUrl: string;\n alt: string;\n}\n\n/**\n * `type ExploreCatalog` — everything the page needs before the first message.\n *\n * `captchaRequired` + `recaptchaSiteKey` are what turn reCAPTCHA v3 on: it is\n * a backend secret change, and no website redeploy is involved.\n */\nexport interface ExploreCatalog {\n enabled: boolean;\n products: ExploreProduct[];\n examplePrompts: string[];\n welcomeTitle: string;\n welcomeBody: string;\n limits: ExploreLimits;\n captchaRequired: boolean;\n recaptchaSiteKey?: string | null;\n /**\n * At most 8, the site's own product first. Non-null and non-nullable per the\n * contract, so a gateway that knows the field always sends an array.\n *\n * A gateway that does NOT know it yet does not answer without it — it refuses\n * the whole document (`GRAPHQL_VALIDATION_FAILED`), which is why the hook\n * retries with `EXPLORE_CATALOG_QUERY_WITHOUT_HIGHLIGHTS` instead of falling\n * back to the built-in catalog. That retry is the one response that reaches\n * `normalizeCatalog` with this field absent, and the hardening there is what\n * keeps `catalog.conceptHighlights.filter(...)` from throwing in render.\n */\n conceptHighlights: ExploreConceptHighlight[];\n}\n\n/** `input SendExploreMessageInput`. */\nexport interface SendExploreMessageInput {\n /** Omit to start a new conversation. */\n conversationToken?: string;\n /** The site the visitor is on — a soft hint, not a hard filter. */\n productSlug?: string;\n message: string;\n /** Only sent when `catalog.captchaRequired`. */\n recaptchaToken?: string;\n locale?: string;\n pageUrl?: string;\n /**\n * Files attached as extra context. At most 5, each at most 10 MB — re-enforced server-side,\n * so these are the limits the composer shows, not the limits that hold.\n */\n attachments?: ExploreAttachmentInput[];\n}\n\n/** `input ExploreAttachmentInput`. `textContent` is null for a format the browser cannot read. */\nexport interface ExploreAttachmentInput {\n name: string;\n mimeType: string;\n size: number;\n textContent: string | null;\n}\n\n/** `type ExploreAttachment` — what the server accepted, echoed back. */\nexport interface ExploreAttachment {\n name: string;\n mimeType: string;\n size: number;\n /** False when only the filename and type could be used as context. */\n textExtracted: boolean;\n}\n\n/**\n * `type SendExploreMessageResult`.\n *\n * **`assistantMessage.id` is the id to poll** — it comes back `PENDING`.\n */\nexport interface SendExploreMessageResult {\n conversation: ExploreConversation;\n userMessage: ExploreMessage;\n assistantMessage: ExploreMessage;\n remainingToday?: number | null;\n}\n\n// ============================================================================\n// GraphQL documents\n//\n// Only the fields the UI actually renders are requested — a narrower selection\n// set is cheaper to poll (this runs once every ~1.5s per active visitor) and\n// keeps the contract surface the websites depend on small.\n// ============================================================================\n\n/**\n * Selection set for an `ExploreMessage` that ANYONE may read. Inlined as a\n * template string rather than a GraphQL `fragment` so each document stays a\n * single self-contained operation (the SDK client posts raw strings and has no\n * fragment registry).\n *\n * Deliberately WITHOUT `feedback` — see `EXPLORE_OWN_MESSAGE_FIELDS`.\n */\nconst EXPLORE_MESSAGE_FIELDS = /* GraphQL */ `\n id\n conversationId\n role\n status\n content\n partialContent\n activity\n references {\n url\n title\n description\n product\n imageUrl\n index\n }\n ctas {\n kind\n label\n url\n product\n }\n followUps\n answered\n attachments {\n name\n mimeType\n size\n textExtracted\n }\n errorCode\n createdAt\n completedAt\n`;\n\n/**\n * The same message PLUS the visitor's own rating of it.\n *\n * Used by the reads that are scoped to a `conversationToken`, so the person\n * making them is the person who rated the answer — that is what lets the row\n * come back already-rated after a reload instead of re-offering the choice.\n *\n * `EXPLORE_SHARED_CONVERSATION_QUERY` deliberately does NOT use this one. A\n * share link is the one read performed by somebody ELSE, and it exists to be\n * forwarded; `comment` is where a visitor types the specifics that made the\n * answer wrong for them — the price they are actually being charged, an\n * invoice number, a name — so it must not travel with a transcript sent to a\n * colleague. The server omits it there too; this is the client half of the\n * same rule, and keeping the selection sets separate is what stops a future\n * \"why are there two of these?\" tidy-up from re-merging them.\n */\nconst EXPLORE_OWN_MESSAGE_FIELDS = /* GraphQL */ `\n ${EXPLORE_MESSAGE_FIELDS}\n feedback {\n rating\n reason\n comment\n createdAt\n }\n`;\n\n/**\n * Everything on `ExploreCatalog` that every deployed gateway has served since\n * the surface shipped. Shared by both catalog documents below so the pair can\n * never drift: the ONLY difference between them is `conceptHighlights`.\n */\nconst EXPLORE_CATALOG_ESTABLISHED_FIELDS = /* GraphQL */ `\n enabled\n products {\n slug\n name\n tagline\n website\n }\n examplePrompts\n welcomeTitle\n welcomeBody\n limits {\n maxMessageLength\n maxTurnsPerConversation\n messagesPerDay\n historyTurns\n }\n captchaRequired\n recaptchaSiteKey`;\n\n/** The field added with the welcome strip — the only thing a new gateway has that an old one does not. */\nconst EXPLORE_CATALOG_HIGHLIGHT_FIELD = /* GraphQL */ `\n conceptHighlights {\n product\n productName\n title\n url\n imageUrl\n alt\n }`;\n\nfunction exploreCatalogDocument(extraFields: string): string {\n return /* GraphQL */ `\n query ExploreCatalog($productSlug: String) {\n exploreCatalog(productSlug: $productSlug) {${EXPLORE_CATALOG_ESTABLISHED_FIELDS}${extraFields}\n }\n }\n`;\n}\n\n/** Loaded once per page. Safe to serve from the SDK's 5-minute query cache. */\nexport const EXPLORE_CATALOG_QUERY = exploreCatalogDocument(\n EXPLORE_CATALOG_HIGHLIGHT_FIELD,\n);\n\n/**\n * The same catalog WITHOUT `conceptHighlights`, for a gateway whose supergraph\n * predates the field.\n *\n * This is not belt-and-braces. GraphQL validation is all-or-nothing: a gateway\n * that does not know the field rejects the ENTIRE document and returns no\n * `data` at all, so selecting `conceptHighlights` against an older supergraph\n * costs the whole catalog — `enabled`, `captchaRequired`, `recaptchaSiteKey`,\n * the welcome copy and `limits` included — and not merely the strip. Measured\n * against production:\n *\n * {\"errors\":[{\"message\":\"Cannot query field \\\\\"conceptHighlights\\\\\" on type\n * \\\\\"ExploreCatalog\\\\\".\",\"extensions\":{\"code\":\"GRAPHQL_VALIDATION_FAILED\"}}]}\n *\n * That window is guaranteed even with perfect deploy ordering, because the prod\n * gateway's CDN edge serves a stale supergraph for ~30-40 minutes after the\n * subgraph publishes. `useExploreChat` therefore retries with this document\n * (see `catalogRejectedTheHighlightField`) rather than dropping to the built-in\n * fallback, whose hardcoded `enabled: true` would ignore the server-side kill\n * switch and whose `captchaRequired: false` would let every send be rejected\n * server-side while the composer looked fine.\n */\nexport const EXPLORE_CATALOG_QUERY_WITHOUT_HIGHLIGHTS =\n exploreCatalogDocument(\"\");\n\n/**\n * The poll. MUST be issued with `client.query(..., { cache: false })` — the\n * default 5-minute cache would return the first PENDING snapshot forever and\n * the answer would never appear.\n */\nexport const EXPLORE_MESSAGE_QUERY = /* GraphQL */ `\n query ExploreMessage($conversationToken: String!, $id: ID!) {\n exploreMessage(conversationToken: $conversationToken, id: $id) {\n ${EXPLORE_OWN_MESSAGE_FIELDS}\n }\n }\n`;\n\n/** Submit half of the submit + poll pair. */\nexport const SEND_EXPLORE_MESSAGE_MUTATION = /* GraphQL */ `\n mutation SendExploreMessage($input: SendExploreMessageInput!) {\n sendExploreMessage(input: $input) {\n conversation {\n id\n token\n productSlug\n turnCount\n createdAt\n }\n userMessage {\n ${EXPLORE_OWN_MESSAGE_FIELDS}\n }\n assistantMessage {\n ${EXPLORE_OWN_MESSAGE_FIELDS}\n }\n remainingToday\n }\n }\n`;\n\n// ============================================================================\n// Response envelopes (what `client.query`/`client.mutate` resolve `data` to)\n// ============================================================================\n\nexport interface ExploreCatalogQueryData {\n exploreCatalog: ExploreCatalog;\n}\n\nexport interface ExploreMessageQueryData {\n exploreMessage: ExploreMessage | null;\n}\n\nexport interface SendExploreMessageMutationData {\n sendExploreMessage: SendExploreMessageResult;\n}\n\n/**\n * Record that the visitor followed a link the answer offered.\n *\n * Fire-and-forget: the browser is navigating away as this goes out, so the result is never\n * waited on and a failure is never surfaced. The server reports `recorded: false` rather\n * than erroring for anything it cannot attribute.\n */\nexport const RECORD_EXPLORE_CLICK_MUTATION = /* GraphQL */ `\n mutation RecordExploreClick($input: RecordExploreClickInput!) {\n recordExploreClick(input: $input) {\n recorded\n }\n }\n`;\n\n/** `input SubmitExploreFeedbackInput`. */\nexport interface SubmitExploreFeedbackInput {\n conversationToken: string;\n messageId: string;\n rating: ExploreFeedbackRating;\n /** Only meaningful with `NOT_HELPFUL`; stored null for `HELPFUL`. */\n reason?: ExploreFeedbackReason | null;\n /** Optional free text. Hard-capped server-side — never trusted from the client. */\n comment?: string | null;\n}\n\n/** `type SubmitExploreFeedbackResult`. */\nexport interface SubmitExploreFeedbackResult {\n /**\n * False — NOT an error — when the message is not a COMPLETED assistant turn, or when the\n * supplied `conversationToken` does not own it. Same posture as `recordExploreClick`: the\n * server declines to attribute rather than raising FORBIDDEN at a marketing visitor.\n */\n recorded: boolean;\n /** What is now on record, when the rating was taken. Null when `recorded` is false. */\n feedback?: ExploreFeedback | null;\n}\n\n/**\n * Rate one answer.\n *\n * Unlike {@link RECORD_EXPLORE_CLICK_MUTATION} this one IS awaited: the visitor is still on\n * the page and the control they just pressed has to end up telling the truth about whether\n * anything was recorded. The rating upserts on `messageId`, so re-rating is legal and a\n * second submit is never an error.\n */\nexport const SUBMIT_EXPLORE_FEEDBACK_MUTATION = /* GraphQL */ `\n mutation SubmitExploreFeedback($input: SubmitExploreFeedbackInput!) {\n submitExploreFeedback(input: $input) {\n recorded\n feedback {\n rating\n reason\n comment\n createdAt\n }\n }\n }\n`;\n\nexport interface SubmitExploreFeedbackMutationData {\n submitExploreFeedback: SubmitExploreFeedbackResult;\n}\n\n/**\n * How many characters the comment field accepts before it stops taking more.\n *\n * A courtesy so the box does not invite an essay it will lose, NOT a contract: the server\n * owns the real cap and may truncate or reject below this. Nothing here may be read as the\n * limit that holds.\n */\nexport const EXPLORE_FEEDBACK_COMMENT_SOFT_MAX = 500;\n\n// ============================================================================\n// Handing the conversation to a human (CONTRACT.md §1, \"Handing a conversation\n// to a human\")\n// ============================================================================\n\n/**\n * `input EscalateExploreConversationInput`.\n *\n * `email` is the only thing the visitor is asked for. It is **personal data**: it belongs in\n * this input and nowhere else — never in `localStorage`, never in an `ExploreMessage`, never\n * in an analytics call. See the note on {@link ESCALATE_EXPLORE_CONVERSATION_MUTATION}.\n */\nexport interface EscalateExploreConversationInput {\n /** The thread being handed over. A share (`?c=`) secret is NOT one. */\n conversationToken: string;\n /** Validated strictly server-side; a bad address comes back as `INVALID_EMAIL`. */\n email: string;\n /** Optional free text. Hard-capped server-side at 2000 and TRUNCATED, never rejected. */\n note?: string | null;\n /** Only when `exploreCatalog.captchaRequired`. Same v3 action as a chat message. */\n recaptchaToken?: string;\n /** `PlatformProduct` id of the site, so the ticket reaches that product's support inbox. */\n productId?: string;\n}\n\n/** `type ExploreEscalation` — the handover on record, as the SERVER holds it. */\nexport interface ExploreEscalation {\n /**\n * Where the reply is actually going.\n *\n * On a repeat submit this is the address the FIRST handover used, not the one just typed\n * into the box — so this is the value to show back, never the local draft.\n */\n email: string;\n createdAt: string;\n}\n\n/** `type EscalateExploreConversationResult`. */\nexport interface EscalateExploreConversationResult {\n /**\n * False when a handover already existed — the double-clicked button, the retried request,\n * the reloaded page.\n *\n * **Not an error.** The conversation is with a human either way, and the UI must read as\n * success on both values. The server enforces one handover per conversation with a UNIQUE\n * index rather than a check-then-insert, so two concurrent submits produce one ticket and\n * one of them gets this.\n */\n created: boolean;\n escalation: ExploreEscalation;\n}\n\n/**\n * Hand this conversation to a person.\n *\n * Awaited and NOT fire-and-forget (unlike {@link RECORD_EXPLORE_CLICK_MUTATION}): it is the\n * one explore write that throws, because it ends with a visitor being told a person has\n * their question. \"We passed it on\" must never be shown for a handover that did not happen.\n *\n * **The address the visitor types is personal data.** It travels in these variables and\n * stops there. Do not persist it, do not fold it into the transcript (`messages` is what the\n * hook writes to localStorage), and do not pass it to `onSend` or any analytics call — the\n * server already has everything a support agent needs.\n */\nexport const ESCALATE_EXPLORE_CONVERSATION_MUTATION = /* GraphQL */ `\n mutation EscalateExploreConversation(\n $input: EscalateExploreConversationInput!\n ) {\n escalateExploreConversation(input: $input) {\n created\n escalation {\n email\n createdAt\n }\n }\n }\n`;\n\nexport interface EscalateExploreConversationMutationData {\n escalateExploreConversation: EscalateExploreConversationResult;\n}\n\n/**\n * How many characters the note field accepts before it stops taking more.\n *\n * Mirrors the server's hard cap so the box does not invite text it will silently truncate.\n * Same status as {@link EXPLORE_FEEDBACK_COMMENT_SOFT_MAX}: a courtesy, not the limit that\n * holds.\n */\nexport const EXPLORE_ESCALATION_NOTE_SOFT_MAX = 2000;\n\n/**\n * A dot-atom local part, real DNS labels, an alphabetic TLD — the shape CONTRACT.md says the\n * server insists on.\n *\n * Deliberately no more permissive than that and deliberately no stricter: this exists to\n * catch the typo before a round-trip, not to be the authority. The server is the authority,\n * and the two DO disagree (an address this accepts can still come back `INVALID_EMAIL`),\n * which is why the form surfaces the server's verdict as well as this one.\n */\nconst DELIVERABLE_EMAIL =\n /^[A-Za-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[A-Za-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[A-Za-z0-9](?:[A-Za-z0-9-]*[A-Za-z0-9])?\\.)+[A-Za-z]{2,}$/;\n\n/**\n * Whether `value` is worth sending to the mutation at all.\n *\n * A local pre-flight, never a promise of deliverability. Keep it a SUBSET of what the server\n * accepts: a client that rejects something the server would have taken costs the visitor\n * their answer with nobody able to see why.\n */\nexport function looksLikeDeliverableEmail(value: string): boolean {\n const trimmed = value.trim();\n // 254 is the RFC 5321 ceiling on a forward path; anything longer cannot be delivered\n // anywhere, so it is a typo (or a paste of something that is not an address).\n if (trimmed.length === 0 || trimmed.length > 254) return false;\n return DELIVERABLE_EMAIL.test(trimmed);\n}\n\n/**\n * Mint a read-only link to this conversation.\n *\n * The returned secret is NOT the conversation token — it opens a read-only view and cannot\n * be used to continue the thread, so it is safe to put in a URL that gets forwarded.\n */\nexport const CREATE_EXPLORE_SHARE_LINK_MUTATION = /* GraphQL */ `\n mutation CreateExploreShareLink($conversationToken: String!) {\n createExploreShareLink(conversationToken: $conversationToken) {\n shareToken\n }\n }\n`;\n\n/**\n * Load a conversation someone shared, read-only.\n *\n * Takes the share secret from the `?c=` parameter, NOT a conversation token — the recipient\n * gets the transcript and no ability to continue or modify the thread.\n */\nexport const EXPLORE_SHARED_CONVERSATION_QUERY = /* GraphQL */ `\n query ExploreSharedConversation($shareToken: String!) {\n exploreSharedConversation(shareToken: $shareToken) {\n ${EXPLORE_MESSAGE_FIELDS}\n }\n }\n`;\n","\"use client\";\n\n/**\n * Self-contained prose styles for SDK content renderers.\n *\n * These components inject a scoped `.boff-prose` stylesheet so markdown content\n * renders correctly even when the host website does not install\n * `@tailwindcss/typography` or define `.prose` CSS.\n */\n\nexport const PROSE_CSS = `\n.boff-prose {\n max-width: none;\n}\n\n.boff-prose h1 {\n font-size: 2.25rem;\n font-weight: 800;\n line-height: 1.2;\n margin-top: 0;\n margin-bottom: 1rem;\n color: hsl(var(--foreground));\n}\n\n.boff-prose h2 {\n font-size: 1.75rem;\n font-weight: 700;\n line-height: 1.3;\n margin-top: 2rem;\n margin-bottom: 1rem;\n color: hsl(var(--foreground));\n}\n\n.boff-prose h3 {\n font-size: 1.5rem;\n font-weight: 600;\n line-height: 1.4;\n margin-top: 1.5rem;\n margin-bottom: 0.75rem;\n color: hsl(var(--foreground));\n}\n\n.boff-prose h4 {\n font-size: 1.25rem;\n font-weight: 600;\n line-height: 1.5;\n margin-top: 1.25rem;\n margin-bottom: 0.5rem;\n color: hsl(var(--foreground));\n}\n\n.boff-prose p {\n margin-bottom: 1rem;\n line-height: 1.75;\n color: hsl(var(--foreground));\n}\n\n.boff-prose ul,\n.boff-prose ol {\n margin-bottom: 1rem;\n padding-left: 1.5rem;\n}\n\n.boff-prose ul {\n list-style-type: disc;\n}\n\n.boff-prose ol {\n list-style-type: decimal;\n}\n\n.boff-prose li {\n margin-bottom: 0.25rem;\n line-height: 1.75;\n color: hsl(var(--foreground));\n}\n\n.boff-prose li > ul,\n.boff-prose li > ol {\n margin-top: 0.25rem;\n margin-bottom: 0.25rem;\n}\n\n.boff-prose a {\n color: hsl(var(--primary));\n text-decoration: underline;\n text-underline-offset: 2px;\n}\n\n.boff-prose a:hover {\n opacity: 0.8;\n}\n\n.boff-prose hr {\n border: none;\n height: 1px;\n background-color: hsl(var(--border));\n margin: 2rem 0;\n}\n\n.boff-prose blockquote {\n border-left: 4px solid hsl(var(--border));\n padding-left: 1rem;\n margin: 1.5rem 0;\n font-style: italic;\n color: hsl(var(--muted-foreground));\n}\n\n.boff-prose strong {\n font-weight: 700;\n color: hsl(var(--foreground));\n}\n\n.boff-prose code {\n background-color: hsl(var(--muted));\n padding: 0.125rem 0.25rem;\n border-radius: 0.25rem;\n font-size: 0.875em;\n font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace;\n}\n\n.boff-prose pre {\n background-color: hsl(var(--muted));\n padding: 1rem;\n border-radius: 0.5rem;\n overflow-x: auto;\n margin-bottom: 1rem;\n}\n\n.boff-prose pre code {\n background-color: transparent;\n padding: 0;\n}\n\n.boff-prose img {\n max-width: 100%;\n height: auto;\n}\n\n.boff-prose table {\n width: 100%;\n border-collapse: collapse;\n margin-bottom: 1rem;\n}\n\n.boff-prose th,\n.boff-prose td {\n border: 1px solid hsl(var(--border));\n padding: 0.5rem;\n text-align: left;\n}\n\n.boff-prose th {\n font-weight: 600;\n background-color: hsl(var(--muted));\n}\n\n/* Smaller variant used inside cards and compact panels */\n.boff-prose-sm {\n font-size: 0.875rem;\n}\n\n.boff-prose-sm h1 {\n font-size: 1.75rem;\n}\n\n.boff-prose-sm h2 {\n font-size: 1.5rem;\n}\n\n.boff-prose-sm h3 {\n font-size: 1.25rem;\n}\n\n.boff-prose-sm h4 {\n font-size: 1.125rem;\n}\n\n.boff-prose-sm p,\n.boff-prose-sm li {\n line-height: 1.625;\n}\n`;\n\nexport function ProseStyles() {\n return <style dangerouslySetInnerHTML={{ __html: PROSE_CSS }} />;\n}\n","const LOOPBACK_HOSTS = new Set([\"localhost\", \"127.0.0.1\", \"::1\"]);\nconst RESERVED_HEADERS = new Set([\n \"authorization\",\n \"cookie\",\n \"x-actor-id\",\n \"x-actor-type\",\n \"x-consent-granted-by\",\n \"x-consent-scope\",\n \"x-consent-granted-at\",\n \"x-consent-expires-at\",\n]);\n\nexport function validateGatewayUrl(value: string): string {\n let url: URL;\n\n try {\n url = new URL(value);\n } catch {\n throw new Error(\"Gateway URL must be a valid absolute URL\");\n }\n\n if (url.protocol === \"https:\") {\n return url.toString();\n }\n\n if (\n url.protocol === \"http:\" &&\n LOOPBACK_HOSTS.has(url.hostname.toLowerCase())\n ) {\n return url.toString();\n }\n\n throw new Error(\"Gateway URL must use HTTPS unless it targets localhost\");\n}\n\nexport function sanitizeHeaders(\n headers?: Record<string, string>,\n): Record<string, string> | undefined {\n if (!headers) return undefined;\n\n return Object.fromEntries(\n Object.entries(headers).filter(\n ([key]) => !RESERVED_HEADERS.has(key.toLowerCase()),\n ),\n );\n}\n\n/**\n * Hostnames whose Cloudflare Access application gates the GraphQL gateway.\n *\n * Only the alpha gateways are gated; the production gateways are public, so a token is never\n * attached there even if one is configured.\n */\nconst CF_ACCESS_GATED_HOSTS = new Set([\n \"alphagraphql.burdenoff.com\",\n \"alphagraphqlworkspaces.burdenoff.com\",\n]);\n\n/**\n * Service-token headers for a gated gateway, or nothing.\n *\n * Returns an empty object unless the target really is a gated host AND both halves of the token\n * are present — a half-configured token would send a malformed credential to every request.\n */\nexport function cfAccessHeaders(\n gatewayUrl: string,\n cfAccess?: { clientId?: string; clientSecret?: string },\n): Record<string, string> {\n const clientId = cfAccess?.clientId?.trim();\n const clientSecret = cfAccess?.clientSecret?.trim();\n if (!clientId || !clientSecret) return {};\n\n let host: string;\n try {\n host = new URL(gatewayUrl).hostname.toLowerCase();\n } catch {\n return {};\n }\n if (!CF_ACCESS_GATED_HOSTS.has(host)) return {};\n\n return {\n \"CF-Access-Client-Id\": clientId,\n \"CF-Access-Client-Secret\": clientSecret,\n };\n}\n","/**\n * Lightweight GraphQL client for the Burdenoff Web SDK.\n * Uses native fetch - zero external dependencies.\n * All calls are unauthenticated (public gateway operations only).\n */\n\nimport {\n cfAccessHeaders,\n sanitizeHeaders,\n validateGatewayUrl,\n} from \"./security\";\n\nexport interface WebSDKClientConfig {\n /** Global public gateway URL (e.g. \"https://api.burdenoff.com/global/graphql\") */\n gatewayUrl: string;\n /** Platform product ID for scoping operations */\n productId: string;\n /** Product slug (used for public product queries) */\n productSlug?: string;\n /** reCAPTCHA site key (if not fetched from product config) */\n recaptchaSiteKey?: string;\n /** Rybbit analytics site ID */\n rybbitSiteId?: string;\n /** Custom headers to include in all requests */\n headers?: Record<string, string>;\n /**\n * Cloudflare Access service token, for the ALPHA gateway hosts only.\n *\n * `alphagraphql.burdenoff.com` sits behind a Cloudflare Access application, so an\n * unauthenticated browser XHR is answered with a 302 to the Access login on a different\n * origin — which the browser reports as an opaque CORS failure rather than a 401. Attaching\n * the service-token headers is how every app shell already passes that gate (fe-libs\n * `installGatewayFetchRewrite`); the website SDK previously had no equivalent, so contact,\n * newsletter, waitlist and explore all failed on alpha.\n *\n * Vite only inlines `VITE_*` into APP source, never into a bundled library, so the host app\n * must read `import.meta.env` and pass the values in. Production gateways are not gated and\n * receive no headers.\n */\n cfAccess?: { clientId?: string; clientSecret?: string };\n /**\n * Per-request timeout in ms. Kept below the gateway's operation timeout so a\n * stalled request surfaces as an error the UI can render, instead of leaving\n * a page stuck on loading skeletons forever. Default 12000.\n */\n timeoutMs?: number;\n /**\n * Extra attempts for transient failures (timeout / network / 5xx / 429) on\n * QUERIES ONLY. Mutations are never retried — a retried contact-form or\n * waitlist submit would double-submit. Default 1 (2 attempts total).\n */\n maxRetries?: number;\n}\n\n/**\n * Per-call overrides for {@link WebSDKClient.query}.\n *\n * The defaults (5-minute response cache + in-flight deduplication) are right\n * for the read-once content queries most SDK components make, and wrong for a\n * poll loop: the second poll of the same `(query, variables)` pair would be\n * served straight from the cache and the UI would freeze on the first\n * response forever. Pass `{ cache: false }` for anything polled.\n */\nexport interface WebSDKQueryOptions {\n /**\n * Use the response cache and in-flight deduplication. Default `true`.\n * `false` skips the cache read, the dedupe map AND the cache write, so the\n * call always hits the network and never poisons a later cached read.\n */\n cache?: boolean;\n /** Override the client-wide request timeout for this call only. */\n timeoutMs?: number;\n}\n\n/** Per-call overrides for {@link WebSDKClient.mutate}. */\nexport interface WebSDKMutateOptions {\n /** Override the client-wide request timeout for this call only. */\n timeoutMs?: number;\n}\n\nexport interface GraphQLResponse<T = Record<string, unknown>> {\n data?: T;\n errors?: Array<{\n message: string;\n locations?: Array<{ line: number; column: number }>;\n path?: Array<string | number>;\n extensions?: Record<string, unknown>;\n }>;\n}\n\nexport class WebSDKClient {\n private config: WebSDKClientConfig;\n private queryCache = new Map<\n string,\n { data: GraphQLResponse<unknown>; ts: number }\n >();\n private inflight = new Map<string, Promise<GraphQLResponse<unknown>>>();\n private static CACHE_TTL = 5 * 60 * 1000; // 5 minutes\n private static MAX_CACHE_ENTRIES = 100;\n private static DEFAULT_TIMEOUT_MS = 12_000;\n private static DEFAULT_MAX_RETRIES = 1;\n private static RETRY_BASE_DELAY_MS = 400;\n\n constructor(config: WebSDKClientConfig) {\n this.config = {\n ...config,\n gatewayUrl: validateGatewayUrl(config.gatewayUrl),\n headers: sanitizeHeaders(config.headers),\n };\n }\n\n getConfig(): WebSDKClientConfig {\n return this.config;\n }\n\n /**\n * Execute a GraphQL query (with deduplication and caching).\n *\n * Pass `{ cache: false }` to bypass the cache entirely — required for poll\n * loops, where every tick must reach the network.\n */\n async query<T = Record<string, unknown>>(\n query: string,\n variables?: Record<string, unknown>,\n options?: WebSDKQueryOptions,\n ): Promise<GraphQLResponse<T>> {\n // Uncached path: no cache read, no in-flight dedupe, no cache write.\n // Deliberately bypasses the dedupe map too — two identical polls issued a\n // few hundred ms apart must both hit the network, otherwise the second one\n // resolves with the first one's (already stale) snapshot.\n if (options?.cache === false) {\n return this.request<T>(query, variables, true, options.timeoutMs);\n }\n\n const cacheKey = JSON.stringify({ query, variables });\n\n // Return cached response if still valid, evict if expired\n const cached = this.queryCache.get(cacheKey);\n if (cached) {\n if (Date.now() - cached.ts < WebSDKClient.CACHE_TTL) {\n return cached.data as GraphQLResponse<T>;\n }\n this.queryCache.delete(cacheKey);\n }\n\n // Deduplicate: if same query is already in-flight, reuse the promise\n const existing = this.inflight.get(cacheKey);\n if (existing) {\n return existing as Promise<GraphQLResponse<T>>;\n }\n\n const promise = this.request<T>(query, variables, true, options?.timeoutMs)\n .then((result) => {\n // Cache successful responses only\n if (result.data && !result.errors?.length) {\n if (this.queryCache.size >= WebSDKClient.MAX_CACHE_ENTRIES) {\n const oldestEntry = this.queryCache.keys().next().value;\n if (oldestEntry) {\n this.queryCache.delete(oldestEntry);\n }\n }\n this.queryCache.set(cacheKey, { data: result, ts: Date.now() });\n }\n return result;\n })\n .finally(() => {\n this.inflight.delete(cacheKey);\n });\n\n this.inflight.set(cacheKey, promise);\n return promise;\n }\n\n /**\n * Execute a GraphQL mutation\n */\n async mutate<T = Record<string, unknown>>(\n mutation: string,\n variables?: Record<string, unknown>,\n options?: WebSDKMutateOptions,\n ): Promise<GraphQLResponse<T>> {\n // retry=false: a retried mutation could double-submit (contact form,\n // waitlist signup, order). Only the timeout applies here.\n return this.request<T>(mutation, variables, false, options?.timeoutMs);\n }\n\n /** HTTP statuses worth another attempt — transient server/edge conditions. */\n private static isRetriableStatus(status: number): boolean {\n return status === 429 || status === 408 || (status >= 500 && status < 600);\n }\n\n private static sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n\n /**\n * Perform the HTTP call with a hard timeout. Every outcome resolves to a\n * GraphQLResponse — callers never hang, so a UI's `loading` state always\n * settles into data or a renderable error.\n */\n private async attempt<T>(\n query: string,\n variables: Record<string, unknown> | undefined,\n timeoutMs: number,\n ): Promise<{ res: GraphQLResponse<T>; retriable: boolean }> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n try {\n const response = await fetch(this.config.gatewayUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"x-product-id\": this.config.productId,\n ...this.config.headers,\n ...cfAccessHeaders(this.config.gatewayUrl, this.config.cfAccess),\n },\n body: JSON.stringify({ query, variables }),\n signal: controller.signal,\n });\n\n if (!response.ok) {\n console.error(\n \"[WebSDK] GraphQL request failed\",\n response.status,\n response.statusText,\n );\n return {\n res: {\n errors: [\n {\n message: `HTTP ${response.status}: ${response.statusText}`,\n extensions: { code: `HTTP_${response.status}` },\n },\n ],\n },\n retriable: WebSDKClient.isRetriableStatus(response.status),\n };\n }\n\n return {\n res: (await response.json()) as GraphQLResponse<T>,\n retriable: false,\n };\n } catch (error) {\n const aborted =\n error instanceof Error &&\n (error.name === \"AbortError\" || controller.signal.aborted);\n const message = aborted\n ? `Request timed out after ${timeoutMs}ms`\n : error instanceof Error\n ? error.message\n : \"Network error\";\n console.error(\"[WebSDK] Network error\", message);\n return {\n res: {\n errors: [\n {\n message,\n extensions: { code: aborted ? \"TIMEOUT\" : \"NETWORK_ERROR\" },\n },\n ],\n },\n // Transport-level failures are worth one more try; a genuine outage\n // just fails twice quickly and still renders an error state.\n retriable: true,\n };\n } finally {\n clearTimeout(timer);\n }\n }\n\n private async request<T>(\n query: string,\n variables?: Record<string, unknown>,\n retry = true,\n timeoutOverrideMs?: number,\n ): Promise<GraphQLResponse<T>> {\n const timeoutMs =\n timeoutOverrideMs ??\n this.config.timeoutMs ??\n WebSDKClient.DEFAULT_TIMEOUT_MS;\n const maxRetries = retry\n ? (this.config.maxRetries ?? WebSDKClient.DEFAULT_MAX_RETRIES)\n : 0;\n\n let last: GraphQLResponse<T> | undefined;\n for (let i = 0; i <= maxRetries; i++) {\n const { res, retriable } = await this.attempt<T>(\n query,\n variables,\n timeoutMs,\n );\n if (!retriable || i === maxRetries) return res;\n last = res;\n // Small backoff with jitter so a burst of clients doesn't retry in lockstep.\n await WebSDKClient.sleep(\n WebSDKClient.RETRY_BASE_DELAY_MS * (i + 1) + Math.random() * 200,\n );\n }\n return last as GraphQLResponse<T>;\n }\n}\n","/**\n * React context provider for the Web SDK client.\n * Wraps the application with WebSDKClient configuration.\n */\n\"use client\";\n\nimport { createContext, useContext, useMemo } from \"react\";\nimport type { ReactNode } from \"react\";\n\nimport { resolveGatewayUrl } from \"./gateway-resolver\";\nimport { WebSDKClient, type WebSDKClientConfig } from \"./graphql-client\";\n\nconst WebSDKContext = createContext<WebSDKClient | null>(null);\n\nexport interface WebSDKProviderProps {\n /** SDK client configuration */\n config: WebSDKClientConfig;\n /** Child components */\n children: ReactNode;\n}\n\n/**\n * Provider component that makes the WebSDKClient available to all child components.\n *\n * @example\n * ```tsx\n * <WebSDKProvider config={{\n * gatewayUrl: \"https://api.burdenoff.com/global/graphql\",\n * productId: \"your-product-id\",\n * productSlug: \"your-product\",\n * }}>\n * <App />\n * </WebSDKProvider>\n * ```\n */\nexport function WebSDKProvider({ config, children }: WebSDKProviderProps) {\n const client = useMemo(() => {\n const resolvedConfig = {\n ...config,\n gatewayUrl: resolveGatewayUrl(config.gatewayUrl),\n };\n return new WebSDKClient(resolvedConfig);\n }, [config]);\n\n return (\n <WebSDKContext.Provider value={client}>{children}</WebSDKContext.Provider>\n );\n}\n\n/**\n * Hook to access the WebSDKClient instance.\n * Must be used within a WebSDKProvider.\n */\nexport function useWebSDK(): WebSDKClient {\n const client = useContext(WebSDKContext);\n if (!client) {\n throw new Error(\"useWebSDK must be used within a WebSDKProvider\");\n }\n return client;\n}\n\n/**\n * Hook to access the SDK configuration.\n * Useful for components that need config values like productId, recaptchaSiteKey, etc.\n */\nexport function useWebSDKConfig(): WebSDKClientConfig {\n const client = useWebSDK();\n return client.getConfig();\n}\n","import type { WebsiteSwitcherProduct } from \"../components/website-switcher\";\n\n/**\n * Canonical Burdenoff ecosystem product list used by WebsiteSwitcher.\n *\n * Sourced from `~/products/websites/burdenoff-website/src/data/products.ts`.\n * Keep this in sync when products are added, renamed, or moved.\n */\nexport const ECOSYSTEM_PRODUCTS: WebsiteSwitcherProduct[] = [\n {\n slug: \"workspaces\",\n name: \"Workspaces\",\n websiteUrl: \"https://burdenoff.com\",\n },\n {\n slug: \"vibecontrols\",\n name: \"VibeControls\",\n websiteUrl: \"https://vibecontrols.com\",\n },\n // FluidGrids ships on www.fluidgrids.ai — fluidgrids.com only redirects there. The explore\n // catalog and the site's own sitemap use this origin, and so must the fallback catalog\n // built from this list, or /explore rejects FluidGrids concept images until it loads.\n {\n slug: \"fluidgrids\",\n name: \"FluidGrids\",\n websiteUrl: \"https://www.fluidgrids.ai\",\n },\n // Botlit ships on botlit.ai — botlit.com does not resolve.\n { slug: \"botlit\", name: \"Botlit\", websiteUrl: \"https://www.botlit.ai\" },\n {\n slug: \"bigconsole\",\n name: \"BigConsole\",\n websiteUrl: \"https://bigconsole.com\",\n },\n {\n slug: \"semanticfed\",\n name: \"SemanticFed\",\n websiteUrl: \"https://semanticfed.com\",\n },\n {\n slug: \"intelwatchtower\",\n name: \"IntelWatchtower\",\n websiteUrl: \"https://intelwatchtower.com\",\n },\n { slug: \"buildmyiq\", name: \"BuildMyIQ\", websiteUrl: \"https://buildmyiq.com\" },\n {\n slug: \"assethandler\",\n name: \"AssetHandler\",\n websiteUrl: \"https://assethandler.com\",\n },\n {\n slug: \"crewfoundry\",\n name: \"CrewFoundry\",\n websiteUrl: \"https://crewfoundry.com\",\n },\n {\n slug: \"planmagnet\",\n name: \"PlanMagnet\",\n websiteUrl: \"https://planmagnet.com\",\n },\n {\n slug: \"eventfullymanaged\",\n name: \"EventfullyManaged\",\n websiteUrl: \"https://eventfullymanaged.com\",\n },\n {\n slug: \"headshotmarketing\",\n name: \"HeadshotMarketing\",\n websiteUrl: \"https://headshotmarketing.com\",\n },\n {\n slug: \"technospam\",\n name: \"TechnoSpam\",\n websiteUrl: \"https://technospam.com\",\n },\n { slug: \"kadaikodi\", name: \"Kadaikodi\", websiteUrl: \"https://kadaikodi.com\" },\n {\n slug: \"movethewheels\",\n name: \"MoveTheWheels\",\n websiteUrl: \"https://movethewheels.com\",\n },\n {\n slug: \"healthybowl\",\n name: \"Healthy Bowl\",\n websiteUrl: \"https://gethealthybowl.com\",\n },\n { slug: \"ggnomad\", name: \"GGNomad\", websiteUrl: \"https://ggnomad.com\" },\n {\n slug: \"timecampus\",\n name: \"TimeCampus\",\n websiteUrl: \"https://timecampus.com\",\n },\n {\n slug: \"manufacturedops\",\n name: \"ManufacturedOps\",\n websiteUrl: \"https://manufacturedops.com\",\n },\n {\n slug: \"theglobalfuel\",\n name: \"TheGlobalFuel\",\n websiteUrl: \"https://theglobalfuel.com\",\n },\n {\n slug: \"housingvista\",\n name: \"HousingVista\",\n websiteUrl: \"https://housingvista.com\",\n },\n {\n slug: \"proserviceworld\",\n name: \"ProServiceWorld\",\n websiteUrl: \"https://proserviceworld.com\",\n },\n {\n slug: \"mybodyshield\",\n name: \"MyBodyShield\",\n websiteUrl: \"https://mybodyshield.com\",\n },\n {\n slug: \"artistrybase\",\n name: \"ArtistryBase\",\n websiteUrl: \"https://artistrybase.com\",\n },\n {\n slug: \"theculturepost\",\n name: \"TheCulturePost\",\n websiteUrl: \"https://theculturepost.com\",\n },\n { slug: \"collabkin\", name: \"CollabKin\", websiteUrl: \"https://collabkin.com\" },\n {\n slug: \"comradecircle\",\n name: \"ComradeCircle\",\n websiteUrl: \"https://comradecircle.com\",\n },\n {\n slug: \"brainyrich\",\n name: \"BrainyRich\",\n websiteUrl: \"https://brainyrich.com\",\n },\n {\n slug: \"cosmicintersection\",\n name: \"CosmicIntersection\",\n websiteUrl: \"https://cosmicintersection.com\",\n },\n {\n slug: \"govcitizenhub\",\n name: \"GovCitizenHub\",\n websiteUrl: \"https://govcitizenhub.com\",\n },\n {\n slug: \"adaptercloud\",\n name: \"AdapterCloud\",\n websiteUrl: \"https://adaptercloud.com\",\n },\n {\n slug: \"subscriberbot\",\n name: \"Subscriber Bot\",\n websiteUrl: \"https://subscriberbot.com\",\n },\n {\n slug: \"hookmovies\",\n name: \"HookMovies\",\n websiteUrl: \"https://hookmovies.com\",\n },\n {\n slug: \"coolandlovely\",\n name: \"CoolAndLovely\",\n websiteUrl: \"https://coolandlovely.com\",\n },\n {\n slug: \"atheletebridge\",\n name: \"AthleteBridge\",\n websiteUrl: \"https://atheletebridge.com\",\n },\n {\n slug: \"labsofscience\",\n name: \"LabsOfScience\",\n websiteUrl: \"https://labsofscience.com\",\n },\n {\n slug: \"ecoimpacthub\",\n name: \"EcoImpactHub\",\n websiteUrl: \"https://ecoimpacthub.com\",\n },\n];\n","/**\n * reCAPTCHA v3 (invisible, score-based) loader and token minter.\n *\n * Deliberately dependency-free: the SDK already ships the `react-google-recaptcha`\n * peer for the **v2 checkbox** used by `ContactPage`, and the two widgets cannot\n * share a script tag — v3 needs `?render=<siteKey>` on the URL, v2 must not have\n * it. This module injects its own v3 script and leaves the v2 integration alone.\n *\n * The Explore chat turns v3 on purely from the backend catalog\n * (`exploreCatalog.captchaRequired && recaptchaSiteKey`), so nothing is loaded\n * and no third-party request is made on sites where captcha is off.\n */\n\n/** The slice of the `grecaptcha` global this module uses. */\nexport interface RecaptchaV3 {\n /** Runs the callback once the API is fully initialised. */\n ready(callback: () => void): void;\n /** Mints a single-use token for `action`. */\n execute(siteKey: string, options: { action: string }): Promise<string>;\n}\n\ndeclare global {\n interface Window {\n grecaptcha?: RecaptchaV3;\n }\n}\n\nconst SCRIPT_ID = \"boff-recaptcha-v3\";\nconst SCRIPT_SRC = \"https://www.google.com/recaptcha/api.js?render=\";\n\n/** Default action name reported to reCAPTCHA for Explore chat submissions. */\nexport const EXPLORE_RECAPTCHA_ACTION = \"explore_chat\";\n\n/**\n * One in-flight/settled promise per site key. Guarantees the script tag is\n * injected at most once even when several components mount at the same time,\n * and lets later callers await the same load instead of racing it.\n */\nconst loaders = new Map<string, Promise<RecaptchaV3>>();\n\nfunction isBrowser(): boolean {\n return typeof window !== \"undefined\" && typeof document !== \"undefined\";\n}\n\n/**\n * Load the reCAPTCHA v3 script for `siteKey` and resolve once `grecaptcha` is\n * ready to mint tokens.\n *\n * - Injects the script at most once per site key (subsequent calls reuse the\n * same promise).\n * - Adopts an already-present script tag (e.g. injected by the host site)\n * rather than adding a second one.\n * - Rejects rather than hanging when the script fails to load, so the caller\n * can decide whether to submit without a token or surface an error.\n */\nexport function loadRecaptchaV3(siteKey: string): Promise<RecaptchaV3> {\n if (!siteKey) {\n return Promise.reject(new Error(\"reCAPTCHA site key is required\"));\n }\n if (!isBrowser()) {\n return Promise.reject(\n new Error(\"reCAPTCHA v3 can only be loaded in a browser\"),\n );\n }\n\n const existing = loaders.get(siteKey);\n if (existing) return existing;\n\n const promise = new Promise<RecaptchaV3>((resolve, reject) => {\n const ready = () => {\n const api = window.grecaptcha;\n if (!api) {\n reject(new Error(\"reCAPTCHA loaded but grecaptcha is unavailable\"));\n return;\n }\n // `ready` queues until the API has finished initialising internally;\n // calling `execute` before that throws.\n api.ready(() => resolve(api));\n };\n\n // Already loaded by this module, another SDK instance, or the host site.\n if (window.grecaptcha) {\n ready();\n return;\n }\n\n const scriptId = `${SCRIPT_ID}-${siteKey}`;\n const found = document.getElementById(scriptId);\n if (found) {\n found.addEventListener(\"load\", ready, { once: true });\n found.addEventListener(\n \"error\",\n () => reject(new Error(\"Failed to load reCAPTCHA v3\")),\n { once: true },\n );\n return;\n }\n\n const script = document.createElement(\"script\");\n script.id = scriptId;\n script.src = `${SCRIPT_SRC}${encodeURIComponent(siteKey)}`;\n script.async = true;\n script.defer = true;\n script.addEventListener(\"load\", ready, { once: true });\n script.addEventListener(\n \"error\",\n () => {\n // Drop the memo so a later attempt can retry a transient CDN failure\n // instead of being stuck with a permanently rejected promise.\n loaders.delete(siteKey);\n reject(new Error(\"Failed to load reCAPTCHA v3\"));\n },\n { once: true },\n );\n document.head.appendChild(script);\n });\n\n loaders.set(siteKey, promise);\n return promise;\n}\n\n/**\n * Mint a single-use reCAPTCHA v3 token, loading the script on first use.\n *\n * Tokens are valid for ~2 minutes and are consumed by one verification, so\n * this must be called per submission — never cached.\n */\nexport async function getRecaptchaV3Token(\n siteKey: string,\n action: string = EXPLORE_RECAPTCHA_ACTION,\n): Promise<string> {\n const api = await loadRecaptchaV3(siteKey);\n return api.execute(siteKey, { action });\n}\n","/**\n * useExploreChat — the `/explore` conversation state machine.\n *\n * Implements the client half of CONTRACT.md §1: a **submit + poll** exchange.\n * `sendExploreMessage` returns immediately with a PENDING assistant message;\n * the answer arrives by polling `exploreMessage(conversationToken, id)` roughly\n * every 1.5s until it reports COMPLETED or FAILED. Both gateway hops cap a\n * subgraph call at 20s while a turn takes 5-60s, which is why there is no\n * request that simply waits for the answer.\n *\n * Design rules this hook exists to enforce:\n *\n * 1. **The catalog never gates the first paint.** `catalog` is populated with a\n * static fallback synchronously, so `ExplorePage` can render its `<h1>` on\n * the very first render. The websites' prerender waits for an `h1`; if that\n * heading depended on a network round-trip, 38 static builds would capture a\n * blank page.\n * 2. **Polls bypass the query cache.** `client.query(..., { cache: false })` —\n * the default 5-minute cache would hand every later poll the first PENDING\n * snapshot and the answer would never appear.\n * 3. **Nothing outlives the component.** Unmount and `stop()` both cancel the\n * poll chain through a generation counter, so a late response can never\n * write into an unmounted tree.\n */\n\"use client\";\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\n\nimport { useWebSDK, useWebSDKConfig } from \"../client/provider\";\nimport {\n EXPLORE_CATALOG_QUERY,\n EXPLORE_CATALOG_QUERY_WITHOUT_HIGHLIGHTS,\n EXPLORE_MESSAGE_QUERY,\n EXPLORE_SHARED_CONVERSATION_QUERY,\n CREATE_EXPLORE_SHARE_LINK_MUTATION,\n ESCALATE_EXPLORE_CONVERSATION_MUTATION,\n RECORD_EXPLORE_CLICK_MUTATION,\n SEND_EXPLORE_MESSAGE_MUTATION,\n SUBMIT_EXPLORE_FEEDBACK_MUTATION,\n} from \"../components/explore-types\";\nimport { ECOSYSTEM_PRODUCTS } from \"../data/products\";\nimport { getRecaptchaV3Token } from \"../utils/recaptcha-v3\";\n\nimport type { GraphQLResponse } from \"../client/graphql-client\";\nimport type {\n EscalateExploreConversationInput,\n EscalateExploreConversationMutationData,\n ExploreCatalog,\n ExploreCatalogQueryData,\n ExploreFeedbackRating,\n ExploreFeedbackReason,\n ExploreLimits,\n ExploreMessage,\n ExploreMessageQueryData,\n SendExploreMessageInput,\n SendExploreMessageMutationData,\n SubmitExploreFeedbackInput,\n SubmitExploreFeedbackMutationData,\n} from \"../components/explore-types\";\nimport type { ExploreAttachmentPayload } from \"../utils/explore-attachments\";\n\n// ============================================================================\n// Public types\n// ============================================================================\n\n/**\n * Where the conversation is right now.\n *\n * - `loading` — catalog request in flight (the fallback catalog is already\n * rendered, so this is a refinement, not a blank screen).\n * - `ready` — idle; the composer accepts input.\n * - `sending` — `sendExploreMessage` in flight.\n * - `streaming` — polling the assistant turn; `activity` is live.\n * - `error` — the last turn failed; `retry()` is meaningful and the\n * composer stays usable.\n * - `limited` — rate limited; the composer is disabled.\n * - `disabled` — `exploreCatalog.enabled === false`.\n */\nexport type ExploreChatPhase =\n | \"loading\"\n | \"ready\"\n | \"sending\"\n | \"streaming\"\n | \"error\"\n | \"limited\"\n | \"disabled\";\n\n/** Coarse bucket the UI switches its banner copy and affordances on. */\nexport type ExploreChatErrorKind =\n | \"rate-limit\"\n | \"captcha\"\n | \"timeout\"\n // The question was answerable, but not across this many products at once. Distinct from\n // \"timeout\" because the remedy is different: narrow the question, do not retry it.\n | \"scope\"\n | \"network\"\n | \"disabled\"\n | \"validation\"\n | \"unknown\";\n\nexport interface ExploreChatError {\n /** UI bucket. */\n kind: ExploreChatErrorKind;\n /** Raw `extensions.code` (or a client-side code such as `TIMEOUT`). */\n code: string;\n /** Human-readable, safe to render. */\n message: string;\n /** Whether re-sending the same message could plausibly succeed. */\n retryable: boolean;\n}\n\n/**\n * What came of handing the conversation to a person.\n *\n * `sent` and `already-handed-over` are BOTH successes. The second is the double-clicked\n * button, the retried request and the reloaded page: the server keeps one handover per\n * conversation, so a repeat submit returns the first one rather than filing a second ticket.\n * A visitor who is worried enough to ask for a human must never be told \"you already did\n * that\" — the conversation is with a person either way, and the UI says so either way.\n */\nexport type ExploreEscalateOutcome =\n | \"sent\"\n | \"already-handed-over\"\n /** The SERVER rejected the address (`INVALID_EMAIL`), after the client let it through. */\n | \"invalid-email\"\n | \"rate-limited\"\n | \"captcha\"\n /** No conversation token — nothing to hand over. The form should not have been offered. */\n | \"no-conversation\"\n | \"failed\";\n\nexport interface ExploreEscalateResult {\n outcome: ExploreEscalateOutcome;\n /**\n * The address the SERVER says the reply is going to, on `sent` and `already-handed-over`;\n * null otherwise.\n *\n * On `already-handed-over` this is the address the FIRST handover used, which may not be\n * the one just typed — and it is the one the reply actually reaches, so it is the one to\n * show back.\n */\n email: string | null;\n /** When the handover was filed, as the server holds it. Null unless it exists. */\n createdAt: string | null;\n}\n\nexport interface UseExploreChatOptions {\n /** Slug of the product site this page is on — a soft hint to the harness. */\n productSlug?: string;\n /** Full URL of the page, forwarded as `pageUrl`. */\n pageUrl?: string;\n /** BCP-47 locale, forwarded as `locale`. */\n locale?: string;\n /** Poll cadence in ms. Default 1500 (CONTRACT.md §1). */\n pollIntervalMs?: number;\n /** Give up on a turn after this long. Default 90000 (the edge poll timeout). */\n pollTimeoutMs?: number;\n /**\n * Prompts to offer when `exploreCatalog` supplies none. Resolution order is\n * catalog → this option → {@link DEFAULT_EXPLORE_EXAMPLE_PROMPTS}, so a site\n * can ship product-specific prompts without waiting on the backend and still\n * be overridden centrally once the catalog carries them.\n */\n examplePrompts?: string[];\n /**\n * Welcome copy for the fallback catalog, used only when `exploreCatalog` cannot be reached.\n *\n * The hook's own built-in fallback is English. `ExplorePage` passes the strings for the\n * visitor's locale, so a catalog outage degrades to a translated page rather than an\n * English one — the whole point of shipping six locales is that the failure paths speak\n * them too.\n */\n fallbackWelcome?: { title: string; body: string };\n /** localStorage key for the ACTIVE conversation. Default `boff.explore.v1`. */\n storageKey?: string;\n /** Persist the conversation across reloads within the tab. Default true. */\n persist?: boolean;\n /** Called with the message text each time a send is accepted locally. */\n onSend?: (message: string) => void;\n}\n\nexport interface UseExploreChatResult {\n phase: ExploreChatPhase;\n /** Never null — starts as the static fallback, upgraded by the server. */\n catalog: ExploreCatalog;\n messages: ExploreMessage[];\n /** Latest progress line of the in-flight turn, or null when idle. */\n activity: string | null;\n /** Messages left today for this visitor, when the server reports it. */\n remainingToday: number | null;\n error: ExploreChatError | null;\n /** Product the visitor pinned the conversation to, or null for \"all\". */\n focusProduct: string | null;\n setFocusProduct: (slug: string | null) => void;\n send: (\n message: string,\n attachments?: readonly ExploreAttachmentPayload[],\n ) => Promise<void>;\n /** Stop polling and keep whatever text has streamed so far. */\n stop: () => void;\n /** Re-send the last message after a failed turn. */\n retry: () => void;\n /** Clear the conversation and the persisted session. */\n reset: () => void;\n /** Past conversations held in THIS browser, newest first. */\n history: ArchivedExploreConversation[];\n /** Reopen a past conversation and continue it. */\n openConversation: (token: string) => void;\n /** Forget one past conversation (local only). */\n deleteConversation: (token: string) => void;\n /** Forget every past conversation held in this browser. */\n clearHistory: () => void;\n /**\n * Record that the visitor followed a link this answer offered. Fire-and-forget — never\n * awaited, never throws, and must never delay the navigation it is reporting on.\n */\n recordClick: (\n messageId: string,\n kind: \"CTA\" | \"REFERENCE\",\n url: string,\n ) => void;\n /**\n * Rate one answer. Resolves `true` only when the server reports `recorded: true`.\n *\n * The opposite posture to {@link recordClick}, and deliberately so: the visitor is still on\n * the page and is watching the control they pressed, so the result has to come back far\n * enough for the UI to tell the truth about it. It still never throws — a transport\n * failure, a GraphQL error and an unattributable message all resolve `false`.\n */\n submitFeedback: (\n messageId: string,\n rating: ExploreFeedbackRating,\n detail?: { reason?: ExploreFeedbackReason | null; comment?: string | null },\n ) => Promise<boolean>;\n /**\n * Hand this conversation to a person, so they pick it up with the transcript attached.\n *\n * Awaited, like {@link submitFeedback} and for the same reason — the visitor is watching\n * the control they pressed — but this one has more to say than true/false: \"we could not\n * deliver to that address\", \"you are sending these too fast\" and \"it is already with a\n * human\" are three different things to a worried visitor, and one boolean flattens them\n * into a shrug. It never throws; every outcome comes back in\n * {@link ExploreEscalateResult}.\n *\n * `email` is personal data. It goes into the mutation variables and nowhere else — not\n * into `messages` (which is what this hook persists), not into `onSend`, not into any\n * analytics call.\n */\n escalate: (email: string, note?: string) => Promise<ExploreEscalateResult>;\n /**\n * Whether there is a conversation a person could actually be handed.\n *\n * False on a fresh page and false in a read-only shared view (a `?c=` secret is not a\n * conversation token), which are exactly the cases where {@link escalate} could only\n * answer `no-conversation`. Offer the form on this, rather than offering one that cannot\n * work.\n */\n canEscalate: boolean;\n /**\n * Mint a read-only link to this conversation, or null when there is nothing to share yet.\n * The secret returned is not the conversation token and cannot continue the thread.\n */\n createShareLink: () => Promise<string | null>;\n /**\n * True when the transcript on screen came from a shared link rather than this visitor's own\n * conversation. A shared view is read-only: the share secret cannot continue the thread.\n */\n isSharedView: boolean;\n canSend: boolean;\n}\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst DEFAULT_STORAGE_KEY = \"boff.explore.v1\";\n/** Where past conversations live. Derived from the active key so a custom key stays paired. */\nconst HISTORY_SUFFIX = \".history\";\n/**\n * How many past conversations to keep, and how many messages of each. Bounded on purpose:\n * localStorage is a few MB per origin and shared with everything else the site stores, so an\n * unbounded archive would eventually start throwing QuotaExceededError on write.\n */\nconst MAX_ARCHIVED_CONVERSATIONS = 15;\nconst MAX_ARCHIVED_MESSAGES = 20;\nconst DEFAULT_POLL_INTERVAL_MS = 1_500;\n/** Matches `EXPLORE_AGENT_TIMEOUT_MS` (CONTRACT.md §3) — the edge gives up too. */\nconst DEFAULT_POLL_TIMEOUT_MS = 90_000;\n/** Per-poll HTTP timeout. Short: a stuck poll must not stall the chain. */\nconst POLL_REQUEST_TIMEOUT_MS = 10_000;\n/** The submit hop enqueues a job; generous but well under the gateway's 20s. */\nconst SEND_REQUEST_TIMEOUT_MS = 18_000;\n/** Transient poll failures tolerated before the turn is declared dead. */\nconst MAX_CONSECUTIVE_POLL_FAILURES = 4;\n/** Cap on what goes into localStorage — a conversation must not grow unbounded. */\nconst MAX_PERSISTED_MESSAGES = 40;\n\n/** Fallback limits, mirroring the server defaults in CONTRACT.md §3. */\nexport const FALLBACK_EXPLORE_LIMITS: ExploreLimits = {\n maxMessageLength: 2000,\n maxTurnsPerConversation: 20,\n messagesPerDay: 100,\n historyTurns: 6,\n};\n\n/**\n * Prompts shown when neither the catalog nor the consumer supplies any.\n * Deliberately product-agnostic — this SDK renders on 38 different sites.\n *\n * Problem-first, and kept in step with `support.explore.examplePrompts.*` in\n * global-support-svc. These render precisely when the catalog call failed, so\n * if they disagree with the server the page silently reverts to whatever this\n * file last said — which is how the whole surface can go back to being a\n * brochure without a single copy change being reviewed.\n */\nexport const DEFAULT_EXPLORE_EXAMPLE_PROMPTS: string[] = [\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 \"Which of your products fits a problem like mine?\",\n];\n\nconst FALLBACK_WELCOME_TITLE = \"What problem are you trying to solve?\";\nconst FALLBACK_WELCOME_BODY =\n \"Describe the problem you're facing, in your own words. You can also ask about a specific product or compare a few. Every answer comes straight from our documentation.\";\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\nfunction buildFallbackCatalog(\n examplePrompts?: string[],\n welcome?: { title: string; body: string },\n): ExploreCatalog {\n return {\n enabled: true,\n products: ECOSYSTEM_PRODUCTS.map((p) => ({\n slug: p.slug,\n name: p.name,\n tagline: null,\n website: p.websiteUrl,\n })),\n examplePrompts: examplePrompts?.length\n ? examplePrompts\n : DEFAULT_EXPLORE_EXAMPLE_PROMPTS,\n welcomeTitle: welcome?.title ?? FALLBACK_WELCOME_TITLE,\n welcomeBody: welcome?.body ?? FALLBACK_WELCOME_BODY,\n limits: FALLBACK_EXPLORE_LIMITS,\n captchaRequired: false,\n recaptchaSiteKey: null,\n // Empty, and deliberately not synthesised from `ECOSYSTEM_PRODUCTS`: a concept highlight\n // needs a real published illustration URL, and this SDK has no registry of them. An\n // invented path would render 38 broken frames on the one screen every prerender captures.\n // The strip renders nothing at all when the list is empty, which is the honest fallback.\n conceptHighlights: [],\n };\n}\n\n/**\n * Harden a server catalog against partial/degraded responses so a missing\n * field can never blank the page or produce `maxMessageLength: 0` (which would\n * silently disable the composer).\n */\nfunction normalizeCatalog(\n raw: ExploreCatalog,\n fallback: ExploreCatalog,\n): ExploreCatalog {\n return {\n enabled: raw.enabled !== false,\n products: raw.products?.length ? raw.products : fallback.products,\n examplePrompts: raw.examplePrompts?.length\n ? raw.examplePrompts\n : fallback.examplePrompts,\n welcomeTitle: raw.welcomeTitle || fallback.welcomeTitle,\n welcomeBody: raw.welcomeBody || fallback.welcomeBody,\n limits: {\n maxMessageLength:\n raw.limits?.maxMessageLength || fallback.limits.maxMessageLength,\n maxTurnsPerConversation:\n raw.limits?.maxTurnsPerConversation ||\n fallback.limits.maxTurnsPerConversation,\n messagesPerDay:\n raw.limits?.messagesPerDay || fallback.limits.messagesPerDay,\n historyTurns: raw.limits?.historyTurns || fallback.limits.historyTurns,\n },\n captchaRequired: raw.captchaRequired === true,\n recaptchaSiteKey: raw.recaptchaSiteKey ?? null,\n // `[ExploreConceptHighlight!]!` on the wire, so a gateway that KNOWS the field always\n // sends an array. The one response that arrives without it is the retry against an older\n // supergraph (`EXPLORE_CATALOG_QUERY_WITHOUT_HIGHLIGHTS`) — that gateway does not answer\n // the full document at all, it refuses it. Either way\n // `catalog.conceptHighlights.filter(...)` on `undefined` would throw inside render,\n // blanking the welcome screen over a decorative strip.\n conceptHighlights: raw.conceptHighlights?.length\n ? raw.conceptHighlights\n : fallback.conceptHighlights,\n };\n}\n\n/**\n * Codes that mean \"this gateway would not accept the document\", as opposed to\n * \"the request failed\". `HTTP_400` is in the set because a gateway may surface\n * a validation failure as a status instead of a body — production answers 200\n * with `GRAPHQL_VALIDATION_FAILED`, but that is a server choice, not a promise,\n * and `WebSDKClient` collapses any non-2xx into `HTTP_<status>` with the\n * original message discarded.\n */\nconst CATALOG_DOCUMENT_REJECTED_CODES = new Set([\n \"GRAPHQL_VALIDATION_FAILED\",\n \"HTTP_400\",\n]);\n\n/**\n * True when the catalog came back with nothing usable AND the reason looks like\n * the gateway refusing the document rather than failing to serve it.\n *\n * GraphQL validation is all-or-nothing, so against a supergraph that predates\n * `conceptHighlights` there is no partial response to salvage: no `data`, and\n * the loss is the WHOLE catalog — the server-side `enabled` kill switch,\n * `captchaRequired`/`recaptchaSiteKey`, the reviewed welcome copy and `limits`.\n * One retry without the field recovers all of it.\n */\nexport function catalogRejectedTheHighlightField(\n res: GraphQLResponse<ExploreCatalogQueryData>,\n): boolean {\n if (res.data?.exploreCatalog) return false;\n return (res.errors ?? []).some((error) => {\n const code = error.extensions?.code;\n return (\n (typeof code === \"string\" && CATALOG_DOCUMENT_REJECTED_CODES.has(code)) ||\n error.message.includes(\"conceptHighlights\")\n );\n });\n}\n\nconst RATE_LIMIT_CODES = new Set([\n \"RATE_LIMITED\",\n \"HTTP_429\",\n \"EXPLORE_GLOBAL_LIMIT\",\n]);\nconst CAPTCHA_CODES = new Set([\"CAPTCHA_FAILED\", \"CAPTCHA_REQUIRED\"]);\nconst NETWORK_CODES = new Set([\n \"NETWORK_ERROR\",\n \"UPSTREAM_UNAVAILABLE\",\n \"CONVERSATION_BUSY\",\n \"PROVIDER_ERROR\",\n \"QUEUE_FULL\",\n]);\nconst VALIDATION_CODES = new Set([\n \"MESSAGE_TOO_LONG\",\n \"MESSAGE_EMPTY\",\n \"CONVERSATION_LIMIT\",\n \"INVALID_INPUT\",\n]);\n\n/**\n * Map a `extensions.code` (or a client-side transport code) onto the bucket the\n * UI renders. Unknown codes are treated as retryable — a transient backend\n * condition we have not enumerated is far more likely than a permanent one.\n */\n/**\n * Map an `extensions.code` from `escalateExploreConversation` onto the outcome the form\n * renders.\n *\n * Separate from {@link classifyExploreError} on purpose. That one buckets a failed ANSWER\n * and its buckets carry copy about retrying a question — none of which is true here, and\n * `INVALID_EMAIL` has no bucket there at all (it would land in `unknown` and be shown as\n * \"something went wrong\", which is the one message that leaves the visitor unable to fix\n * the one thing they could actually fix).\n *\n * `EXPLORE_GLOBAL_LIMIT` is deliberately NOT treated as rate limiting here: the contract\n * keeps a handover off the fleet-wide LLM budget, so seeing it would mean something\n * unexpected, not \"you are going too fast\".\n */\nexport function escalateOutcomeForCode(\n code: string | null | undefined,\n): ExploreEscalateOutcome {\n switch (code) {\n case \"INVALID_EMAIL\":\n return \"invalid-email\";\n case \"RATE_LIMITED\":\n case \"HTTP_429\":\n return \"rate-limited\";\n case \"CAPTCHA_REQUIRED\":\n case \"CAPTCHA_FAILED\":\n return \"captcha\";\n // The token owns nothing, or owns a different conversation. The server answers NOT_FOUND\n // rather than FORBIDDEN so the endpoint is not an oracle for whether a thread exists;\n // either way there is nothing this visitor can do about it, so it reads as a failure.\n case \"NOT_FOUND\":\n return \"failed\";\n default:\n return \"failed\";\n }\n}\n\nexport function classifyExploreError(\n code: string | null | undefined,\n serverMessage?: string | null,\n): ExploreChatError {\n const c = code ?? \"UNKNOWN\";\n if (RATE_LIMIT_CODES.has(c)) {\n return {\n kind: \"rate-limit\",\n code: c,\n message:\n \"You've reached the message limit for now. Please try again later.\",\n retryable: false,\n };\n }\n if (CAPTCHA_CODES.has(c)) {\n return {\n kind: \"captcha\",\n code: c,\n message:\n \"We couldn't verify that you're human. Please try sending that again.\",\n retryable: true,\n };\n }\n // TOOL_BUDGET is NOT a timeout and must not be described as one. Measured in production:\n // the failing turn ended in 33s against a 75s budget — it did not run out of time, it ran\n // out of searches. Retrying is also the wrong advice: the same question searches the same\n // way and fails identically, so \"try again\" is a button that cannot work. The honest reply\n // names the actual limit and offers the narrowing that does work.\n if (c === \"TOOL_BUDGET\") {\n return {\n kind: \"scope\",\n code: c,\n message:\n \"That question spans more of our products than I can look through in one go. Try asking about two or three specific products.\",\n retryable: false,\n };\n }\n if (c === \"TIMEOUT\") {\n return {\n kind: \"timeout\",\n code: c,\n message: \"That answer took too long to come back. Try asking again.\",\n retryable: true,\n };\n }\n if (NETWORK_CODES.has(c)) {\n return {\n kind: \"network\",\n code: c,\n message:\n \"We couldn't reach the assistant just now. Check your connection and try again.\",\n retryable: true,\n };\n }\n if (c === \"EXPLORE_DISABLED\") {\n return {\n kind: \"disabled\",\n code: c,\n message: \"Explore is unavailable at the moment. Please check back soon.\",\n retryable: false,\n };\n }\n if (VALIDATION_CODES.has(c)) {\n return {\n kind: \"validation\",\n code: c,\n message: serverMessage || \"That message couldn't be sent.\",\n retryable: false,\n };\n }\n if (c === \"EMPTY_ANSWER\") {\n return {\n kind: \"unknown\",\n code: c,\n message:\n \"No answer came back for that one. Try rephrasing, or ask something more specific.\",\n retryable: true,\n };\n }\n return {\n kind: \"unknown\",\n code: c,\n message: serverMessage || \"Something went wrong. Please try again.\",\n retryable: true,\n };\n}\n\ninterface PersistedExploreState {\n conversationToken: string | null;\n messages: ExploreMessage[];\n focusProduct: string | null;\n}\n\n/** One past conversation, as shown in the history list and restored on click. */\nexport interface ArchivedExploreConversation {\n token: string;\n /** First thing the visitor asked — the human-readable label for the thread. */\n title: string;\n /** ISO timestamp of the last message in the thread. */\n updatedAt: string;\n messageCount: number;\n focusProduct: string | null;\n messages: ExploreMessage[];\n}\n\nfunction historyKey(key: string): string {\n return `${key}${HISTORY_SUFFIX}`;\n}\n\nfunction readArchive(key: string): ArchivedExploreConversation[] {\n if (typeof window === \"undefined\") return [];\n try {\n const raw = window.localStorage.getItem(historyKey(key));\n if (!raw) return [];\n const parsed: unknown = JSON.parse(raw);\n if (!Array.isArray(parsed)) return [];\n return parsed.filter(\n (entry): entry is ArchivedExploreConversation =>\n typeof entry === \"object\" &&\n entry !== null &&\n typeof (entry as ArchivedExploreConversation).token === \"string\" &&\n Array.isArray((entry as ArchivedExploreConversation).messages),\n );\n } catch {\n return [];\n }\n}\n\nfunction writeArchive(\n key: string,\n entries: ArchivedExploreConversation[],\n): void {\n if (typeof window === \"undefined\") return;\n try {\n if (entries.length === 0) {\n window.localStorage.removeItem(historyKey(key));\n return;\n }\n window.localStorage.setItem(historyKey(key), JSON.stringify(entries));\n } catch {\n /* private mode or quota — the archive is a convenience, never load-bearing */\n }\n}\n\n/**\n * Fold the given thread into the archive, newest first.\n *\n * Upsert by token rather than append: the same conversation is archived after every completed\n * turn so an abruptly closed tab still leaves a record, and appending would fill the list with\n * duplicates of one thread.\n */\nfunction upsertArchive(\n key: string,\n thread: {\n token: string | null;\n messages: ExploreMessage[];\n focusProduct: string | null;\n },\n): ArchivedExploreConversation[] {\n if (!thread.token) return readArchive(key);\n const real = thread.messages.filter(\n (m) => m.content.trim() !== \"\" || m.role === \"USER\",\n );\n if (real.length === 0) return readArchive(key);\n\n const firstUser = real.find((m) => m.role === \"USER\");\n const entry: ArchivedExploreConversation = {\n token: thread.token,\n title: (firstUser?.content ?? \"Conversation\").trim().slice(0, 80),\n updatedAt: real[real.length - 1]?.createdAt ?? new Date().toISOString(),\n messageCount: real.length,\n focusProduct: thread.focusProduct,\n messages: real.slice(-MAX_ARCHIVED_MESSAGES),\n };\n\n const rest = readArchive(key).filter((e) => e.token !== entry.token);\n const next = [entry, ...rest].slice(0, MAX_ARCHIVED_CONVERSATIONS);\n writeArchive(key, next);\n return next;\n}\n\nfunction readPersisted(key: string): PersistedExploreState | null {\n // SSR / prerender: there is no localStorage, and reading one during the\n // first client render would desync hydration anyway.\n if (typeof window === \"undefined\") return null;\n try {\n const raw = window.localStorage.getItem(key);\n if (!raw) return null;\n const parsed: unknown = JSON.parse(raw);\n if (!parsed || typeof parsed !== \"object\") return null;\n const record = parsed as Partial<PersistedExploreState>;\n return {\n conversationToken:\n typeof record.conversationToken === \"string\"\n ? record.conversationToken\n : null,\n messages: Array.isArray(record.messages)\n ? record.messages.slice(-MAX_PERSISTED_MESSAGES)\n : [],\n focusProduct:\n typeof record.focusProduct === \"string\" ? record.focusProduct : null,\n };\n } catch {\n /* corrupt or unavailable storage — start a fresh conversation */\n return null;\n }\n}\n\n/**\n * A turn that never produced any text is worth dropping rather than rendering\n * as an empty bubble — used by `stop()` and by the failure paths.\n */\n/**\n * The `?c=` share secret, or null.\n *\n * Read from `window.location` rather than from a router: the explore page ships to 39\n * separate marketing sites, and only some of them mount it under a router whose search\n * params this hook could reach.\n */\nfunction readShareToken(): string | null {\n if (typeof window === \"undefined\") return null;\n try {\n return new URL(window.location.href).searchParams.get(\"c\");\n } catch {\n // A malformed href — fall through to the normal path rather than blanking the page.\n return null;\n }\n}\n\nfunction visibleText(message: ExploreMessage): string {\n return message.content || message.partialContent || \"\";\n}\n\nfunction countUserTurns(messages: ExploreMessage[]): number {\n return messages.filter((m) => m.role === \"USER\").length;\n}\n\n// ============================================================================\n// Hook\n// ============================================================================\n\nexport function useExploreChat(\n options: UseExploreChatOptions = {},\n): UseExploreChatResult {\n const {\n productSlug,\n pageUrl,\n locale,\n examplePrompts,\n fallbackWelcome,\n pollIntervalMs = DEFAULT_POLL_INTERVAL_MS,\n pollTimeoutMs = DEFAULT_POLL_TIMEOUT_MS,\n storageKey = DEFAULT_STORAGE_KEY,\n persist = true,\n onSend,\n } = options;\n\n const client = useWebSDK();\n // The site's `PlatformProduct` id, so a handover reaches THAT product's support inbox\n // rather than a generic one. Optional in the contract: a site that has not configured one\n // still gets its conversation to a person.\n const { productId } = useWebSDKConfig();\n\n // The fallback catalog is the initial value AND the merge base for the\n // server response. Keyed on the prompt CONTENT, not the array identity —\n // a consumer passing an inline `examplePrompts={[...]}` literal would\n // otherwise rebuild it every render and re-fire the catalog effect.\n const promptKey = JSON.stringify(examplePrompts ?? []);\n // Same reasoning for the welcome copy: keyed on content so an inline object literal from the\n // caller does not rebuild the catalog every render.\n const welcomeKey = JSON.stringify(fallbackWelcome ?? null);\n const fallbackCatalog = useMemo(\n () =>\n buildFallbackCatalog(\n JSON.parse(promptKey) as string[],\n (JSON.parse(welcomeKey) as { title: string; body: string } | null) ??\n undefined,\n ),\n [promptKey, welcomeKey],\n );\n\n const [catalog, setCatalog] = useState<ExploreCatalog>(fallbackCatalog);\n const [messages, setMessages] = useState<ExploreMessage[]>([]);\n const [phase, setPhase] = useState<ExploreChatPhase>(\"loading\");\n const [error, setError] = useState<ExploreChatError | null>(null);\n const [remainingToday, setRemainingToday] = useState<number | null>(null);\n const [focusProduct, setFocusProductState] = useState<string | null>(null);\n const [turnCount, setTurnCount] = useState(0);\n // Mirror of `messages` for callbacks that must not re-create on every message.\n const messagesRef = useRef<ExploreMessage[]>([]);\n const [archive, setArchive] = useState<ArchivedExploreConversation[]>([]);\n\n const [hydrated, setHydrated] = useState(false);\n\n // Refs mirror the state that async callbacks read, so `send`/`poll` never\n // close over a stale value and never need to be re-created mid-flight.\n const mountedRef = useRef(true);\n const pollGenerationRef = useRef(0);\n const pollTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const conversationTokenRef = useRef<string | null>(null);\n /**\n * Render-visible mirror of `conversationTokenRef`.\n *\n * The ref alone cannot gate a control: a ref write does not re-render, so a form offered\n * on `conversationTokenRef.current !== null` would still be absent on the render after the\n * first message landed. Everything that assigns the token goes through\n * {@link rememberConversationToken} so the two cannot drift.\n */\n const [hasConversation, setHasConversation] = useState(false);\n /**\n * The `?c=` share token, read ONCE and synchronously.\n *\n * It cannot be discovered inside the share effect and then relied on by the hydration\n * effect: both run in the same commit, so the hydration effect would still close over\n * `isSharedView === false` and load the visitor's own stored thread underneath the shared\n * one. On a slow link that shows their old chat first and then swaps it; if the share\n * lookup fails, they are left staring at their old conversation next to a \"not found\"\n * error. Reading it here makes both effects agree on the first render.\n */\n const shareTokenRef = useRef<string | null | undefined>(undefined);\n if (shareTokenRef.current === undefined) {\n shareTokenRef.current = readShareToken();\n }\n // Derived, not state: the token comes from the URL, and leaving the shared view is a\n // full navigation (the \"New chat\" button drops `?c=` via `location.href`), so there is no\n // in-place transition for a setter to model.\n const isSharedView = shareTokenRef.current !== null;\n const catalogRef = useRef<ExploreCatalog>(fallbackCatalog);\n const turnCountRef = useRef(0);\n const focusProductRef = useRef<string | null>(null);\n const lastSentTextRef = useRef<string | null>(null);\n // Retried alongside the text. Without this a retry after a network failure would re-ask the\n // question with the documents silently dropped, and the visitor would get a confidently\n // wrong answer with nothing on screen saying their files were not used.\n const lastSentAttachmentsRef = useRef<readonly ExploreAttachmentPayload[]>(\n [],\n );\n const inFlightRef = useRef(false);\n\n catalogRef.current = catalog;\n\n /**\n * The single writer for the conversation token.\n *\n * Async callbacks read the ref (so they never close over a stale value); render reads the\n * state (so a control can appear the moment a conversation exists). Writing both here is\n * what keeps \"we have a thread\" from being true in one and false in the other.\n */\n const rememberConversationToken = useCallback((token: string | null) => {\n conversationTokenRef.current = token;\n setHasConversation(token !== null);\n }, []);\n\n const clearPollTimer = useCallback(() => {\n if (pollTimerRef.current !== null) {\n clearTimeout(pollTimerRef.current);\n pollTimerRef.current = null;\n }\n }, []);\n\n /** Invalidate any running poll chain. Late responses become no-ops. */\n const cancelPolling = useCallback(() => {\n pollGenerationRef.current += 1;\n clearPollTimer();\n }, [clearPollTimer]);\n\n useEffect(() => {\n mountedRef.current = true;\n return () => {\n mountedRef.current = false;\n pollGenerationRef.current += 1;\n if (pollTimerRef.current !== null) {\n clearTimeout(pollTimerRef.current);\n pollTimerRef.current = null;\n }\n };\n }, []);\n\n // --------------------------------------------------------------------------\n // A shared link (`?c=<shareToken>`).\n //\n // Runs BEFORE the localStorage hydration below and short-circuits it: someone opening a\n // link they were sent must see that conversation, not whatever they happened to ask this\n // site last week. The secret in the URL is a read-only share token, never a conversation\n // token, so this view cannot continue the thread — which is why `isSharedView` is exposed\n // and the composer is disabled on it.\n // --------------------------------------------------------------------------\n useEffect(() => {\n const shareToken = shareTokenRef.current;\n if (!shareToken) return;\n\n let cancelled = false;\n setHydrated(true);\n\n void client\n .query<{ exploreSharedConversation?: ExploreMessage[] | null }>(\n EXPLORE_SHARED_CONVERSATION_QUERY,\n { shareToken },\n { cache: false },\n )\n .then((res) => {\n if (cancelled || !mountedRef.current) return;\n const shared = res?.data?.exploreSharedConversation;\n if (shared && shared.length > 0) {\n setMessages(shared);\n return;\n }\n // A token that resolves to nothing is an expired or wrong link. Say so rather than\n // showing an empty chat that looks like the feature is broken.\n setError({\n kind: \"unknown\",\n code: \"SHARE_NOT_FOUND\",\n message:\n \"That shared conversation could not be found. The link may have expired.\",\n // Nothing to retry: a bad token will stay bad.\n retryable: false,\n });\n })\n .catch(() => {\n if (cancelled || !mountedRef.current) return;\n setError({\n kind: \"unknown\",\n code: \"SHARE_NOT_FOUND\",\n message: \"That shared conversation could not be loaded.\",\n retryable: true,\n });\n });\n\n return () => {\n cancelled = true;\n };\n }, [client]);\n\n // --------------------------------------------------------------------------\n // Hydrate from localStorage (effect, not lazy state, so the FIRST client\n // render matches the prerendered HTML and hydration stays clean).\n // --------------------------------------------------------------------------\n useEffect(() => {\n // A shared link owns the transcript; never let stored history replace it. The ref, not\n // the state: this effect and the share effect run in the same commit.\n if (shareTokenRef.current !== null) return;\n if (!persist) {\n setHydrated(true);\n return;\n }\n setArchive(readArchive(storageKey));\n const stored = readPersisted(storageKey);\n if (stored) {\n rememberConversationToken(stored.conversationToken);\n focusProductRef.current = stored.focusProduct;\n // A turn that was still streaming when the tab was closed can never be\n // resumed from here — the poll chain is gone. Land it as-is.\n const settled = stored.messages.flatMap<ExploreMessage>((m) => {\n if (m.role !== \"ASSISTANT\") return [m];\n if (m.status !== \"PENDING\" && m.status !== \"RUNNING\") return [m];\n const text = visibleText(m);\n if (!text) return [];\n return [{ ...m, status: \"COMPLETED\", content: text }];\n });\n setMessages(settled);\n setFocusProductState(stored.focusProduct);\n const turns = countUserTurns(settled);\n turnCountRef.current = turns;\n setTurnCount(turns);\n }\n setHydrated(true);\n }, [persist, rememberConversationToken, storageKey]);\n\n // --------------------------------------------------------------------------\n // Persist (after hydration, so the initial empty state never wipes storage).\n // --------------------------------------------------------------------------\n useEffect(() => {\n if (!persist || !hydrated || typeof window === \"undefined\") return;\n try {\n const payload: PersistedExploreState = {\n conversationToken: conversationTokenRef.current,\n messages: messages.slice(-MAX_PERSISTED_MESSAGES),\n focusProduct,\n };\n // Nothing worth restoring (fresh page, or just after reset()): drop the\n // key entirely rather than leaving an empty husk behind.\n if (\n !payload.conversationToken &&\n payload.messages.length === 0 &&\n !payload.focusProduct\n ) {\n window.localStorage.removeItem(storageKey);\n return;\n }\n window.localStorage.setItem(storageKey, JSON.stringify(payload));\n } catch {\n /* private mode / quota exceeded — persistence is a nicety, not a feature */\n }\n }, [persist, hydrated, storageKey, messages, focusProduct]);\n\n // Mirror messages into a ref for callbacks, and fold a settled thread into the archive.\n // Archiving on every settled turn (not only on reset) is what makes an abruptly closed tab\n // still leave a record the visitor can come back to.\n useEffect(() => {\n messagesRef.current = messages;\n if (!persist || !hydrated) return;\n const settled = messages.some(\n (m) =>\n m.role === \"ASSISTANT\" &&\n (m.status === \"COMPLETED\" || m.status === \"FAILED\"),\n );\n if (!settled) return;\n setArchive(\n upsertArchive(storageKey, {\n token: conversationTokenRef.current,\n messages,\n focusProduct: focusProductRef.current,\n }),\n );\n }, [messages, persist, hydrated, storageKey]);\n\n // --------------------------------------------------------------------------\n // Catalog. Cached (the default) — it is per-page-load configuration, not a\n // poll. A failure keeps the fallback so the page NEVER renders blank.\n // --------------------------------------------------------------------------\n useEffect(() => {\n let cancelled = false;\n const load = async () => {\n const variables = { productSlug: productSlug ?? null };\n let res = await client.query<ExploreCatalogQueryData>(\n EXPLORE_CATALOG_QUERY,\n variables,\n );\n if (cancelled || !mountedRef.current) return;\n\n // A gateway whose supergraph predates `conceptHighlights` does not answer this\n // document without the field — it refuses the document outright, so `res.data` is\n // undefined and the loss is the entire catalog, not the strip. Retry once with the\n // field dropped rather than spending the whole window on `buildFallbackCatalog()`,\n // which hardcodes `enabled: true` (ignoring the only kill switch that needs no\n // redeploy) and `captchaRequired: false` (every send then rejected server-side while\n // the composer looks fine). The window is unavoidable even with perfect deploy\n // ordering: the prod gateway's CDN edge serves a stale supergraph for ~30-40 min\n // after the subgraph publishes.\n if (catalogRejectedTheHighlightField(res)) {\n res = await client.query<ExploreCatalogQueryData>(\n EXPLORE_CATALOG_QUERY_WITHOUT_HIGHLIGHTS,\n variables,\n );\n if (cancelled || !mountedRef.current) return;\n }\n\n const raw = res.data?.exploreCatalog;\n if (res.errors?.length || !raw) {\n console.warn(\n \"[WebSDK] exploreCatalog unavailable — using the built-in fallback catalog\",\n res.errors?.[0]?.message,\n );\n setPhase((prev) => (prev === \"loading\" ? \"ready\" : prev));\n return;\n }\n\n const next = normalizeCatalog(raw, fallbackCatalog);\n setCatalog(next);\n catalogRef.current = next;\n setPhase((prev) => {\n if (!next.enabled) return \"disabled\";\n return prev === \"loading\" ? \"ready\" : prev;\n });\n };\n void load();\n return () => {\n cancelled = true;\n };\n }, [client, productSlug, fallbackCatalog]);\n\n // --------------------------------------------------------------------------\n // Poll chain\n // --------------------------------------------------------------------------\n const startPolling = useCallback(\n (conversationToken: string, messageId: string) => {\n pollGenerationRef.current += 1;\n const generation = pollGenerationRef.current;\n const startedAt = Date.now();\n let consecutiveFailures = 0;\n\n const isStale = () =>\n !mountedRef.current || generation !== pollGenerationRef.current;\n\n const finishWithError = (chatError: ExploreChatError) => {\n inFlightRef.current = false;\n setMessages((prev) =>\n prev.flatMap<ExploreMessage>((m) => {\n if (m.id !== messageId) return [m];\n const text = visibleText(m);\n if (!text) return [];\n return [{ ...m, status: \"FAILED\", content: text }];\n }),\n );\n setError(chatError);\n setPhase(chatError.kind === \"rate-limit\" ? \"limited\" : \"error\");\n };\n\n const tick = async () => {\n if (isStale()) return;\n\n if (Date.now() - startedAt > pollTimeoutMs) {\n finishWithError(classifyExploreError(\"TIMEOUT\"));\n return;\n }\n\n // `cache: false` is load-bearing — see CONTRACT.md §4.\n const res = await client.query<ExploreMessageQueryData>(\n EXPLORE_MESSAGE_QUERY,\n { conversationToken, id: messageId },\n { cache: false, timeoutMs: POLL_REQUEST_TIMEOUT_MS },\n );\n if (isStale()) return;\n\n const first = res.errors?.[0];\n if (first) {\n const code =\n typeof first.extensions?.code === \"string\"\n ? first.extensions.code\n : undefined;\n const classified = classifyExploreError(code, first.message);\n // Hard stops: retrying a rate limit or a disabled feature is pointless.\n if (!classified.retryable) {\n finishWithError(classified);\n return;\n }\n consecutiveFailures += 1;\n if (consecutiveFailures >= MAX_CONSECUTIVE_POLL_FAILURES) {\n finishWithError(classified);\n return;\n }\n pollTimerRef.current = setTimeout(() => void tick(), pollIntervalMs);\n return;\n }\n\n const message = res.data?.exploreMessage;\n if (!message) {\n // Can happen briefly right after submit; tolerate a few misses.\n consecutiveFailures += 1;\n if (consecutiveFailures >= MAX_CONSECUTIVE_POLL_FAILURES) {\n finishWithError(classifyExploreError(\"NOT_FOUND\"));\n return;\n }\n pollTimerRef.current = setTimeout(() => void tick(), pollIntervalMs);\n return;\n }\n\n consecutiveFailures = 0;\n // Replace in place so `partialContent` renders as it streams.\n setMessages((prev) =>\n prev.map((m) => (m.id === messageId ? message : m)),\n );\n\n if (message.status === \"COMPLETED\") {\n inFlightRef.current = false;\n setError(null);\n setPhase(\"ready\");\n return;\n }\n if (message.status === \"FAILED\") {\n finishWithError(\n classifyExploreError(message.errorCode ?? \"UPSTREAM_UNAVAILABLE\"),\n );\n return;\n }\n\n setPhase(\"streaming\");\n pollTimerRef.current = setTimeout(() => void tick(), pollIntervalMs);\n };\n\n // First poll after one interval — the turn cannot possibly be done sooner.\n pollTimerRef.current = setTimeout(() => void tick(), pollIntervalMs);\n },\n [client, pollIntervalMs, pollTimeoutMs],\n );\n\n // --------------------------------------------------------------------------\n // send\n // --------------------------------------------------------------------------\n const submit = useCallback(\n async (\n text: string,\n optimisticId: string,\n captchaAttempt: number,\n attachments: readonly ExploreAttachmentPayload[],\n ): Promise<void> => {\n const activeCatalog = catalogRef.current;\n\n let recaptchaToken: string | undefined;\n if (activeCatalog.captchaRequired && activeCatalog.recaptchaSiteKey) {\n try {\n recaptchaToken = await getRecaptchaV3Token(\n activeCatalog.recaptchaSiteKey,\n );\n } catch (err) {\n console.warn(\"[WebSDK] reCAPTCHA v3 token could not be minted\", err);\n // Send without a token and let the backend decide — it owns the\n // policy, and a blocked third-party script must not silently kill\n // the whole feature.\n }\n }\n\n const input: SendExploreMessageInput = {\n message: text,\n ...(conversationTokenRef.current\n ? { conversationToken: conversationTokenRef.current }\n : {}),\n ...(focusProductRef.current || productSlug\n ? { productSlug: focusProductRef.current ?? productSlug }\n : {}),\n ...(recaptchaToken ? { recaptchaToken } : {}),\n ...(locale ? { locale } : {}),\n ...(pageUrl ? { pageUrl } : {}),\n ...(attachments.length > 0 ? { attachments: [...attachments] } : {}),\n };\n\n const res = await client.mutate<SendExploreMessageMutationData>(\n SEND_EXPLORE_MESSAGE_MUTATION,\n { input },\n { timeoutMs: SEND_REQUEST_TIMEOUT_MS },\n );\n if (!mountedRef.current) return;\n\n const first = res.errors?.[0];\n const result = res.data?.sendExploreMessage;\n\n if (first || !result) {\n const code =\n typeof first?.extensions?.code === \"string\"\n ? first.extensions.code\n : undefined;\n const classified = classifyExploreError(code, first?.message);\n\n // CAPTCHA_FAILED: one silent re-mint + re-send before bothering the\n // visitor. v3 tokens expire in ~2 minutes and are single-use, so a\n // stale one is a routine, self-healing failure.\n if (classified.kind === \"captcha\" && captchaAttempt === 0) {\n await submit(text, optimisticId, 1, attachments);\n return;\n }\n\n inFlightRef.current = false;\n setError(classified);\n setPhase(classified.kind === \"rate-limit\" ? \"limited\" : \"error\");\n return;\n }\n\n rememberConversationToken(result.conversation.token);\n turnCountRef.current = result.conversation.turnCount;\n setTurnCount(result.conversation.turnCount);\n setRemainingToday(result.remainingToday ?? null);\n\n const userMessage = result.userMessage;\n const assistantMessage = result.assistantMessage;\n\n // Swap the optimistic user bubble for the server's, then append the\n // PENDING assistant turn that the poll chain will fill in. The `some`\n // guard keeps the visitor's words on screen even in the impossible case\n // where the optimistic bubble is already gone.\n setMessages((prev) => {\n const replaced = prev.some((m) => m.id === optimisticId)\n ? prev.map((m) => (m.id === optimisticId ? userMessage : m))\n : [...prev, userMessage];\n return [...replaced, assistantMessage];\n });\n\n if (\n assistantMessage.status === \"COMPLETED\" ||\n assistantMessage.status === \"FAILED\"\n ) {\n inFlightRef.current = false;\n if (assistantMessage.status === \"FAILED\") {\n const classified = classifyExploreError(\n assistantMessage.errorCode ?? \"UPSTREAM_UNAVAILABLE\",\n );\n setError(classified);\n setPhase(\"error\");\n } else {\n setPhase(\"ready\");\n }\n return;\n }\n\n setPhase(\"streaming\");\n startPolling(result.conversation.token, assistantMessage.id);\n },\n [\n client,\n locale,\n pageUrl,\n productSlug,\n rememberConversationToken,\n startPolling,\n ],\n );\n\n const send = useCallback(\n async (\n message: string,\n attachments: readonly ExploreAttachmentPayload[] = [],\n ): Promise<void> => {\n const text = message.trim();\n // A question is still required: files are extra context for a question, not a question\n // on their own. The model has no way to guess what to do with a bare document.\n if (!text) return;\n if (inFlightRef.current) return;\n\n const activeCatalog = catalogRef.current;\n if (!activeCatalog.enabled) {\n setError(classifyExploreError(\"EXPLORE_DISABLED\"));\n setPhase(\"disabled\");\n return;\n }\n if (text.length > activeCatalog.limits.maxMessageLength) {\n setError({\n kind: \"validation\",\n code: \"MESSAGE_TOO_LONG\",\n message: `That message is ${text.length} characters — the limit is ${activeCatalog.limits.maxMessageLength}.`,\n retryable: false,\n });\n return;\n }\n if (\n turnCountRef.current >= activeCatalog.limits.maxTurnsPerConversation\n ) {\n setError({\n kind: \"validation\",\n code: \"CONVERSATION_LIMIT\",\n message: `This conversation has reached its ${activeCatalog.limits.maxTurnsPerConversation}-message limit. Start a new chat to keep going.`,\n retryable: false,\n });\n return;\n }\n\n inFlightRef.current = true;\n lastSentTextRef.current = text;\n lastSentAttachmentsRef.current = attachments;\n setError(null);\n setPhase(\"sending\");\n cancelPolling();\n\n // Optimistic user bubble — the composer clears instantly instead of\n // waiting a network round-trip for the visitor's own words.\n const optimistic: ExploreMessage = {\n id: makeOptimisticId(),\n conversationId: conversationTokenRef.current ?? \"pending\",\n role: \"USER\",\n status: \"COMPLETED\",\n content: text,\n partialContent: null,\n activity: [],\n references: [],\n ctas: [],\n errorCode: null,\n createdAt: new Date().toISOString(),\n completedAt: new Date().toISOString(),\n };\n setMessages((prev) => [...prev, optimistic]);\n turnCountRef.current += 1;\n setTurnCount(turnCountRef.current);\n onSend?.(text);\n\n try {\n await submit(text, optimistic.id, 0, attachments);\n } catch (err) {\n if (!mountedRef.current) return;\n console.error(\"[WebSDK] Explore send failed\", err);\n inFlightRef.current = false;\n setError(classifyExploreError(\"NETWORK_ERROR\"));\n setPhase(\"error\");\n }\n },\n [cancelPolling, onSend, submit],\n );\n\n const stop = useCallback(() => {\n cancelPolling();\n inFlightRef.current = false;\n setMessages((prev) =>\n prev.flatMap<ExploreMessage>((m) => {\n if (m.role !== \"ASSISTANT\") return [m];\n if (m.status !== \"PENDING\" && m.status !== \"RUNNING\") return [m];\n const text = visibleText(m);\n // Nothing streamed yet — drop the placeholder instead of leaving an\n // empty bubble behind.\n if (!text) return [];\n return [\n {\n ...m,\n status: \"COMPLETED\",\n content: text,\n completedAt: new Date().toISOString(),\n },\n ];\n }),\n );\n setPhase((prev) =>\n prev === \"sending\" || prev === \"streaming\" ? \"ready\" : prev,\n );\n }, [cancelPolling]);\n\n const retry = useCallback(() => {\n const text = lastSentTextRef.current;\n if (!text) return;\n cancelPolling();\n inFlightRef.current = false;\n // Drop the failed turn (and the user bubble that produced it) so the retry\n // does not stack a duplicate pair into the transcript.\n setMessages((prev) => {\n const next = [...prev];\n const last = next[next.length - 1];\n if (last?.role === \"ASSISTANT\" && last.status === \"FAILED\") next.pop();\n const prior = next[next.length - 1];\n if (prior?.role === \"USER\" && prior.content === text) next.pop();\n return next;\n });\n turnCountRef.current = Math.max(0, turnCountRef.current - 1);\n setTurnCount(turnCountRef.current);\n void send(text, lastSentAttachmentsRef.current);\n }, [cancelPolling, send]);\n\n const reset = useCallback(() => {\n // Archive the thread being left behind, so \"New chat\" never destroys history.\n setArchive(\n upsertArchive(storageKey, {\n token: conversationTokenRef.current,\n messages: messagesRef.current,\n focusProduct: focusProductRef.current,\n }),\n );\n cancelPolling();\n inFlightRef.current = false;\n rememberConversationToken(null);\n lastSentTextRef.current = null;\n lastSentAttachmentsRef.current = [];\n turnCountRef.current = 0;\n setTurnCount(0);\n setMessages([]);\n setError(null);\n setRemainingToday(null);\n setPhase(catalogRef.current.enabled ? \"ready\" : \"disabled\");\n if (typeof window !== \"undefined\") {\n try {\n window.localStorage.removeItem(storageKey);\n } catch {\n /* storage unavailable — nothing to clear */\n }\n }\n }, [cancelPolling, rememberConversationToken, storageKey]);\n\n /**\n * Reopen a past conversation. The messages come from the local archive rather than the server:\n * the backend expires a job's state, and a visitor looking at their own history should see it\n * whether or not the server still holds anything. The token is restored too, so the next\n * message continues the SAME server-side conversation.\n */\n const openConversation = useCallback(\n (token: string) => {\n const entry = readArchive(storageKey).find((e) => e.token === token);\n if (!entry) return;\n // Archive whatever is on screen first, or switching away would lose it.\n upsertArchive(storageKey, {\n token: conversationTokenRef.current,\n messages: messagesRef.current,\n focusProduct: focusProductRef.current,\n });\n cancelPolling();\n inFlightRef.current = false;\n rememberConversationToken(entry.token);\n turnCountRef.current = entry.messages.filter(\n (m) => m.role === \"USER\",\n ).length;\n setTurnCount(turnCountRef.current);\n setMessages(entry.messages);\n focusProductRef.current = entry.focusProduct;\n setFocusProductState(entry.focusProduct);\n setError(null);\n setPhase(catalogRef.current.enabled ? \"ready\" : \"disabled\");\n setArchive(readArchive(storageKey));\n },\n [cancelPolling, rememberConversationToken, storageKey],\n );\n\n /** Forget one past conversation. Local only — see the page's storage notice. */\n const deleteConversation = useCallback(\n (token: string) => {\n const next = readArchive(storageKey).filter((e) => e.token !== token);\n writeArchive(storageKey, next);\n setArchive(next);\n },\n [storageKey],\n );\n\n /** Forget every past conversation held in this browser. */\n const clearHistory = useCallback(() => {\n writeArchive(storageKey, []);\n setArchive([]);\n }, [storageKey]);\n\n const setFocusProduct = useCallback((slug: string | null) => {\n focusProductRef.current = slug;\n setFocusProductState(slug);\n }, []);\n\n const activity = useMemo<string | null>(() => {\n for (let i = messages.length - 1; i >= 0; i -= 1) {\n const m = messages[i];\n if (!m || m.role !== \"ASSISTANT\") continue;\n if (m.status !== \"PENDING\" && m.status !== \"RUNNING\") return null;\n const lines = m.activity ?? [];\n return lines.length ? (lines[lines.length - 1] ?? null) : null;\n }\n return null;\n }, [messages]);\n\n const canSend =\n (phase === \"ready\" || phase === \"error\") &&\n catalog.enabled &&\n turnCount < catalog.limits.maxTurnsPerConversation;\n\n /**\n * Tell the server the visitor followed one of the links this answer offered.\n *\n * Deliberately fire-and-forget and never awaited: the browser is navigating away as this\n * goes out, so anything that blocked on it would delay the click the visitor actually\n * made. Failures are swallowed — analytics must never break navigation.\n */\n const createShareLink = useCallback(async (): Promise<string | null> => {\n const token = conversationTokenRef.current;\n if (!token) return null;\n try {\n const result = await client.mutate<{\n createExploreShareLink?: { shareToken?: string | null } | null;\n }>(CREATE_EXPLORE_SHARE_LINK_MUTATION, { conversationToken: token });\n return result?.data?.createExploreShareLink?.shareToken ?? null;\n } catch {\n // Sharing is a convenience; a failure must not take the conversation down with it.\n return null;\n }\n }, [client]);\n\n const recordClick = useCallback(\n (messageId: string, kind: \"CTA\" | \"REFERENCE\", url: string): void => {\n const token = conversationTokenRef.current;\n if (!token) return;\n try {\n void client\n .mutate(RECORD_EXPLORE_CLICK_MUTATION, {\n input: { conversationToken: token, messageId, kind, url },\n })\n .catch(() => {\n /* the visitor is mid-navigation; there is nothing useful to do here */\n });\n } catch {\n /* client unavailable — same reasoning */\n }\n },\n [client],\n );\n\n /**\n * Rate one answer, and fold the server's record back into the transcript.\n *\n * The fold matters beyond the control that triggered it: `messages` is what the persist\n * effect writes to localStorage, so a rating stored here survives a reload of the same\n * conversation and not just this render. The optimistic state in the UI covers the moment\n * before this resolves; this covers everything after.\n */\n const submitFeedback = useCallback(\n async (\n messageId: string,\n rating: ExploreFeedbackRating,\n detail?: {\n reason?: ExploreFeedbackReason | null;\n comment?: string | null;\n },\n ): Promise<boolean> => {\n const token = conversationTokenRef.current;\n // No conversation of our own (a fresh page, or a read-only shared view, whose `?c=`\n // secret is not a conversation token): the server could only answer `recorded: false`.\n if (!token) return false;\n\n const comment = detail?.comment?.trim();\n // Annotated, not inferred. `client.mutate` types its variables as an open\n // `Record<string, unknown>`, so an input literal passed inline is unchecked — renaming\n // `messageId` to `id`, or adding a key the server does not accept, would compile\n // cleanly and fail only at runtime against the live gateway. Naming the type is what\n // makes CONTRACT.md compile-checked. `sendMessage` above does the same.\n const input: SubmitExploreFeedbackInput = {\n conversationToken: token,\n messageId,\n rating,\n // Only meaningful with NOT_HELPFUL. The server stores null for HELPFUL either\n // way; sending it would just be noise the backend has to defend against.\n reason: rating === \"NOT_HELPFUL\" ? (detail?.reason ?? null) : null,\n comment: comment ? comment : null,\n };\n try {\n const res = await client.mutate<SubmitExploreFeedbackMutationData>(\n SUBMIT_EXPLORE_FEEDBACK_MUTATION,\n { input },\n );\n const result = res?.data?.submitExploreFeedback;\n if (!result?.recorded) return false;\n\n const recorded = result.feedback;\n if (recorded && mountedRef.current) {\n setMessages((current) =>\n current.map((message) =>\n message.id === messageId\n ? { ...message, feedback: recorded }\n : message,\n ),\n );\n }\n return true;\n } catch {\n // `client.mutate` resolves every outcome rather than throwing, so this is belt and\n // braces for a client that is not there at all. Either way: not recorded.\n return false;\n }\n },\n [client],\n );\n\n /**\n * Hand the conversation to a person.\n *\n * The visitor pressed a control and is waiting on it, so this is awaited and reports what\n * actually happened rather than a boolean: `already-handed-over` in particular is a\n * SUCCESS the caller has to be able to tell apart from a failure, and `invalid-email` is\n * the server's verdict on an address the form's own check let through.\n *\n * `email` never leaves this function except in the mutation variables. It is not folded\n * into `messages` (the persist effect writes those to localStorage), not written to\n * storage directly, and not passed to `onSend`. Anyone adding \"just log the address\" here\n * is putting personal data in a place nothing ever deletes it from.\n */\n const escalate = useCallback(\n async (email: string, note?: string): Promise<ExploreEscalateResult> => {\n const token = conversationTokenRef.current;\n // A read-only shared view (its `?c=` secret is not a conversation token) and a page\n // where nothing has been asked yet both land here. The server could only answer\n // NOT_FOUND, so do not spend a request finding that out.\n if (!token) {\n return { outcome: \"no-conversation\", email: null, createdAt: null };\n }\n\n const attempt = async (\n captchaAttempt: number,\n ): Promise<ExploreEscalateResult> => {\n const activeCatalog = catalogRef.current;\n\n // Exactly what `submit` does, including the default action — the contract puts the\n // whole explore surface on ONE v3 action on purpose, because an action mismatch is a\n // silent 100% rejection.\n let recaptchaToken: string | undefined;\n if (activeCatalog.captchaRequired && activeCatalog.recaptchaSiteKey) {\n try {\n recaptchaToken = await getRecaptchaV3Token(\n activeCatalog.recaptchaSiteKey,\n );\n } catch (err) {\n console.warn(\n \"[WebSDK] reCAPTCHA v3 token could not be minted\",\n err,\n );\n // Send without one and let the backend decide: it owns the policy, and a\n // blocked third-party script must not be what stops someone reaching a human.\n }\n }\n\n // Annotated, not inferred — `client.mutate` types its variables as an open\n // `Record<string, unknown>`, so an inline literal is unchecked and a renamed field\n // would compile cleanly and fail against the live gateway. Same rule as\n // `submitFeedback` and `submit`.\n const input: EscalateExploreConversationInput = {\n conversationToken: token,\n email: email.trim(),\n note: note?.trim() ? note.trim() : null,\n ...(recaptchaToken ? { recaptchaToken } : {}),\n ...(productId ? { productId } : {}),\n };\n\n try {\n const res =\n await client.mutate<EscalateExploreConversationMutationData>(\n ESCALATE_EXPLORE_CONVERSATION_MUTATION,\n { input },\n );\n\n const first = res?.errors?.[0];\n const result = res?.data?.escalateExploreConversation;\n\n if (first || !result) {\n const code =\n typeof first?.extensions?.code === \"string\"\n ? first.extensions.code\n : \"ESCALATION_FAILED\";\n\n // One silent re-mint, exactly as `submit` does: a v3 token is single-use and\n // expires in ~2 minutes, so a rejected one is routine and self-healing.\n if (code === \"CAPTCHA_FAILED\" && captchaAttempt === 0) {\n return attempt(1);\n }\n\n return {\n outcome: escalateOutcomeForCode(code),\n email: null,\n createdAt: null,\n };\n }\n\n return {\n // `created: false` is the double-click, the retry, the reload. The handover\n // exists, so this is a success — and the address comes from the SERVER, because\n // on a repeat submit the reply goes to whatever the FIRST handover used.\n outcome: result.created ? \"sent\" : \"already-handed-over\",\n email: result.escalation?.email ?? null,\n createdAt: result.escalation?.createdAt ?? null,\n };\n } catch {\n // `client.mutate` resolves every transport outcome rather than throwing, so this\n // is for a client that is not there at all. Either way: nothing was handed over,\n // and this function's contract is that it never throws at the caller.\n return { outcome: \"failed\", email: null, createdAt: null };\n }\n };\n\n return attempt(0);\n },\n [client, productId],\n );\n\n /**\n * A shared view holds a share secret, not a conversation token, so `hasConversation` is\n * already false there. Both are named anyway: the second is the reason, and a later\n * refactor that starts restoring a token under a shared transcript should fail this\n * condition rather than quietly start offering the form.\n */\n const canEscalate = hasConversation && !isSharedView;\n\n return {\n phase,\n catalog,\n messages,\n activity,\n remainingToday,\n error,\n focusProduct,\n setFocusProduct,\n send,\n stop,\n retry,\n reset,\n canSend,\n history: archive,\n openConversation,\n deleteConversation,\n clearHistory,\n recordClick,\n submitFeedback,\n escalate,\n canEscalate,\n createShareLink,\n isSharedView,\n };\n}\n\n/**\n * Client-only id for the optimistic user bubble, swapped for the server's\n * `userMessage.id` as soon as the mutation resolves. The counter only has to\n * make ids unique within a tab, never across one.\n */\nlet optimisticCounter = 0;\n\nfunction makeOptimisticId(): string {\n optimisticCounter += 1;\n return `boff-explore-local-${Date.now()}-${optimisticCounter}`;\n}\n","\"use client\";\n\nimport { useEffect, useRef, useState } from \"react\";\n\n/**\n * Reveal an in-flight answer at a readable pace instead of in poll-sized blocks.\n *\n * ## What this is NOT\n *\n * It is not a transport change. `/explore` answers arrive by submit-and-poll, one\n * `exploreMessage` read every ~1.5s (CONTRACT.md §1), and nothing here touches that: no\n * extra request, no shorter interval, no socket. Every character this reveals had already\n * been fetched — the hook only decides *when it is painted*.\n *\n * ## The guarantees\n *\n * - **Only text that arrived.** What it returns is always a PREFIX of the string it was\n * given, so it can neither invent a word nor reorder one. When the answer is rewritten\n * rather than appended to — the final `content` replacing a `partialContent` that was cut\n * mid-token — it jumps to the end rather than showing a prefix of the old answer inside\n * the new one.\n * - **Never behind a finished answer.** `settled` (the turn is COMPLETED or FAILED) returns\n * the whole string immediately, on the render it flips. Nobody waits on an animation for\n * text that is already in hand, and a restored or shared transcript paints in full on its\n * first frame.\n * - **A table is painted as a table or not at all.** A GFM header row without its `| --- |`\n * row renders as a paragraph of pipes, so one is held back until that row arrives, for as\n * long as the answer is still running (CONTRACT.md §7). It is the one construct whose\n * rendering changes retroactively when a LATER line lands.\n * - **Reduced motion is not \"slower\".** `prefers-reduced-motion: reduce` gets the text at\n * once, with no timer started at all.\n * - **No scrolling, no measuring.** The hook returns a string. It reads no box, writes no\n * scroll position and renders no element, so it cannot fight the transcript's\n * `stickToBottom` logic or the pane geometry — the page was fixed once already for\n * showing nothing but the site footer, and the fix lives in effects that this cannot\n * reach.\n *\n * ## The pace\n *\n * Adaptive rather than a fixed characters-per-second: the cursor moves at whatever speed\n * drains the *backlog* in {@link DRAIN_TARGET_MS}, which is a little under the poll\n * interval. A fast turn therefore reads fast and a trickling one still moves, and the\n * cursor catches up with the arrived text before the next chunk lands instead of falling\n * further behind with every poll.\n */\n\n/** Drain whatever has arrived in about this long — just inside the ~1.5s poll interval. */\nconst DRAIN_TARGET_MS = 1200;\n/** A floor, so the last few characters of a chunk still move rather than crawl. */\nconst MIN_CHARS_PER_SECOND = 90;\n/** A ceiling, so a large backlog is caught up with quickly but not in one frame. */\nconst MAX_CHARS_PER_SECOND = 2200;\n/**\n * The most one step may advance by, however long the gap was. A backgrounded tab stops\n * firing frames entirely, and without this the first frame after it comes back would paint\n * the whole answer at once — the snap this exists to remove.\n */\nconst MAX_STEP_MS = 250;\n/**\n * How often a step is allowed to re-render. Every commit re-parses the answer's markdown,\n * and doing that once a frame is wasted work nobody can see; ~22 commits a second reads as\n * continuous.\n */\nconst COMMIT_INTERVAL_MS = 45;\n/** Only used where `requestAnimationFrame` does not exist. */\nconst FALLBACK_STEP_MS = 50;\n\n/** A ``` or ~~~ fence, which opens or closes a verbatim block. */\nconst FENCE = /^ {0,3}(?:```|~~~)/;\n/** A GFM table row. */\nconst TABLE_ROW = /^ {0,3}\\|/;\n/** A block marker with nothing after it yet — a bullet or heading mid-keystroke. */\nconst EMPTY_BLOCK_MARKER = /^ {0,3}(?:[-+>]|#{1,6}|\\d{1,9}[.)])\\s*$/;\n\n/**\n * A character that makes `_` part of a word rather than emphasis. Deliberately wider than\n * ASCII: `día_uno` is one word in Spanish exactly as `day_one` is in English.\n */\nfunction isWordCharacter(char: string | undefined): boolean {\n return char !== undefined && /[\\p{L}\\p{N}]/u.test(char);\n}\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.min(Math.max(value, min), max);\n}\n\nfunction now(): number {\n return typeof performance !== \"undefined\" &&\n typeof performance.now === \"function\"\n ? performance.now()\n : Date.now();\n}\n\n/** The first half of an astral character — a cut here would paint a replacement glyph. */\nfunction isHighSurrogate(code: number): boolean {\n return code >= 0xd800 && code <= 0xdbff;\n}\n\n/**\n * Where an incomplete LINE may be cut: before the first inline construct it has left open.\n *\n * Markdown is not revealable one character at a time as written. Cutting `**Starter**` after\n * `**Star` paints two literal asterisks, and the same half-written `[label](https://…` paints\n * a bracket and a raw URL, which then rearrange themselves a frame later. Holding the cut at\n * the point the construct OPENED costs a few characters of delay and never paints syntax.\n *\n * Scanned per line on purpose. Emphasis that spans a line break is rare, and carrying an\n * unclosed marker across lines would pin the cut arbitrarily far back.\n *\n * ## What is NOT an open construct\n *\n * A marker character in ordinary prose must not pin the cut, because the pin lasts for the\n * REST OF THE LINE: an answer's paragraph is one unwrapped line, so a `~` that never closes\n * would freeze the reveal mid-sentence and then paint the remaining hundred characters in a\n * single commit — the snap this hook exists to remove. So:\n *\n * - **A lone `*`, `_` or `~` opens nothing.** `answerPlainText` reached the same rule from\n * the other side (\"single-delimiter emphasis only when it wraps a run\"): a `* ` bullet, a\n * `snake_case` identifier, a `~30 seconds`, and a `per seat*` footnote mark are all one\n * literal character, and one literal character on screen for a frame is far cheaper than a\n * frozen paragraph. A run of two or more (`**`, `__`, `~~`) is markup often enough to be\n * worth the wait.\n * - **Intraword `_` is not emphasis at all**, per CommonMark — `MAX__TURNS__PER` neither\n * opens nor closes, whatever the run length.\n * - **A run with whitespace after it opens nothing**, also per CommonMark: it is not a\n * left-flanking delimiter run. Whitespace after the END of the arrived text is unknown,\n * not absent, so a line ending in `**` still holds — that is the `**29` case above.\n */\nfunction safeInlineEnd(line: string): number {\n let codeSpan: number | null = null;\n let link: number | null = null;\n const emphasis: Array<{ marker: string; start: number }> = [];\n\n let at = 0;\n while (at < line.length) {\n const char = line[at] ?? \"\";\n if (char === \"\\\\\") {\n // An escape and whatever it escapes are one unit and carry no meaning of their own.\n at += 2;\n continue;\n }\n if (char === \"`\") {\n let run = 1;\n while (line[at + run] === \"`\") run += 1;\n codeSpan = codeSpan === null ? at : null;\n at += run;\n continue;\n }\n if (codeSpan !== null) {\n // Inside a code span nothing else is markup.\n at += 1;\n continue;\n }\n if (char === \"[\") {\n // `![` is an image; either way the bracket is what opens it.\n if (link === null) link = line[at - 1] === \"!\" ? at - 1 : at;\n at += 1;\n continue;\n }\n if (char === \"]\") {\n // `[3]` is a citation marker and closes here. `](` carries on into the destination.\n if (link !== null && line[at + 1] !== \"(\") link = null;\n at += 1;\n continue;\n }\n if (char === \")\") {\n link = null;\n at += 1;\n continue;\n }\n if (char === \"*\" || char === \"_\" || char === \"~\") {\n let run = 1;\n while (line[at + run] === char) run += 1;\n const start = at;\n at += run;\n const before = line[start - 1];\n const after = line[start + run];\n\n // See \"What is NOT an open construct\" above for all three of these.\n if (run < 2) continue;\n if (char === \"_\" && isWordCharacter(before) && isWordCharacter(after)) {\n continue;\n }\n\n const marker = char.repeat(run);\n const open = emphasis.findIndex((entry) => entry.marker === marker);\n // Closing first: a run that ends emphasis is usually followed by a space, and the\n // opener guard below would otherwise leave that run open forever.\n if (open !== -1) {\n emphasis.splice(open, 1);\n continue;\n }\n if (after !== undefined && /\\s/.test(after)) continue;\n emphasis.push({ marker, start });\n continue;\n }\n at += 1;\n }\n\n const open = [codeSpan, link, emphasis[0]?.start ?? null].filter(\n (value): value is number => value !== null,\n );\n return open.length === 0 ? line.length : Math.min(...open);\n}\n\n/**\n * The largest index at or below `limit` that `text` may be cut at and still render as the\n * markdown it will eventually be.\n *\n * Three block rules, then the inline scan above:\n *\n * - **A half-written fenced block is held at its fence.** Until the closing fence arrives\n * the opening one is just three backticks and a word, and the code inside it is prose.\n * - **A table is held until its delimiter row is complete.** A GFM table is only a table\n * once the `| --- |` row exists; before that the header renders as a paragraph full of\n * pipes, which then becomes a table — the single most jarring thing an answer can do.\n * Complete means a WHOLE line: half of `| --- | --- |` is not a delimiter row, and one\n * that has not been closed by a newline may still grow another column. Afterwards only\n * the incomplete row is held, so the table grows a row at a time.\n * - **A bare block marker is held.** `-`, `>` or `####` with nothing after it yet paints an\n * empty bullet or an empty heading.\n *\n * Reaching the end of the arrived text (`limit >= text.length`) releases all of it but the\n * table, because the cursor being level with the text is the NORMAL end state of a poll, not\n * an edge case: the pace drains a chunk in {@link DRAIN_TARGET_MS}, inside the ~1.5s\n * interval, so every poll ends caught up. A construct that is only ever held while the\n * cursor is behind is therefore held only for the part of a chunk it happens to land in.\n *\n * The table is the one that cannot be left to that, and it is the only one that NEEDS more\n * than the text in hand to render correctly. A header row whose delimiter row is in the next\n * poll would be painted as a paragraph of pipes and then, because a cut never moves\n * backwards, stay one on screen while the rest of the table grows below it. An unclosed\n * fence, by contrast, already renders as the code block it will be (CommonMark runs it to\n * the end of the document), and a `- ` bullet already renders as a bullet.\n *\n * Nothing here decides what a FINISHED answer paints: {@link useProgressiveReveal} returns\n * `content` whole the moment the turn settles, without asking.\n */\nexport function revealBoundary(text: string, limit: number): number {\n if (limit <= 0) return 0;\n\n /** True when the cursor has reached everything that has arrived. */\n const caughtUp = limit >= text.length;\n const head = caughtUp ? text : text.slice(0, limit);\n const lineStart = head.lastIndexOf(\"\\n\") + 1;\n const line = head.slice(lineStart);\n\n // Block state, from the WHOLE lines before the cut.\n let fenceStart: number | null = null;\n let tableStart: number | null = null;\n let tableRows = 0;\n let at = 0;\n while (at < lineStart) {\n const breakAt = head.indexOf(\"\\n\", at);\n const end = breakAt === -1 ? lineStart : breakAt;\n const row = head.slice(at, end);\n if (fenceStart !== null) {\n if (FENCE.test(row)) fenceStart = null;\n } else if (FENCE.test(row)) {\n fenceStart = at;\n } else if (TABLE_ROW.test(row)) {\n if (tableStart === null) {\n tableStart = at;\n tableRows = 0;\n }\n tableRows += 1;\n } else if (tableStart !== null) {\n tableStart = null;\n tableRows = 0;\n }\n at = end + 1;\n }\n\n // The last line is not a whole line: the rest of it may still be on its way. A `|` on it\n // still OPENS a table, and an empty one (the text ends at the newline after the row above)\n // has not closed the table it follows either.\n if (fenceStart === null) {\n const lastIsRow = TABLE_ROW.test(line);\n if (lastIsRow && tableStart === null) {\n // It opens a table. It does not COUNT as one of the two rows a table needs: half of\n // `| --- |` is not a delimiter row.\n tableStart = lineStart;\n tableRows = 0;\n } else if (!lastIsRow && line !== \"\") {\n tableStart = null;\n tableRows = 0;\n }\n // Held even at the end of the arrived text — see the note above.\n if (tableStart !== null && tableRows < 2) return tableStart;\n }\n\n if (caughtUp) return text.length;\n if (fenceStart !== null) return fenceStart;\n if (TABLE_ROW.test(line)) return lineStart;\n if (EMPTY_BLOCK_MARKER.test(line)) return lineStart;\n\n const cut = lineStart + safeInlineEnd(line);\n return isHighSurrogate(text.charCodeAt(cut - 1)) ? cut - 1 : cut;\n}\n\n/**\n * True when the visitor has asked for less movement. Read once per mount rather than per\n * render: `matchMedia` is absent on some engines (and in jsdom), and a setting that changes\n * mid-answer is not worth a subscription.\n *\n * Server-side this answers true, so a prerender serialises the finished text rather than an\n * animation's first frame.\n */\nfunction prefersReducedMotion(): boolean {\n if (typeof window === \"undefined\") return true;\n try {\n return (\n window.matchMedia?.(\"(prefers-reduced-motion: reduce)\").matches === true\n );\n } catch {\n /* an engine whose matchMedia throws on an unknown feature — treat as no preference */\n return false;\n }\n}\n\n/**\n * The part of `text` that is currently on screen.\n *\n * @param text everything that has arrived so far — `content` once the turn completes,\n * `partialContent` while it runs.\n * @param settled true once the turn is COMPLETED or FAILED and `text` will not grow again.\n */\nexport function useProgressiveReveal(text: string, settled: boolean): string {\n const [, setFrame] = useState(0);\n const [reduced] = useState(prefersReducedMotion);\n const immediate = settled || reduced;\n\n /** The text the cursor below points into. */\n const textRef = useRef(text);\n /** How far the cursor has travelled, fractionally — a step is usually part of a character. */\n const cursorRef = useRef(immediate ? text.length : 0);\n /** The last cut actually rendered, so a cut can never move backwards. */\n const cutRef = useRef(immediate ? text.length : 0);\n const committedRef = useRef(0);\n\n // Reconciled during render, not in an effect: what this function returns has to describe\n // the text it was handed THIS render, never the previous answer for a frame.\n if (text !== textRef.current) {\n const revealed = textRef.current.slice(0, Math.floor(cursorRef.current));\n if (revealed !== \"\" && !text.startsWith(revealed)) {\n // Rewritten rather than appended to. Everything on screen must be text that arrived,\n // so finish rather than show the old prefix inside the new answer.\n cursorRef.current = text.length;\n }\n cursorRef.current = Math.min(cursorRef.current, text.length);\n cutRef.current = Math.min(cutRef.current, text.length);\n textRef.current = text;\n }\n if (immediate) cursorRef.current = text.length;\n\n // A settled turn paints whole rather than asking the boundary. `content` is the entire\n // answer, so a table it stops in the middle of is all the table there is ever going to\n // be, and holding it back would hold it back for good.\n const cut = immediate\n ? text.length\n : Math.max(\n cutRef.current,\n revealBoundary(text, Math.floor(cursorRef.current)),\n );\n cutRef.current = cut;\n\n useEffect(() => {\n if (immediate) return;\n if (cursorRef.current >= text.length) return;\n\n let cancelled = false;\n let cancelStep: (() => void) | null = null;\n let previous = now();\n\n const commit = (at: number, force: boolean): void => {\n if (!force && at - committedRef.current < COMMIT_INTERVAL_MS) return;\n committedRef.current = at;\n setFrame((value) => value + 1);\n };\n\n const step = (): void => {\n cancelStep = null;\n if (cancelled) return;\n\n const at = now();\n const elapsed = clamp(at - previous, 0, MAX_STEP_MS);\n previous = at;\n\n const length = textRef.current.length;\n const pending = length - cursorRef.current;\n if (pending <= 0) {\n commit(at, true);\n return;\n }\n\n const perSecond = clamp(\n pending / (DRAIN_TARGET_MS / 1000),\n MIN_CHARS_PER_SECOND,\n MAX_CHARS_PER_SECOND,\n );\n cursorRef.current = Math.min(\n length,\n cursorRef.current + (perSecond * elapsed) / 1000,\n );\n\n const done = cursorRef.current >= length;\n commit(at, done);\n if (!done) schedule();\n };\n\n const schedule = (): void => {\n if (typeof window.requestAnimationFrame === \"function\") {\n const id = window.requestAnimationFrame(step);\n cancelStep = () => window.cancelAnimationFrame(id);\n return;\n }\n const id = setTimeout(step, FALLBACK_STEP_MS);\n cancelStep = () => clearTimeout(id);\n };\n\n schedule();\n return () => {\n cancelled = true;\n cancelStep?.();\n };\n }, [text, immediate]);\n\n return text.slice(0, cut);\n}\n","\"use client\";\n\nimport { useCallback, useEffect, useRef, useState } from \"react\";\n\n/**\n * Dictation for the explore composer, on the browser's own speech recogniser.\n *\n * Uses the Web Speech API directly — no dependency, no network call of our own, no audio ever\n * leaving the browser through us. Support is genuinely partial (Chrome, Edge and Safari expose\n * it, most commonly behind the `webkit` prefix; Firefox does not implement it at all), so the\n * caller MUST hide the microphone entirely when `supported` is false rather than offering a\n * control that cannot work.\n *\n * Interim results are surfaced separately from final ones so the composer can show speech\n * appearing live while only committing settled text to the draft.\n *\n * ## Mobile\n *\n * Mobile took three separate fixes, each of which looked like the whole problem:\n *\n * 1. **The prompt never appeared.** `recognition.start()` raises the permission prompt on\n * desktop Chrome but on Android Chrome and iOS fires `not-allowed` without showing\n * anything, so a visitor who had never been asked was told to change a browser setting.\n * `getUserMedia` is what actually prompts, so it is primed first.\n * 2. **Granting still failed.** Recognition opens its OWN capture, and starting it in the same\n * tick that the primed stream is being torn down races that teardown. It now waits for the\n * release, and retries once — Android frequently refuses the first attempt after a\n * permission is newly granted and accepts the second.\n * 3. **`continuous` is not honoured on mobile.** Android Chrome ends the session after a\n * single utterance regardless, and asking for continuous mode makes it fail sooner. Mobile\n * therefore runs single-shot and is restarted from `onend` for as long as the visitor is\n * still dictating, which behaves like continuous without fighting the platform.\n */\n\ninterface SpeechRecognitionAlternativeLike {\n transcript: string;\n}\ninterface SpeechRecognitionResultLike {\n readonly isFinal: boolean;\n readonly length: number;\n [index: number]: SpeechRecognitionAlternativeLike;\n}\ninterface SpeechRecognitionEventLike {\n readonly resultIndex: number;\n readonly results: {\n readonly length: number;\n [index: number]: SpeechRecognitionResultLike;\n };\n}\ninterface SpeechRecognitionErrorEventLike {\n readonly error: string;\n}\ninterface SpeechRecognitionLike {\n lang: string;\n continuous: boolean;\n interimResults: boolean;\n maxAlternatives: number;\n start: () => void;\n stop: () => void;\n abort: () => void;\n onresult: ((event: SpeechRecognitionEventLike) => void) | null;\n onerror: ((event: SpeechRecognitionErrorEventLike) => void) | null;\n onend: (() => void) | null;\n onstart: (() => void) | null;\n}\ntype SpeechRecognitionCtor = new () => SpeechRecognitionLike;\n\ninterface SpeechWindow {\n SpeechRecognition?: SpeechRecognitionCtor;\n webkitSpeechRecognition?: SpeechRecognitionCtor;\n}\n\nfunction getRecognitionCtor(): SpeechRecognitionCtor | null {\n if (typeof window === \"undefined\") return null;\n const w = window as unknown as SpeechWindow;\n return w.SpeechRecognition ?? w.webkitSpeechRecognition ?? null;\n}\n\n/**\n * Coarse pointer means a touch device, which is what actually predicts the recogniser's\n * behaviour here — not the screen size, and not a UA string that lies.\n */\nfunction isTouchDevice(): boolean {\n if (typeof window === \"undefined\" || !window.matchMedia) return false;\n try {\n return window.matchMedia(\"(pointer: coarse)\").matches;\n } catch {\n return false;\n }\n}\n\nconst MIC_DENIED_MESSAGE =\n \"Microphone access was blocked. Allow it in your browser's site settings to dictate.\";\nconst MIC_UNAVAILABLE_MESSAGE =\n \"Dictation isn't available in this browser. You can type instead.\";\n\n/** Let a released capture settle before recognition opens its own. */\nconst RELEASE_SETTLE_MS = 250;\n/** Android often refuses the first start after a fresh grant and accepts the next. */\nconst RETRY_DELAY_MS = 350;\n\nconst sleep = (ms: number): Promise<void> =>\n new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\n\n/**\n * Ask for the microphone the only way that reliably raises a prompt on mobile.\n *\n * `confirmed` reports whether access was actually VERIFIED, which is what separates \"you need\n * to grant this\" from \"your browser cannot do this\" further down.\n *\n * Must be called synchronously from the user gesture that requested dictation — awaiting\n * anything first spends the gesture and the browser then rejects the request outright.\n */\nasync function ensureMicrophoneAccess(): Promise<\n | { ok: true; confirmed: boolean; primed: boolean }\n | { ok: false; message: string }\n> {\n const media =\n typeof navigator === \"undefined\" ? undefined : navigator.mediaDevices;\n // Older/unusual browsers without mediaDevices: fall through and let recognition try. It\n // may well work, and refusing here would remove dictation from browsers that support it.\n if (!media?.getUserMedia)\n return { ok: true, confirmed: false, primed: false };\n\n // `granted` means the prompt would not appear anyway, so skip the extra capture — which\n // also avoids the teardown race entirely on repeat use.\n //\n // A `denied` reading is deliberately NOT trusted to short-circuit. The Permissions API\n // reports `denied` for a prompt the visitor merely dismissed, and its microphone support\n // is uneven across mobile browsers — believing it would recreate the exact bug this\n // function exists to fix, telling someone to change a setting instead of asking them.\n // getUserMedia is the authoritative check, and when access really is denied it rejects\n // immediately without showing anything, so the only cost of asking is a settled promise.\n //\n // `permissions` is absent on Safari and `microphone` is not a valid name everywhere, so\n // every part of this is optional and failure is non-fatal.\n try {\n const status = await navigator.permissions?.query({\n name: \"microphone\" as PermissionName,\n });\n if (status?.state === \"granted\")\n return { ok: true, confirmed: true, primed: false };\n } catch {\n /* permissions API unavailable or the name is unsupported — prompt below instead */\n }\n\n try {\n const stream = await media.getUserMedia({ audio: true });\n // Release immediately: this capture existed only to raise the prompt, and leaving it\n // open would show a recording indicator for the whole session — and on mobile would\n // occupy the very microphone recognition is about to ask for.\n for (const track of stream.getTracks()) track.stop();\n return { ok: true, confirmed: true, primed: true };\n } catch (error) {\n const name =\n typeof error === \"object\" && error !== null && \"name\" in error\n ? String((error as { name: unknown }).name)\n : \"\";\n if (name === \"NotAllowedError\" || name === \"SecurityError\") {\n return { ok: false, message: MIC_DENIED_MESSAGE };\n }\n if (name === \"NotFoundError\" || name === \"DevicesNotFoundError\") {\n return { ok: false, message: \"No microphone was found.\" };\n }\n return {\n ok: false,\n message: \"Dictation could not start. You can type instead.\",\n };\n }\n}\n\n/** Messages a visitor can act on. `not-allowed` is the one that needs real explanation. */\nfunction describeError(code: string): string {\n switch (code) {\n case \"not-allowed\":\n case \"service-not-allowed\":\n return MIC_DENIED_MESSAGE;\n case \"no-speech\":\n return \"I didn't catch anything — try again a little closer to the mic.\";\n case \"audio-capture\":\n return \"No microphone was found.\";\n case \"network\":\n return \"Speech recognition needs a network connection.\";\n case \"aborted\":\n return \"\";\n default:\n return \"Dictation stopped unexpectedly. You can type instead.\";\n }\n}\n\nexport interface UseSpeechInputOptions {\n /** Receives settled text as it is recognised. Append it to the draft. */\n onFinalTranscript: (text: string) => void;\n /** BCP-47 tag. Defaults to the browser's language. */\n lang?: string;\n /** Called when the recogniser reports a problem worth showing. */\n onError?: (message: string) => void;\n}\n\nexport interface UseSpeechInputResult {\n /** False when the browser has no speech recogniser — hide the control entirely. */\n supported: boolean;\n listening: boolean;\n /** Words recognised but not yet settled; render as a live hint, do not store. */\n interim: string;\n error: string | null;\n start: () => void;\n stop: () => void;\n toggle: () => void;\n}\n\nexport function useSpeechInput({\n onFinalTranscript,\n lang,\n onError,\n}: UseSpeechInputOptions): UseSpeechInputResult {\n const [supported] = useState(() => getRecognitionCtor() !== null);\n const [listening, setListening] = useState(false);\n const [interim, setInterim] = useState(\"\");\n const [error, setError] = useState<string | null>(null);\n\n const recognitionRef = useRef<SpeechRecognitionLike | null>(null);\n /**\n * Bumped on every start()/stop(). A permission prompt, a settle delay or a retry resolving\n * after the visitor moved on must not open a microphone behind them.\n */\n const startTokenRef = useRef(0);\n /**\n * True only when the microphone was actually VERIFIED for this attempt — permission\n * reported granted, or getUserMedia succeeded. Stays false on browsers with no\n * mediaDevices, where nothing was checked and a recogniser `not-allowed` may still be a\n * real permission problem.\n */\n const micConfirmedRef = useRef(false);\n /** The visitor's intent, as opposed to whether a session happens to be open right now. */\n const wantsListeningRef = useRef(false);\n /** One retry per start(), for the Android \"refuses the first attempt\" case. */\n const retriedRef = useRef(false);\n\n // Held in refs so the recogniser's long-lived handlers always call the latest closures\n // without tearing down and re-creating the recogniser on every render.\n const finalRef = useRef(onFinalTranscript);\n const errorRef = useRef(onError);\n finalRef.current = onFinalTranscript;\n errorRef.current = onError;\n\n const langRef = useRef(lang);\n langRef.current = lang;\n\n const stop = useCallback(() => {\n startTokenRef.current += 1;\n wantsListeningRef.current = false;\n setListening(false);\n setInterim(\"\");\n const recognition = recognitionRef.current;\n if (!recognition) return;\n try {\n recognition.stop();\n } catch {\n /* already stopped */\n }\n }, []);\n\n /** Open a recogniser session. Separate from start() so a retry can reuse it. */\n const openSession = useCallback((token: number) => {\n const Ctor = getRecognitionCtor();\n if (!Ctor || token !== startTokenRef.current) return;\n\n const recognition = new Ctor();\n recognition.lang =\n langRef.current ??\n (typeof navigator === \"undefined\"\n ? \"en-US\"\n : navigator.language || \"en-US\");\n // Continuous mode is a desktop-only affordance. Android Chrome ends the session after a\n // single utterance whatever this says, and asking for continuous makes it fail sooner —\n // mobile is restarted from `onend` instead, which behaves the same to the visitor.\n recognition.continuous = !isTouchDevice();\n recognition.interimResults = true;\n recognition.maxAlternatives = 1;\n\n recognition.onstart = () => {\n if (token !== startTokenRef.current) return;\n // NOTE: the retry budget is deliberately NOT reset here. It belongs to the visitor's\n // press, not to the session — a browser that fires onstart and then immediately\n // errors would otherwise retry forever.\n setError(null);\n setListening(true);\n };\n\n recognition.onresult = (event) => {\n if (token !== startTokenRef.current) return;\n let settled = \"\";\n let pending = \"\";\n for (let i = event.resultIndex; i < event.results.length; i += 1) {\n const result = event.results[i];\n if (!result) continue;\n const text = result[0]?.transcript ?? \"\";\n if (result.isFinal) settled += text;\n else pending += text;\n }\n setInterim(pending);\n if (settled.trim() !== \"\") finalRef.current(settled);\n };\n\n recognition.onerror = (event) => {\n if (token !== startTokenRef.current) return;\n\n // Android commonly refuses the FIRST start after a permission is newly granted and\n // accepts the next one. Retry once, silently, before telling the visitor anything —\n // an error message they can do nothing about is worse than a short pause.\n if (\n (event.error === \"not-allowed\" ||\n event.error === \"service-not-allowed\") &&\n micConfirmedRef.current &&\n !retriedRef.current\n ) {\n retriedRef.current = true;\n void sleep(RETRY_DELAY_MS).then(() => {\n if (token !== startTokenRef.current || !wantsListeningRef.current)\n return;\n openSessionRef.current?.(token);\n });\n return;\n }\n\n // The microphone was verified moments ago, so a `not-allowed` that survived the retry\n // is the SPEECH SERVICE refusing, not a permission the visitor can grant. Sending them\n // to a site setting would point at something that cannot help.\n const message =\n micConfirmedRef.current &&\n (event.error === \"not-allowed\" || event.error === \"service-not-allowed\")\n ? MIC_UNAVAILABLE_MESSAGE\n : describeError(event.error);\n\n wantsListeningRef.current = false;\n setListening(false);\n setInterim(\"\");\n if (message !== \"\") {\n setError(message);\n errorRef.current?.(message);\n }\n };\n\n recognition.onend = () => {\n if (token !== startTokenRef.current) return;\n setInterim(\"\");\n // Single-shot mobile sessions end after each utterance. While the visitor still has\n // dictation switched on, reopen so it behaves like continuous mode.\n if (wantsListeningRef.current && isTouchDevice()) {\n void sleep(120).then(() => {\n if (token !== startTokenRef.current || !wantsListeningRef.current)\n return;\n openSessionRef.current?.(token);\n });\n return;\n }\n setListening(false);\n };\n\n recognitionRef.current = recognition;\n try {\n recognition.start();\n } catch {\n // Chrome throws InvalidStateError if start() races a session that is still closing.\n // The onend handler above will not fire for a session that never began, so settle here.\n wantsListeningRef.current = false;\n setListening(false);\n }\n }, []);\n\n // openSession refers to itself from its own handlers (retry, mobile restart), which a plain\n // const cannot do inside useCallback.\n const openSessionRef = useRef<((token: number) => void) | null>(null);\n openSessionRef.current = openSession;\n\n const start = useCallback(() => {\n if (!getRecognitionCtor()) return;\n\n startTokenRef.current += 1;\n const token = startTokenRef.current;\n wantsListeningRef.current = true;\n retriedRef.current = false;\n micConfirmedRef.current = false;\n\n // Show the pressed state straight away: the permission prompt can sit on screen for a\n // while on mobile, and a mic button that looks inert invites a second tap.\n setError(null);\n setListening(true);\n\n void ensureMicrophoneAccess().then(async (access) => {\n // A stop() or a newer start() landed while the prompt was open — abandon this attempt.\n if (token !== startTokenRef.current) return;\n\n if (!access.ok) {\n wantsListeningRef.current = false;\n setListening(false);\n setError(access.message);\n errorRef.current?.(access.message);\n return;\n }\n\n micConfirmedRef.current = access.confirmed;\n\n // Recognition opens its own capture. Starting in the same tick that the primed stream\n // is being torn down races that teardown and is refused — this is what made \"I granted\n // it and it still says blocked\" happen on mobile.\n if (access.primed) {\n await sleep(RELEASE_SETTLE_MS);\n if (token !== startTokenRef.current) return;\n }\n\n openSessionRef.current?.(token);\n });\n }, []);\n\n const toggle = useCallback(() => {\n if (listening) stop();\n else start();\n }, [listening, start, stop]);\n\n // Never leave the microphone open behind a closed page.\n useEffect(\n () => () => {\n startTokenRef.current += 1;\n wantsListeningRef.current = false;\n const recognition = recognitionRef.current;\n if (!recognition) return;\n recognition.onresult = null;\n recognition.onerror = null;\n recognition.onend = null;\n recognition.onstart = null;\n try {\n recognition.abort();\n } catch {\n /* nothing to abort */\n }\n },\n [],\n );\n\n return { supported, listening, interim, error, start, stop, toggle };\n}\n","\"use client\";\n\nimport { useCallback, useEffect, useRef, useState } from \"react\";\n\n/**\n * Read an answer aloud, on the browser's own speech synthesiser.\n *\n * The other half of {@link useSpeechInput}: that one turns a visitor's voice into a\n * question, this one turns our answer back into speech. Same posture — the Web Speech API\n * directly, no dependency, no request of ours, no cost, and nothing leaves the browser.\n *\n * ## Why `supported` can go false after a press\n *\n * `window.speechSynthesis` existing proves nothing. Several browsers expose the object and\n * then never speak: some Android WebViews with no TTS engine installed, Chrome on a machine\n * with no voices, and any engine where the utterance is refused without an `error` event.\n * There is no capability flag for that, so the only honest test is to try once — a press\n * that neither starts nor errors within {@link SILENT_FAILURE_MS}, while\n * `speechSynthesis.speaking` is still false, means this browser cannot do it and the control\n * removes itself. A button that does nothing, twice, is worse than no button.\n *\n * ## One voice per page\n *\n * `speechSynthesis` is a single queue shared by the whole document, so two answers reading\n * at once is not a thing the platform can do — a second `speak()` would simply queue behind\n * the first, minutes later. Every instance of this hook therefore registers with the\n * module-level owner below, and taking the voice stops whoever had it. {@link stopSpeaking}\n * is the same handle for code that is not a hook: the composer calls it when a new message\n * is sent, because an answer still reading aloud over the next question is the complaint\n * people actually make about pages that talk.\n */\n\ninterface SpeechSynthesisVoiceLike {\n readonly lang: string;\n readonly name: string;\n readonly default: boolean;\n}\n\ninterface SpeechSynthesisUtteranceLike {\n text: string;\n lang: string;\n voice: SpeechSynthesisVoiceLike | null;\n onstart: (() => void) | null;\n onend: (() => void) | null;\n onerror: ((event: { error?: string }) => void) | null;\n}\n\ntype SpeechSynthesisUtteranceCtor = new (\n text: string,\n) => SpeechSynthesisUtteranceLike;\n\ninterface SpeechSynthesisLike {\n readonly speaking: boolean;\n speak: (utterance: SpeechSynthesisUtteranceLike) => void;\n cancel: () => void;\n getVoices: () => SpeechSynthesisVoiceLike[];\n}\n\ninterface SpeechOutputWindow {\n speechSynthesis?: SpeechSynthesisLike;\n SpeechSynthesisUtterance?: SpeechSynthesisUtteranceCtor;\n}\n\n/** How long a press has to produce speech before the browser is taken at its word. */\nconst SILENT_FAILURE_MS = 1500;\n\n/**\n * The two API pieces, or null when this browser has no synthesiser at all (every iOS\n * in-app WebView without the entitlement, and anything server-side).\n */\nfunction speechPlatform(): {\n synth: SpeechSynthesisLike;\n Utterance: SpeechSynthesisUtteranceCtor;\n} | null {\n if (typeof window === \"undefined\") return null;\n const scope = window as unknown as SpeechOutputWindow;\n const synth = scope.speechSynthesis;\n const Utterance = scope.SpeechSynthesisUtterance;\n if (!synth || typeof synth.speak !== \"function\") return null;\n if (typeof Utterance !== \"function\") return null;\n return { synth, Utterance };\n}\n\n/** Lowercased, `-` separated: platforms spell the same tag `en_US`, `en-us` and `en-US`. */\nfunction normaliseTag(tag: string): string {\n return tag.trim().toLowerCase().replace(/_/g, \"-\");\n}\n\nfunction primaryOf(tag: string): string {\n return normaliseTag(tag).split(\"-\")[0] ?? \"\";\n}\n\n/**\n * The best voice for `lang`, or null to let the platform choose.\n *\n * Exact tag first (`ta-IN` over `ta-LK`), then the platform's default for the language, then\n * anything speaking it. Null rather than a wrong-language voice: an utterance with no voice\n * and the right `lang` is read by the platform's own fallback, which is closer than reading\n * Tamil with an English voice.\n */\nexport function pickVoice(\n voices: readonly SpeechSynthesisVoiceLike[],\n lang: string,\n): SpeechSynthesisVoiceLike | null {\n const wanted = normaliseTag(lang);\n if (wanted === \"\") return null;\n const primary = primaryOf(wanted);\n\n const exact = voices.filter((voice) => normaliseTag(voice.lang) === wanted);\n const related = voices.filter((voice) => primaryOf(voice.lang) === primary);\n\n return (\n exact.find((voice) => voice.default) ??\n exact[0] ??\n related.find((voice) => voice.default) ??\n related[0] ??\n null\n );\n}\n\n/** Whoever currently holds the page's one voice, and how to take it off them. */\nlet activeOwner: object | null = null;\nlet activeStop: (() => void) | null = null;\n\n/**\n * Stop whatever this SDK is reading aloud, from outside a component.\n *\n * A no-op when nothing of ours is speaking — deliberately, rather than calling\n * `speechSynthesis.cancel()` unconditionally, which would also silence a host page that is\n * using the same queue for its own reasons.\n */\nexport function stopSpeaking(): void {\n activeStop?.();\n}\n\nexport interface UseSpeechOutputOptions {\n /** BCP-47 tag to read in. Omit to let the platform pick its default voice. */\n lang?: string;\n}\n\nexport interface UseSpeechOutputResult {\n /**\n * False when this browser has no synthesiser, or has one that was asked to speak and did\n * not. Render no control at all when it is false — see the note at the top of the file.\n */\n supported: boolean;\n speaking: boolean;\n speak: (text: string) => void;\n stop: () => void;\n toggle: (text: string) => void;\n}\n\nexport function useSpeechOutput({\n lang,\n}: UseSpeechOutputOptions = {}): UseSpeechOutputResult {\n const [available, setAvailable] = useState(() => speechPlatform() !== null);\n const [speaking, setSpeaking] = useState(false);\n\n /** The utterance this instance is waiting on. Also \"do we own the voice right now\". */\n const utteranceRef = useRef<SpeechSynthesisUtteranceLike | null>(null);\n const watchdogRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n /** A stable identity for this instance, so the module-level owner can be compared. */\n const ownerRef = useRef<object>({});\n /** Lets the owner registration call the latest `stop` without re-registering. */\n const stopRef = useRef<() => void>(() => undefined);\n\n const langRef = useRef(lang);\n langRef.current = lang;\n\n const clearWatchdog = useCallback(() => {\n if (watchdogRef.current === null) return;\n clearTimeout(watchdogRef.current);\n watchdogRef.current = null;\n }, []);\n\n /** Forget this turn without touching the platform — for `end`, `error` and the watchdog. */\n const settle = useCallback(() => {\n clearWatchdog();\n utteranceRef.current = null;\n if (activeOwner === ownerRef.current) {\n activeOwner = null;\n activeStop = null;\n }\n setSpeaking(false);\n }, [clearWatchdog]);\n\n const stop = useCallback(() => {\n // Only cancel a queue we are actually using. Unmounting one answer's controls must not\n // silence a different answer that is mid-sentence.\n const owned = utteranceRef.current !== null;\n settle();\n if (owned) speechPlatform()?.synth.cancel();\n }, [settle]);\n\n stopRef.current = stop;\n\n const speak = useCallback(\n (text: string) => {\n const platform = speechPlatform();\n if (!platform) {\n setAvailable(false);\n return;\n }\n const spoken = text.trim();\n if (spoken === \"\") return;\n\n // Take the page's one voice, and clear anything already queued on it.\n if (activeStop && activeOwner !== ownerRef.current) activeStop();\n platform.synth.cancel();\n\n const utterance = new platform.Utterance(spoken);\n const wanted = langRef.current;\n if (wanted !== undefined && wanted !== \"\") {\n // Voices are fetched at press time rather than subscribed to: `getVoices()` is\n // empty until the platform has loaded them, and by the time a visitor has read an\n // answer and reached for this button, it has.\n const voice = pickVoice(platform.synth.getVoices(), wanted);\n utterance.lang = voice?.lang ?? wanted;\n if (voice) utterance.voice = voice;\n }\n\n const mine = (): boolean => utteranceRef.current === utterance;\n utterance.onstart = () => {\n if (!mine()) return;\n clearWatchdog();\n setSpeaking(true);\n };\n utterance.onend = () => {\n if (!mine()) return;\n settle();\n };\n utterance.onerror = (event) => {\n if (!mine()) return;\n const code = typeof event?.error === \"string\" ? event.error : \"\";\n settle();\n // `interrupted`/`canceled` is our own `cancel()` coming back — the visitor pressed\n // stop, or sent another message. Anything else is the engine refusing, and a\n // control that has now failed once is a control worth removing.\n if (code !== \"interrupted\" && code !== \"canceled\") setAvailable(false);\n };\n\n utteranceRef.current = utterance;\n activeOwner = ownerRef.current;\n activeStop = () => {\n stopRef.current();\n };\n // Optimistic, like the microphone: the engine can take a moment to start and a\n // control that looks inert invites a second press.\n setSpeaking(true);\n platform.synth.speak(utterance);\n\n clearWatchdog();\n watchdogRef.current = setTimeout(() => {\n watchdogRef.current = null;\n if (!mine()) return;\n // It is talking and simply never fired `start` — leave it alone.\n if (platform.synth.speaking) return;\n settle();\n setAvailable(false);\n }, SILENT_FAILURE_MS);\n },\n [clearWatchdog, settle],\n );\n\n const toggle = useCallback(\n (text: string) => {\n if (speaking) stop();\n else speak(text);\n },\n [speak, speaking, stop],\n );\n\n // A page that keeps talking after you leave it is the failure people complain about.\n // `pagehide` covers a real navigation and a bfcache freeze alike; unmount covers an SPA\n // route change and the transcript being reset.\n useEffect(() => {\n if (!speaking || typeof window === \"undefined\") return;\n const onHide = () => {\n stopRef.current();\n };\n window.addEventListener(\"pagehide\", onHide);\n return () => window.removeEventListener(\"pagehide\", onHide);\n }, [speaking]);\n\n useEffect(\n () => () => {\n stopRef.current();\n },\n [],\n );\n\n return { supported: available, speaking, speak, stop, toggle };\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 * PageHead Component\n * Manages dynamic meta tags for SEO optimization on a per-page basis.\n * Supports JSON-LD structured data, Open Graph, Twitter Cards, favicons, and robots directives.\n *\n * @example\n * ```tsx\n * <PageHead\n * title=\"About Us\"\n * description=\"Learn about our mission and team\"\n * productName=\"MyProduct\"\n * keywords=\"about, team, mission\"\n * image=\"/og-about.png\"\n * url=\"https://myproduct.com/about\"\n * favicon=\"/favicon.ico\"\n * robots=\"index, follow\"\n * locale=\"en_US\"\n * twitterHandle=\"@burdenoff\"\n * themeColor=\"#1a1a2e\"\n * structuredData={{\n * \"@context\": \"https://schema.org\",\n * \"@type\": \"WebPage\",\n * name: \"About Us\",\n * }}\n * />\n * ```\n */\n\nimport { Helmet } from \"react-helmet-async\";\n\nexport interface PageHeadProps {\n /** Page title */\n title: string;\n /** Meta description */\n description?: string;\n /** Product/brand name (appended to title) */\n productName?: string;\n /** SEO keywords */\n keywords?: string;\n /** Open Graph image URL */\n image?: string;\n /** Page canonical URL */\n url?: string;\n /** Favicon URL */\n favicon?: string;\n /** Robots directive (e.g., \"index, follow\") */\n robots?: string;\n /** Open Graph locale (e.g., \"en_US\") */\n locale?: string;\n /** Twitter handle (e.g., \"@burdenoff\") */\n twitterHandle?: string;\n /** Theme color for mobile browsers */\n themeColor?: string;\n /** JSON-LD structured data objects */\n structuredData?: Record<string, unknown> | Array<Record<string, unknown>>;\n /** Additional meta tags */\n additionalMeta?: Array<{\n name?: string;\n property?: string;\n content: string;\n }>;\n}\n\n/**\n * Build a self-referencing canonical URL from the current location.\n *\n * Query strings and hashes are dropped (they never identify a distinct\n * canonical document here) and the trailing slash is normalised away for\n * everything but the site root. Returns `undefined` outside a DOM so the\n * component degrades to its previous behaviour under plain string rendering.\n */\nfunction canonicalFromLocation(): string | undefined {\n if (typeof window === \"undefined\" || !window.location) return undefined;\n const { origin, pathname } = window.location;\n if (!origin || origin === \"null\") return undefined;\n const path = pathname === \"/\" ? \"/\" : pathname.replace(/\\/+$/, \"\");\n return `${origin}${path}`;\n}\n\n/**\n * Absolutise an Open Graph image URL.\n *\n * Already-absolute URLs pass through. A root-relative path resolves against\n * the origin, and any other relative path against the page URL. Without a\n * resolvable base the original value is returned unchanged.\n */\nfunction resolveImageUrl(\n image: string | undefined,\n base: string | undefined,\n): string | undefined {\n if (!image || /^https?:\\/\\//i.test(image)) return image;\n if (!base) return image;\n try {\n return new URL(image, base).toString();\n } catch {\n return image;\n }\n}\n\n/**\n * JSON-LD as the body of a `<script>` element.\n *\n * `JSON.stringify` leaves `<` alone, and a script body ends at the first `</script` whatever\n * the quoting around it. The prerender serialises the live DOM with script text verbatim,\n * so a `</script><script>…` inside any string field (a caption, a title) would close the\n * JSON-LD block in the static HTML and run what follows. `\\u003c` is the same character to\n * every JSON parser; U+2028 / U+2029 are escaped for engines that still read them as line\n * breaks.\n */\nfunction serializeJsonLd(data: Record<string, unknown>): string {\n return JSON.stringify(data)\n .replace(/</g, \"\\\\u003c\")\n .replace(/\\u2028/g, \"\\\\u2028\")\n .replace(/\\u2029/g, \"\\\\u2029\");\n}\n\nexport function PageHead({\n title,\n description,\n productName,\n keywords,\n image,\n url,\n favicon,\n robots = \"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\",\n locale = \"en_US\",\n twitterHandle,\n themeColor = \"#000000\",\n structuredData,\n additionalMeta,\n}: PageHeadProps) {\n const fullTitle =\n productName && !title.includes(productName)\n ? `${title} | ${productName}`\n : title;\n\n // Self-referencing canonical by default.\n //\n // Without this, a route that renders PageHead but omits `url` emits no\n // canonical at all, so the static `<link rel=\"canonical\">` in index.html\n // survives and every such page declares itself a duplicate of the home\n // page — Google then drops /pricing, /privacy, /terms and friends from the\n // index. Deriving it from the current location keeps each page pointing at\n // itself; callers that genuinely need a cross-canonical still pass `url`.\n //\n // During prerender the DOM location already reflects the route being\n // rendered, so this resolves correctly ahead of hydration.\n const resolvedUrl = url ?? canonicalFromLocation();\n\n // Root-relative images (\"/og.png\") belong to the ORIGIN, not to the current\n // path — concatenating them onto the page URL yields /features/og.png and a\n // broken share card. Anything else is resolved relative to the page itself.\n const fullImageUrl = resolveImageUrl(image, resolvedUrl);\n\n // Normalize structured data to an array\n const structuredDataItems: Array<Record<string, unknown>> = structuredData\n ? Array.isArray(structuredData)\n ? structuredData\n : [structuredData]\n : [];\n\n return (\n <Helmet>\n {/* Primary Meta Tags */}\n <title>{fullTitle}</title>\n <meta name=\"title\" content={fullTitle} />\n {description && <meta name=\"description\" content={description} />}\n {keywords && <meta name=\"keywords\" content={keywords} />}\n <meta name=\"author\" content=\"Burdenoff Consultancy Services Pvt Ltd\" />\n <meta name=\"robots\" content={robots} />\n\n {/* Canonical URL */}\n {resolvedUrl && <link rel=\"canonical\" href={resolvedUrl} />}\n\n {/* Favicon */}\n {favicon && <link rel=\"icon\" href={favicon} />}\n\n {/* Open Graph / Facebook */}\n <meta property=\"og:type\" content=\"website\" />\n <meta property=\"og:title\" content={fullTitle} />\n {description && <meta property=\"og:description\" content={description} />}\n {fullImageUrl && <meta property=\"og:image\" content={fullImageUrl} />}\n {resolvedUrl && <meta property=\"og:url\" content={resolvedUrl} />}\n <meta property=\"og:locale\" content={locale} />\n {productName && <meta property=\"og:site_name\" content={productName} />}\n\n {/* Twitter Card */}\n <meta name=\"twitter:card\" content=\"summary_large_image\" />\n <meta name=\"twitter:title\" content={fullTitle} />\n {description && <meta name=\"twitter:description\" content={description} />}\n {fullImageUrl && <meta name=\"twitter:image\" content={fullImageUrl} />}\n {twitterHandle && <meta name=\"twitter:creator\" content={twitterHandle} />}\n\n {/* Theme Color */}\n <meta name=\"theme-color\" content={themeColor} />\n\n {/* JSON-LD Structured Data */}\n {structuredDataItems.map((data, index) => (\n <script key={`ld-${index}`} type=\"application/ld+json\">\n {serializeJsonLd(data)}\n </script>\n ))}\n\n {/* Additional Meta Tags */}\n {additionalMeta?.map((meta, index) => (\n <meta\n key={`meta-${index}`}\n {...(meta.name ? { name: meta.name } : {})}\n {...(meta.property ? { property: meta.property } : {})}\n content={meta.content}\n />\n ))}\n </Helmet>\n );\n}\n","import * as React from \"react\";\n\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\n\nimport { cn } from \"../utils/cn\";\n\nconst buttonVariants = cva(\n \"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0\",\n {\n variants: {\n variant: {\n default:\n \"bg-primary text-primary-foreground shadow hover:bg-primary/90\",\n destructive:\n \"bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90\",\n outline:\n \"border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground\",\n secondary:\n \"bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80\",\n ghost: \"hover:bg-accent hover:text-accent-foreground\",\n link: \"text-primary underline-offset-4 hover:underline\",\n },\n size: {\n default: \"h-9 px-4 py-2\",\n sm: \"h-8 rounded-md px-3 text-xs\",\n lg: \"h-10 rounded-md px-8\",\n icon: \"h-9 w-9\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n },\n);\n\nexport interface ButtonProps\n extends\n React.ButtonHTMLAttributes<HTMLButtonElement>,\n VariantProps<typeof buttonVariants> {\n asChild?: boolean;\n}\n\nconst Button = React.forwardRef<HTMLButtonElement, ButtonProps>(\n ({ className, variant, size, asChild = false, ...props }, ref) => {\n const Comp = asChild ? Slot : \"button\";\n return (\n <Comp\n className={cn(buttonVariants({ variant, size, className }))}\n ref={ref}\n {...props}\n />\n );\n },\n);\nButton.displayName = \"Button\";\n\nexport { Button, buttonVariants };\n","import * as React from \"react\";\n\nimport { cn } from \"../utils/cn\";\n\nconst Textarea = React.forwardRef<\n HTMLTextAreaElement,\n React.ComponentProps<\"textarea\">\n>(({ className, ...props }, ref) => {\n return (\n <textarea\n className={cn(\n \"flex min-h-[60px] w-full rounded-md border border-input bg-transparent px-3 py-2 text-base shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm\",\n className,\n )}\n ref={ref}\n {...props}\n />\n );\n});\nTextarea.displayName = \"Textarea\";\n\nexport { Textarea };\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 { useCallback, useEffect, useMemo, useRef, useState } 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} from \"./explore-answer\";\nimport {\n type ExploreLocale,\n type ExploreStrings,\n exploreStrings,\n fill,\n isRtlLocale,\n resolveExploreLocale,\n speechLocaleOf,\n} from \"./explore-i18n\";\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 { useExploreChat } 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\";\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.\n */\nexport {\n answerPlainText,\n answerSpeechText,\n inlineImageOrigins,\n isInlineImageAllowed,\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 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\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\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@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.45);\n box-shadow:\n 0 0 0 4px hsl(var(--primary) / 0.08),\n 0 8px 24px -12px hsl(var(--primary) / 0.45);\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.07), 0 8px 24px -12px hsl(var(--primary) / 0.40); }\n 50% { box-shadow: 0 0 0 7px hsl(var(--primary) / 0.13), 0 8px 28px -12px hsl(var(--primary) / 0.55); }\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/* ---- 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\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 },\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 },\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 },\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/** 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}: {\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 const speech = useSpeechOutput({ lang });\n if (!speech.supported) return null;\n\n const label = speech.speaking ? T.stopReading : T.readAloud;\n return (\n <button\n data-boff-explore=\"read-aloud\"\n data-speaking={speech.speaking ? \"true\" : \"false\"}\n type=\"button\"\n title={label}\n aria-pressed={speech.speaking}\n onClick={() => speech.toggle(text)}\n className={cn(\n ANSWER_ACTION_PILL,\n speech.speaking ? ANSWER_ACTION_ACTIVE : ANSWER_ACTION_IDLE,\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}: {\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}) {\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 strings={T} text={speechText} lang={speechLang} />\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 productNames,\n speechLang,\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 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 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 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 />\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 prompts,\n onPrompt,\n disabled,\n}: {\n strings: ExploreStrings;\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 return (\n <div\n className=\"flex min-w-0 touch-pan-y items-center gap-1.5\"\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 {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=\"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\"\n >\n <ChevronLeft className=\"h-4 w-4\" />\n </button>\n ) : null}\n\n <button\n key={current}\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. */\n className=\"boff-explore-fade group flex min-w-0 flex-1 items-center gap-2 rounded-full border border-border bg-card px-4 py-2 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 >\n <Sparkles className=\"h-3.5 w-3.5 shrink-0 text-primary\" />\n <span className=\"truncate\">{current}</span>\n <ArrowUp className=\"ml-auto h-3.5 w-3.5 shrink-0 rotate-45 text-muted-foreground transition-colors group-hover:text-primary\" />\n </button>\n\n {count > 1 ? (\n <button\n type=\"button\"\n aria-label={T.nextSuggestion}\n onClick={() => go(1)}\n className=\"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\"\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 ? \"flex-wrap\" : \"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 <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={focusProduct === product.slug}\n title={product.tagline ?? product.name}\n onClick={() =>\n onFocus(focusProduct === product.slug ? null : product.slug)\n }\n className={chipClass(focusProduct === product.slug)}\n >\n {product.name}\n </button>\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 // 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(el.scrollLeft > 1);\n setCanRight(el.scrollLeft + el.clientWidth < el.scrollWidth - 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 return () => window.removeEventListener(\"resize\", onResize);\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-5\"\n >\n <p className=\"mb-2 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 className=\"boff-explore-strip flex min-w-0 snap-x gap-3 overflow-x-auto pb-1\"\n >\n {visible.map((highlight) => (\n <li\n key={`${highlight.product}:${highlight.url}`}\n className=\"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-48\"\n >\n <span className=\"relative block aspect-[16/9] 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=\"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-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=\"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}: {\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}) {\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-5 sm:py-6\">\n <div className=\"boff-explore-rise text-center\">\n <span className=\"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 <h1 className=\"mt-3 text-balance break-words text-2xl font-bold tracking-tight sm:text-3xl\">\n {title}\n </h1>\n <p className=\"mx-auto mt-2 max-w-2xl text-pretty text-sm leading-relaxed text-muted-foreground sm:text-base\">\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. */}\n <ul className=\"boff-explore-rise boff-explore-rise-1 mt-5 grid grid-cols-3 gap-2 sm:gap-2.5\">\n {CAPABILITIES.map(({ icon: Icon, body: capBody }, i) => (\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-3 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-normal\">\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 </ul>\n\n {prompts.length > 0 ? (\n <div className=\"boff-explore-rise boff-explore-rise-2 mt-5\">\n <p className=\"mb-2 text-xs font-semibold uppercase tracking-wide text-muted-foreground\">\n {T.tryAsking}\n </p>\n <PromptCarousel\n strings={T}\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-5\">\n <p className=\"mb-2 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\nexport function ExplorePage({\n seo,\n productSlug,\n examplePrompts,\n className,\n heightMode = \"viewport\",\n viewportOffset,\n onNavigate,\n onSend,\n welcomeTitle,\n welcomeBody,\n locale,\n}: ExplorePageProps) {\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 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 } = useExploreChat({\n productSlug,\n pageUrl,\n onSend,\n // Locale-aware, so a catalog outage degrades to a translated welcome rather than an\n // English one. `T.prompts` seeds the chips the same way.\n examplePrompts: examplePrompts ?? T.prompts,\n fallbackWelcome: { title: T.welcomeTitle, body: T.welcomeBody },\n });\n\n const [draft, setDraft] = useState(\"\");\n const textareaRef = useRef<HTMLTextAreaElement>(null);\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 // 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 [staged, setStaged] = useState<StagedAttachment[]>([]);\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 const resolvedTitle = welcomeTitle ?? catalog.welcomeTitle;\n const resolvedBody = welcomeBody ?? catalog.welcomeBody;\n // Resolution order (catalog → prop → SDK built-in) lives in the hook, which\n // seeds its fallback catalog from the `examplePrompts` prop.\n const prompts = catalog.examplePrompts;\n\n const focusedProductName = useMemo(\n () => catalog.products.find((p) => p.slug === focusProduct)?.name ?? null,\n [catalog.products, focusProduct],\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.\n const headProductName = useMemo(\n () =>\n productSlug\n ? (catalog.products.find((p) => p.slug === productSlug)?.name ?? null)\n : null,\n [catalog.products, 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\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 (heightMode !== \"viewport\") 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 }, [heightMode]);\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 if (typeof window === \"undefined\") 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]);\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 (heightMode !== \"viewport\" || 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 }, [heightMode, 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 useEffect(() => {\n if (typeof window === \"undefined\") 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 }, []);\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.\n if (!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]);\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 (!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]);\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 const url = 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 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],\n );\n\n const removeAttachment = useCallback((id: string) => {\n setStaged((prev) => prev.filter((entry) => entry.id !== id));\n setAttachmentNotice(null);\n }, []);\n\n // --- send --------------------------------------------------------------\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 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 }, [busy, canSend, draft, overLimit, send, stopDictation]);\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 // 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, send],\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 // 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 (heightMode === \"viewport\") {\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=\"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 \"flex w-full min-w-0 flex-col overflow-x-hidden bg-background text-foreground\",\n heightMode === \"viewport\" && \"boff-explore-viewport\",\n heightMode === \"auto\" && \"min-h-[70vh]\",\n className,\n )}\n style={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 <PageHead\n title={seo?.title ?? T.seoTitle}\n description={\n seo?.description ??\n (headProductName\n ? fill(T.seoDescriptionProduct, { product: headProductName })\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 <ProseStyles />\n <ExploreStyles />\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 <h1 className=\"truncate text-sm font-semibold\">{resolvedTitle}</h1>\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 strings={T}\n title={resolvedTitle}\n body={resolvedBody}\n prompts={prompts}\n products={catalog.products}\n conceptHighlights={catalog.conceptHighlights}\n focusProduct={focusProduct}\n onPrompt={sendPrompt}\n onFocus={setFocusProduct}\n disabled={!canSend || busy}\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 productNames={productNames}\n speechLang={speechLang}\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 {error ? (\n <ErrorBanner error={error} onRetry={retry} onReset={reset} />\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 \"flex min-w-0 items-end gap-2 rounded-2xl border bg-card p-2 shadow-sm transition-all\",\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(T.placeholderProduct, {\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 <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 title={speech.listening ? T.stopDictating : T.dictate}\n onClick={speech.toggle}\n className={cn(speech.listening && \"animate-pulse\")}\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\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 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"]}
|
|
1
|
+
{"version":3,"sources":["../../src/content/Markdown.tsx","../../src/utils/cn.ts","../../src/components/explore-answer.tsx","../../src/components/explore-i18n.ts","../../src/components/explore-types.ts","../../src/content/prose-styles.tsx","../../src/client/security.ts","../../src/client/graphql-client.ts","../../src/client/provider.tsx","../../src/data/products.ts","../../src/utils/recaptcha-v3.ts","../../src/hooks/use-explore-chat.ts","../../src/hooks/use-progressive-reveal.ts","../../src/hooks/use-speech-input.ts","../../src/hooks/use-speech-output.ts","../../src/hooks/use-swipe.ts","../../src/seo/page-head.tsx","../../src/ui/button.tsx","../../src/ui/textarea.tsx","../../src/utils/explore-attachments.ts","../../src/components/explore.tsx"],"names":["jsx","createContext","useContext","useMemo","useState","useCallback","open","useRef","useEffect","id","jsxs","React2","clamp","delta","HistoryIcon"],"mappings":"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","file":"explore.mjs","sourcesContent":["import type { ComponentProps, ReactNode } from \"react\";\n\nimport ReactMarkdown from \"react-markdown\";\nimport rehypeSanitize from \"rehype-sanitize\";\nimport remarkGfm from \"remark-gfm\";\n\nimport type { Components, ExtraProps } from \"react-markdown\";\n\nexport interface MarkdownProps {\n /** Markdown source to render. */\n children: string;\n /** Additional classes for the wrapper element. */\n className?: string;\n /** Render without a wrapping block element, suitable for inline content. */\n inline?: boolean;\n /** Optional react-markdown component overrides. */\n components?: Components;\n}\n\n/**\n * The default markdown link: external links open in a new tab, every link gets safe `rel`\n * attributes. Exported so a caller overriding `a` (to add context around links, say) can\n * still render the same element.\n */\nexport function MarkdownLink({\n href,\n children,\n // react-markdown passes the hast node to every override; it is not a DOM attribute.\n node: _node,\n ...props\n}: ComponentProps<\"a\"> & ExtraProps) {\n const isExternal =\n typeof href === \"string\" &&\n (href.startsWith(\"http://\") || href.startsWith(\"https://\"));\n return (\n <a\n href={href}\n {...props}\n {...(isExternal\n ? { target: \"_blank\", rel: \"noopener noreferrer\" }\n : { rel: \"noopener noreferrer\" })}\n >\n {children}\n </a>\n );\n}\n\nconst defaultComponents: Components = {\n a: MarkdownLink,\n};\n\n/**\n * Shared markdown renderer for website content.\n *\n * - Uses `react-markdown` for standards-compliant parsing.\n * - Enables GitHub Flavored Markdown (tables, task lists, strikethrough, autolinks).\n * - Sanitizes HTML via `rehype-sanitize` so raw markup in markdown is stripped.\n * - External links open in a new tab with safe rel attributes.\n */\nexport function Markdown({\n children,\n className,\n inline,\n components,\n}: MarkdownProps): ReactNode {\n const content = (\n <ReactMarkdown\n remarkPlugins={[remarkGfm]}\n rehypePlugins={[rehypeSanitize]}\n components={{ ...defaultComponents, ...components }}\n {...(inline ? { disallowedElements: [\"p\"], unwrapDisallowed: true } : {})}\n >\n {children}\n </ReactMarkdown>\n );\n\n if (inline) {\n return <span className={className}>{content}</span>;\n }\n\n return <div className={className}>{content}</div>;\n}\n","/**\n * Utility function to merge Tailwind CSS classes\n * Combines clsx and tailwind-merge for optimal class handling\n */\n\nimport { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Merge multiple class names intelligently\n * - Handles conditional classes via clsx\n * - Deduplicates and resolves Tailwind conflicts via tailwind-merge\n *\n * @example\n * ```ts\n * cn('px-4 py-2', 'bg-blue-500', { 'text-white': isActive })\n * // => 'px-4 py-2 bg-blue-500 text-white' (if isActive is true)\n * ```\n */\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\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/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 — 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 useMemo,\n useState,\n} from \"react\";\nimport type { ComponentProps, ReactElement } from \"react\";\n\nimport { Markdown, MarkdownLink } from \"../content/Markdown\";\nimport { cn } from \"../utils/cn\";\n\nimport type { ExploreProduct } from \"./explore-types\";\nimport type { Components, ExtraProps } 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\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 (Botlit ships on www.botlit.ai, 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 * 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 */\nexport function isInlineImageAllowed(\n src: unknown,\n origins: ReadonlySet<string>,\n): src is string {\n if (typeof src !== \"string\" || src === \"\") return false;\n let url: URL;\n try {\n url = new URL(src);\n } catch {\n return false;\n }\n if (url.protocol !== \"https:\" || url.username || url.password) return false;\n return origins.has(url.origin);\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 two places — links and tables —\n * and nowhere else, which is why they are one function and not two.\n */\ntype ReadableFor = \"clipboard\" | \"speech\";\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 // Images before links: `` also matches the link pattern.\n line = line.replace(/!\\[[^\\]]*\\]\\([^)\\s]*(?:\\s+\"[^\"]*\")?\\)/g, \"\");\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(/\\[([^\\]]+)\\]\\(([^)\\s]+)(?:\\s+\"[^\"]*\")?\\)/g, \"$1\")\n : line.replace(/\\[([^\\]]+)\\]\\(([^)\\s]+)(?:\\s+\"[^\"]*\")?\\)/g, \"$1 ($2)\");\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 * - **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 two 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 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 three fields rather than the whole `ExploreStrings`: the chat and a published\n * answer page carry different chrome vocabularies, and these three are the only words the\n * ANSWER itself needs. `ExploreStrings` satisfies this structurally, so the chat passes its\n * own `T` unchanged.\n */\nexport interface AnswerRendererStrings {\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}\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 /** 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\nfunction AnswerLink(props: ComponentProps<\"a\"> & ExtraProps) {\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 children?: MarkdownNode[];\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 * 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\nexport interface ExploreAnswerBodyProps {\n /** The answer, exactly as the harness wrote it: GitHub-flavoured markdown. */\n children: string;\n /** The three 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 * False while the answer is still streaming, which suppresses its images: a partial is cut\n * mid-token, so an image URL in it may be half-written, and the backend has not yet dropped\n * the images it does not allow. A settled answer — every published one — is `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 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 failed,\n onFailed,\n }),\n [strings, enabled, imageOrigins, failed, onFailed],\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}>{children}</Markdown>\n </AnswerScopeContext.Provider>\n </div>\n );\n}\n","/**\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 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 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 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 /** 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 capabilities: [string, string, string];\n prompts: string[];\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 you're facing, in your own words. You can also ask about a specific product or compare a few. 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 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 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 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 you're facing 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 you're facing 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 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 \"Which of your products fits a problem like mine?\",\n ],\n};\n\nconst ZH: ExploreStrings = {\n badge: \"基于我们文档的 AI 回答\",\n welcomeTitle: \"你想解决什么问题?\",\n welcomeBody:\n \"用你自己的话描述你遇到的问题。你也可以询问某一款产品,或比较几款产品。所有回答都直接来自我们的文档。\",\n tryAsking: \"试着问\",\n focusProduct: \"聚焦某个产品\",\n allProducts: \"全部产品\",\n showAll: \"全部\",\n showLess: \"收起\",\n sources: \"来源\",\n nextYouCouldAsk: \"你还可以问\",\n placeholder: \"描述你的问题…\",\n placeholderProduct: \"描述问题,或询问 {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 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 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 capabilities: [\"基于我们自己的文档\", \"跨产品对比\", \"直达正确的页面\"],\n prompts: [\n \"每门课程都记在不同的表格里。\",\n \"机器停了,要等整条线停下来才知道。\",\n \"会员慢慢就不来了,我们也不知道为什么。\",\n \"哪个产品适合我这样的问题?\",\n ],\n};\n\nconst HI: ExploreStrings = {\n badge: \"हमारे दस्तावेज़ों पर आधारित AI उत्तर\",\n welcomeTitle: \"आप कौन सी समस्या हल करना चाहते हैं?\",\n welcomeBody:\n \"अपनी समस्या अपने शब्दों में बताएं। आप किसी एक उत्पाद के बारे में भी पूछ सकते हैं या कुछ की तुलना कर सकते हैं। हर उत्तर सीधे हमारे दस्तावेज़ से आता है।\",\n tryAsking: \"यह पूछकर देखें\",\n focusProduct: \"किसी उत्पाद पर ध्यान दें\",\n allProducts: \"सभी उत्पाद\",\n showAll: \"सभी\",\n showLess: \"कम दिखाएँ\",\n sources: \"स्रोत\",\n nextYouCouldAsk: \"आगे आप पूछ सकते हैं\",\n placeholder: \"अपनी समस्या बताएं…\",\n placeholderProduct: \"समस्या बताएं, या {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 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 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 capabilities: [\n \"हमारे अपने दस्तावेज़ों पर आधारित\",\n \"सभी उत्पादों की तुलना करें\",\n \"सीधे सही पेज पर\",\n ],\n prompts: [\n \"हर कोर्स का हिसाब अलग शीट में रखा जाता है।\",\n \"मशीन बंद होने का पता तभी चलता है जब लाइन रुक जाए।\",\n \"सदस्य धीरे-धीरे आना बंद कर देते हैं, वजह पता नहीं चलती।\",\n \"मेरी जैसी समस्या के लिए कौन सा उत्पाद सही है?\",\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 que tienes con tus propias palabras. También puedes preguntar por un producto concreto o comparar varios. 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 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 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 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 con tus palabras el problema que tienes 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 con tus palabras el problema que tienes 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 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 \"¿Qué producto encaja con un problema como el mío?\",\n ],\n};\n\nconst AR: ExploreStrings = {\n badge: \"إجابات ذكاء اصطناعي مبنية على وثائقنا\",\n welcomeTitle: \"ما المشكلة التي تحاول حلها؟\",\n welcomeBody:\n \"صف المشكلة التي تواجهها بكلماتك أنت. يمكنك أيضًا السؤال عن منتج بعينه أو المقارنة بين عدة منتجات. تأتي كل إجابة مباشرة من وثائقنا.\",\n tryAsking: \"جرّب أن تسأل\",\n focusProduct: \"التركيز على منتج\",\n allProducts: \"كل المنتجات\",\n showAll: \"الكل\",\n showLess: \"عرض أقل\",\n sources: \"المصادر\",\n nextYouCouldAsk: \"يمكنك أن تسأل بعد ذلك\",\n placeholder: \"صف المشكلة…\",\n placeholderProduct: \"صف مشكلتك أو اسأل عن {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 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 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 capabilities: [\n \"مبني على وثائقنا\",\n \"قارن عبر المنظومة\",\n \"مباشرةً إلى الصفحة الصحيحة\",\n ],\n prompts: [\n \"كل دورة تدريبية لدينا في جدول بيانات مختلف.\",\n \"لا نعلم بتعطل الماكينة إلا بعد توقف خط الإنتاج.\",\n \"أعضاؤنا يتوقفون عن الحضور تدريجيًا دون أن نعرف السبب.\",\n \"أي منتج يناسب مشكلة مثل مشكلتي؟\",\n ],\n};\n\nconst TA: ExploreStrings = {\n badge: \"எங்கள் ஆவணங்களை அடிப்படையாகக் கொண்ட AI பதில்கள்\",\n welcomeTitle: \"நீங்கள் எந்தச் சிக்கலைத் தீர்க்க முயல்கிறீர்கள்?\",\n welcomeBody:\n \"நீங்கள் எதிர்கொள்ளும் சிக்கலை உங்கள் சொந்த வார்த்தைகளில் விவரியுங்கள். ஒரு குறிப்பிட்ட தயாரிப்பு பற்றியும் கேட்கலாம், சிலவற்றை ஒப்பிடவும் செய்யலாம். ஒவ்வொரு பதிலும் எங்கள் ஆவணப்படுத்தலிலிருந்து நேரடியாக வருகிறது.\",\n tryAsking: \"இதைக் கேட்டுப் பாருங்கள்\",\n focusProduct: \"ஒரு தயாரிப்பில் கவனம்\",\n allProducts: \"அனைத்து தயாரிப்புகள்\",\n showAll: \"அனைத்தும்\",\n showLess: \"குறைவாகக் காட்டு\",\n sources: \"மூலங்கள்\",\n nextYouCouldAsk: \"அடுத்து நீங்கள் கேட்கலாம்\",\n placeholder: \"சிக்கலை விவரியுங்கள்…\",\n placeholderProduct:\n \"சிக்கலை விவரியுங்கள், அல்லது {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 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 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 capabilities: [\n \"எங்கள் சொந்த ஆவணங்களின் அடிப்படையில்\",\n \"தயாரிப்புகளை ஒப்பிடுங்கள்\",\n \"நேராக சரியான பக்கத்திற்கு\",\n ],\n prompts: [\n \"ஒவ்வொரு பயிற்சி வகுப்பும் வெவ்வேறு விரிதாளில் உள்ளது.\",\n \"இயந்திரம் நின்றது லைன் நிற்கும்போதுதான் தெரிய வருகிறது.\",\n \"உறுப்பினர்கள் மெல்ல வருவதை நிறுத்துகிறார்கள், காரணம் தெரியாது.\",\n \"என் பிரச்சினைக்கு எந்தத் தயாரிப்பு பொருந்தும்?\",\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/** Substitute `{product}` and friends without pulling in a formatting library. */\nexport function fill(template: string, values: Record<string, string>): string {\n return template.replace(/\\{(\\w+)\\}/g, (match, key) => values[key] ?? match);\n}\n","/**\n * Explore chat — TypeScript mirror of the public `/explore` GraphQL contract.\n *\n * Canonical source: `~/products/dev/platform/context/explore/CONTRACT.md` §1\n * (global-support-svc, served through the global PUBLIC gateway with\n * `@rbac(public: true, scopeType: \"global\")`).\n *\n * Nothing in this file may drift from that document. If a shape here looks\n * wrong, fix CONTRACT.md first and tell the backend workstreams — never patch\n * it locally.\n *\n * Nullability note: the contract marks `title`, `description`, `product`,\n * `imageUrl`, `partialContent`, `errorCode`, `completedAt`, `productSlug`,\n * `recaptchaSiteKey` and `remainingToday` as nullable, so every one of them is\n * `?: T | null` here — a GraphQL `null` and an omitted selection both have to\n * be representable.\n */\n\n// ============================================================================\n// Enums (string unions — the wire format is the enum name)\n// ============================================================================\n\nexport type ExploreMessageRole = \"USER\" | \"ASSISTANT\";\n\nexport type ExploreMessageStatus =\n \"PENDING\" | \"RUNNING\" | \"COMPLETED\" | \"FAILED\";\n\n/** `enum ExploreFeedbackRating` — the visitor's verdict on one answer. */\nexport type ExploreFeedbackRating = \"HELPFUL\" | \"NOT_HELPFUL\";\n\n/**\n * The reasons offered alongside `NOT_HELPFUL`, in the order the chooser shows them.\n *\n * `reason` is `String` on the wire, not an enum, so this list is the SDK's half of the\n * agreement rather than something the schema enforces — the same treatment\n * {@link ExploreCtaKind} gets. Use the union when you are *producing* a reason; read one\n * back as a plain string.\n */\nexport const EXPLORE_FEEDBACK_REASONS = [\n \"INACCURATE\",\n \"INCOMPLETE\",\n \"OFF_TOPIC\",\n \"HARD_TO_FOLLOW\",\n \"OTHER\",\n] as const;\n\nexport type ExploreFeedbackReason = (typeof EXPLORE_FEEDBACK_REASONS)[number];\n\n/**\n * The `ExploreCta.kind` values enumerated in CONTRACT.md §1.\n *\n * `ExploreCtaLink.kind` is deliberately typed `string`, not this union: the\n * field is `String!` on the wire, and a kind added server-side must render\n * (falling back to the neutral CTA style) rather than break the build of 38\n * websites. Use this union when you are *producing* a kind.\n */\nexport type ExploreCtaKind =\n | \"CONTACT\"\n | \"PARTNERS\"\n | \"PRICING\"\n | \"SERVICES\"\n | \"WAITLIST\"\n | \"STORE\"\n | \"APP\"\n | \"DOCS\"\n | \"OTHER\";\n\n/**\n * Error codes surfaced through `extensions.code`. `HTTP_429` is what the\n * gateway emits when it rate-limits at the edge; the SDK client also produces\n * `TIMEOUT` / `NETWORK_ERROR` for transport failures.\n */\nexport type ExploreErrorCode =\n | \"EXPLORE_DISABLED\"\n | \"RATE_LIMITED\"\n | \"EXPLORE_GLOBAL_LIMIT\"\n | \"CAPTCHA_REQUIRED\"\n | \"CAPTCHA_FAILED\"\n | \"MESSAGE_TOO_LONG\"\n | \"MESSAGE_EMPTY\"\n | \"CONVERSATION_LIMIT\"\n | \"CONVERSATION_BUSY\"\n | \"UPSTREAM_UNAVAILABLE\"\n | \"NOT_FOUND\"\n // Handover-only. `INVALID_EMAIL` is the server's verdict on an address the client's own\n // pre-flight let through, and has to be shown rather than folded into a generic failure.\n | \"INVALID_EMAIL\"\n | \"ESCALATION_FAILED\"\n | \"HTTP_429\"\n | \"TIMEOUT\"\n | \"NETWORK_ERROR\";\n\n// ============================================================================\n// Object types\n// ============================================================================\n\n/** `type ExploreReference` — a cited source page for an answer. */\nexport interface ExploreReference {\n url: string;\n title?: string | null;\n description?: string | null;\n product?: string | null;\n imageUrl?: string | null;\n /** 1-based citation number; the answer text carries a matching `[n]` marker. */\n index?: number | null;\n}\n\n/**\n * `type ExploreCta` — a suggested next step attached to an answer.\n *\n * Named `ExploreCtaLink` in the SDK because `ExploreCta` is taken by the\n * exported nav component (`<ExploreCta variant=\"header\" />`). Same shape,\n * different name; the GraphQL type is unchanged.\n */\nexport interface ExploreCtaLink {\n /** One of {@link ExploreCtaKind}; unknown values render with the neutral style. */\n kind: string;\n label: string;\n url: string;\n product?: string | null;\n}\n\n/**\n * `type ExploreFeedback` — what is on record for one answer, as the server holds it.\n *\n * A rating REPLACES the previous one (the server upserts on `messageId`), so this is the\n * visitor's current opinion and never a history. `reason` is null for `HELPFUL` by\n * definition, and typed `string` rather than the union because it is `String` on the wire —\n * a reason added server-side must read back, not break the build of 38 websites.\n */\nexport interface ExploreFeedback {\n rating: ExploreFeedbackRating;\n /** One of {@link EXPLORE_FEEDBACK_REASONS}. Null for `HELPFUL`. */\n reason?: string | null;\n comment?: string | null;\n createdAt: string;\n}\n\n/** `type ExploreMessage`. `content` is `\"\"` while the turn is PENDING. */\nexport interface ExploreMessage {\n id: string;\n conversationId: string;\n role: ExploreMessageRole;\n status: ExploreMessageStatus;\n /** Final answer, markdown. Empty string until the turn completes. */\n content: string;\n /** Streaming preview while PENDING/RUNNING. */\n partialContent?: string | null;\n /** Human-readable progress lines, e.g. \"Searching vibecontrols…\". */\n activity: string[];\n references: ExploreReference[];\n ctas: ExploreCtaLink[];\n /** Up to three suggested next questions, derived from what the answer covered. */\n followUps?: string[] | null;\n /**\n * False when the corpus could not answer. A grounded answer always cites, so an answer\n * with no source is the honest \"we do not have this\" signal rather than a hedge.\n */\n answered?: boolean | null;\n /** Files the visitor attached to this turn. Present on USER messages only. */\n attachments?: ExploreAttachment[] | null;\n /**\n * The rating this visitor already gave this answer, or null for an unrated one.\n *\n * Selected only by the reads scoped to a `conversationToken`, so a polled or restored\n * transcript shows what was already rated instead of offering the row again. It is always\n * null on a SHARED transcript — that read is performed by someone else, and the rater's\n * verdict and free-text note are not theirs to receive. See\n * `EXPLORE_OWN_MESSAGE_FIELDS`.\n */\n feedback?: ExploreFeedback | null;\n errorCode?: string | null;\n createdAt: string;\n completedAt?: string | null;\n}\n\n/** `type ExploreConversation`. `token` is the client's only handle. */\nexport interface ExploreConversation {\n id: string;\n token: string;\n productSlug?: string | null;\n turnCount: number;\n createdAt: string;\n}\n\n/** `type ExploreProduct` — one product the harness can answer about. */\nexport interface ExploreProduct {\n slug: string;\n name: string;\n tagline?: string | null;\n website: string;\n}\n\n/** `type ExploreLimits` — server-owned caps the composer enforces locally. */\nexport interface ExploreLimits {\n maxMessageLength: number;\n maxTurnsPerConversation: number;\n messagesPerDay: number;\n historyTurns: number;\n}\n\n/**\n * `type ExploreConceptHighlight` — one published concept illustration, offered\n * as a way into the conversation before the visitor has typed anything.\n *\n * Every field is non-null on the wire: a highlight with no picture or no\n * destination is not a highlight, so the server drops it rather than sending a\n * half-built one. `product` is the slug, `productName` the display casing the\n * product's own pages use.\n *\n * The pictures are the published concept mockups — illustrations of an idea,\n * not screenshots of shipping software — which is why every surface that shows\n * one also labels it (`ExploreStrings.conceptIllustration`).\n */\nexport interface ExploreConceptHighlight {\n product: string;\n productName: string;\n title: string;\n url: string;\n imageUrl: string;\n alt: string;\n}\n\n/**\n * `type ExploreCatalog` — everything the page needs before the first message.\n *\n * `captchaRequired` + `recaptchaSiteKey` are what turn reCAPTCHA v3 on: it is\n * a backend secret change, and no website redeploy is involved.\n */\nexport interface ExploreCatalog {\n enabled: boolean;\n products: ExploreProduct[];\n examplePrompts: string[];\n welcomeTitle: string;\n welcomeBody: string;\n limits: ExploreLimits;\n captchaRequired: boolean;\n recaptchaSiteKey?: string | null;\n /**\n * At most 8, the site's own product first. Non-null and non-nullable per the\n * contract, so a gateway that knows the field always sends an array.\n *\n * A gateway that does NOT know it yet does not answer without it — it refuses\n * the whole document (`GRAPHQL_VALIDATION_FAILED`), which is why the hook\n * retries with `EXPLORE_CATALOG_QUERY_WITHOUT_HIGHLIGHTS` instead of falling\n * back to the built-in catalog. That retry is the one response that reaches\n * `normalizeCatalog` with this field absent, and the hardening there is what\n * keeps `catalog.conceptHighlights.filter(...)` from throwing in render.\n */\n conceptHighlights: ExploreConceptHighlight[];\n}\n\n/** `input SendExploreMessageInput`. */\nexport interface SendExploreMessageInput {\n /** Omit to start a new conversation. */\n conversationToken?: string;\n /** The site the visitor is on — a soft hint, not a hard filter. */\n productSlug?: string;\n message: string;\n /** Only sent when `catalog.captchaRequired`. */\n recaptchaToken?: string;\n locale?: string;\n pageUrl?: string;\n /**\n * Files attached as extra context. At most 5, each at most 10 MB — re-enforced server-side,\n * so these are the limits the composer shows, not the limits that hold.\n */\n attachments?: ExploreAttachmentInput[];\n}\n\n/** `input ExploreAttachmentInput`. `textContent` is null for a format the browser cannot read. */\nexport interface ExploreAttachmentInput {\n name: string;\n mimeType: string;\n size: number;\n textContent: string | null;\n}\n\n/** `type ExploreAttachment` — what the server accepted, echoed back. */\nexport interface ExploreAttachment {\n name: string;\n mimeType: string;\n size: number;\n /** False when only the filename and type could be used as context. */\n textExtracted: boolean;\n}\n\n/**\n * `type SendExploreMessageResult`.\n *\n * **`assistantMessage.id` is the id to poll** — it comes back `PENDING`.\n */\nexport interface SendExploreMessageResult {\n conversation: ExploreConversation;\n userMessage: ExploreMessage;\n assistantMessage: ExploreMessage;\n remainingToday?: number | null;\n}\n\n// ============================================================================\n// GraphQL documents\n//\n// Only the fields the UI actually renders are requested — a narrower selection\n// set is cheaper to poll (this runs once every ~1.5s per active visitor) and\n// keeps the contract surface the websites depend on small.\n// ============================================================================\n\n/**\n * Selection set for an `ExploreMessage` that ANYONE may read. Inlined as a\n * template string rather than a GraphQL `fragment` so each document stays a\n * single self-contained operation (the SDK client posts raw strings and has no\n * fragment registry).\n *\n * Deliberately WITHOUT `feedback` — see `EXPLORE_OWN_MESSAGE_FIELDS`.\n */\nconst EXPLORE_MESSAGE_FIELDS = /* GraphQL */ `\n id\n conversationId\n role\n status\n content\n partialContent\n activity\n references {\n url\n title\n description\n product\n imageUrl\n index\n }\n ctas {\n kind\n label\n url\n product\n }\n followUps\n answered\n attachments {\n name\n mimeType\n size\n textExtracted\n }\n errorCode\n createdAt\n completedAt\n`;\n\n/**\n * The same message PLUS the visitor's own rating of it.\n *\n * Used by the reads that are scoped to a `conversationToken`, so the person\n * making them is the person who rated the answer — that is what lets the row\n * come back already-rated after a reload instead of re-offering the choice.\n *\n * `EXPLORE_SHARED_CONVERSATION_QUERY` deliberately does NOT use this one. A\n * share link is the one read performed by somebody ELSE, and it exists to be\n * forwarded; `comment` is where a visitor types the specifics that made the\n * answer wrong for them — the price they are actually being charged, an\n * invoice number, a name — so it must not travel with a transcript sent to a\n * colleague. The server omits it there too; this is the client half of the\n * same rule, and keeping the selection sets separate is what stops a future\n * \"why are there two of these?\" tidy-up from re-merging them.\n */\nconst EXPLORE_OWN_MESSAGE_FIELDS = /* GraphQL */ `\n ${EXPLORE_MESSAGE_FIELDS}\n feedback {\n rating\n reason\n comment\n createdAt\n }\n`;\n\n/**\n * Everything on `ExploreCatalog` that every deployed gateway has served since\n * the surface shipped. Shared by both catalog documents below so the pair can\n * never drift: the ONLY difference between them is `conceptHighlights`.\n */\nconst EXPLORE_CATALOG_ESTABLISHED_FIELDS = /* GraphQL */ `\n enabled\n products {\n slug\n name\n tagline\n website\n }\n examplePrompts\n welcomeTitle\n welcomeBody\n limits {\n maxMessageLength\n maxTurnsPerConversation\n messagesPerDay\n historyTurns\n }\n captchaRequired\n recaptchaSiteKey`;\n\n/** The field added with the welcome strip — the only thing a new gateway has that an old one does not. */\nconst EXPLORE_CATALOG_HIGHLIGHT_FIELD = /* GraphQL */ `\n conceptHighlights {\n product\n productName\n title\n url\n imageUrl\n alt\n }`;\n\nfunction exploreCatalogDocument(extraFields: string): string {\n return /* GraphQL */ `\n query ExploreCatalog($productSlug: String) {\n exploreCatalog(productSlug: $productSlug) {${EXPLORE_CATALOG_ESTABLISHED_FIELDS}${extraFields}\n }\n }\n`;\n}\n\n/** Loaded once per page. Safe to serve from the SDK's 5-minute query cache. */\nexport const EXPLORE_CATALOG_QUERY = exploreCatalogDocument(\n EXPLORE_CATALOG_HIGHLIGHT_FIELD,\n);\n\n/**\n * The same catalog WITHOUT `conceptHighlights`, for a gateway whose supergraph\n * predates the field.\n *\n * This is not belt-and-braces. GraphQL validation is all-or-nothing: a gateway\n * that does not know the field rejects the ENTIRE document and returns no\n * `data` at all, so selecting `conceptHighlights` against an older supergraph\n * costs the whole catalog — `enabled`, `captchaRequired`, `recaptchaSiteKey`,\n * the welcome copy and `limits` included — and not merely the strip. Measured\n * against production:\n *\n * {\"errors\":[{\"message\":\"Cannot query field \\\\\"conceptHighlights\\\\\" on type\n * \\\\\"ExploreCatalog\\\\\".\",\"extensions\":{\"code\":\"GRAPHQL_VALIDATION_FAILED\"}}]}\n *\n * That window is guaranteed even with perfect deploy ordering, because the prod\n * gateway's CDN edge serves a stale supergraph for ~30-40 minutes after the\n * subgraph publishes. `useExploreChat` therefore retries with this document\n * (see `catalogRejectedTheHighlightField`) rather than dropping to the built-in\n * fallback, whose hardcoded `enabled: true` would ignore the server-side kill\n * switch and whose `captchaRequired: false` would let every send be rejected\n * server-side while the composer looked fine.\n */\nexport const EXPLORE_CATALOG_QUERY_WITHOUT_HIGHLIGHTS =\n exploreCatalogDocument(\"\");\n\n/**\n * The poll. MUST be issued with `client.query(..., { cache: false })` — the\n * default 5-minute cache would return the first PENDING snapshot forever and\n * the answer would never appear.\n */\nexport const EXPLORE_MESSAGE_QUERY = /* GraphQL */ `\n query ExploreMessage($conversationToken: String!, $id: ID!) {\n exploreMessage(conversationToken: $conversationToken, id: $id) {\n ${EXPLORE_OWN_MESSAGE_FIELDS}\n }\n }\n`;\n\n/** Submit half of the submit + poll pair. */\nexport const SEND_EXPLORE_MESSAGE_MUTATION = /* GraphQL */ `\n mutation SendExploreMessage($input: SendExploreMessageInput!) {\n sendExploreMessage(input: $input) {\n conversation {\n id\n token\n productSlug\n turnCount\n createdAt\n }\n userMessage {\n ${EXPLORE_OWN_MESSAGE_FIELDS}\n }\n assistantMessage {\n ${EXPLORE_OWN_MESSAGE_FIELDS}\n }\n remainingToday\n }\n }\n`;\n\n// ============================================================================\n// Response envelopes (what `client.query`/`client.mutate` resolve `data` to)\n// ============================================================================\n\nexport interface ExploreCatalogQueryData {\n exploreCatalog: ExploreCatalog;\n}\n\nexport interface ExploreMessageQueryData {\n exploreMessage: ExploreMessage | null;\n}\n\nexport interface SendExploreMessageMutationData {\n sendExploreMessage: SendExploreMessageResult;\n}\n\n/**\n * Record that the visitor followed a link the answer offered.\n *\n * Fire-and-forget: the browser is navigating away as this goes out, so the result is never\n * waited on and a failure is never surfaced. The server reports `recorded: false` rather\n * than erroring for anything it cannot attribute.\n */\nexport const RECORD_EXPLORE_CLICK_MUTATION = /* GraphQL */ `\n mutation RecordExploreClick($input: RecordExploreClickInput!) {\n recordExploreClick(input: $input) {\n recorded\n }\n }\n`;\n\n/** `input SubmitExploreFeedbackInput`. */\nexport interface SubmitExploreFeedbackInput {\n conversationToken: string;\n messageId: string;\n rating: ExploreFeedbackRating;\n /** Only meaningful with `NOT_HELPFUL`; stored null for `HELPFUL`. */\n reason?: ExploreFeedbackReason | null;\n /** Optional free text. Hard-capped server-side — never trusted from the client. */\n comment?: string | null;\n}\n\n/** `type SubmitExploreFeedbackResult`. */\nexport interface SubmitExploreFeedbackResult {\n /**\n * False — NOT an error — when the message is not a COMPLETED assistant turn, or when the\n * supplied `conversationToken` does not own it. Same posture as `recordExploreClick`: the\n * server declines to attribute rather than raising FORBIDDEN at a marketing visitor.\n */\n recorded: boolean;\n /** What is now on record, when the rating was taken. Null when `recorded` is false. */\n feedback?: ExploreFeedback | null;\n}\n\n/**\n * Rate one answer.\n *\n * Unlike {@link RECORD_EXPLORE_CLICK_MUTATION} this one IS awaited: the visitor is still on\n * the page and the control they just pressed has to end up telling the truth about whether\n * anything was recorded. The rating upserts on `messageId`, so re-rating is legal and a\n * second submit is never an error.\n */\nexport const SUBMIT_EXPLORE_FEEDBACK_MUTATION = /* GraphQL */ `\n mutation SubmitExploreFeedback($input: SubmitExploreFeedbackInput!) {\n submitExploreFeedback(input: $input) {\n recorded\n feedback {\n rating\n reason\n comment\n createdAt\n }\n }\n }\n`;\n\nexport interface SubmitExploreFeedbackMutationData {\n submitExploreFeedback: SubmitExploreFeedbackResult;\n}\n\n/**\n * How many characters the comment field accepts before it stops taking more.\n *\n * A courtesy so the box does not invite an essay it will lose, NOT a contract: the server\n * owns the real cap and may truncate or reject below this. Nothing here may be read as the\n * limit that holds.\n */\nexport const EXPLORE_FEEDBACK_COMMENT_SOFT_MAX = 500;\n\n// ============================================================================\n// Handing the conversation to a human (CONTRACT.md §1, \"Handing a conversation\n// to a human\")\n// ============================================================================\n\n/**\n * `input EscalateExploreConversationInput`.\n *\n * `email` is the only thing the visitor is asked for. It is **personal data**: it belongs in\n * this input and nowhere else — never in `localStorage`, never in an `ExploreMessage`, never\n * in an analytics call. See the note on {@link ESCALATE_EXPLORE_CONVERSATION_MUTATION}.\n */\nexport interface EscalateExploreConversationInput {\n /** The thread being handed over. A share (`?c=`) secret is NOT one. */\n conversationToken: string;\n /** Validated strictly server-side; a bad address comes back as `INVALID_EMAIL`. */\n email: string;\n /** Optional free text. Hard-capped server-side at 2000 and TRUNCATED, never rejected. */\n note?: string | null;\n /** Only when `exploreCatalog.captchaRequired`. Same v3 action as a chat message. */\n recaptchaToken?: string;\n /** `PlatformProduct` id of the site, so the ticket reaches that product's support inbox. */\n productId?: string;\n}\n\n/** `type ExploreEscalation` — the handover on record, as the SERVER holds it. */\nexport interface ExploreEscalation {\n /**\n * Where the reply is actually going.\n *\n * On a repeat submit this is the address the FIRST handover used, not the one just typed\n * into the box — so this is the value to show back, never the local draft.\n */\n email: string;\n createdAt: string;\n}\n\n/** `type EscalateExploreConversationResult`. */\nexport interface EscalateExploreConversationResult {\n /**\n * False when a handover already existed — the double-clicked button, the retried request,\n * the reloaded page.\n *\n * **Not an error.** The conversation is with a human either way, and the UI must read as\n * success on both values. The server enforces one handover per conversation with a UNIQUE\n * index rather than a check-then-insert, so two concurrent submits produce one ticket and\n * one of them gets this.\n */\n created: boolean;\n escalation: ExploreEscalation;\n}\n\n/**\n * Hand this conversation to a person.\n *\n * Awaited and NOT fire-and-forget (unlike {@link RECORD_EXPLORE_CLICK_MUTATION}): it is the\n * one explore write that throws, because it ends with a visitor being told a person has\n * their question. \"We passed it on\" must never be shown for a handover that did not happen.\n *\n * **The address the visitor types is personal data.** It travels in these variables and\n * stops there. Do not persist it, do not fold it into the transcript (`messages` is what the\n * hook writes to localStorage), and do not pass it to `onSend` or any analytics call — the\n * server already has everything a support agent needs.\n */\nexport const ESCALATE_EXPLORE_CONVERSATION_MUTATION = /* GraphQL */ `\n mutation EscalateExploreConversation(\n $input: EscalateExploreConversationInput!\n ) {\n escalateExploreConversation(input: $input) {\n created\n escalation {\n email\n createdAt\n }\n }\n }\n`;\n\nexport interface EscalateExploreConversationMutationData {\n escalateExploreConversation: EscalateExploreConversationResult;\n}\n\n/**\n * How many characters the note field accepts before it stops taking more.\n *\n * Mirrors the server's hard cap so the box does not invite text it will silently truncate.\n * Same status as {@link EXPLORE_FEEDBACK_COMMENT_SOFT_MAX}: a courtesy, not the limit that\n * holds.\n */\nexport const EXPLORE_ESCALATION_NOTE_SOFT_MAX = 2000;\n\n/**\n * A dot-atom local part, real DNS labels, an alphabetic TLD — the shape CONTRACT.md says the\n * server insists on.\n *\n * Deliberately no more permissive than that and deliberately no stricter: this exists to\n * catch the typo before a round-trip, not to be the authority. The server is the authority,\n * and the two DO disagree (an address this accepts can still come back `INVALID_EMAIL`),\n * which is why the form surfaces the server's verdict as well as this one.\n */\nconst DELIVERABLE_EMAIL =\n /^[A-Za-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[A-Za-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[A-Za-z0-9](?:[A-Za-z0-9-]*[A-Za-z0-9])?\\.)+[A-Za-z]{2,}$/;\n\n/**\n * Whether `value` is worth sending to the mutation at all.\n *\n * A local pre-flight, never a promise of deliverability. Keep it a SUBSET of what the server\n * accepts: a client that rejects something the server would have taken costs the visitor\n * their answer with nobody able to see why.\n */\nexport function looksLikeDeliverableEmail(value: string): boolean {\n const trimmed = value.trim();\n // 254 is the RFC 5321 ceiling on a forward path; anything longer cannot be delivered\n // anywhere, so it is a typo (or a paste of something that is not an address).\n if (trimmed.length === 0 || trimmed.length > 254) return false;\n return DELIVERABLE_EMAIL.test(trimmed);\n}\n\n/**\n * Mint a read-only link to this conversation.\n *\n * The returned secret is NOT the conversation token — it opens a read-only view and cannot\n * be used to continue the thread, so it is safe to put in a URL that gets forwarded.\n */\nexport const CREATE_EXPLORE_SHARE_LINK_MUTATION = /* GraphQL */ `\n mutation CreateExploreShareLink($conversationToken: String!) {\n createExploreShareLink(conversationToken: $conversationToken) {\n shareToken\n }\n }\n`;\n\n/**\n * Load a conversation someone shared, read-only.\n *\n * Takes the share secret from the `?c=` parameter, NOT a conversation token — the recipient\n * gets the transcript and no ability to continue or modify the thread.\n */\nexport const EXPLORE_SHARED_CONVERSATION_QUERY = /* GraphQL */ `\n query ExploreSharedConversation($shareToken: String!) {\n exploreSharedConversation(shareToken: $shareToken) {\n ${EXPLORE_MESSAGE_FIELDS}\n }\n }\n`;\n","\"use client\";\n\n/**\n * Self-contained prose styles for SDK content renderers.\n *\n * These components inject a scoped `.boff-prose` stylesheet so markdown content\n * renders correctly even when the host website does not install\n * `@tailwindcss/typography` or define `.prose` CSS.\n */\n\nexport const PROSE_CSS = `\n.boff-prose {\n max-width: none;\n}\n\n.boff-prose h1 {\n font-size: 2.25rem;\n font-weight: 800;\n line-height: 1.2;\n margin-top: 0;\n margin-bottom: 1rem;\n color: hsl(var(--foreground));\n}\n\n.boff-prose h2 {\n font-size: 1.75rem;\n font-weight: 700;\n line-height: 1.3;\n margin-top: 2rem;\n margin-bottom: 1rem;\n color: hsl(var(--foreground));\n}\n\n.boff-prose h3 {\n font-size: 1.5rem;\n font-weight: 600;\n line-height: 1.4;\n margin-top: 1.5rem;\n margin-bottom: 0.75rem;\n color: hsl(var(--foreground));\n}\n\n.boff-prose h4 {\n font-size: 1.25rem;\n font-weight: 600;\n line-height: 1.5;\n margin-top: 1.25rem;\n margin-bottom: 0.5rem;\n color: hsl(var(--foreground));\n}\n\n.boff-prose p {\n margin-bottom: 1rem;\n line-height: 1.75;\n color: hsl(var(--foreground));\n}\n\n.boff-prose ul,\n.boff-prose ol {\n margin-bottom: 1rem;\n padding-left: 1.5rem;\n}\n\n.boff-prose ul {\n list-style-type: disc;\n}\n\n.boff-prose ol {\n list-style-type: decimal;\n}\n\n.boff-prose li {\n margin-bottom: 0.25rem;\n line-height: 1.75;\n color: hsl(var(--foreground));\n}\n\n.boff-prose li > ul,\n.boff-prose li > ol {\n margin-top: 0.25rem;\n margin-bottom: 0.25rem;\n}\n\n.boff-prose a {\n color: hsl(var(--primary));\n text-decoration: underline;\n text-underline-offset: 2px;\n}\n\n.boff-prose a:hover {\n opacity: 0.8;\n}\n\n.boff-prose hr {\n border: none;\n height: 1px;\n background-color: hsl(var(--border));\n margin: 2rem 0;\n}\n\n.boff-prose blockquote {\n border-left: 4px solid hsl(var(--border));\n padding-left: 1rem;\n margin: 1.5rem 0;\n font-style: italic;\n color: hsl(var(--muted-foreground));\n}\n\n.boff-prose strong {\n font-weight: 700;\n color: hsl(var(--foreground));\n}\n\n.boff-prose code {\n background-color: hsl(var(--muted));\n padding: 0.125rem 0.25rem;\n border-radius: 0.25rem;\n font-size: 0.875em;\n font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace;\n}\n\n.boff-prose pre {\n background-color: hsl(var(--muted));\n padding: 1rem;\n border-radius: 0.5rem;\n overflow-x: auto;\n margin-bottom: 1rem;\n}\n\n.boff-prose pre code {\n background-color: transparent;\n padding: 0;\n}\n\n.boff-prose img {\n max-width: 100%;\n height: auto;\n}\n\n.boff-prose table {\n width: 100%;\n border-collapse: collapse;\n margin-bottom: 1rem;\n}\n\n.boff-prose th,\n.boff-prose td {\n border: 1px solid hsl(var(--border));\n padding: 0.5rem;\n text-align: left;\n}\n\n.boff-prose th {\n font-weight: 600;\n background-color: hsl(var(--muted));\n}\n\n/* Smaller variant used inside cards and compact panels */\n.boff-prose-sm {\n font-size: 0.875rem;\n}\n\n.boff-prose-sm h1 {\n font-size: 1.75rem;\n}\n\n.boff-prose-sm h2 {\n font-size: 1.5rem;\n}\n\n.boff-prose-sm h3 {\n font-size: 1.25rem;\n}\n\n.boff-prose-sm h4 {\n font-size: 1.125rem;\n}\n\n.boff-prose-sm p,\n.boff-prose-sm li {\n line-height: 1.625;\n}\n`;\n\nexport function ProseStyles() {\n return <style dangerouslySetInnerHTML={{ __html: PROSE_CSS }} />;\n}\n","const LOOPBACK_HOSTS = new Set([\"localhost\", \"127.0.0.1\", \"::1\"]);\nconst RESERVED_HEADERS = new Set([\n \"authorization\",\n \"cookie\",\n \"x-actor-id\",\n \"x-actor-type\",\n \"x-consent-granted-by\",\n \"x-consent-scope\",\n \"x-consent-granted-at\",\n \"x-consent-expires-at\",\n]);\n\nexport function validateGatewayUrl(value: string): string {\n let url: URL;\n\n try {\n url = new URL(value);\n } catch {\n throw new Error(\"Gateway URL must be a valid absolute URL\");\n }\n\n if (url.protocol === \"https:\") {\n return url.toString();\n }\n\n if (\n url.protocol === \"http:\" &&\n LOOPBACK_HOSTS.has(url.hostname.toLowerCase())\n ) {\n return url.toString();\n }\n\n throw new Error(\"Gateway URL must use HTTPS unless it targets localhost\");\n}\n\nexport function sanitizeHeaders(\n headers?: Record<string, string>,\n): Record<string, string> | undefined {\n if (!headers) return undefined;\n\n return Object.fromEntries(\n Object.entries(headers).filter(\n ([key]) => !RESERVED_HEADERS.has(key.toLowerCase()),\n ),\n );\n}\n\n/**\n * Hostnames whose Cloudflare Access application gates the GraphQL gateway.\n *\n * Only the alpha gateways are gated; the production gateways are public, so a token is never\n * attached there even if one is configured.\n */\nconst CF_ACCESS_GATED_HOSTS = new Set([\n \"alphagraphql.burdenoff.com\",\n \"alphagraphqlworkspaces.burdenoff.com\",\n]);\n\n/**\n * Service-token headers for a gated gateway, or nothing.\n *\n * Returns an empty object unless the target really is a gated host AND both halves of the token\n * are present — a half-configured token would send a malformed credential to every request.\n */\nexport function cfAccessHeaders(\n gatewayUrl: string,\n cfAccess?: { clientId?: string; clientSecret?: string },\n): Record<string, string> {\n const clientId = cfAccess?.clientId?.trim();\n const clientSecret = cfAccess?.clientSecret?.trim();\n if (!clientId || !clientSecret) return {};\n\n let host: string;\n try {\n host = new URL(gatewayUrl).hostname.toLowerCase();\n } catch {\n return {};\n }\n if (!CF_ACCESS_GATED_HOSTS.has(host)) return {};\n\n return {\n \"CF-Access-Client-Id\": clientId,\n \"CF-Access-Client-Secret\": clientSecret,\n };\n}\n","/**\n * Lightweight GraphQL client for the Burdenoff Web SDK.\n * Uses native fetch - zero external dependencies.\n * All calls are unauthenticated (public gateway operations only).\n */\n\nimport {\n cfAccessHeaders,\n sanitizeHeaders,\n validateGatewayUrl,\n} from \"./security\";\n\nexport interface WebSDKClientConfig {\n /** Global public gateway URL (e.g. \"https://api.burdenoff.com/global/graphql\") */\n gatewayUrl: string;\n /** Platform product ID for scoping operations */\n productId: string;\n /** Product slug (used for public product queries) */\n productSlug?: string;\n /** reCAPTCHA site key (if not fetched from product config) */\n recaptchaSiteKey?: string;\n /** Rybbit analytics site ID */\n rybbitSiteId?: string;\n /** Custom headers to include in all requests */\n headers?: Record<string, string>;\n /**\n * Cloudflare Access service token, for the ALPHA gateway hosts only.\n *\n * `alphagraphql.burdenoff.com` sits behind a Cloudflare Access application, so an\n * unauthenticated browser XHR is answered with a 302 to the Access login on a different\n * origin — which the browser reports as an opaque CORS failure rather than a 401. Attaching\n * the service-token headers is how every app shell already passes that gate (fe-libs\n * `installGatewayFetchRewrite`); the website SDK previously had no equivalent, so contact,\n * newsletter, waitlist and explore all failed on alpha.\n *\n * Vite only inlines `VITE_*` into APP source, never into a bundled library, so the host app\n * must read `import.meta.env` and pass the values in. Production gateways are not gated and\n * receive no headers.\n */\n cfAccess?: { clientId?: string; clientSecret?: string };\n /**\n * Per-request timeout in ms. Kept below the gateway's operation timeout so a\n * stalled request surfaces as an error the UI can render, instead of leaving\n * a page stuck on loading skeletons forever. Default 12000.\n */\n timeoutMs?: number;\n /**\n * Extra attempts for transient failures (timeout / network / 5xx / 429) on\n * QUERIES ONLY. Mutations are never retried — a retried contact-form or\n * waitlist submit would double-submit. Default 1 (2 attempts total).\n */\n maxRetries?: number;\n}\n\n/**\n * Per-call overrides for {@link WebSDKClient.query}.\n *\n * The defaults (5-minute response cache + in-flight deduplication) are right\n * for the read-once content queries most SDK components make, and wrong for a\n * poll loop: the second poll of the same `(query, variables)` pair would be\n * served straight from the cache and the UI would freeze on the first\n * response forever. Pass `{ cache: false }` for anything polled.\n */\nexport interface WebSDKQueryOptions {\n /**\n * Use the response cache and in-flight deduplication. Default `true`.\n * `false` skips the cache read, the dedupe map AND the cache write, so the\n * call always hits the network and never poisons a later cached read.\n */\n cache?: boolean;\n /** Override the client-wide request timeout for this call only. */\n timeoutMs?: number;\n}\n\n/** Per-call overrides for {@link WebSDKClient.mutate}. */\nexport interface WebSDKMutateOptions {\n /** Override the client-wide request timeout for this call only. */\n timeoutMs?: number;\n}\n\nexport interface GraphQLResponse<T = Record<string, unknown>> {\n data?: T;\n errors?: Array<{\n message: string;\n locations?: Array<{ line: number; column: number }>;\n path?: Array<string | number>;\n extensions?: Record<string, unknown>;\n }>;\n}\n\nexport class WebSDKClient {\n private config: WebSDKClientConfig;\n private queryCache = new Map<\n string,\n { data: GraphQLResponse<unknown>; ts: number }\n >();\n private inflight = new Map<string, Promise<GraphQLResponse<unknown>>>();\n private static CACHE_TTL = 5 * 60 * 1000; // 5 minutes\n private static MAX_CACHE_ENTRIES = 100;\n private static DEFAULT_TIMEOUT_MS = 12_000;\n private static DEFAULT_MAX_RETRIES = 1;\n private static RETRY_BASE_DELAY_MS = 400;\n\n constructor(config: WebSDKClientConfig) {\n this.config = {\n ...config,\n gatewayUrl: validateGatewayUrl(config.gatewayUrl),\n headers: sanitizeHeaders(config.headers),\n };\n }\n\n getConfig(): WebSDKClientConfig {\n return this.config;\n }\n\n /**\n * Execute a GraphQL query (with deduplication and caching).\n *\n * Pass `{ cache: false }` to bypass the cache entirely — required for poll\n * loops, where every tick must reach the network.\n */\n async query<T = Record<string, unknown>>(\n query: string,\n variables?: Record<string, unknown>,\n options?: WebSDKQueryOptions,\n ): Promise<GraphQLResponse<T>> {\n // Uncached path: no cache read, no in-flight dedupe, no cache write.\n // Deliberately bypasses the dedupe map too — two identical polls issued a\n // few hundred ms apart must both hit the network, otherwise the second one\n // resolves with the first one's (already stale) snapshot.\n if (options?.cache === false) {\n return this.request<T>(query, variables, true, options.timeoutMs);\n }\n\n const cacheKey = JSON.stringify({ query, variables });\n\n // Return cached response if still valid, evict if expired\n const cached = this.queryCache.get(cacheKey);\n if (cached) {\n if (Date.now() - cached.ts < WebSDKClient.CACHE_TTL) {\n return cached.data as GraphQLResponse<T>;\n }\n this.queryCache.delete(cacheKey);\n }\n\n // Deduplicate: if same query is already in-flight, reuse the promise\n const existing = this.inflight.get(cacheKey);\n if (existing) {\n return existing as Promise<GraphQLResponse<T>>;\n }\n\n const promise = this.request<T>(query, variables, true, options?.timeoutMs)\n .then((result) => {\n // Cache successful responses only\n if (result.data && !result.errors?.length) {\n if (this.queryCache.size >= WebSDKClient.MAX_CACHE_ENTRIES) {\n const oldestEntry = this.queryCache.keys().next().value;\n if (oldestEntry) {\n this.queryCache.delete(oldestEntry);\n }\n }\n this.queryCache.set(cacheKey, { data: result, ts: Date.now() });\n }\n return result;\n })\n .finally(() => {\n this.inflight.delete(cacheKey);\n });\n\n this.inflight.set(cacheKey, promise);\n return promise;\n }\n\n /**\n * Execute a GraphQL mutation\n */\n async mutate<T = Record<string, unknown>>(\n mutation: string,\n variables?: Record<string, unknown>,\n options?: WebSDKMutateOptions,\n ): Promise<GraphQLResponse<T>> {\n // retry=false: a retried mutation could double-submit (contact form,\n // waitlist signup, order). Only the timeout applies here.\n return this.request<T>(mutation, variables, false, options?.timeoutMs);\n }\n\n /** HTTP statuses worth another attempt — transient server/edge conditions. */\n private static isRetriableStatus(status: number): boolean {\n return status === 429 || status === 408 || (status >= 500 && status < 600);\n }\n\n private static sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n\n /**\n * Perform the HTTP call with a hard timeout. Every outcome resolves to a\n * GraphQLResponse — callers never hang, so a UI's `loading` state always\n * settles into data or a renderable error.\n */\n private async attempt<T>(\n query: string,\n variables: Record<string, unknown> | undefined,\n timeoutMs: number,\n ): Promise<{ res: GraphQLResponse<T>; retriable: boolean }> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n try {\n const response = await fetch(this.config.gatewayUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"x-product-id\": this.config.productId,\n ...this.config.headers,\n ...cfAccessHeaders(this.config.gatewayUrl, this.config.cfAccess),\n },\n body: JSON.stringify({ query, variables }),\n signal: controller.signal,\n });\n\n if (!response.ok) {\n console.error(\n \"[WebSDK] GraphQL request failed\",\n response.status,\n response.statusText,\n );\n return {\n res: {\n errors: [\n {\n message: `HTTP ${response.status}: ${response.statusText}`,\n extensions: { code: `HTTP_${response.status}` },\n },\n ],\n },\n retriable: WebSDKClient.isRetriableStatus(response.status),\n };\n }\n\n return {\n res: (await response.json()) as GraphQLResponse<T>,\n retriable: false,\n };\n } catch (error) {\n const aborted =\n error instanceof Error &&\n (error.name === \"AbortError\" || controller.signal.aborted);\n const message = aborted\n ? `Request timed out after ${timeoutMs}ms`\n : error instanceof Error\n ? error.message\n : \"Network error\";\n console.error(\"[WebSDK] Network error\", message);\n return {\n res: {\n errors: [\n {\n message,\n extensions: { code: aborted ? \"TIMEOUT\" : \"NETWORK_ERROR\" },\n },\n ],\n },\n // Transport-level failures are worth one more try; a genuine outage\n // just fails twice quickly and still renders an error state.\n retriable: true,\n };\n } finally {\n clearTimeout(timer);\n }\n }\n\n private async request<T>(\n query: string,\n variables?: Record<string, unknown>,\n retry = true,\n timeoutOverrideMs?: number,\n ): Promise<GraphQLResponse<T>> {\n const timeoutMs =\n timeoutOverrideMs ??\n this.config.timeoutMs ??\n WebSDKClient.DEFAULT_TIMEOUT_MS;\n const maxRetries = retry\n ? (this.config.maxRetries ?? WebSDKClient.DEFAULT_MAX_RETRIES)\n : 0;\n\n let last: GraphQLResponse<T> | undefined;\n for (let i = 0; i <= maxRetries; i++) {\n const { res, retriable } = await this.attempt<T>(\n query,\n variables,\n timeoutMs,\n );\n if (!retriable || i === maxRetries) return res;\n last = res;\n // Small backoff with jitter so a burst of clients doesn't retry in lockstep.\n await WebSDKClient.sleep(\n WebSDKClient.RETRY_BASE_DELAY_MS * (i + 1) + Math.random() * 200,\n );\n }\n return last as GraphQLResponse<T>;\n }\n}\n","/**\n * React context provider for the Web SDK client.\n * Wraps the application with WebSDKClient configuration.\n */\n\"use client\";\n\nimport { createContext, useContext, useMemo } from \"react\";\nimport type { ReactNode } from \"react\";\n\nimport { resolveGatewayUrl } from \"./gateway-resolver\";\nimport { WebSDKClient, type WebSDKClientConfig } from \"./graphql-client\";\n\nconst WebSDKContext = createContext<WebSDKClient | null>(null);\n\nexport interface WebSDKProviderProps {\n /** SDK client configuration */\n config: WebSDKClientConfig;\n /** Child components */\n children: ReactNode;\n}\n\n/**\n * Provider component that makes the WebSDKClient available to all child components.\n *\n * @example\n * ```tsx\n * <WebSDKProvider config={{\n * gatewayUrl: \"https://api.burdenoff.com/global/graphql\",\n * productId: \"your-product-id\",\n * productSlug: \"your-product\",\n * }}>\n * <App />\n * </WebSDKProvider>\n * ```\n */\nexport function WebSDKProvider({ config, children }: WebSDKProviderProps) {\n const client = useMemo(() => {\n const resolvedConfig = {\n ...config,\n gatewayUrl: resolveGatewayUrl(config.gatewayUrl),\n };\n return new WebSDKClient(resolvedConfig);\n }, [config]);\n\n return (\n <WebSDKContext.Provider value={client}>{children}</WebSDKContext.Provider>\n );\n}\n\n/**\n * Hook to access the WebSDKClient instance.\n * Must be used within a WebSDKProvider.\n */\nexport function useWebSDK(): WebSDKClient {\n const client = useContext(WebSDKContext);\n if (!client) {\n throw new Error(\"useWebSDK must be used within a WebSDKProvider\");\n }\n return client;\n}\n\n/**\n * Hook to access the SDK configuration.\n * Useful for components that need config values like productId, recaptchaSiteKey, etc.\n */\nexport function useWebSDKConfig(): WebSDKClientConfig {\n const client = useWebSDK();\n return client.getConfig();\n}\n","import type { WebsiteSwitcherProduct } from \"../components/website-switcher\";\n\n/**\n * Canonical Burdenoff ecosystem product list used by WebsiteSwitcher.\n *\n * Sourced from `~/products/websites/burdenoff-website/src/data/products.ts`.\n * Keep this in sync when products are added, renamed, or moved.\n */\nexport const ECOSYSTEM_PRODUCTS: WebsiteSwitcherProduct[] = [\n {\n slug: \"workspaces\",\n name: \"Workspaces\",\n websiteUrl: \"https://burdenoff.com\",\n },\n {\n slug: \"vibecontrols\",\n name: \"VibeControls\",\n websiteUrl: \"https://vibecontrols.com\",\n },\n // FluidGrids ships on www.fluidgrids.ai — fluidgrids.com only redirects there. The explore\n // catalog and the site's own sitemap use this origin, and so must the fallback catalog\n // built from this list, or /explore rejects FluidGrids concept images until it loads.\n {\n slug: \"fluidgrids\",\n name: \"FluidGrids\",\n websiteUrl: \"https://www.fluidgrids.ai\",\n },\n // Botlit ships on botlit.ai — botlit.com does not resolve.\n { slug: \"botlit\", name: \"Botlit\", websiteUrl: \"https://www.botlit.ai\" },\n {\n slug: \"bigconsole\",\n name: \"BigConsole\",\n websiteUrl: \"https://bigconsole.com\",\n },\n {\n slug: \"semanticfed\",\n name: \"SemanticFed\",\n websiteUrl: \"https://semanticfed.com\",\n },\n {\n slug: \"intelwatchtower\",\n name: \"IntelWatchtower\",\n websiteUrl: \"https://intelwatchtower.com\",\n },\n { slug: \"buildmyiq\", name: \"BuildMyIQ\", websiteUrl: \"https://buildmyiq.com\" },\n {\n slug: \"assethandler\",\n name: \"AssetHandler\",\n websiteUrl: \"https://assethandler.com\",\n },\n {\n slug: \"crewfoundry\",\n name: \"CrewFoundry\",\n websiteUrl: \"https://crewfoundry.com\",\n },\n {\n slug: \"planmagnet\",\n name: \"PlanMagnet\",\n websiteUrl: \"https://planmagnet.com\",\n },\n {\n slug: \"eventfullymanaged\",\n name: \"EventfullyManaged\",\n websiteUrl: \"https://eventfullymanaged.com\",\n },\n {\n slug: \"headshotmarketing\",\n name: \"HeadshotMarketing\",\n websiteUrl: \"https://headshotmarketing.com\",\n },\n {\n slug: \"technospam\",\n name: \"TechnoSpam\",\n websiteUrl: \"https://technospam.com\",\n },\n { slug: \"kadaikodi\", name: \"Kadaikodi\", websiteUrl: \"https://kadaikodi.com\" },\n {\n slug: \"movethewheels\",\n name: \"MoveTheWheels\",\n websiteUrl: \"https://movethewheels.com\",\n },\n {\n slug: \"healthybowl\",\n name: \"Healthy Bowl\",\n websiteUrl: \"https://gethealthybowl.com\",\n },\n { slug: \"ggnomad\", name: \"GGNomad\", websiteUrl: \"https://ggnomad.com\" },\n {\n slug: \"timecampus\",\n name: \"TimeCampus\",\n websiteUrl: \"https://timecampus.com\",\n },\n {\n slug: \"manufacturedops\",\n name: \"ManufacturedOps\",\n websiteUrl: \"https://manufacturedops.com\",\n },\n {\n slug: \"theglobalfuel\",\n name: \"TheGlobalFuel\",\n websiteUrl: \"https://theglobalfuel.com\",\n },\n {\n slug: \"housingvista\",\n name: \"HousingVista\",\n websiteUrl: \"https://housingvista.com\",\n },\n {\n slug: \"proserviceworld\",\n name: \"ProServiceWorld\",\n websiteUrl: \"https://proserviceworld.com\",\n },\n {\n slug: \"mybodyshield\",\n name: \"MyBodyShield\",\n websiteUrl: \"https://mybodyshield.com\",\n },\n {\n slug: \"artistrybase\",\n name: \"ArtistryBase\",\n websiteUrl: \"https://artistrybase.com\",\n },\n {\n slug: \"theculturepost\",\n name: \"TheCulturePost\",\n websiteUrl: \"https://theculturepost.com\",\n },\n { slug: \"collabkin\", name: \"CollabKin\", websiteUrl: \"https://collabkin.com\" },\n {\n slug: \"comradecircle\",\n name: \"ComradeCircle\",\n websiteUrl: \"https://comradecircle.com\",\n },\n {\n slug: \"brainyrich\",\n name: \"BrainyRich\",\n websiteUrl: \"https://brainyrich.com\",\n },\n {\n slug: \"cosmicintersection\",\n name: \"CosmicIntersection\",\n websiteUrl: \"https://cosmicintersection.com\",\n },\n {\n slug: \"govcitizenhub\",\n name: \"GovCitizenHub\",\n websiteUrl: \"https://govcitizenhub.com\",\n },\n {\n slug: \"adaptercloud\",\n name: \"AdapterCloud\",\n websiteUrl: \"https://adaptercloud.com\",\n },\n {\n slug: \"subscriberbot\",\n name: \"Subscriber Bot\",\n websiteUrl: \"https://subscriberbot.com\",\n },\n {\n slug: \"hookmovies\",\n name: \"HookMovies\",\n websiteUrl: \"https://hookmovies.com\",\n },\n {\n slug: \"coolandlovely\",\n name: \"CoolAndLovely\",\n websiteUrl: \"https://coolandlovely.com\",\n },\n {\n slug: \"atheletebridge\",\n name: \"AthleteBridge\",\n websiteUrl: \"https://atheletebridge.com\",\n },\n {\n slug: \"labsofscience\",\n name: \"LabsOfScience\",\n websiteUrl: \"https://labsofscience.com\",\n },\n {\n slug: \"ecoimpacthub\",\n name: \"EcoImpactHub\",\n websiteUrl: \"https://ecoimpacthub.com\",\n },\n];\n","/**\n * reCAPTCHA v3 (invisible, score-based) loader and token minter.\n *\n * Deliberately dependency-free: the SDK already ships the `react-google-recaptcha`\n * peer for the **v2 checkbox** used by `ContactPage`, and the two widgets cannot\n * share a script tag — v3 needs `?render=<siteKey>` on the URL, v2 must not have\n * it. This module injects its own v3 script and leaves the v2 integration alone.\n *\n * The Explore chat turns v3 on purely from the backend catalog\n * (`exploreCatalog.captchaRequired && recaptchaSiteKey`), so nothing is loaded\n * and no third-party request is made on sites where captcha is off.\n */\n\n/** The slice of the `grecaptcha` global this module uses. */\nexport interface RecaptchaV3 {\n /** Runs the callback once the API is fully initialised. */\n ready(callback: () => void): void;\n /** Mints a single-use token for `action`. */\n execute(siteKey: string, options: { action: string }): Promise<string>;\n}\n\ndeclare global {\n interface Window {\n grecaptcha?: RecaptchaV3;\n }\n}\n\nconst SCRIPT_ID = \"boff-recaptcha-v3\";\nconst SCRIPT_SRC = \"https://www.google.com/recaptcha/api.js?render=\";\n\n/** Default action name reported to reCAPTCHA for Explore chat submissions. */\nexport const EXPLORE_RECAPTCHA_ACTION = \"explore_chat\";\n\n/**\n * One in-flight/settled promise per site key. Guarantees the script tag is\n * injected at most once even when several components mount at the same time,\n * and lets later callers await the same load instead of racing it.\n */\nconst loaders = new Map<string, Promise<RecaptchaV3>>();\n\nfunction isBrowser(): boolean {\n return typeof window !== \"undefined\" && typeof document !== \"undefined\";\n}\n\n/**\n * Load the reCAPTCHA v3 script for `siteKey` and resolve once `grecaptcha` is\n * ready to mint tokens.\n *\n * - Injects the script at most once per site key (subsequent calls reuse the\n * same promise).\n * - Adopts an already-present script tag (e.g. injected by the host site)\n * rather than adding a second one.\n * - Rejects rather than hanging when the script fails to load, so the caller\n * can decide whether to submit without a token or surface an error.\n */\nexport function loadRecaptchaV3(siteKey: string): Promise<RecaptchaV3> {\n if (!siteKey) {\n return Promise.reject(new Error(\"reCAPTCHA site key is required\"));\n }\n if (!isBrowser()) {\n return Promise.reject(\n new Error(\"reCAPTCHA v3 can only be loaded in a browser\"),\n );\n }\n\n const existing = loaders.get(siteKey);\n if (existing) return existing;\n\n const promise = new Promise<RecaptchaV3>((resolve, reject) => {\n const ready = () => {\n const api = window.grecaptcha;\n if (!api) {\n reject(new Error(\"reCAPTCHA loaded but grecaptcha is unavailable\"));\n return;\n }\n // `ready` queues until the API has finished initialising internally;\n // calling `execute` before that throws.\n api.ready(() => resolve(api));\n };\n\n // Already loaded by this module, another SDK instance, or the host site.\n if (window.grecaptcha) {\n ready();\n return;\n }\n\n const scriptId = `${SCRIPT_ID}-${siteKey}`;\n const found = document.getElementById(scriptId);\n if (found) {\n found.addEventListener(\"load\", ready, { once: true });\n found.addEventListener(\n \"error\",\n () => reject(new Error(\"Failed to load reCAPTCHA v3\")),\n { once: true },\n );\n return;\n }\n\n const script = document.createElement(\"script\");\n script.id = scriptId;\n script.src = `${SCRIPT_SRC}${encodeURIComponent(siteKey)}`;\n script.async = true;\n script.defer = true;\n script.addEventListener(\"load\", ready, { once: true });\n script.addEventListener(\n \"error\",\n () => {\n // Drop the memo so a later attempt can retry a transient CDN failure\n // instead of being stuck with a permanently rejected promise.\n loaders.delete(siteKey);\n reject(new Error(\"Failed to load reCAPTCHA v3\"));\n },\n { once: true },\n );\n document.head.appendChild(script);\n });\n\n loaders.set(siteKey, promise);\n return promise;\n}\n\n/**\n * Mint a single-use reCAPTCHA v3 token, loading the script on first use.\n *\n * Tokens are valid for ~2 minutes and are consumed by one verification, so\n * this must be called per submission — never cached.\n */\nexport async function getRecaptchaV3Token(\n siteKey: string,\n action: string = EXPLORE_RECAPTCHA_ACTION,\n): Promise<string> {\n const api = await loadRecaptchaV3(siteKey);\n return api.execute(siteKey, { action });\n}\n","/**\n * useExploreChat — the `/explore` conversation state machine.\n *\n * Implements the client half of CONTRACT.md §1: a **submit + poll** exchange.\n * `sendExploreMessage` returns immediately with a PENDING assistant message;\n * the answer arrives by polling `exploreMessage(conversationToken, id)` roughly\n * every 1.5s until it reports COMPLETED or FAILED. Both gateway hops cap a\n * subgraph call at 20s while a turn takes 5-60s, which is why there is no\n * request that simply waits for the answer.\n *\n * Design rules this hook exists to enforce:\n *\n * 1. **The catalog never gates the first paint.** `catalog` is populated with a\n * static fallback synchronously, so `ExplorePage` can render its `<h1>` on\n * the very first render. The websites' prerender waits for an `h1`; if that\n * heading depended on a network round-trip, 38 static builds would capture a\n * blank page.\n * 2. **Polls bypass the query cache.** `client.query(..., { cache: false })` —\n * the default 5-minute cache would hand every later poll the first PENDING\n * snapshot and the answer would never appear.\n * 3. **Nothing outlives the component.** Unmount and `stop()` both cancel the\n * poll chain through a generation counter, so a late response can never\n * write into an unmounted tree.\n */\n\"use client\";\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\n\nimport { useWebSDK, useWebSDKConfig } from \"../client/provider\";\nimport {\n EXPLORE_CATALOG_QUERY,\n EXPLORE_CATALOG_QUERY_WITHOUT_HIGHLIGHTS,\n EXPLORE_MESSAGE_QUERY,\n EXPLORE_SHARED_CONVERSATION_QUERY,\n CREATE_EXPLORE_SHARE_LINK_MUTATION,\n ESCALATE_EXPLORE_CONVERSATION_MUTATION,\n RECORD_EXPLORE_CLICK_MUTATION,\n SEND_EXPLORE_MESSAGE_MUTATION,\n SUBMIT_EXPLORE_FEEDBACK_MUTATION,\n} from \"../components/explore-types\";\nimport { ECOSYSTEM_PRODUCTS } from \"../data/products\";\nimport { getRecaptchaV3Token } from \"../utils/recaptcha-v3\";\n\nimport type { GraphQLResponse } from \"../client/graphql-client\";\nimport type {\n EscalateExploreConversationInput,\n EscalateExploreConversationMutationData,\n ExploreCatalog,\n ExploreCatalogQueryData,\n ExploreFeedbackRating,\n ExploreFeedbackReason,\n ExploreLimits,\n ExploreMessage,\n ExploreMessageQueryData,\n SendExploreMessageInput,\n SendExploreMessageMutationData,\n SubmitExploreFeedbackInput,\n SubmitExploreFeedbackMutationData,\n} from \"../components/explore-types\";\nimport type { ExploreAttachmentPayload } from \"../utils/explore-attachments\";\n\n// ============================================================================\n// Public types\n// ============================================================================\n\n/**\n * Where the conversation is right now.\n *\n * - `loading` — catalog request in flight (the fallback catalog is already\n * rendered, so this is a refinement, not a blank screen).\n * - `ready` — idle; the composer accepts input.\n * - `sending` — `sendExploreMessage` in flight.\n * - `streaming` — polling the assistant turn; `activity` is live.\n * - `error` — the last turn failed; `retry()` is meaningful and the\n * composer stays usable.\n * - `limited` — rate limited; the composer is disabled.\n * - `disabled` — `exploreCatalog.enabled === false`.\n */\nexport type ExploreChatPhase =\n | \"loading\"\n | \"ready\"\n | \"sending\"\n | \"streaming\"\n | \"error\"\n | \"limited\"\n | \"disabled\";\n\n/** Coarse bucket the UI switches its banner copy and affordances on. */\nexport type ExploreChatErrorKind =\n | \"rate-limit\"\n | \"captcha\"\n | \"timeout\"\n // The question was answerable, but not across this many products at once. Distinct from\n // \"timeout\" because the remedy is different: narrow the question, do not retry it.\n | \"scope\"\n | \"network\"\n | \"disabled\"\n | \"validation\"\n | \"unknown\";\n\nexport interface ExploreChatError {\n /** UI bucket. */\n kind: ExploreChatErrorKind;\n /** Raw `extensions.code` (or a client-side code such as `TIMEOUT`). */\n code: string;\n /** Human-readable, safe to render. */\n message: string;\n /** Whether re-sending the same message could plausibly succeed. */\n retryable: boolean;\n}\n\n/**\n * What came of handing the conversation to a person.\n *\n * `sent` and `already-handed-over` are BOTH successes. The second is the double-clicked\n * button, the retried request and the reloaded page: the server keeps one handover per\n * conversation, so a repeat submit returns the first one rather than filing a second ticket.\n * A visitor who is worried enough to ask for a human must never be told \"you already did\n * that\" — the conversation is with a person either way, and the UI says so either way.\n */\nexport type ExploreEscalateOutcome =\n | \"sent\"\n | \"already-handed-over\"\n /** The SERVER rejected the address (`INVALID_EMAIL`), after the client let it through. */\n | \"invalid-email\"\n | \"rate-limited\"\n | \"captcha\"\n /** No conversation token — nothing to hand over. The form should not have been offered. */\n | \"no-conversation\"\n | \"failed\";\n\nexport interface ExploreEscalateResult {\n outcome: ExploreEscalateOutcome;\n /**\n * The address the SERVER says the reply is going to, on `sent` and `already-handed-over`;\n * null otherwise.\n *\n * On `already-handed-over` this is the address the FIRST handover used, which may not be\n * the one just typed — and it is the one the reply actually reaches, so it is the one to\n * show back.\n */\n email: string | null;\n /** When the handover was filed, as the server holds it. Null unless it exists. */\n createdAt: string | null;\n}\n\nexport interface UseExploreChatOptions {\n /** Slug of the product site this page is on — a soft hint to the harness. */\n productSlug?: string;\n /** Full URL of the page, forwarded as `pageUrl`. */\n pageUrl?: string;\n /** BCP-47 locale, forwarded as `locale`. */\n locale?: string;\n /** Poll cadence in ms. Default 1500 (CONTRACT.md §1). */\n pollIntervalMs?: number;\n /** Give up on a turn after this long. Default 90000 (the edge poll timeout). */\n pollTimeoutMs?: number;\n /**\n * Prompts to offer when `exploreCatalog` supplies none. Resolution order is\n * catalog → this option → {@link DEFAULT_EXPLORE_EXAMPLE_PROMPTS}, so a site\n * can ship product-specific prompts without waiting on the backend and still\n * be overridden centrally once the catalog carries them.\n */\n examplePrompts?: string[];\n /**\n * Welcome copy for the fallback catalog, used only when `exploreCatalog` cannot be reached.\n *\n * The hook's own built-in fallback is English. `ExplorePage` passes the strings for the\n * visitor's locale, so a catalog outage degrades to a translated page rather than an\n * English one — the whole point of shipping six locales is that the failure paths speak\n * them too.\n */\n fallbackWelcome?: { title: string; body: string };\n /** localStorage key for the ACTIVE conversation. Default `boff.explore.v1`. */\n storageKey?: string;\n /** Persist the conversation across reloads within the tab. Default true. */\n persist?: boolean;\n /** Called with the message text each time a send is accepted locally. */\n onSend?: (message: string) => void;\n}\n\nexport interface UseExploreChatResult {\n phase: ExploreChatPhase;\n /** Never null — starts as the static fallback, upgraded by the server. */\n catalog: ExploreCatalog;\n messages: ExploreMessage[];\n /** Latest progress line of the in-flight turn, or null when idle. */\n activity: string | null;\n /** Messages left today for this visitor, when the server reports it. */\n remainingToday: number | null;\n error: ExploreChatError | null;\n /** Product the visitor pinned the conversation to, or null for \"all\". */\n focusProduct: string | null;\n setFocusProduct: (slug: string | null) => void;\n send: (\n message: string,\n attachments?: readonly ExploreAttachmentPayload[],\n ) => Promise<void>;\n /** Stop polling and keep whatever text has streamed so far. */\n stop: () => void;\n /** Re-send the last message after a failed turn. */\n retry: () => void;\n /** Clear the conversation and the persisted session. */\n reset: () => void;\n /** Past conversations held in THIS browser, newest first. */\n history: ArchivedExploreConversation[];\n /** Reopen a past conversation and continue it. */\n openConversation: (token: string) => void;\n /** Forget one past conversation (local only). */\n deleteConversation: (token: string) => void;\n /** Forget every past conversation held in this browser. */\n clearHistory: () => void;\n /**\n * Record that the visitor followed a link this answer offered. Fire-and-forget — never\n * awaited, never throws, and must never delay the navigation it is reporting on.\n */\n recordClick: (\n messageId: string,\n kind: \"CTA\" | \"REFERENCE\",\n url: string,\n ) => void;\n /**\n * Rate one answer. Resolves `true` only when the server reports `recorded: true`.\n *\n * The opposite posture to {@link recordClick}, and deliberately so: the visitor is still on\n * the page and is watching the control they pressed, so the result has to come back far\n * enough for the UI to tell the truth about it. It still never throws — a transport\n * failure, a GraphQL error and an unattributable message all resolve `false`.\n */\n submitFeedback: (\n messageId: string,\n rating: ExploreFeedbackRating,\n detail?: { reason?: ExploreFeedbackReason | null; comment?: string | null },\n ) => Promise<boolean>;\n /**\n * Hand this conversation to a person, so they pick it up with the transcript attached.\n *\n * Awaited, like {@link submitFeedback} and for the same reason — the visitor is watching\n * the control they pressed — but this one has more to say than true/false: \"we could not\n * deliver to that address\", \"you are sending these too fast\" and \"it is already with a\n * human\" are three different things to a worried visitor, and one boolean flattens them\n * into a shrug. It never throws; every outcome comes back in\n * {@link ExploreEscalateResult}.\n *\n * `email` is personal data. It goes into the mutation variables and nowhere else — not\n * into `messages` (which is what this hook persists), not into `onSend`, not into any\n * analytics call.\n */\n escalate: (email: string, note?: string) => Promise<ExploreEscalateResult>;\n /**\n * Whether there is a conversation a person could actually be handed.\n *\n * False on a fresh page and false in a read-only shared view (a `?c=` secret is not a\n * conversation token), which are exactly the cases where {@link escalate} could only\n * answer `no-conversation`. Offer the form on this, rather than offering one that cannot\n * work.\n */\n canEscalate: boolean;\n /**\n * Mint a read-only link to this conversation, or null when there is nothing to share yet.\n * The secret returned is not the conversation token and cannot continue the thread.\n */\n createShareLink: () => Promise<string | null>;\n /**\n * True when the transcript on screen came from a shared link rather than this visitor's own\n * conversation. A shared view is read-only: the share secret cannot continue the thread.\n */\n isSharedView: boolean;\n canSend: boolean;\n}\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst DEFAULT_STORAGE_KEY = \"boff.explore.v1\";\n/** Where past conversations live. Derived from the active key so a custom key stays paired. */\nconst HISTORY_SUFFIX = \".history\";\n/**\n * How many past conversations to keep, and how many messages of each. Bounded on purpose:\n * localStorage is a few MB per origin and shared with everything else the site stores, so an\n * unbounded archive would eventually start throwing QuotaExceededError on write.\n */\nconst MAX_ARCHIVED_CONVERSATIONS = 15;\nconst MAX_ARCHIVED_MESSAGES = 20;\nconst DEFAULT_POLL_INTERVAL_MS = 1_500;\n/** Matches `EXPLORE_AGENT_TIMEOUT_MS` (CONTRACT.md §3) — the edge gives up too. */\nconst DEFAULT_POLL_TIMEOUT_MS = 90_000;\n/** Per-poll HTTP timeout. Short: a stuck poll must not stall the chain. */\nconst POLL_REQUEST_TIMEOUT_MS = 10_000;\n/** The submit hop enqueues a job; generous but well under the gateway's 20s. */\nconst SEND_REQUEST_TIMEOUT_MS = 18_000;\n/** Transient poll failures tolerated before the turn is declared dead. */\nconst MAX_CONSECUTIVE_POLL_FAILURES = 4;\n/** Cap on what goes into localStorage — a conversation must not grow unbounded. */\nconst MAX_PERSISTED_MESSAGES = 40;\n\n/** Fallback limits, mirroring the server defaults in CONTRACT.md §3. */\nexport const FALLBACK_EXPLORE_LIMITS: ExploreLimits = {\n maxMessageLength: 2000,\n maxTurnsPerConversation: 20,\n messagesPerDay: 100,\n historyTurns: 6,\n};\n\n/**\n * Prompts shown when neither the catalog nor the consumer supplies any.\n * Deliberately product-agnostic — this SDK renders on 38 different sites.\n *\n * Problem-first, and kept in step with `support.explore.examplePrompts.*` in\n * global-support-svc. These render precisely when the catalog call failed, so\n * if they disagree with the server the page silently reverts to whatever this\n * file last said — which is how the whole surface can go back to being a\n * brochure without a single copy change being reviewed.\n */\nexport const DEFAULT_EXPLORE_EXAMPLE_PROMPTS: string[] = [\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 \"Which of your products fits a problem like mine?\",\n];\n\nconst FALLBACK_WELCOME_TITLE = \"What problem are you trying to solve?\";\nconst FALLBACK_WELCOME_BODY =\n \"Describe the problem you're facing, in your own words. You can also ask about a specific product or compare a few. Every answer comes straight from our documentation.\";\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\nfunction buildFallbackCatalog(\n examplePrompts?: string[],\n welcome?: { title: string; body: string },\n): ExploreCatalog {\n return {\n enabled: true,\n products: ECOSYSTEM_PRODUCTS.map((p) => ({\n slug: p.slug,\n name: p.name,\n tagline: null,\n website: p.websiteUrl,\n })),\n examplePrompts: examplePrompts?.length\n ? examplePrompts\n : DEFAULT_EXPLORE_EXAMPLE_PROMPTS,\n welcomeTitle: welcome?.title ?? FALLBACK_WELCOME_TITLE,\n welcomeBody: welcome?.body ?? FALLBACK_WELCOME_BODY,\n limits: FALLBACK_EXPLORE_LIMITS,\n captchaRequired: false,\n recaptchaSiteKey: null,\n // Empty, and deliberately not synthesised from `ECOSYSTEM_PRODUCTS`: a concept highlight\n // needs a real published illustration URL, and this SDK has no registry of them. An\n // invented path would render 38 broken frames on the one screen every prerender captures.\n // The strip renders nothing at all when the list is empty, which is the honest fallback.\n conceptHighlights: [],\n };\n}\n\n/**\n * Harden a server catalog against partial/degraded responses so a missing\n * field can never blank the page or produce `maxMessageLength: 0` (which would\n * silently disable the composer).\n */\nfunction normalizeCatalog(\n raw: ExploreCatalog,\n fallback: ExploreCatalog,\n): ExploreCatalog {\n return {\n enabled: raw.enabled !== false,\n products: raw.products?.length ? raw.products : fallback.products,\n examplePrompts: raw.examplePrompts?.length\n ? raw.examplePrompts\n : fallback.examplePrompts,\n welcomeTitle: raw.welcomeTitle || fallback.welcomeTitle,\n welcomeBody: raw.welcomeBody || fallback.welcomeBody,\n limits: {\n maxMessageLength:\n raw.limits?.maxMessageLength || fallback.limits.maxMessageLength,\n maxTurnsPerConversation:\n raw.limits?.maxTurnsPerConversation ||\n fallback.limits.maxTurnsPerConversation,\n messagesPerDay:\n raw.limits?.messagesPerDay || fallback.limits.messagesPerDay,\n historyTurns: raw.limits?.historyTurns || fallback.limits.historyTurns,\n },\n captchaRequired: raw.captchaRequired === true,\n recaptchaSiteKey: raw.recaptchaSiteKey ?? null,\n // `[ExploreConceptHighlight!]!` on the wire, so a gateway that KNOWS the field always\n // sends an array. The one response that arrives without it is the retry against an older\n // supergraph (`EXPLORE_CATALOG_QUERY_WITHOUT_HIGHLIGHTS`) — that gateway does not answer\n // the full document at all, it refuses it. Either way\n // `catalog.conceptHighlights.filter(...)` on `undefined` would throw inside render,\n // blanking the welcome screen over a decorative strip.\n conceptHighlights: raw.conceptHighlights?.length\n ? raw.conceptHighlights\n : fallback.conceptHighlights,\n };\n}\n\n/**\n * Codes that mean \"this gateway would not accept the document\", as opposed to\n * \"the request failed\". `HTTP_400` is in the set because a gateway may surface\n * a validation failure as a status instead of a body — production answers 200\n * with `GRAPHQL_VALIDATION_FAILED`, but that is a server choice, not a promise,\n * and `WebSDKClient` collapses any non-2xx into `HTTP_<status>` with the\n * original message discarded.\n */\nconst CATALOG_DOCUMENT_REJECTED_CODES = new Set([\n \"GRAPHQL_VALIDATION_FAILED\",\n \"HTTP_400\",\n]);\n\n/**\n * True when the catalog came back with nothing usable AND the reason looks like\n * the gateway refusing the document rather than failing to serve it.\n *\n * GraphQL validation is all-or-nothing, so against a supergraph that predates\n * `conceptHighlights` there is no partial response to salvage: no `data`, and\n * the loss is the WHOLE catalog — the server-side `enabled` kill switch,\n * `captchaRequired`/`recaptchaSiteKey`, the reviewed welcome copy and `limits`.\n * One retry without the field recovers all of it.\n */\nexport function catalogRejectedTheHighlightField(\n res: GraphQLResponse<ExploreCatalogQueryData>,\n): boolean {\n if (res.data?.exploreCatalog) return false;\n return (res.errors ?? []).some((error) => {\n const code = error.extensions?.code;\n return (\n (typeof code === \"string\" && CATALOG_DOCUMENT_REJECTED_CODES.has(code)) ||\n error.message.includes(\"conceptHighlights\")\n );\n });\n}\n\nconst RATE_LIMIT_CODES = new Set([\n \"RATE_LIMITED\",\n \"HTTP_429\",\n \"EXPLORE_GLOBAL_LIMIT\",\n]);\nconst CAPTCHA_CODES = new Set([\"CAPTCHA_FAILED\", \"CAPTCHA_REQUIRED\"]);\nconst NETWORK_CODES = new Set([\n \"NETWORK_ERROR\",\n \"UPSTREAM_UNAVAILABLE\",\n \"CONVERSATION_BUSY\",\n \"PROVIDER_ERROR\",\n \"QUEUE_FULL\",\n]);\nconst VALIDATION_CODES = new Set([\n \"MESSAGE_TOO_LONG\",\n \"MESSAGE_EMPTY\",\n \"CONVERSATION_LIMIT\",\n \"INVALID_INPUT\",\n]);\n\n/**\n * Map a `extensions.code` (or a client-side transport code) onto the bucket the\n * UI renders. Unknown codes are treated as retryable — a transient backend\n * condition we have not enumerated is far more likely than a permanent one.\n */\n/**\n * Map an `extensions.code` from `escalateExploreConversation` onto the outcome the form\n * renders.\n *\n * Separate from {@link classifyExploreError} on purpose. That one buckets a failed ANSWER\n * and its buckets carry copy about retrying a question — none of which is true here, and\n * `INVALID_EMAIL` has no bucket there at all (it would land in `unknown` and be shown as\n * \"something went wrong\", which is the one message that leaves the visitor unable to fix\n * the one thing they could actually fix).\n *\n * `EXPLORE_GLOBAL_LIMIT` is deliberately NOT treated as rate limiting here: the contract\n * keeps a handover off the fleet-wide LLM budget, so seeing it would mean something\n * unexpected, not \"you are going too fast\".\n */\nexport function escalateOutcomeForCode(\n code: string | null | undefined,\n): ExploreEscalateOutcome {\n switch (code) {\n case \"INVALID_EMAIL\":\n return \"invalid-email\";\n case \"RATE_LIMITED\":\n case \"HTTP_429\":\n return \"rate-limited\";\n case \"CAPTCHA_REQUIRED\":\n case \"CAPTCHA_FAILED\":\n return \"captcha\";\n // The token owns nothing, or owns a different conversation. The server answers NOT_FOUND\n // rather than FORBIDDEN so the endpoint is not an oracle for whether a thread exists;\n // either way there is nothing this visitor can do about it, so it reads as a failure.\n case \"NOT_FOUND\":\n return \"failed\";\n default:\n return \"failed\";\n }\n}\n\nexport function classifyExploreError(\n code: string | null | undefined,\n serverMessage?: string | null,\n): ExploreChatError {\n const c = code ?? \"UNKNOWN\";\n if (RATE_LIMIT_CODES.has(c)) {\n return {\n kind: \"rate-limit\",\n code: c,\n message:\n \"You've reached the message limit for now. Please try again later.\",\n retryable: false,\n };\n }\n if (CAPTCHA_CODES.has(c)) {\n return {\n kind: \"captcha\",\n code: c,\n message:\n \"We couldn't verify that you're human. Please try sending that again.\",\n retryable: true,\n };\n }\n // TOOL_BUDGET is NOT a timeout and must not be described as one. Measured in production:\n // the failing turn ended in 33s against a 75s budget — it did not run out of time, it ran\n // out of searches. Retrying is also the wrong advice: the same question searches the same\n // way and fails identically, so \"try again\" is a button that cannot work. The honest reply\n // names the actual limit and offers the narrowing that does work.\n if (c === \"TOOL_BUDGET\") {\n return {\n kind: \"scope\",\n code: c,\n message:\n \"That question spans more of our products than I can look through in one go. Try asking about two or three specific products.\",\n retryable: false,\n };\n }\n if (c === \"TIMEOUT\") {\n return {\n kind: \"timeout\",\n code: c,\n message: \"That answer took too long to come back. Try asking again.\",\n retryable: true,\n };\n }\n if (NETWORK_CODES.has(c)) {\n return {\n kind: \"network\",\n code: c,\n message:\n \"We couldn't reach the assistant just now. Check your connection and try again.\",\n retryable: true,\n };\n }\n if (c === \"EXPLORE_DISABLED\") {\n return {\n kind: \"disabled\",\n code: c,\n message: \"Explore is unavailable at the moment. Please check back soon.\",\n retryable: false,\n };\n }\n if (VALIDATION_CODES.has(c)) {\n return {\n kind: \"validation\",\n code: c,\n message: serverMessage || \"That message couldn't be sent.\",\n retryable: false,\n };\n }\n if (c === \"EMPTY_ANSWER\") {\n return {\n kind: \"unknown\",\n code: c,\n message:\n \"No answer came back for that one. Try rephrasing, or ask something more specific.\",\n retryable: true,\n };\n }\n return {\n kind: \"unknown\",\n code: c,\n message: serverMessage || \"Something went wrong. Please try again.\",\n retryable: true,\n };\n}\n\ninterface PersistedExploreState {\n conversationToken: string | null;\n messages: ExploreMessage[];\n focusProduct: string | null;\n}\n\n/** One past conversation, as shown in the history list and restored on click. */\nexport interface ArchivedExploreConversation {\n token: string;\n /** First thing the visitor asked — the human-readable label for the thread. */\n title: string;\n /** ISO timestamp of the last message in the thread. */\n updatedAt: string;\n messageCount: number;\n focusProduct: string | null;\n messages: ExploreMessage[];\n}\n\nfunction historyKey(key: string): string {\n return `${key}${HISTORY_SUFFIX}`;\n}\n\nfunction readArchive(key: string): ArchivedExploreConversation[] {\n if (typeof window === \"undefined\") return [];\n try {\n const raw = window.localStorage.getItem(historyKey(key));\n if (!raw) return [];\n const parsed: unknown = JSON.parse(raw);\n if (!Array.isArray(parsed)) return [];\n return parsed.filter(\n (entry): entry is ArchivedExploreConversation =>\n typeof entry === \"object\" &&\n entry !== null &&\n typeof (entry as ArchivedExploreConversation).token === \"string\" &&\n Array.isArray((entry as ArchivedExploreConversation).messages),\n );\n } catch {\n return [];\n }\n}\n\nfunction writeArchive(\n key: string,\n entries: ArchivedExploreConversation[],\n): void {\n if (typeof window === \"undefined\") return;\n try {\n if (entries.length === 0) {\n window.localStorage.removeItem(historyKey(key));\n return;\n }\n window.localStorage.setItem(historyKey(key), JSON.stringify(entries));\n } catch {\n /* private mode or quota — the archive is a convenience, never load-bearing */\n }\n}\n\n/**\n * Fold the given thread into the archive, newest first.\n *\n * Upsert by token rather than append: the same conversation is archived after every completed\n * turn so an abruptly closed tab still leaves a record, and appending would fill the list with\n * duplicates of one thread.\n */\nfunction upsertArchive(\n key: string,\n thread: {\n token: string | null;\n messages: ExploreMessage[];\n focusProduct: string | null;\n },\n): ArchivedExploreConversation[] {\n if (!thread.token) return readArchive(key);\n const real = thread.messages.filter(\n (m) => m.content.trim() !== \"\" || m.role === \"USER\",\n );\n if (real.length === 0) return readArchive(key);\n\n const firstUser = real.find((m) => m.role === \"USER\");\n const entry: ArchivedExploreConversation = {\n token: thread.token,\n title: (firstUser?.content ?? \"Conversation\").trim().slice(0, 80),\n updatedAt: real[real.length - 1]?.createdAt ?? new Date().toISOString(),\n messageCount: real.length,\n focusProduct: thread.focusProduct,\n messages: real.slice(-MAX_ARCHIVED_MESSAGES),\n };\n\n const rest = readArchive(key).filter((e) => e.token !== entry.token);\n const next = [entry, ...rest].slice(0, MAX_ARCHIVED_CONVERSATIONS);\n writeArchive(key, next);\n return next;\n}\n\nfunction readPersisted(key: string): PersistedExploreState | null {\n // SSR / prerender: there is no localStorage, and reading one during the\n // first client render would desync hydration anyway.\n if (typeof window === \"undefined\") return null;\n try {\n const raw = window.localStorage.getItem(key);\n if (!raw) return null;\n const parsed: unknown = JSON.parse(raw);\n if (!parsed || typeof parsed !== \"object\") return null;\n const record = parsed as Partial<PersistedExploreState>;\n return {\n conversationToken:\n typeof record.conversationToken === \"string\"\n ? record.conversationToken\n : null,\n messages: Array.isArray(record.messages)\n ? record.messages.slice(-MAX_PERSISTED_MESSAGES)\n : [],\n focusProduct:\n typeof record.focusProduct === \"string\" ? record.focusProduct : null,\n };\n } catch {\n /* corrupt or unavailable storage — start a fresh conversation */\n return null;\n }\n}\n\n/**\n * A turn that never produced any text is worth dropping rather than rendering\n * as an empty bubble — used by `stop()` and by the failure paths.\n */\n/**\n * The `?c=` share secret, or null.\n *\n * Read from `window.location` rather than from a router: the explore page ships to 39\n * separate marketing sites, and only some of them mount it under a router whose search\n * params this hook could reach.\n */\nfunction readShareToken(): string | null {\n if (typeof window === \"undefined\") return null;\n try {\n return new URL(window.location.href).searchParams.get(\"c\");\n } catch {\n // A malformed href — fall through to the normal path rather than blanking the page.\n return null;\n }\n}\n\nfunction visibleText(message: ExploreMessage): string {\n return message.content || message.partialContent || \"\";\n}\n\nfunction countUserTurns(messages: ExploreMessage[]): number {\n return messages.filter((m) => m.role === \"USER\").length;\n}\n\n// ============================================================================\n// Hook\n// ============================================================================\n\nexport function useExploreChat(\n options: UseExploreChatOptions = {},\n): UseExploreChatResult {\n const {\n productSlug,\n pageUrl,\n locale,\n examplePrompts,\n fallbackWelcome,\n pollIntervalMs = DEFAULT_POLL_INTERVAL_MS,\n pollTimeoutMs = DEFAULT_POLL_TIMEOUT_MS,\n storageKey = DEFAULT_STORAGE_KEY,\n persist = true,\n onSend,\n } = options;\n\n const client = useWebSDK();\n // The site's `PlatformProduct` id, so a handover reaches THAT product's support inbox\n // rather than a generic one. Optional in the contract: a site that has not configured one\n // still gets its conversation to a person.\n const { productId } = useWebSDKConfig();\n\n // The fallback catalog is the initial value AND the merge base for the\n // server response. Keyed on the prompt CONTENT, not the array identity —\n // a consumer passing an inline `examplePrompts={[...]}` literal would\n // otherwise rebuild it every render and re-fire the catalog effect.\n const promptKey = JSON.stringify(examplePrompts ?? []);\n // Same reasoning for the welcome copy: keyed on content so an inline object literal from the\n // caller does not rebuild the catalog every render.\n const welcomeKey = JSON.stringify(fallbackWelcome ?? null);\n const fallbackCatalog = useMemo(\n () =>\n buildFallbackCatalog(\n JSON.parse(promptKey) as string[],\n (JSON.parse(welcomeKey) as { title: string; body: string } | null) ??\n undefined,\n ),\n [promptKey, welcomeKey],\n );\n\n const [catalog, setCatalog] = useState<ExploreCatalog>(fallbackCatalog);\n const [messages, setMessages] = useState<ExploreMessage[]>([]);\n const [phase, setPhase] = useState<ExploreChatPhase>(\"loading\");\n const [error, setError] = useState<ExploreChatError | null>(null);\n const [remainingToday, setRemainingToday] = useState<number | null>(null);\n const [focusProduct, setFocusProductState] = useState<string | null>(null);\n const [turnCount, setTurnCount] = useState(0);\n // Mirror of `messages` for callbacks that must not re-create on every message.\n const messagesRef = useRef<ExploreMessage[]>([]);\n const [archive, setArchive] = useState<ArchivedExploreConversation[]>([]);\n\n const [hydrated, setHydrated] = useState(false);\n\n // Refs mirror the state that async callbacks read, so `send`/`poll` never\n // close over a stale value and never need to be re-created mid-flight.\n const mountedRef = useRef(true);\n const pollGenerationRef = useRef(0);\n const pollTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const conversationTokenRef = useRef<string | null>(null);\n /**\n * Render-visible mirror of `conversationTokenRef`.\n *\n * The ref alone cannot gate a control: a ref write does not re-render, so a form offered\n * on `conversationTokenRef.current !== null` would still be absent on the render after the\n * first message landed. Everything that assigns the token goes through\n * {@link rememberConversationToken} so the two cannot drift.\n */\n const [hasConversation, setHasConversation] = useState(false);\n /**\n * The `?c=` share token, read ONCE and synchronously.\n *\n * It cannot be discovered inside the share effect and then relied on by the hydration\n * effect: both run in the same commit, so the hydration effect would still close over\n * `isSharedView === false` and load the visitor's own stored thread underneath the shared\n * one. On a slow link that shows their old chat first and then swaps it; if the share\n * lookup fails, they are left staring at their old conversation next to a \"not found\"\n * error. Reading it here makes both effects agree on the first render.\n */\n const shareTokenRef = useRef<string | null | undefined>(undefined);\n if (shareTokenRef.current === undefined) {\n shareTokenRef.current = readShareToken();\n }\n // Derived, not state: the token comes from the URL, and leaving the shared view is a\n // full navigation (the \"New chat\" button drops `?c=` via `location.href`), so there is no\n // in-place transition for a setter to model.\n const isSharedView = shareTokenRef.current !== null;\n const catalogRef = useRef<ExploreCatalog>(fallbackCatalog);\n const turnCountRef = useRef(0);\n const focusProductRef = useRef<string | null>(null);\n const lastSentTextRef = useRef<string | null>(null);\n // Retried alongside the text. Without this a retry after a network failure would re-ask the\n // question with the documents silently dropped, and the visitor would get a confidently\n // wrong answer with nothing on screen saying their files were not used.\n const lastSentAttachmentsRef = useRef<readonly ExploreAttachmentPayload[]>(\n [],\n );\n const inFlightRef = useRef(false);\n\n catalogRef.current = catalog;\n\n /**\n * The single writer for the conversation token.\n *\n * Async callbacks read the ref (so they never close over a stale value); render reads the\n * state (so a control can appear the moment a conversation exists). Writing both here is\n * what keeps \"we have a thread\" from being true in one and false in the other.\n */\n const rememberConversationToken = useCallback((token: string | null) => {\n conversationTokenRef.current = token;\n setHasConversation(token !== null);\n }, []);\n\n const clearPollTimer = useCallback(() => {\n if (pollTimerRef.current !== null) {\n clearTimeout(pollTimerRef.current);\n pollTimerRef.current = null;\n }\n }, []);\n\n /** Invalidate any running poll chain. Late responses become no-ops. */\n const cancelPolling = useCallback(() => {\n pollGenerationRef.current += 1;\n clearPollTimer();\n }, [clearPollTimer]);\n\n useEffect(() => {\n mountedRef.current = true;\n return () => {\n mountedRef.current = false;\n pollGenerationRef.current += 1;\n if (pollTimerRef.current !== null) {\n clearTimeout(pollTimerRef.current);\n pollTimerRef.current = null;\n }\n };\n }, []);\n\n // --------------------------------------------------------------------------\n // A shared link (`?c=<shareToken>`).\n //\n // Runs BEFORE the localStorage hydration below and short-circuits it: someone opening a\n // link they were sent must see that conversation, not whatever they happened to ask this\n // site last week. The secret in the URL is a read-only share token, never a conversation\n // token, so this view cannot continue the thread — which is why `isSharedView` is exposed\n // and the composer is disabled on it.\n // --------------------------------------------------------------------------\n useEffect(() => {\n const shareToken = shareTokenRef.current;\n if (!shareToken) return;\n\n let cancelled = false;\n setHydrated(true);\n\n void client\n .query<{ exploreSharedConversation?: ExploreMessage[] | null }>(\n EXPLORE_SHARED_CONVERSATION_QUERY,\n { shareToken },\n { cache: false },\n )\n .then((res) => {\n if (cancelled || !mountedRef.current) return;\n const shared = res?.data?.exploreSharedConversation;\n if (shared && shared.length > 0) {\n setMessages(shared);\n return;\n }\n // A token that resolves to nothing is an expired or wrong link. Say so rather than\n // showing an empty chat that looks like the feature is broken.\n setError({\n kind: \"unknown\",\n code: \"SHARE_NOT_FOUND\",\n message:\n \"That shared conversation could not be found. The link may have expired.\",\n // Nothing to retry: a bad token will stay bad.\n retryable: false,\n });\n })\n .catch(() => {\n if (cancelled || !mountedRef.current) return;\n setError({\n kind: \"unknown\",\n code: \"SHARE_NOT_FOUND\",\n message: \"That shared conversation could not be loaded.\",\n retryable: true,\n });\n });\n\n return () => {\n cancelled = true;\n };\n }, [client]);\n\n // --------------------------------------------------------------------------\n // Hydrate from localStorage (effect, not lazy state, so the FIRST client\n // render matches the prerendered HTML and hydration stays clean).\n // --------------------------------------------------------------------------\n useEffect(() => {\n // A shared link owns the transcript; never let stored history replace it. The ref, not\n // the state: this effect and the share effect run in the same commit.\n if (shareTokenRef.current !== null) return;\n if (!persist) {\n setHydrated(true);\n return;\n }\n setArchive(readArchive(storageKey));\n const stored = readPersisted(storageKey);\n if (stored) {\n rememberConversationToken(stored.conversationToken);\n focusProductRef.current = stored.focusProduct;\n // A turn that was still streaming when the tab was closed can never be\n // resumed from here — the poll chain is gone. Land it as-is.\n const settled = stored.messages.flatMap<ExploreMessage>((m) => {\n if (m.role !== \"ASSISTANT\") return [m];\n if (m.status !== \"PENDING\" && m.status !== \"RUNNING\") return [m];\n const text = visibleText(m);\n if (!text) return [];\n return [{ ...m, status: \"COMPLETED\", content: text }];\n });\n setMessages(settled);\n setFocusProductState(stored.focusProduct);\n const turns = countUserTurns(settled);\n turnCountRef.current = turns;\n setTurnCount(turns);\n }\n setHydrated(true);\n }, [persist, rememberConversationToken, storageKey]);\n\n // --------------------------------------------------------------------------\n // Persist (after hydration, so the initial empty state never wipes storage).\n // --------------------------------------------------------------------------\n useEffect(() => {\n if (!persist || !hydrated || typeof window === \"undefined\") return;\n try {\n const payload: PersistedExploreState = {\n conversationToken: conversationTokenRef.current,\n messages: messages.slice(-MAX_PERSISTED_MESSAGES),\n focusProduct,\n };\n // Nothing worth restoring (fresh page, or just after reset()): drop the\n // key entirely rather than leaving an empty husk behind.\n if (\n !payload.conversationToken &&\n payload.messages.length === 0 &&\n !payload.focusProduct\n ) {\n window.localStorage.removeItem(storageKey);\n return;\n }\n window.localStorage.setItem(storageKey, JSON.stringify(payload));\n } catch {\n /* private mode / quota exceeded — persistence is a nicety, not a feature */\n }\n }, [persist, hydrated, storageKey, messages, focusProduct]);\n\n // Mirror messages into a ref for callbacks, and fold a settled thread into the archive.\n // Archiving on every settled turn (not only on reset) is what makes an abruptly closed tab\n // still leave a record the visitor can come back to.\n useEffect(() => {\n messagesRef.current = messages;\n if (!persist || !hydrated) return;\n const settled = messages.some(\n (m) =>\n m.role === \"ASSISTANT\" &&\n (m.status === \"COMPLETED\" || m.status === \"FAILED\"),\n );\n if (!settled) return;\n setArchive(\n upsertArchive(storageKey, {\n token: conversationTokenRef.current,\n messages,\n focusProduct: focusProductRef.current,\n }),\n );\n }, [messages, persist, hydrated, storageKey]);\n\n // --------------------------------------------------------------------------\n // Catalog. Cached (the default) — it is per-page-load configuration, not a\n // poll. A failure keeps the fallback so the page NEVER renders blank.\n // --------------------------------------------------------------------------\n useEffect(() => {\n let cancelled = false;\n const load = async () => {\n const variables = { productSlug: productSlug ?? null };\n let res = await client.query<ExploreCatalogQueryData>(\n EXPLORE_CATALOG_QUERY,\n variables,\n );\n if (cancelled || !mountedRef.current) return;\n\n // A gateway whose supergraph predates `conceptHighlights` does not answer this\n // document without the field — it refuses the document outright, so `res.data` is\n // undefined and the loss is the entire catalog, not the strip. Retry once with the\n // field dropped rather than spending the whole window on `buildFallbackCatalog()`,\n // which hardcodes `enabled: true` (ignoring the only kill switch that needs no\n // redeploy) and `captchaRequired: false` (every send then rejected server-side while\n // the composer looks fine). The window is unavoidable even with perfect deploy\n // ordering: the prod gateway's CDN edge serves a stale supergraph for ~30-40 min\n // after the subgraph publishes.\n if (catalogRejectedTheHighlightField(res)) {\n res = await client.query<ExploreCatalogQueryData>(\n EXPLORE_CATALOG_QUERY_WITHOUT_HIGHLIGHTS,\n variables,\n );\n if (cancelled || !mountedRef.current) return;\n }\n\n const raw = res.data?.exploreCatalog;\n if (res.errors?.length || !raw) {\n console.warn(\n \"[WebSDK] exploreCatalog unavailable — using the built-in fallback catalog\",\n res.errors?.[0]?.message,\n );\n setPhase((prev) => (prev === \"loading\" ? \"ready\" : prev));\n return;\n }\n\n const next = normalizeCatalog(raw, fallbackCatalog);\n setCatalog(next);\n catalogRef.current = next;\n setPhase((prev) => {\n if (!next.enabled) return \"disabled\";\n return prev === \"loading\" ? \"ready\" : prev;\n });\n };\n void load();\n return () => {\n cancelled = true;\n };\n }, [client, productSlug, fallbackCatalog]);\n\n // --------------------------------------------------------------------------\n // Poll chain\n // --------------------------------------------------------------------------\n const startPolling = useCallback(\n (conversationToken: string, messageId: string) => {\n pollGenerationRef.current += 1;\n const generation = pollGenerationRef.current;\n const startedAt = Date.now();\n let consecutiveFailures = 0;\n\n const isStale = () =>\n !mountedRef.current || generation !== pollGenerationRef.current;\n\n const finishWithError = (chatError: ExploreChatError) => {\n inFlightRef.current = false;\n setMessages((prev) =>\n prev.flatMap<ExploreMessage>((m) => {\n if (m.id !== messageId) return [m];\n const text = visibleText(m);\n if (!text) return [];\n return [{ ...m, status: \"FAILED\", content: text }];\n }),\n );\n setError(chatError);\n setPhase(chatError.kind === \"rate-limit\" ? \"limited\" : \"error\");\n };\n\n const tick = async () => {\n if (isStale()) return;\n\n if (Date.now() - startedAt > pollTimeoutMs) {\n finishWithError(classifyExploreError(\"TIMEOUT\"));\n return;\n }\n\n // `cache: false` is load-bearing — see CONTRACT.md §4.\n const res = await client.query<ExploreMessageQueryData>(\n EXPLORE_MESSAGE_QUERY,\n { conversationToken, id: messageId },\n { cache: false, timeoutMs: POLL_REQUEST_TIMEOUT_MS },\n );\n if (isStale()) return;\n\n const first = res.errors?.[0];\n if (first) {\n const code =\n typeof first.extensions?.code === \"string\"\n ? first.extensions.code\n : undefined;\n const classified = classifyExploreError(code, first.message);\n // Hard stops: retrying a rate limit or a disabled feature is pointless.\n if (!classified.retryable) {\n finishWithError(classified);\n return;\n }\n consecutiveFailures += 1;\n if (consecutiveFailures >= MAX_CONSECUTIVE_POLL_FAILURES) {\n finishWithError(classified);\n return;\n }\n pollTimerRef.current = setTimeout(() => void tick(), pollIntervalMs);\n return;\n }\n\n const message = res.data?.exploreMessage;\n if (!message) {\n // Can happen briefly right after submit; tolerate a few misses.\n consecutiveFailures += 1;\n if (consecutiveFailures >= MAX_CONSECUTIVE_POLL_FAILURES) {\n finishWithError(classifyExploreError(\"NOT_FOUND\"));\n return;\n }\n pollTimerRef.current = setTimeout(() => void tick(), pollIntervalMs);\n return;\n }\n\n consecutiveFailures = 0;\n // Replace in place so `partialContent` renders as it streams.\n setMessages((prev) =>\n prev.map((m) => (m.id === messageId ? message : m)),\n );\n\n if (message.status === \"COMPLETED\") {\n inFlightRef.current = false;\n setError(null);\n setPhase(\"ready\");\n return;\n }\n if (message.status === \"FAILED\") {\n finishWithError(\n classifyExploreError(message.errorCode ?? \"UPSTREAM_UNAVAILABLE\"),\n );\n return;\n }\n\n setPhase(\"streaming\");\n pollTimerRef.current = setTimeout(() => void tick(), pollIntervalMs);\n };\n\n // First poll after one interval — the turn cannot possibly be done sooner.\n pollTimerRef.current = setTimeout(() => void tick(), pollIntervalMs);\n },\n [client, pollIntervalMs, pollTimeoutMs],\n );\n\n // --------------------------------------------------------------------------\n // send\n // --------------------------------------------------------------------------\n const submit = useCallback(\n async (\n text: string,\n optimisticId: string,\n captchaAttempt: number,\n attachments: readonly ExploreAttachmentPayload[],\n ): Promise<void> => {\n const activeCatalog = catalogRef.current;\n\n let recaptchaToken: string | undefined;\n if (activeCatalog.captchaRequired && activeCatalog.recaptchaSiteKey) {\n try {\n recaptchaToken = await getRecaptchaV3Token(\n activeCatalog.recaptchaSiteKey,\n );\n } catch (err) {\n console.warn(\"[WebSDK] reCAPTCHA v3 token could not be minted\", err);\n // Send without a token and let the backend decide — it owns the\n // policy, and a blocked third-party script must not silently kill\n // the whole feature.\n }\n }\n\n const input: SendExploreMessageInput = {\n message: text,\n ...(conversationTokenRef.current\n ? { conversationToken: conversationTokenRef.current }\n : {}),\n ...(focusProductRef.current || productSlug\n ? { productSlug: focusProductRef.current ?? productSlug }\n : {}),\n ...(recaptchaToken ? { recaptchaToken } : {}),\n ...(locale ? { locale } : {}),\n ...(pageUrl ? { pageUrl } : {}),\n ...(attachments.length > 0 ? { attachments: [...attachments] } : {}),\n };\n\n const res = await client.mutate<SendExploreMessageMutationData>(\n SEND_EXPLORE_MESSAGE_MUTATION,\n { input },\n { timeoutMs: SEND_REQUEST_TIMEOUT_MS },\n );\n if (!mountedRef.current) return;\n\n const first = res.errors?.[0];\n const result = res.data?.sendExploreMessage;\n\n if (first || !result) {\n const code =\n typeof first?.extensions?.code === \"string\"\n ? first.extensions.code\n : undefined;\n const classified = classifyExploreError(code, first?.message);\n\n // CAPTCHA_FAILED: one silent re-mint + re-send before bothering the\n // visitor. v3 tokens expire in ~2 minutes and are single-use, so a\n // stale one is a routine, self-healing failure.\n if (classified.kind === \"captcha\" && captchaAttempt === 0) {\n await submit(text, optimisticId, 1, attachments);\n return;\n }\n\n inFlightRef.current = false;\n setError(classified);\n setPhase(classified.kind === \"rate-limit\" ? \"limited\" : \"error\");\n return;\n }\n\n rememberConversationToken(result.conversation.token);\n turnCountRef.current = result.conversation.turnCount;\n setTurnCount(result.conversation.turnCount);\n setRemainingToday(result.remainingToday ?? null);\n\n const userMessage = result.userMessage;\n const assistantMessage = result.assistantMessage;\n\n // Swap the optimistic user bubble for the server's, then append the\n // PENDING assistant turn that the poll chain will fill in. The `some`\n // guard keeps the visitor's words on screen even in the impossible case\n // where the optimistic bubble is already gone.\n setMessages((prev) => {\n const replaced = prev.some((m) => m.id === optimisticId)\n ? prev.map((m) => (m.id === optimisticId ? userMessage : m))\n : [...prev, userMessage];\n return [...replaced, assistantMessage];\n });\n\n if (\n assistantMessage.status === \"COMPLETED\" ||\n assistantMessage.status === \"FAILED\"\n ) {\n inFlightRef.current = false;\n if (assistantMessage.status === \"FAILED\") {\n const classified = classifyExploreError(\n assistantMessage.errorCode ?? \"UPSTREAM_UNAVAILABLE\",\n );\n setError(classified);\n setPhase(\"error\");\n } else {\n setPhase(\"ready\");\n }\n return;\n }\n\n setPhase(\"streaming\");\n startPolling(result.conversation.token, assistantMessage.id);\n },\n [\n client,\n locale,\n pageUrl,\n productSlug,\n rememberConversationToken,\n startPolling,\n ],\n );\n\n const send = useCallback(\n async (\n message: string,\n attachments: readonly ExploreAttachmentPayload[] = [],\n ): Promise<void> => {\n const text = message.trim();\n // A question is still required: files are extra context for a question, not a question\n // on their own. The model has no way to guess what to do with a bare document.\n if (!text) return;\n if (inFlightRef.current) return;\n\n const activeCatalog = catalogRef.current;\n if (!activeCatalog.enabled) {\n setError(classifyExploreError(\"EXPLORE_DISABLED\"));\n setPhase(\"disabled\");\n return;\n }\n if (text.length > activeCatalog.limits.maxMessageLength) {\n setError({\n kind: \"validation\",\n code: \"MESSAGE_TOO_LONG\",\n message: `That message is ${text.length} characters — the limit is ${activeCatalog.limits.maxMessageLength}.`,\n retryable: false,\n });\n return;\n }\n if (\n turnCountRef.current >= activeCatalog.limits.maxTurnsPerConversation\n ) {\n setError({\n kind: \"validation\",\n code: \"CONVERSATION_LIMIT\",\n message: `This conversation has reached its ${activeCatalog.limits.maxTurnsPerConversation}-message limit. Start a new chat to keep going.`,\n retryable: false,\n });\n return;\n }\n\n inFlightRef.current = true;\n lastSentTextRef.current = text;\n lastSentAttachmentsRef.current = attachments;\n setError(null);\n setPhase(\"sending\");\n cancelPolling();\n\n // Optimistic user bubble — the composer clears instantly instead of\n // waiting a network round-trip for the visitor's own words.\n const optimistic: ExploreMessage = {\n id: makeOptimisticId(),\n conversationId: conversationTokenRef.current ?? \"pending\",\n role: \"USER\",\n status: \"COMPLETED\",\n content: text,\n partialContent: null,\n activity: [],\n references: [],\n ctas: [],\n errorCode: null,\n createdAt: new Date().toISOString(),\n completedAt: new Date().toISOString(),\n };\n setMessages((prev) => [...prev, optimistic]);\n turnCountRef.current += 1;\n setTurnCount(turnCountRef.current);\n onSend?.(text);\n\n try {\n await submit(text, optimistic.id, 0, attachments);\n } catch (err) {\n if (!mountedRef.current) return;\n console.error(\"[WebSDK] Explore send failed\", err);\n inFlightRef.current = false;\n setError(classifyExploreError(\"NETWORK_ERROR\"));\n setPhase(\"error\");\n }\n },\n [cancelPolling, onSend, submit],\n );\n\n const stop = useCallback(() => {\n cancelPolling();\n inFlightRef.current = false;\n setMessages((prev) =>\n prev.flatMap<ExploreMessage>((m) => {\n if (m.role !== \"ASSISTANT\") return [m];\n if (m.status !== \"PENDING\" && m.status !== \"RUNNING\") return [m];\n const text = visibleText(m);\n // Nothing streamed yet — drop the placeholder instead of leaving an\n // empty bubble behind.\n if (!text) return [];\n return [\n {\n ...m,\n status: \"COMPLETED\",\n content: text,\n completedAt: new Date().toISOString(),\n },\n ];\n }),\n );\n setPhase((prev) =>\n prev === \"sending\" || prev === \"streaming\" ? \"ready\" : prev,\n );\n }, [cancelPolling]);\n\n const retry = useCallback(() => {\n const text = lastSentTextRef.current;\n if (!text) return;\n cancelPolling();\n inFlightRef.current = false;\n // Drop the failed turn (and the user bubble that produced it) so the retry\n // does not stack a duplicate pair into the transcript.\n setMessages((prev) => {\n const next = [...prev];\n const last = next[next.length - 1];\n if (last?.role === \"ASSISTANT\" && last.status === \"FAILED\") next.pop();\n const prior = next[next.length - 1];\n if (prior?.role === \"USER\" && prior.content === text) next.pop();\n return next;\n });\n turnCountRef.current = Math.max(0, turnCountRef.current - 1);\n setTurnCount(turnCountRef.current);\n void send(text, lastSentAttachmentsRef.current);\n }, [cancelPolling, send]);\n\n const reset = useCallback(() => {\n // Archive the thread being left behind, so \"New chat\" never destroys history.\n setArchive(\n upsertArchive(storageKey, {\n token: conversationTokenRef.current,\n messages: messagesRef.current,\n focusProduct: focusProductRef.current,\n }),\n );\n cancelPolling();\n inFlightRef.current = false;\n rememberConversationToken(null);\n lastSentTextRef.current = null;\n lastSentAttachmentsRef.current = [];\n turnCountRef.current = 0;\n setTurnCount(0);\n setMessages([]);\n setError(null);\n setRemainingToday(null);\n setPhase(catalogRef.current.enabled ? \"ready\" : \"disabled\");\n if (typeof window !== \"undefined\") {\n try {\n window.localStorage.removeItem(storageKey);\n } catch {\n /* storage unavailable — nothing to clear */\n }\n }\n }, [cancelPolling, rememberConversationToken, storageKey]);\n\n /**\n * Reopen a past conversation. The messages come from the local archive rather than the server:\n * the backend expires a job's state, and a visitor looking at their own history should see it\n * whether or not the server still holds anything. The token is restored too, so the next\n * message continues the SAME server-side conversation.\n */\n const openConversation = useCallback(\n (token: string) => {\n const entry = readArchive(storageKey).find((e) => e.token === token);\n if (!entry) return;\n // Archive whatever is on screen first, or switching away would lose it.\n upsertArchive(storageKey, {\n token: conversationTokenRef.current,\n messages: messagesRef.current,\n focusProduct: focusProductRef.current,\n });\n cancelPolling();\n inFlightRef.current = false;\n rememberConversationToken(entry.token);\n turnCountRef.current = entry.messages.filter(\n (m) => m.role === \"USER\",\n ).length;\n setTurnCount(turnCountRef.current);\n setMessages(entry.messages);\n focusProductRef.current = entry.focusProduct;\n setFocusProductState(entry.focusProduct);\n setError(null);\n setPhase(catalogRef.current.enabled ? \"ready\" : \"disabled\");\n setArchive(readArchive(storageKey));\n },\n [cancelPolling, rememberConversationToken, storageKey],\n );\n\n /** Forget one past conversation. Local only — see the page's storage notice. */\n const deleteConversation = useCallback(\n (token: string) => {\n const next = readArchive(storageKey).filter((e) => e.token !== token);\n writeArchive(storageKey, next);\n setArchive(next);\n },\n [storageKey],\n );\n\n /** Forget every past conversation held in this browser. */\n const clearHistory = useCallback(() => {\n writeArchive(storageKey, []);\n setArchive([]);\n }, [storageKey]);\n\n const setFocusProduct = useCallback((slug: string | null) => {\n focusProductRef.current = slug;\n setFocusProductState(slug);\n }, []);\n\n const activity = useMemo<string | null>(() => {\n for (let i = messages.length - 1; i >= 0; i -= 1) {\n const m = messages[i];\n if (!m || m.role !== \"ASSISTANT\") continue;\n if (m.status !== \"PENDING\" && m.status !== \"RUNNING\") return null;\n const lines = m.activity ?? [];\n return lines.length ? (lines[lines.length - 1] ?? null) : null;\n }\n return null;\n }, [messages]);\n\n const canSend =\n (phase === \"ready\" || phase === \"error\") &&\n catalog.enabled &&\n turnCount < catalog.limits.maxTurnsPerConversation;\n\n /**\n * Tell the server the visitor followed one of the links this answer offered.\n *\n * Deliberately fire-and-forget and never awaited: the browser is navigating away as this\n * goes out, so anything that blocked on it would delay the click the visitor actually\n * made. Failures are swallowed — analytics must never break navigation.\n */\n const createShareLink = useCallback(async (): Promise<string | null> => {\n const token = conversationTokenRef.current;\n if (!token) return null;\n try {\n const result = await client.mutate<{\n createExploreShareLink?: { shareToken?: string | null } | null;\n }>(CREATE_EXPLORE_SHARE_LINK_MUTATION, { conversationToken: token });\n return result?.data?.createExploreShareLink?.shareToken ?? null;\n } catch {\n // Sharing is a convenience; a failure must not take the conversation down with it.\n return null;\n }\n }, [client]);\n\n const recordClick = useCallback(\n (messageId: string, kind: \"CTA\" | \"REFERENCE\", url: string): void => {\n const token = conversationTokenRef.current;\n if (!token) return;\n try {\n void client\n .mutate(RECORD_EXPLORE_CLICK_MUTATION, {\n input: { conversationToken: token, messageId, kind, url },\n })\n .catch(() => {\n /* the visitor is mid-navigation; there is nothing useful to do here */\n });\n } catch {\n /* client unavailable — same reasoning */\n }\n },\n [client],\n );\n\n /**\n * Rate one answer, and fold the server's record back into the transcript.\n *\n * The fold matters beyond the control that triggered it: `messages` is what the persist\n * effect writes to localStorage, so a rating stored here survives a reload of the same\n * conversation and not just this render. The optimistic state in the UI covers the moment\n * before this resolves; this covers everything after.\n */\n const submitFeedback = useCallback(\n async (\n messageId: string,\n rating: ExploreFeedbackRating,\n detail?: {\n reason?: ExploreFeedbackReason | null;\n comment?: string | null;\n },\n ): Promise<boolean> => {\n const token = conversationTokenRef.current;\n // No conversation of our own (a fresh page, or a read-only shared view, whose `?c=`\n // secret is not a conversation token): the server could only answer `recorded: false`.\n if (!token) return false;\n\n const comment = detail?.comment?.trim();\n // Annotated, not inferred. `client.mutate` types its variables as an open\n // `Record<string, unknown>`, so an input literal passed inline is unchecked — renaming\n // `messageId` to `id`, or adding a key the server does not accept, would compile\n // cleanly and fail only at runtime against the live gateway. Naming the type is what\n // makes CONTRACT.md compile-checked. `sendMessage` above does the same.\n const input: SubmitExploreFeedbackInput = {\n conversationToken: token,\n messageId,\n rating,\n // Only meaningful with NOT_HELPFUL. The server stores null for HELPFUL either\n // way; sending it would just be noise the backend has to defend against.\n reason: rating === \"NOT_HELPFUL\" ? (detail?.reason ?? null) : null,\n comment: comment ? comment : null,\n };\n try {\n const res = await client.mutate<SubmitExploreFeedbackMutationData>(\n SUBMIT_EXPLORE_FEEDBACK_MUTATION,\n { input },\n );\n const result = res?.data?.submitExploreFeedback;\n if (!result?.recorded) return false;\n\n const recorded = result.feedback;\n if (recorded && mountedRef.current) {\n setMessages((current) =>\n current.map((message) =>\n message.id === messageId\n ? { ...message, feedback: recorded }\n : message,\n ),\n );\n }\n return true;\n } catch {\n // `client.mutate` resolves every outcome rather than throwing, so this is belt and\n // braces for a client that is not there at all. Either way: not recorded.\n return false;\n }\n },\n [client],\n );\n\n /**\n * Hand the conversation to a person.\n *\n * The visitor pressed a control and is waiting on it, so this is awaited and reports what\n * actually happened rather than a boolean: `already-handed-over` in particular is a\n * SUCCESS the caller has to be able to tell apart from a failure, and `invalid-email` is\n * the server's verdict on an address the form's own check let through.\n *\n * `email` never leaves this function except in the mutation variables. It is not folded\n * into `messages` (the persist effect writes those to localStorage), not written to\n * storage directly, and not passed to `onSend`. Anyone adding \"just log the address\" here\n * is putting personal data in a place nothing ever deletes it from.\n */\n const escalate = useCallback(\n async (email: string, note?: string): Promise<ExploreEscalateResult> => {\n const token = conversationTokenRef.current;\n // A read-only shared view (its `?c=` secret is not a conversation token) and a page\n // where nothing has been asked yet both land here. The server could only answer\n // NOT_FOUND, so do not spend a request finding that out.\n if (!token) {\n return { outcome: \"no-conversation\", email: null, createdAt: null };\n }\n\n const attempt = async (\n captchaAttempt: number,\n ): Promise<ExploreEscalateResult> => {\n const activeCatalog = catalogRef.current;\n\n // Exactly what `submit` does, including the default action — the contract puts the\n // whole explore surface on ONE v3 action on purpose, because an action mismatch is a\n // silent 100% rejection.\n let recaptchaToken: string | undefined;\n if (activeCatalog.captchaRequired && activeCatalog.recaptchaSiteKey) {\n try {\n recaptchaToken = await getRecaptchaV3Token(\n activeCatalog.recaptchaSiteKey,\n );\n } catch (err) {\n console.warn(\n \"[WebSDK] reCAPTCHA v3 token could not be minted\",\n err,\n );\n // Send without one and let the backend decide: it owns the policy, and a\n // blocked third-party script must not be what stops someone reaching a human.\n }\n }\n\n // Annotated, not inferred — `client.mutate` types its variables as an open\n // `Record<string, unknown>`, so an inline literal is unchecked and a renamed field\n // would compile cleanly and fail against the live gateway. Same rule as\n // `submitFeedback` and `submit`.\n const input: EscalateExploreConversationInput = {\n conversationToken: token,\n email: email.trim(),\n note: note?.trim() ? note.trim() : null,\n ...(recaptchaToken ? { recaptchaToken } : {}),\n ...(productId ? { productId } : {}),\n };\n\n try {\n const res =\n await client.mutate<EscalateExploreConversationMutationData>(\n ESCALATE_EXPLORE_CONVERSATION_MUTATION,\n { input },\n );\n\n const first = res?.errors?.[0];\n const result = res?.data?.escalateExploreConversation;\n\n if (first || !result) {\n const code =\n typeof first?.extensions?.code === \"string\"\n ? first.extensions.code\n : \"ESCALATION_FAILED\";\n\n // One silent re-mint, exactly as `submit` does: a v3 token is single-use and\n // expires in ~2 minutes, so a rejected one is routine and self-healing.\n if (code === \"CAPTCHA_FAILED\" && captchaAttempt === 0) {\n return attempt(1);\n }\n\n return {\n outcome: escalateOutcomeForCode(code),\n email: null,\n createdAt: null,\n };\n }\n\n return {\n // `created: false` is the double-click, the retry, the reload. The handover\n // exists, so this is a success — and the address comes from the SERVER, because\n // on a repeat submit the reply goes to whatever the FIRST handover used.\n outcome: result.created ? \"sent\" : \"already-handed-over\",\n email: result.escalation?.email ?? null,\n createdAt: result.escalation?.createdAt ?? null,\n };\n } catch {\n // `client.mutate` resolves every transport outcome rather than throwing, so this\n // is for a client that is not there at all. Either way: nothing was handed over,\n // and this function's contract is that it never throws at the caller.\n return { outcome: \"failed\", email: null, createdAt: null };\n }\n };\n\n return attempt(0);\n },\n [client, productId],\n );\n\n /**\n * A shared view holds a share secret, not a conversation token, so `hasConversation` is\n * already false there. Both are named anyway: the second is the reason, and a later\n * refactor that starts restoring a token under a shared transcript should fail this\n * condition rather than quietly start offering the form.\n */\n const canEscalate = hasConversation && !isSharedView;\n\n return {\n phase,\n catalog,\n messages,\n activity,\n remainingToday,\n error,\n focusProduct,\n setFocusProduct,\n send,\n stop,\n retry,\n reset,\n canSend,\n history: archive,\n openConversation,\n deleteConversation,\n clearHistory,\n recordClick,\n submitFeedback,\n escalate,\n canEscalate,\n createShareLink,\n isSharedView,\n };\n}\n\n/**\n * Client-only id for the optimistic user bubble, swapped for the server's\n * `userMessage.id` as soon as the mutation resolves. The counter only has to\n * make ids unique within a tab, never across one.\n */\nlet optimisticCounter = 0;\n\nfunction makeOptimisticId(): string {\n optimisticCounter += 1;\n return `boff-explore-local-${Date.now()}-${optimisticCounter}`;\n}\n","\"use client\";\n\nimport { useEffect, useRef, useState } from \"react\";\n\n/**\n * Reveal an in-flight answer at a readable pace instead of in poll-sized blocks.\n *\n * ## What this is NOT\n *\n * It is not a transport change. `/explore` answers arrive by submit-and-poll, one\n * `exploreMessage` read every ~1.5s (CONTRACT.md §1), and nothing here touches that: no\n * extra request, no shorter interval, no socket. Every character this reveals had already\n * been fetched — the hook only decides *when it is painted*.\n *\n * ## The guarantees\n *\n * - **Only text that arrived.** What it returns is always a PREFIX of the string it was\n * given, so it can neither invent a word nor reorder one. When the answer is rewritten\n * rather than appended to — the final `content` replacing a `partialContent` that was cut\n * mid-token — it jumps to the end rather than showing a prefix of the old answer inside\n * the new one.\n * - **Never behind a finished answer.** `settled` (the turn is COMPLETED or FAILED) returns\n * the whole string immediately, on the render it flips. Nobody waits on an animation for\n * text that is already in hand, and a restored or shared transcript paints in full on its\n * first frame.\n * - **A table is painted as a table or not at all.** A GFM header row without its `| --- |`\n * row renders as a paragraph of pipes, so one is held back until that row arrives, for as\n * long as the answer is still running (CONTRACT.md §7). It is the one construct whose\n * rendering changes retroactively when a LATER line lands.\n * - **Reduced motion is not \"slower\".** `prefers-reduced-motion: reduce` gets the text at\n * once, with no timer started at all.\n * - **No scrolling, no measuring.** The hook returns a string. It reads no box, writes no\n * scroll position and renders no element, so it cannot fight the transcript's\n * `stickToBottom` logic or the pane geometry — the page was fixed once already for\n * showing nothing but the site footer, and the fix lives in effects that this cannot\n * reach.\n *\n * ## The pace\n *\n * Adaptive rather than a fixed characters-per-second: the cursor moves at whatever speed\n * drains the *backlog* in {@link DRAIN_TARGET_MS}, which is a little under the poll\n * interval. A fast turn therefore reads fast and a trickling one still moves, and the\n * cursor catches up with the arrived text before the next chunk lands instead of falling\n * further behind with every poll.\n */\n\n/** Drain whatever has arrived in about this long — just inside the ~1.5s poll interval. */\nconst DRAIN_TARGET_MS = 1200;\n/** A floor, so the last few characters of a chunk still move rather than crawl. */\nconst MIN_CHARS_PER_SECOND = 90;\n/** A ceiling, so a large backlog is caught up with quickly but not in one frame. */\nconst MAX_CHARS_PER_SECOND = 2200;\n/**\n * The most one step may advance by, however long the gap was. A backgrounded tab stops\n * firing frames entirely, and without this the first frame after it comes back would paint\n * the whole answer at once — the snap this exists to remove.\n */\nconst MAX_STEP_MS = 250;\n/**\n * How often a step is allowed to re-render. Every commit re-parses the answer's markdown,\n * and doing that once a frame is wasted work nobody can see; ~22 commits a second reads as\n * continuous.\n */\nconst COMMIT_INTERVAL_MS = 45;\n/** Only used where `requestAnimationFrame` does not exist. */\nconst FALLBACK_STEP_MS = 50;\n\n/** A ``` or ~~~ fence, which opens or closes a verbatim block. */\nconst FENCE = /^ {0,3}(?:```|~~~)/;\n/** A GFM table row. */\nconst TABLE_ROW = /^ {0,3}\\|/;\n/** A block marker with nothing after it yet — a bullet or heading mid-keystroke. */\nconst EMPTY_BLOCK_MARKER = /^ {0,3}(?:[-+>]|#{1,6}|\\d{1,9}[.)])\\s*$/;\n\n/**\n * A character that makes `_` part of a word rather than emphasis. Deliberately wider than\n * ASCII: `día_uno` is one word in Spanish exactly as `day_one` is in English.\n */\nfunction isWordCharacter(char: string | undefined): boolean {\n return char !== undefined && /[\\p{L}\\p{N}]/u.test(char);\n}\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.min(Math.max(value, min), max);\n}\n\nfunction now(): number {\n return typeof performance !== \"undefined\" &&\n typeof performance.now === \"function\"\n ? performance.now()\n : Date.now();\n}\n\n/** The first half of an astral character — a cut here would paint a replacement glyph. */\nfunction isHighSurrogate(code: number): boolean {\n return code >= 0xd800 && code <= 0xdbff;\n}\n\n/**\n * Where an incomplete LINE may be cut: before the first inline construct it has left open.\n *\n * Markdown is not revealable one character at a time as written. Cutting `**Starter**` after\n * `**Star` paints two literal asterisks, and the same half-written `[label](https://…` paints\n * a bracket and a raw URL, which then rearrange themselves a frame later. Holding the cut at\n * the point the construct OPENED costs a few characters of delay and never paints syntax.\n *\n * Scanned per line on purpose. Emphasis that spans a line break is rare, and carrying an\n * unclosed marker across lines would pin the cut arbitrarily far back.\n *\n * ## What is NOT an open construct\n *\n * A marker character in ordinary prose must not pin the cut, because the pin lasts for the\n * REST OF THE LINE: an answer's paragraph is one unwrapped line, so a `~` that never closes\n * would freeze the reveal mid-sentence and then paint the remaining hundred characters in a\n * single commit — the snap this hook exists to remove. So:\n *\n * - **A lone `*`, `_` or `~` opens nothing.** `answerPlainText` reached the same rule from\n * the other side (\"single-delimiter emphasis only when it wraps a run\"): a `* ` bullet, a\n * `snake_case` identifier, a `~30 seconds`, and a `per seat*` footnote mark are all one\n * literal character, and one literal character on screen for a frame is far cheaper than a\n * frozen paragraph. A run of two or more (`**`, `__`, `~~`) is markup often enough to be\n * worth the wait.\n * - **Intraword `_` is not emphasis at all**, per CommonMark — `MAX__TURNS__PER` neither\n * opens nor closes, whatever the run length.\n * - **A run with whitespace after it opens nothing**, also per CommonMark: it is not a\n * left-flanking delimiter run. Whitespace after the END of the arrived text is unknown,\n * not absent, so a line ending in `**` still holds — that is the `**29` case above.\n */\nfunction safeInlineEnd(line: string): number {\n let codeSpan: number | null = null;\n let link: number | null = null;\n const emphasis: Array<{ marker: string; start: number }> = [];\n\n let at = 0;\n while (at < line.length) {\n const char = line[at] ?? \"\";\n if (char === \"\\\\\") {\n // An escape and whatever it escapes are one unit and carry no meaning of their own.\n at += 2;\n continue;\n }\n if (char === \"`\") {\n let run = 1;\n while (line[at + run] === \"`\") run += 1;\n codeSpan = codeSpan === null ? at : null;\n at += run;\n continue;\n }\n if (codeSpan !== null) {\n // Inside a code span nothing else is markup.\n at += 1;\n continue;\n }\n if (char === \"[\") {\n // `![` is an image; either way the bracket is what opens it.\n if (link === null) link = line[at - 1] === \"!\" ? at - 1 : at;\n at += 1;\n continue;\n }\n if (char === \"]\") {\n // `[3]` is a citation marker and closes here. `](` carries on into the destination.\n if (link !== null && line[at + 1] !== \"(\") link = null;\n at += 1;\n continue;\n }\n if (char === \")\") {\n link = null;\n at += 1;\n continue;\n }\n if (char === \"*\" || char === \"_\" || char === \"~\") {\n let run = 1;\n while (line[at + run] === char) run += 1;\n const start = at;\n at += run;\n const before = line[start - 1];\n const after = line[start + run];\n\n // See \"What is NOT an open construct\" above for all three of these.\n if (run < 2) continue;\n if (char === \"_\" && isWordCharacter(before) && isWordCharacter(after)) {\n continue;\n }\n\n const marker = char.repeat(run);\n const open = emphasis.findIndex((entry) => entry.marker === marker);\n // Closing first: a run that ends emphasis is usually followed by a space, and the\n // opener guard below would otherwise leave that run open forever.\n if (open !== -1) {\n emphasis.splice(open, 1);\n continue;\n }\n if (after !== undefined && /\\s/.test(after)) continue;\n emphasis.push({ marker, start });\n continue;\n }\n at += 1;\n }\n\n const open = [codeSpan, link, emphasis[0]?.start ?? null].filter(\n (value): value is number => value !== null,\n );\n return open.length === 0 ? line.length : Math.min(...open);\n}\n\n/**\n * The largest index at or below `limit` that `text` may be cut at and still render as the\n * markdown it will eventually be.\n *\n * Three block rules, then the inline scan above:\n *\n * - **A half-written fenced block is held at its fence.** Until the closing fence arrives\n * the opening one is just three backticks and a word, and the code inside it is prose.\n * - **A table is held until its delimiter row is complete.** A GFM table is only a table\n * once the `| --- |` row exists; before that the header renders as a paragraph full of\n * pipes, which then becomes a table — the single most jarring thing an answer can do.\n * Complete means a WHOLE line: half of `| --- | --- |` is not a delimiter row, and one\n * that has not been closed by a newline may still grow another column. Afterwards only\n * the incomplete row is held, so the table grows a row at a time.\n * - **A bare block marker is held.** `-`, `>` or `####` with nothing after it yet paints an\n * empty bullet or an empty heading.\n *\n * Reaching the end of the arrived text (`limit >= text.length`) releases all of it but the\n * table, because the cursor being level with the text is the NORMAL end state of a poll, not\n * an edge case: the pace drains a chunk in {@link DRAIN_TARGET_MS}, inside the ~1.5s\n * interval, so every poll ends caught up. A construct that is only ever held while the\n * cursor is behind is therefore held only for the part of a chunk it happens to land in.\n *\n * The table is the one that cannot be left to that, and it is the only one that NEEDS more\n * than the text in hand to render correctly. A header row whose delimiter row is in the next\n * poll would be painted as a paragraph of pipes and then, because a cut never moves\n * backwards, stay one on screen while the rest of the table grows below it. An unclosed\n * fence, by contrast, already renders as the code block it will be (CommonMark runs it to\n * the end of the document), and a `- ` bullet already renders as a bullet.\n *\n * Nothing here decides what a FINISHED answer paints: {@link useProgressiveReveal} returns\n * `content` whole the moment the turn settles, without asking.\n */\nexport function revealBoundary(text: string, limit: number): number {\n if (limit <= 0) return 0;\n\n /** True when the cursor has reached everything that has arrived. */\n const caughtUp = limit >= text.length;\n const head = caughtUp ? text : text.slice(0, limit);\n const lineStart = head.lastIndexOf(\"\\n\") + 1;\n const line = head.slice(lineStart);\n\n // Block state, from the WHOLE lines before the cut.\n let fenceStart: number | null = null;\n let tableStart: number | null = null;\n let tableRows = 0;\n let at = 0;\n while (at < lineStart) {\n const breakAt = head.indexOf(\"\\n\", at);\n const end = breakAt === -1 ? lineStart : breakAt;\n const row = head.slice(at, end);\n if (fenceStart !== null) {\n if (FENCE.test(row)) fenceStart = null;\n } else if (FENCE.test(row)) {\n fenceStart = at;\n } else if (TABLE_ROW.test(row)) {\n if (tableStart === null) {\n tableStart = at;\n tableRows = 0;\n }\n tableRows += 1;\n } else if (tableStart !== null) {\n tableStart = null;\n tableRows = 0;\n }\n at = end + 1;\n }\n\n // The last line is not a whole line: the rest of it may still be on its way. A `|` on it\n // still OPENS a table, and an empty one (the text ends at the newline after the row above)\n // has not closed the table it follows either.\n if (fenceStart === null) {\n const lastIsRow = TABLE_ROW.test(line);\n if (lastIsRow && tableStart === null) {\n // It opens a table. It does not COUNT as one of the two rows a table needs: half of\n // `| --- |` is not a delimiter row.\n tableStart = lineStart;\n tableRows = 0;\n } else if (!lastIsRow && line !== \"\") {\n tableStart = null;\n tableRows = 0;\n }\n // Held even at the end of the arrived text — see the note above.\n if (tableStart !== null && tableRows < 2) return tableStart;\n }\n\n if (caughtUp) return text.length;\n if (fenceStart !== null) return fenceStart;\n if (TABLE_ROW.test(line)) return lineStart;\n if (EMPTY_BLOCK_MARKER.test(line)) return lineStart;\n\n const cut = lineStart + safeInlineEnd(line);\n return isHighSurrogate(text.charCodeAt(cut - 1)) ? cut - 1 : cut;\n}\n\n/**\n * True when the visitor has asked for less movement. Read once per mount rather than per\n * render: `matchMedia` is absent on some engines (and in jsdom), and a setting that changes\n * mid-answer is not worth a subscription.\n *\n * Server-side this answers true, so a prerender serialises the finished text rather than an\n * animation's first frame.\n */\nfunction prefersReducedMotion(): boolean {\n if (typeof window === \"undefined\") return true;\n try {\n return (\n window.matchMedia?.(\"(prefers-reduced-motion: reduce)\").matches === true\n );\n } catch {\n /* an engine whose matchMedia throws on an unknown feature — treat as no preference */\n return false;\n }\n}\n\n/**\n * The part of `text` that is currently on screen.\n *\n * @param text everything that has arrived so far — `content` once the turn completes,\n * `partialContent` while it runs.\n * @param settled true once the turn is COMPLETED or FAILED and `text` will not grow again.\n */\nexport function useProgressiveReveal(text: string, settled: boolean): string {\n const [, setFrame] = useState(0);\n const [reduced] = useState(prefersReducedMotion);\n const immediate = settled || reduced;\n\n /** The text the cursor below points into. */\n const textRef = useRef(text);\n /** How far the cursor has travelled, fractionally — a step is usually part of a character. */\n const cursorRef = useRef(immediate ? text.length : 0);\n /** The last cut actually rendered, so a cut can never move backwards. */\n const cutRef = useRef(immediate ? text.length : 0);\n const committedRef = useRef(0);\n\n // Reconciled during render, not in an effect: what this function returns has to describe\n // the text it was handed THIS render, never the previous answer for a frame.\n if (text !== textRef.current) {\n const revealed = textRef.current.slice(0, Math.floor(cursorRef.current));\n if (revealed !== \"\" && !text.startsWith(revealed)) {\n // Rewritten rather than appended to. Everything on screen must be text that arrived,\n // so finish rather than show the old prefix inside the new answer.\n cursorRef.current = text.length;\n }\n cursorRef.current = Math.min(cursorRef.current, text.length);\n cutRef.current = Math.min(cutRef.current, text.length);\n textRef.current = text;\n }\n if (immediate) cursorRef.current = text.length;\n\n // A settled turn paints whole rather than asking the boundary. `content` is the entire\n // answer, so a table it stops in the middle of is all the table there is ever going to\n // be, and holding it back would hold it back for good.\n const cut = immediate\n ? text.length\n : Math.max(\n cutRef.current,\n revealBoundary(text, Math.floor(cursorRef.current)),\n );\n cutRef.current = cut;\n\n useEffect(() => {\n if (immediate) return;\n if (cursorRef.current >= text.length) return;\n\n let cancelled = false;\n let cancelStep: (() => void) | null = null;\n let previous = now();\n\n const commit = (at: number, force: boolean): void => {\n if (!force && at - committedRef.current < COMMIT_INTERVAL_MS) return;\n committedRef.current = at;\n setFrame((value) => value + 1);\n };\n\n const step = (): void => {\n cancelStep = null;\n if (cancelled) return;\n\n const at = now();\n const elapsed = clamp(at - previous, 0, MAX_STEP_MS);\n previous = at;\n\n const length = textRef.current.length;\n const pending = length - cursorRef.current;\n if (pending <= 0) {\n commit(at, true);\n return;\n }\n\n const perSecond = clamp(\n pending / (DRAIN_TARGET_MS / 1000),\n MIN_CHARS_PER_SECOND,\n MAX_CHARS_PER_SECOND,\n );\n cursorRef.current = Math.min(\n length,\n cursorRef.current + (perSecond * elapsed) / 1000,\n );\n\n const done = cursorRef.current >= length;\n commit(at, done);\n if (!done) schedule();\n };\n\n const schedule = (): void => {\n if (typeof window.requestAnimationFrame === \"function\") {\n const id = window.requestAnimationFrame(step);\n cancelStep = () => window.cancelAnimationFrame(id);\n return;\n }\n const id = setTimeout(step, FALLBACK_STEP_MS);\n cancelStep = () => clearTimeout(id);\n };\n\n schedule();\n return () => {\n cancelled = true;\n cancelStep?.();\n };\n }, [text, immediate]);\n\n return text.slice(0, cut);\n}\n","\"use client\";\n\nimport { useCallback, useEffect, useRef, useState } from \"react\";\n\n/**\n * Dictation for the explore composer, on the browser's own speech recogniser.\n *\n * Uses the Web Speech API directly — no dependency, no network call of our own, no audio ever\n * leaving the browser through us. Support is genuinely partial (Chrome, Edge and Safari expose\n * it, most commonly behind the `webkit` prefix; Firefox does not implement it at all), so the\n * caller MUST hide the microphone entirely when `supported` is false rather than offering a\n * control that cannot work.\n *\n * Interim results are surfaced separately from final ones so the composer can show speech\n * appearing live while only committing settled text to the draft.\n *\n * ## Mobile\n *\n * Mobile took three separate fixes, each of which looked like the whole problem:\n *\n * 1. **The prompt never appeared.** `recognition.start()` raises the permission prompt on\n * desktop Chrome but on Android Chrome and iOS fires `not-allowed` without showing\n * anything, so a visitor who had never been asked was told to change a browser setting.\n * `getUserMedia` is what actually prompts, so it is primed first.\n * 2. **Granting still failed.** Recognition opens its OWN capture, and starting it in the same\n * tick that the primed stream is being torn down races that teardown. It now waits for the\n * release, and retries once — Android frequently refuses the first attempt after a\n * permission is newly granted and accepts the second.\n * 3. **`continuous` is not honoured on mobile.** Android Chrome ends the session after a\n * single utterance regardless, and asking for continuous mode makes it fail sooner. Mobile\n * therefore runs single-shot and is restarted from `onend` for as long as the visitor is\n * still dictating, which behaves like continuous without fighting the platform.\n */\n\ninterface SpeechRecognitionAlternativeLike {\n transcript: string;\n}\ninterface SpeechRecognitionResultLike {\n readonly isFinal: boolean;\n readonly length: number;\n [index: number]: SpeechRecognitionAlternativeLike;\n}\ninterface SpeechRecognitionEventLike {\n readonly resultIndex: number;\n readonly results: {\n readonly length: number;\n [index: number]: SpeechRecognitionResultLike;\n };\n}\ninterface SpeechRecognitionErrorEventLike {\n readonly error: string;\n}\ninterface SpeechRecognitionLike {\n lang: string;\n continuous: boolean;\n interimResults: boolean;\n maxAlternatives: number;\n start: () => void;\n stop: () => void;\n abort: () => void;\n onresult: ((event: SpeechRecognitionEventLike) => void) | null;\n onerror: ((event: SpeechRecognitionErrorEventLike) => void) | null;\n onend: (() => void) | null;\n onstart: (() => void) | null;\n}\ntype SpeechRecognitionCtor = new () => SpeechRecognitionLike;\n\ninterface SpeechWindow {\n SpeechRecognition?: SpeechRecognitionCtor;\n webkitSpeechRecognition?: SpeechRecognitionCtor;\n}\n\nfunction getRecognitionCtor(): SpeechRecognitionCtor | null {\n if (typeof window === \"undefined\") return null;\n const w = window as unknown as SpeechWindow;\n return w.SpeechRecognition ?? w.webkitSpeechRecognition ?? null;\n}\n\n/**\n * Coarse pointer means a touch device, which is what actually predicts the recogniser's\n * behaviour here — not the screen size, and not a UA string that lies.\n */\nfunction isTouchDevice(): boolean {\n if (typeof window === \"undefined\" || !window.matchMedia) return false;\n try {\n return window.matchMedia(\"(pointer: coarse)\").matches;\n } catch {\n return false;\n }\n}\n\nconst MIC_DENIED_MESSAGE =\n \"Microphone access was blocked. Allow it in your browser's site settings to dictate.\";\nconst MIC_UNAVAILABLE_MESSAGE =\n \"Dictation isn't available in this browser. You can type instead.\";\n\n/** Let a released capture settle before recognition opens its own. */\nconst RELEASE_SETTLE_MS = 250;\n/** Android often refuses the first start after a fresh grant and accepts the next. */\nconst RETRY_DELAY_MS = 350;\n\nconst sleep = (ms: number): Promise<void> =>\n new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\n\n/**\n * Ask for the microphone the only way that reliably raises a prompt on mobile.\n *\n * `confirmed` reports whether access was actually VERIFIED, which is what separates \"you need\n * to grant this\" from \"your browser cannot do this\" further down.\n *\n * Must be called synchronously from the user gesture that requested dictation — awaiting\n * anything first spends the gesture and the browser then rejects the request outright.\n */\nasync function ensureMicrophoneAccess(): Promise<\n | { ok: true; confirmed: boolean; primed: boolean }\n | { ok: false; message: string }\n> {\n const media =\n typeof navigator === \"undefined\" ? undefined : navigator.mediaDevices;\n // Older/unusual browsers without mediaDevices: fall through and let recognition try. It\n // may well work, and refusing here would remove dictation from browsers that support it.\n if (!media?.getUserMedia)\n return { ok: true, confirmed: false, primed: false };\n\n // `granted` means the prompt would not appear anyway, so skip the extra capture — which\n // also avoids the teardown race entirely on repeat use.\n //\n // A `denied` reading is deliberately NOT trusted to short-circuit. The Permissions API\n // reports `denied` for a prompt the visitor merely dismissed, and its microphone support\n // is uneven across mobile browsers — believing it would recreate the exact bug this\n // function exists to fix, telling someone to change a setting instead of asking them.\n // getUserMedia is the authoritative check, and when access really is denied it rejects\n // immediately without showing anything, so the only cost of asking is a settled promise.\n //\n // `permissions` is absent on Safari and `microphone` is not a valid name everywhere, so\n // every part of this is optional and failure is non-fatal.\n try {\n const status = await navigator.permissions?.query({\n name: \"microphone\" as PermissionName,\n });\n if (status?.state === \"granted\")\n return { ok: true, confirmed: true, primed: false };\n } catch {\n /* permissions API unavailable or the name is unsupported — prompt below instead */\n }\n\n try {\n const stream = await media.getUserMedia({ audio: true });\n // Release immediately: this capture existed only to raise the prompt, and leaving it\n // open would show a recording indicator for the whole session — and on mobile would\n // occupy the very microphone recognition is about to ask for.\n for (const track of stream.getTracks()) track.stop();\n return { ok: true, confirmed: true, primed: true };\n } catch (error) {\n const name =\n typeof error === \"object\" && error !== null && \"name\" in error\n ? String((error as { name: unknown }).name)\n : \"\";\n if (name === \"NotAllowedError\" || name === \"SecurityError\") {\n return { ok: false, message: MIC_DENIED_MESSAGE };\n }\n if (name === \"NotFoundError\" || name === \"DevicesNotFoundError\") {\n return { ok: false, message: \"No microphone was found.\" };\n }\n return {\n ok: false,\n message: \"Dictation could not start. You can type instead.\",\n };\n }\n}\n\n/** Messages a visitor can act on. `not-allowed` is the one that needs real explanation. */\nfunction describeError(code: string): string {\n switch (code) {\n case \"not-allowed\":\n case \"service-not-allowed\":\n return MIC_DENIED_MESSAGE;\n case \"no-speech\":\n return \"I didn't catch anything — try again a little closer to the mic.\";\n case \"audio-capture\":\n return \"No microphone was found.\";\n case \"network\":\n return \"Speech recognition needs a network connection.\";\n case \"aborted\":\n return \"\";\n default:\n return \"Dictation stopped unexpectedly. You can type instead.\";\n }\n}\n\nexport interface UseSpeechInputOptions {\n /** Receives settled text as it is recognised. Append it to the draft. */\n onFinalTranscript: (text: string) => void;\n /** BCP-47 tag. Defaults to the browser's language. */\n lang?: string;\n /** Called when the recogniser reports a problem worth showing. */\n onError?: (message: string) => void;\n}\n\nexport interface UseSpeechInputResult {\n /** False when the browser has no speech recogniser — hide the control entirely. */\n supported: boolean;\n listening: boolean;\n /** Words recognised but not yet settled; render as a live hint, do not store. */\n interim: string;\n error: string | null;\n start: () => void;\n stop: () => void;\n toggle: () => void;\n}\n\nexport function useSpeechInput({\n onFinalTranscript,\n lang,\n onError,\n}: UseSpeechInputOptions): UseSpeechInputResult {\n const [supported] = useState(() => getRecognitionCtor() !== null);\n const [listening, setListening] = useState(false);\n const [interim, setInterim] = useState(\"\");\n const [error, setError] = useState<string | null>(null);\n\n const recognitionRef = useRef<SpeechRecognitionLike | null>(null);\n /**\n * Bumped on every start()/stop(). A permission prompt, a settle delay or a retry resolving\n * after the visitor moved on must not open a microphone behind them.\n */\n const startTokenRef = useRef(0);\n /**\n * True only when the microphone was actually VERIFIED for this attempt — permission\n * reported granted, or getUserMedia succeeded. Stays false on browsers with no\n * mediaDevices, where nothing was checked and a recogniser `not-allowed` may still be a\n * real permission problem.\n */\n const micConfirmedRef = useRef(false);\n /** The visitor's intent, as opposed to whether a session happens to be open right now. */\n const wantsListeningRef = useRef(false);\n /** One retry per start(), for the Android \"refuses the first attempt\" case. */\n const retriedRef = useRef(false);\n\n // Held in refs so the recogniser's long-lived handlers always call the latest closures\n // without tearing down and re-creating the recogniser on every render.\n const finalRef = useRef(onFinalTranscript);\n const errorRef = useRef(onError);\n finalRef.current = onFinalTranscript;\n errorRef.current = onError;\n\n const langRef = useRef(lang);\n langRef.current = lang;\n\n const stop = useCallback(() => {\n startTokenRef.current += 1;\n wantsListeningRef.current = false;\n setListening(false);\n setInterim(\"\");\n const recognition = recognitionRef.current;\n if (!recognition) return;\n try {\n recognition.stop();\n } catch {\n /* already stopped */\n }\n }, []);\n\n /** Open a recogniser session. Separate from start() so a retry can reuse it. */\n const openSession = useCallback((token: number) => {\n const Ctor = getRecognitionCtor();\n if (!Ctor || token !== startTokenRef.current) return;\n\n const recognition = new Ctor();\n recognition.lang =\n langRef.current ??\n (typeof navigator === \"undefined\"\n ? \"en-US\"\n : navigator.language || \"en-US\");\n // Continuous mode is a desktop-only affordance. Android Chrome ends the session after a\n // single utterance whatever this says, and asking for continuous makes it fail sooner —\n // mobile is restarted from `onend` instead, which behaves the same to the visitor.\n recognition.continuous = !isTouchDevice();\n recognition.interimResults = true;\n recognition.maxAlternatives = 1;\n\n recognition.onstart = () => {\n if (token !== startTokenRef.current) return;\n // NOTE: the retry budget is deliberately NOT reset here. It belongs to the visitor's\n // press, not to the session — a browser that fires onstart and then immediately\n // errors would otherwise retry forever.\n setError(null);\n setListening(true);\n };\n\n recognition.onresult = (event) => {\n if (token !== startTokenRef.current) return;\n let settled = \"\";\n let pending = \"\";\n for (let i = event.resultIndex; i < event.results.length; i += 1) {\n const result = event.results[i];\n if (!result) continue;\n const text = result[0]?.transcript ?? \"\";\n if (result.isFinal) settled += text;\n else pending += text;\n }\n setInterim(pending);\n if (settled.trim() !== \"\") finalRef.current(settled);\n };\n\n recognition.onerror = (event) => {\n if (token !== startTokenRef.current) return;\n\n // Android commonly refuses the FIRST start after a permission is newly granted and\n // accepts the next one. Retry once, silently, before telling the visitor anything —\n // an error message they can do nothing about is worse than a short pause.\n if (\n (event.error === \"not-allowed\" ||\n event.error === \"service-not-allowed\") &&\n micConfirmedRef.current &&\n !retriedRef.current\n ) {\n retriedRef.current = true;\n void sleep(RETRY_DELAY_MS).then(() => {\n if (token !== startTokenRef.current || !wantsListeningRef.current)\n return;\n openSessionRef.current?.(token);\n });\n return;\n }\n\n // The microphone was verified moments ago, so a `not-allowed` that survived the retry\n // is the SPEECH SERVICE refusing, not a permission the visitor can grant. Sending them\n // to a site setting would point at something that cannot help.\n const message =\n micConfirmedRef.current &&\n (event.error === \"not-allowed\" || event.error === \"service-not-allowed\")\n ? MIC_UNAVAILABLE_MESSAGE\n : describeError(event.error);\n\n wantsListeningRef.current = false;\n setListening(false);\n setInterim(\"\");\n if (message !== \"\") {\n setError(message);\n errorRef.current?.(message);\n }\n };\n\n recognition.onend = () => {\n if (token !== startTokenRef.current) return;\n setInterim(\"\");\n // Single-shot mobile sessions end after each utterance. While the visitor still has\n // dictation switched on, reopen so it behaves like continuous mode.\n if (wantsListeningRef.current && isTouchDevice()) {\n void sleep(120).then(() => {\n if (token !== startTokenRef.current || !wantsListeningRef.current)\n return;\n openSessionRef.current?.(token);\n });\n return;\n }\n setListening(false);\n };\n\n recognitionRef.current = recognition;\n try {\n recognition.start();\n } catch {\n // Chrome throws InvalidStateError if start() races a session that is still closing.\n // The onend handler above will not fire for a session that never began, so settle here.\n wantsListeningRef.current = false;\n setListening(false);\n }\n }, []);\n\n // openSession refers to itself from its own handlers (retry, mobile restart), which a plain\n // const cannot do inside useCallback.\n const openSessionRef = useRef<((token: number) => void) | null>(null);\n openSessionRef.current = openSession;\n\n const start = useCallback(() => {\n if (!getRecognitionCtor()) return;\n\n startTokenRef.current += 1;\n const token = startTokenRef.current;\n wantsListeningRef.current = true;\n retriedRef.current = false;\n micConfirmedRef.current = false;\n\n // Show the pressed state straight away: the permission prompt can sit on screen for a\n // while on mobile, and a mic button that looks inert invites a second tap.\n setError(null);\n setListening(true);\n\n void ensureMicrophoneAccess().then(async (access) => {\n // A stop() or a newer start() landed while the prompt was open — abandon this attempt.\n if (token !== startTokenRef.current) return;\n\n if (!access.ok) {\n wantsListeningRef.current = false;\n setListening(false);\n setError(access.message);\n errorRef.current?.(access.message);\n return;\n }\n\n micConfirmedRef.current = access.confirmed;\n\n // Recognition opens its own capture. Starting in the same tick that the primed stream\n // is being torn down races that teardown and is refused — this is what made \"I granted\n // it and it still says blocked\" happen on mobile.\n if (access.primed) {\n await sleep(RELEASE_SETTLE_MS);\n if (token !== startTokenRef.current) return;\n }\n\n openSessionRef.current?.(token);\n });\n }, []);\n\n const toggle = useCallback(() => {\n if (listening) stop();\n else start();\n }, [listening, start, stop]);\n\n // Never leave the microphone open behind a closed page.\n useEffect(\n () => () => {\n startTokenRef.current += 1;\n wantsListeningRef.current = false;\n const recognition = recognitionRef.current;\n if (!recognition) return;\n recognition.onresult = null;\n recognition.onerror = null;\n recognition.onend = null;\n recognition.onstart = null;\n try {\n recognition.abort();\n } catch {\n /* nothing to abort */\n }\n },\n [],\n );\n\n return { supported, listening, interim, error, start, stop, toggle };\n}\n","\"use client\";\n\nimport { useCallback, useEffect, useRef, useState } from \"react\";\n\n/**\n * Read an answer aloud, on the browser's own speech synthesiser.\n *\n * The other half of {@link useSpeechInput}: that one turns a visitor's voice into a\n * question, this one turns our answer back into speech. Same posture — the Web Speech API\n * directly, no dependency, no request of ours, no cost, and nothing leaves the browser.\n *\n * ## Why `supported` can go false after a press\n *\n * `window.speechSynthesis` existing proves nothing. Several browsers expose the object and\n * then never speak: some Android WebViews with no TTS engine installed, Chrome on a machine\n * with no voices, and any engine where the utterance is refused without an `error` event.\n * There is no capability flag for that, so the only honest test is to try once — a press\n * that neither starts nor errors within {@link SILENT_FAILURE_MS}, while\n * `speechSynthesis.speaking` is still false, means this browser cannot do it and the control\n * removes itself. A button that does nothing, twice, is worse than no button.\n *\n * ## One voice per page\n *\n * `speechSynthesis` is a single queue shared by the whole document, so two answers reading\n * at once is not a thing the platform can do — a second `speak()` would simply queue behind\n * the first, minutes later. Every instance of this hook therefore registers with the\n * module-level owner below, and taking the voice stops whoever had it. {@link stopSpeaking}\n * is the same handle for code that is not a hook: the composer calls it when a new message\n * is sent, because an answer still reading aloud over the next question is the complaint\n * people actually make about pages that talk.\n */\n\ninterface SpeechSynthesisVoiceLike {\n readonly lang: string;\n readonly name: string;\n readonly default: boolean;\n}\n\ninterface SpeechSynthesisUtteranceLike {\n text: string;\n lang: string;\n voice: SpeechSynthesisVoiceLike | null;\n onstart: (() => void) | null;\n onend: (() => void) | null;\n onerror: ((event: { error?: string }) => void) | null;\n}\n\ntype SpeechSynthesisUtteranceCtor = new (\n text: string,\n) => SpeechSynthesisUtteranceLike;\n\ninterface SpeechSynthesisLike {\n readonly speaking: boolean;\n speak: (utterance: SpeechSynthesisUtteranceLike) => void;\n cancel: () => void;\n getVoices: () => SpeechSynthesisVoiceLike[];\n}\n\ninterface SpeechOutputWindow {\n speechSynthesis?: SpeechSynthesisLike;\n SpeechSynthesisUtterance?: SpeechSynthesisUtteranceCtor;\n}\n\n/** How long a press has to produce speech before the browser is taken at its word. */\nconst SILENT_FAILURE_MS = 1500;\n\n/**\n * The two API pieces, or null when this browser has no synthesiser at all (every iOS\n * in-app WebView without the entitlement, and anything server-side).\n */\nfunction speechPlatform(): {\n synth: SpeechSynthesisLike;\n Utterance: SpeechSynthesisUtteranceCtor;\n} | null {\n if (typeof window === \"undefined\") return null;\n const scope = window as unknown as SpeechOutputWindow;\n const synth = scope.speechSynthesis;\n const Utterance = scope.SpeechSynthesisUtterance;\n if (!synth || typeof synth.speak !== \"function\") return null;\n if (typeof Utterance !== \"function\") return null;\n return { synth, Utterance };\n}\n\n/** Lowercased, `-` separated: platforms spell the same tag `en_US`, `en-us` and `en-US`. */\nfunction normaliseTag(tag: string): string {\n return tag.trim().toLowerCase().replace(/_/g, \"-\");\n}\n\nfunction primaryOf(tag: string): string {\n return normaliseTag(tag).split(\"-\")[0] ?? \"\";\n}\n\n/**\n * The best voice for `lang`, or null to let the platform choose.\n *\n * Exact tag first (`ta-IN` over `ta-LK`), then the platform's default for the language, then\n * anything speaking it. Null rather than a wrong-language voice: an utterance with no voice\n * and the right `lang` is read by the platform's own fallback, which is closer than reading\n * Tamil with an English voice.\n */\nexport function pickVoice(\n voices: readonly SpeechSynthesisVoiceLike[],\n lang: string,\n): SpeechSynthesisVoiceLike | null {\n const wanted = normaliseTag(lang);\n if (wanted === \"\") return null;\n const primary = primaryOf(wanted);\n\n const exact = voices.filter((voice) => normaliseTag(voice.lang) === wanted);\n const related = voices.filter((voice) => primaryOf(voice.lang) === primary);\n\n return (\n exact.find((voice) => voice.default) ??\n exact[0] ??\n related.find((voice) => voice.default) ??\n related[0] ??\n null\n );\n}\n\n/** Whoever currently holds the page's one voice, and how to take it off them. */\nlet activeOwner: object | null = null;\nlet activeStop: (() => void) | null = null;\n\n/**\n * Stop whatever this SDK is reading aloud, from outside a component.\n *\n * A no-op when nothing of ours is speaking — deliberately, rather than calling\n * `speechSynthesis.cancel()` unconditionally, which would also silence a host page that is\n * using the same queue for its own reasons.\n */\nexport function stopSpeaking(): void {\n activeStop?.();\n}\n\nexport interface UseSpeechOutputOptions {\n /** BCP-47 tag to read in. Omit to let the platform pick its default voice. */\n lang?: string;\n}\n\nexport interface UseSpeechOutputResult {\n /**\n * False when this browser has no synthesiser, or has one that was asked to speak and did\n * not. Render no control at all when it is false — see the note at the top of the file.\n */\n supported: boolean;\n speaking: boolean;\n speak: (text: string) => void;\n stop: () => void;\n toggle: (text: string) => void;\n}\n\nexport function useSpeechOutput({\n lang,\n}: UseSpeechOutputOptions = {}): UseSpeechOutputResult {\n const [available, setAvailable] = useState(() => speechPlatform() !== null);\n const [speaking, setSpeaking] = useState(false);\n\n /** The utterance this instance is waiting on. Also \"do we own the voice right now\". */\n const utteranceRef = useRef<SpeechSynthesisUtteranceLike | null>(null);\n const watchdogRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n /** A stable identity for this instance, so the module-level owner can be compared. */\n const ownerRef = useRef<object>({});\n /** Lets the owner registration call the latest `stop` without re-registering. */\n const stopRef = useRef<() => void>(() => undefined);\n\n const langRef = useRef(lang);\n langRef.current = lang;\n\n const clearWatchdog = useCallback(() => {\n if (watchdogRef.current === null) return;\n clearTimeout(watchdogRef.current);\n watchdogRef.current = null;\n }, []);\n\n /** Forget this turn without touching the platform — for `end`, `error` and the watchdog. */\n const settle = useCallback(() => {\n clearWatchdog();\n utteranceRef.current = null;\n if (activeOwner === ownerRef.current) {\n activeOwner = null;\n activeStop = null;\n }\n setSpeaking(false);\n }, [clearWatchdog]);\n\n const stop = useCallback(() => {\n // Only cancel a queue we are actually using. Unmounting one answer's controls must not\n // silence a different answer that is mid-sentence.\n const owned = utteranceRef.current !== null;\n settle();\n if (owned) speechPlatform()?.synth.cancel();\n }, [settle]);\n\n stopRef.current = stop;\n\n const speak = useCallback(\n (text: string) => {\n const platform = speechPlatform();\n if (!platform) {\n setAvailable(false);\n return;\n }\n const spoken = text.trim();\n if (spoken === \"\") return;\n\n // Take the page's one voice, and clear anything already queued on it.\n if (activeStop && activeOwner !== ownerRef.current) activeStop();\n platform.synth.cancel();\n\n const utterance = new platform.Utterance(spoken);\n const wanted = langRef.current;\n if (wanted !== undefined && wanted !== \"\") {\n // Voices are fetched at press time rather than subscribed to: `getVoices()` is\n // empty until the platform has loaded them, and by the time a visitor has read an\n // answer and reached for this button, it has.\n const voice = pickVoice(platform.synth.getVoices(), wanted);\n utterance.lang = voice?.lang ?? wanted;\n if (voice) utterance.voice = voice;\n }\n\n const mine = (): boolean => utteranceRef.current === utterance;\n utterance.onstart = () => {\n if (!mine()) return;\n clearWatchdog();\n setSpeaking(true);\n };\n utterance.onend = () => {\n if (!mine()) return;\n settle();\n };\n utterance.onerror = (event) => {\n if (!mine()) return;\n const code = typeof event?.error === \"string\" ? event.error : \"\";\n settle();\n // `interrupted`/`canceled` is our own `cancel()` coming back — the visitor pressed\n // stop, or sent another message. Anything else is the engine refusing, and a\n // control that has now failed once is a control worth removing.\n if (code !== \"interrupted\" && code !== \"canceled\") setAvailable(false);\n };\n\n utteranceRef.current = utterance;\n activeOwner = ownerRef.current;\n activeStop = () => {\n stopRef.current();\n };\n // Optimistic, like the microphone: the engine can take a moment to start and a\n // control that looks inert invites a second press.\n setSpeaking(true);\n platform.synth.speak(utterance);\n\n clearWatchdog();\n watchdogRef.current = setTimeout(() => {\n watchdogRef.current = null;\n if (!mine()) return;\n // It is talking and simply never fired `start` — leave it alone.\n if (platform.synth.speaking) return;\n settle();\n setAvailable(false);\n }, SILENT_FAILURE_MS);\n },\n [clearWatchdog, settle],\n );\n\n const toggle = useCallback(\n (text: string) => {\n if (speaking) stop();\n else speak(text);\n },\n [speak, speaking, stop],\n );\n\n // A page that keeps talking after you leave it is the failure people complain about.\n // `pagehide` covers a real navigation and a bfcache freeze alike; unmount covers an SPA\n // route change and the transcript being reset.\n useEffect(() => {\n if (!speaking || typeof window === \"undefined\") return;\n const onHide = () => {\n stopRef.current();\n };\n window.addEventListener(\"pagehide\", onHide);\n return () => window.removeEventListener(\"pagehide\", onHide);\n }, [speaking]);\n\n useEffect(\n () => () => {\n stopRef.current();\n },\n [],\n );\n\n return { supported: available, speaking, speak, stop, toggle };\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 * PageHead Component\n * Manages dynamic meta tags for SEO optimization on a per-page basis.\n * Supports JSON-LD structured data, Open Graph, Twitter Cards, favicons, and robots directives.\n *\n * @example\n * ```tsx\n * <PageHead\n * title=\"About Us\"\n * description=\"Learn about our mission and team\"\n * productName=\"MyProduct\"\n * keywords=\"about, team, mission\"\n * image=\"/og-about.png\"\n * url=\"https://myproduct.com/about\"\n * favicon=\"/favicon.ico\"\n * robots=\"index, follow\"\n * locale=\"en_US\"\n * twitterHandle=\"@burdenoff\"\n * themeColor=\"#1a1a2e\"\n * structuredData={{\n * \"@context\": \"https://schema.org\",\n * \"@type\": \"WebPage\",\n * name: \"About Us\",\n * }}\n * />\n * ```\n */\n\nimport { Helmet } from \"react-helmet-async\";\n\nexport interface PageHeadProps {\n /** Page title */\n title: string;\n /** Meta description */\n description?: string;\n /** Product/brand name (appended to title) */\n productName?: string;\n /** SEO keywords */\n keywords?: string;\n /** Open Graph image URL */\n image?: string;\n /** Page canonical URL */\n url?: string;\n /** Favicon URL */\n favicon?: string;\n /** Robots directive (e.g., \"index, follow\") */\n robots?: string;\n /** Open Graph locale (e.g., \"en_US\") */\n locale?: string;\n /** Twitter handle (e.g., \"@burdenoff\") */\n twitterHandle?: string;\n /** Theme color for mobile browsers */\n themeColor?: string;\n /** JSON-LD structured data objects */\n structuredData?: Record<string, unknown> | Array<Record<string, unknown>>;\n /** Additional meta tags */\n additionalMeta?: Array<{\n name?: string;\n property?: string;\n content: string;\n }>;\n}\n\n/**\n * Build a self-referencing canonical URL from the current location.\n *\n * Query strings and hashes are dropped (they never identify a distinct\n * canonical document here) and the trailing slash is normalised away for\n * everything but the site root. Returns `undefined` outside a DOM so the\n * component degrades to its previous behaviour under plain string rendering.\n */\nfunction canonicalFromLocation(): string | undefined {\n if (typeof window === \"undefined\" || !window.location) return undefined;\n const { origin, pathname } = window.location;\n if (!origin || origin === \"null\") return undefined;\n const path = pathname === \"/\" ? \"/\" : pathname.replace(/\\/+$/, \"\");\n return `${origin}${path}`;\n}\n\n/**\n * Absolutise an Open Graph image URL.\n *\n * Already-absolute URLs pass through. A root-relative path resolves against\n * the origin, and any other relative path against the page URL. Without a\n * resolvable base the original value is returned unchanged.\n */\nfunction resolveImageUrl(\n image: string | undefined,\n base: string | undefined,\n): string | undefined {\n if (!image || /^https?:\\/\\//i.test(image)) return image;\n if (!base) return image;\n try {\n return new URL(image, base).toString();\n } catch {\n return image;\n }\n}\n\n/**\n * JSON-LD as the body of a `<script>` element.\n *\n * `JSON.stringify` leaves `<` alone, and a script body ends at the first `</script` whatever\n * the quoting around it. The prerender serialises the live DOM with script text verbatim,\n * so a `</script><script>…` inside any string field (a caption, a title) would close the\n * JSON-LD block in the static HTML and run what follows. `\\u003c` is the same character to\n * every JSON parser; U+2028 / U+2029 are escaped for engines that still read them as line\n * breaks.\n */\nfunction serializeJsonLd(data: Record<string, unknown>): string {\n return JSON.stringify(data)\n .replace(/</g, \"\\\\u003c\")\n .replace(/\\u2028/g, \"\\\\u2028\")\n .replace(/\\u2029/g, \"\\\\u2029\");\n}\n\nexport function PageHead({\n title,\n description,\n productName,\n keywords,\n image,\n url,\n favicon,\n robots = \"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\",\n locale = \"en_US\",\n twitterHandle,\n themeColor = \"#000000\",\n structuredData,\n additionalMeta,\n}: PageHeadProps) {\n const fullTitle =\n productName && !title.includes(productName)\n ? `${title} | ${productName}`\n : title;\n\n // Self-referencing canonical by default.\n //\n // Without this, a route that renders PageHead but omits `url` emits no\n // canonical at all, so the static `<link rel=\"canonical\">` in index.html\n // survives and every such page declares itself a duplicate of the home\n // page — Google then drops /pricing, /privacy, /terms and friends from the\n // index. Deriving it from the current location keeps each page pointing at\n // itself; callers that genuinely need a cross-canonical still pass `url`.\n //\n // During prerender the DOM location already reflects the route being\n // rendered, so this resolves correctly ahead of hydration.\n const resolvedUrl = url ?? canonicalFromLocation();\n\n // Root-relative images (\"/og.png\") belong to the ORIGIN, not to the current\n // path — concatenating them onto the page URL yields /features/og.png and a\n // broken share card. Anything else is resolved relative to the page itself.\n const fullImageUrl = resolveImageUrl(image, resolvedUrl);\n\n // Normalize structured data to an array\n const structuredDataItems: Array<Record<string, unknown>> = structuredData\n ? Array.isArray(structuredData)\n ? structuredData\n : [structuredData]\n : [];\n\n return (\n <Helmet>\n {/* Primary Meta Tags */}\n <title>{fullTitle}</title>\n <meta name=\"title\" content={fullTitle} />\n {description && <meta name=\"description\" content={description} />}\n {keywords && <meta name=\"keywords\" content={keywords} />}\n <meta name=\"author\" content=\"Burdenoff Consultancy Services Pvt Ltd\" />\n <meta name=\"robots\" content={robots} />\n\n {/* Canonical URL */}\n {resolvedUrl && <link rel=\"canonical\" href={resolvedUrl} />}\n\n {/* Favicon */}\n {favicon && <link rel=\"icon\" href={favicon} />}\n\n {/* Open Graph / Facebook */}\n <meta property=\"og:type\" content=\"website\" />\n <meta property=\"og:title\" content={fullTitle} />\n {description && <meta property=\"og:description\" content={description} />}\n {fullImageUrl && <meta property=\"og:image\" content={fullImageUrl} />}\n {resolvedUrl && <meta property=\"og:url\" content={resolvedUrl} />}\n <meta property=\"og:locale\" content={locale} />\n {productName && <meta property=\"og:site_name\" content={productName} />}\n\n {/* Twitter Card */}\n <meta name=\"twitter:card\" content=\"summary_large_image\" />\n <meta name=\"twitter:title\" content={fullTitle} />\n {description && <meta name=\"twitter:description\" content={description} />}\n {fullImageUrl && <meta name=\"twitter:image\" content={fullImageUrl} />}\n {twitterHandle && <meta name=\"twitter:creator\" content={twitterHandle} />}\n\n {/* Theme Color */}\n <meta name=\"theme-color\" content={themeColor} />\n\n {/* JSON-LD Structured Data */}\n {structuredDataItems.map((data, index) => (\n <script key={`ld-${index}`} type=\"application/ld+json\">\n {serializeJsonLd(data)}\n </script>\n ))}\n\n {/* Additional Meta Tags */}\n {additionalMeta?.map((meta, index) => (\n <meta\n key={`meta-${index}`}\n {...(meta.name ? { name: meta.name } : {})}\n {...(meta.property ? { property: meta.property } : {})}\n content={meta.content}\n />\n ))}\n </Helmet>\n );\n}\n","import * as React from \"react\";\n\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\n\nimport { cn } from \"../utils/cn\";\n\nconst buttonVariants = cva(\n \"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0\",\n {\n variants: {\n variant: {\n default:\n \"bg-primary text-primary-foreground shadow hover:bg-primary/90\",\n destructive:\n \"bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90\",\n outline:\n \"border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground\",\n secondary:\n \"bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80\",\n ghost: \"hover:bg-accent hover:text-accent-foreground\",\n link: \"text-primary underline-offset-4 hover:underline\",\n },\n size: {\n default: \"h-9 px-4 py-2\",\n sm: \"h-8 rounded-md px-3 text-xs\",\n lg: \"h-10 rounded-md px-8\",\n icon: \"h-9 w-9\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n },\n);\n\nexport interface ButtonProps\n extends\n React.ButtonHTMLAttributes<HTMLButtonElement>,\n VariantProps<typeof buttonVariants> {\n asChild?: boolean;\n}\n\nconst Button = React.forwardRef<HTMLButtonElement, ButtonProps>(\n ({ className, variant, size, asChild = false, ...props }, ref) => {\n const Comp = asChild ? Slot : \"button\";\n return (\n <Comp\n className={cn(buttonVariants({ variant, size, className }))}\n ref={ref}\n {...props}\n />\n );\n },\n);\nButton.displayName = \"Button\";\n\nexport { Button, buttonVariants };\n","import * as React from \"react\";\n\nimport { cn } from \"../utils/cn\";\n\nconst Textarea = React.forwardRef<\n HTMLTextAreaElement,\n React.ComponentProps<\"textarea\">\n>(({ className, ...props }, ref) => {\n return (\n <textarea\n className={cn(\n \"flex min-h-[60px] w-full rounded-md border border-input bg-transparent px-3 py-2 text-base shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm\",\n className,\n )}\n ref={ref}\n {...props}\n />\n );\n});\nTextarea.displayName = \"Textarea\";\n\nexport { Textarea };\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 { useCallback, useEffect, useMemo, useRef, useState } 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} from \"./explore-answer\";\nimport {\n type ExploreLocale,\n type ExploreStrings,\n exploreStrings,\n fill,\n isRtlLocale,\n resolveExploreLocale,\n speechLocaleOf,\n} from \"./explore-i18n\";\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 { useExploreChat } 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\";\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.\n */\nexport {\n answerPlainText,\n answerSpeechText,\n inlineImageOrigins,\n isInlineImageAllowed,\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 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\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\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@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.45);\n box-shadow:\n 0 0 0 4px hsl(var(--primary) / 0.08),\n 0 8px 24px -12px hsl(var(--primary) / 0.45);\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.07), 0 8px 24px -12px hsl(var(--primary) / 0.40); }\n 50% { box-shadow: 0 0 0 7px hsl(var(--primary) / 0.13), 0 8px 28px -12px hsl(var(--primary) / 0.55); }\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/* ---- 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\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 },\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 },\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 },\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/** 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}: {\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 const speech = useSpeechOutput({ lang });\n if (!speech.supported) return null;\n\n const label = speech.speaking ? T.stopReading : T.readAloud;\n return (\n <button\n data-boff-explore=\"read-aloud\"\n data-speaking={speech.speaking ? \"true\" : \"false\"}\n type=\"button\"\n title={label}\n aria-pressed={speech.speaking}\n onClick={() => speech.toggle(text)}\n className={cn(\n ANSWER_ACTION_PILL,\n speech.speaking ? ANSWER_ACTION_ACTIVE : ANSWER_ACTION_IDLE,\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}: {\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}) {\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 strings={T} text={speechText} lang={speechLang} />\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 productNames,\n speechLang,\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 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 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 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 />\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 prompts,\n onPrompt,\n disabled,\n}: {\n strings: ExploreStrings;\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 return (\n <div\n className=\"flex min-w-0 touch-pan-y items-center gap-1.5\"\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 {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=\"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\"\n >\n <ChevronLeft className=\"h-4 w-4\" />\n </button>\n ) : null}\n\n <button\n key={current}\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. */\n className=\"boff-explore-fade group flex min-w-0 flex-1 items-center gap-2 rounded-full border border-border bg-card px-4 py-2 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 >\n <Sparkles className=\"h-3.5 w-3.5 shrink-0 text-primary\" />\n <span className=\"truncate\">{current}</span>\n <ArrowUp className=\"ml-auto h-3.5 w-3.5 shrink-0 rotate-45 text-muted-foreground transition-colors group-hover:text-primary\" />\n </button>\n\n {count > 1 ? (\n <button\n type=\"button\"\n aria-label={T.nextSuggestion}\n onClick={() => go(1)}\n className=\"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\"\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 ? \"flex-wrap\" : \"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 <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={focusProduct === product.slug}\n title={product.tagline ?? product.name}\n onClick={() =>\n onFocus(focusProduct === product.slug ? null : product.slug)\n }\n className={chipClass(focusProduct === product.slug)}\n >\n {product.name}\n </button>\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 // 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(el.scrollLeft > 1);\n setCanRight(el.scrollLeft + el.clientWidth < el.scrollWidth - 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 return () => window.removeEventListener(\"resize\", onResize);\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-5\"\n >\n <p className=\"mb-2 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 className=\"boff-explore-strip flex min-w-0 snap-x gap-3 overflow-x-auto pb-1\"\n >\n {visible.map((highlight) => (\n <li\n key={`${highlight.product}:${highlight.url}`}\n className=\"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-48\"\n >\n <span className=\"relative block aspect-[16/9] 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=\"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-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=\"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}: {\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}) {\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-5 sm:py-6\">\n <div className=\"boff-explore-rise text-center\">\n <span className=\"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 <h1 className=\"mt-3 text-balance break-words text-2xl font-bold tracking-tight sm:text-3xl\">\n {title}\n </h1>\n <p className=\"mx-auto mt-2 max-w-2xl text-pretty text-sm leading-relaxed text-muted-foreground sm:text-base\">\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. */}\n <ul className=\"boff-explore-rise boff-explore-rise-1 mt-5 grid grid-cols-3 gap-2 sm:gap-2.5\">\n {CAPABILITIES.map(({ icon: Icon, body: capBody }, i) => (\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-3 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-normal\">\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 </ul>\n\n {prompts.length > 0 ? (\n <div className=\"boff-explore-rise boff-explore-rise-2 mt-5\">\n <p className=\"mb-2 text-xs font-semibold uppercase tracking-wide text-muted-foreground\">\n {T.tryAsking}\n </p>\n <PromptCarousel\n strings={T}\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-5\">\n <p className=\"mb-2 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\nexport function ExplorePage({\n seo,\n productSlug,\n examplePrompts,\n className,\n heightMode = \"viewport\",\n viewportOffset,\n onNavigate,\n onSend,\n welcomeTitle,\n welcomeBody,\n locale,\n}: ExplorePageProps) {\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 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 } = useExploreChat({\n productSlug,\n pageUrl,\n onSend,\n // Locale-aware, so a catalog outage degrades to a translated welcome rather than an\n // English one. `T.prompts` seeds the chips the same way.\n examplePrompts: examplePrompts ?? T.prompts,\n fallbackWelcome: { title: T.welcomeTitle, body: T.welcomeBody },\n });\n\n const [draft, setDraft] = useState(\"\");\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 if (typeof window === \"undefined\") 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 }, []);\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 // 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 [staged, setStaged] = useState<StagedAttachment[]>([]);\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 const resolvedTitle = welcomeTitle ?? catalog.welcomeTitle;\n const resolvedBody = welcomeBody ?? catalog.welcomeBody;\n // Resolution order (catalog → prop → SDK built-in) lives in the hook, which\n // seeds its fallback catalog from the `examplePrompts` prop.\n const prompts = catalog.examplePrompts;\n\n const focusedProductName = useMemo(\n () => catalog.products.find((p) => p.slug === focusProduct)?.name ?? null,\n [catalog.products, focusProduct],\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.\n const headProductName = useMemo(\n () =>\n productSlug\n ? (catalog.products.find((p) => p.slug === productSlug)?.name ?? null)\n : null,\n [catalog.products, 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\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 (heightMode !== \"viewport\") 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 }, [heightMode]);\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 if (typeof window === \"undefined\") 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]);\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 (heightMode !== \"viewport\" || 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 }, [heightMode, 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 useEffect(() => {\n if (typeof window === \"undefined\") 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 }, []);\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.\n if (!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]);\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 (!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]);\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 const url = 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 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],\n );\n\n const removeAttachment = useCallback((id: string) => {\n setStaged((prev) => prev.filter((entry) => entry.id !== id));\n setAttachmentNotice(null);\n }, []);\n\n // --- send --------------------------------------------------------------\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 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 }, [busy, canSend, draft, overLimit, send, stopDictation]);\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 // 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, send],\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 // 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 (heightMode === \"viewport\") {\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=\"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 \"flex w-full min-w-0 flex-col overflow-x-hidden bg-background text-foreground\",\n heightMode === \"viewport\" && \"boff-explore-viewport\",\n heightMode === \"auto\" && \"min-h-[70vh]\",\n className,\n )}\n style={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 <PageHead\n title={seo?.title ?? T.seoTitle}\n description={\n seo?.description ??\n (headProductName\n ? fill(T.seoDescriptionProduct, { product: headProductName })\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 <ProseStyles />\n <ExploreStyles />\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 <h1 className=\"truncate text-sm font-semibold\">{resolvedTitle}</h1>\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 strings={T}\n title={resolvedTitle}\n body={resolvedBody}\n prompts={prompts}\n products={catalog.products}\n conceptHighlights={catalog.conceptHighlights}\n focusProduct={focusProduct}\n onPrompt={sendPrompt}\n onFocus={setFocusProduct}\n disabled={!canSend || busy}\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 productNames={productNames}\n speechLang={speechLang}\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 {error ? (\n <ErrorBanner error={error} onRetry={retry} onReset={reset} />\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 \"flex min-w-0 items-end gap-2 rounded-2xl border bg-card p-2 shadow-sm transition-all\",\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(T.placeholderProduct, {\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 <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 title={speech.listening ? T.stopDictating : T.dictate}\n onClick={speech.toggle}\n className={cn(speech.listening && \"animate-pulse\")}\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\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 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"]}
|