@burdenoff/website-sdk 2026.829.4 → 2026.829.6

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.
@@ -1,6 +1,6 @@
1
1
  import * as React from 'react';
2
2
  import { createContext, useMemo, useState, useRef, useCallback, useEffect, useContext } from 'react';
3
- import { Sparkles, RotateCcw, Link2, History, Trash2, Mic, Square, ArrowUp, BookOpenText, Layers, TriangleAlert, ChevronLeft, ChevronRight, ExternalLink } from 'lucide-react';
3
+ import { Sparkles, RotateCcw, Link2, History, Trash2, Paperclip, X, Mic, Square, ArrowUp, BookOpenText, Layers, TriangleAlert, ChevronLeft, ChevronRight, ExternalLink } from 'lucide-react';
4
4
  import ReactMarkdown from 'react-markdown';
5
5
  import rehypeSanitize from 'rehype-sanitize';
6
6
  import remarkGfm from 'remark-gfm';
@@ -14,6 +14,325 @@ import { twMerge } from 'tailwind-merge';
14
14
  var __defProp = Object.defineProperty;
15
15
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
16
16
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
17
+
18
+ // src/components/explore-i18n.ts
19
+ var EXPLORE_LOCALES = ["en", "zh", "hi", "es", "ar", "ta"];
20
+ var RTL_LOCALES = /* @__PURE__ */ new Set(["ar"]);
21
+ function isRtlLocale(locale) {
22
+ return RTL_LOCALES.has(locale);
23
+ }
24
+ var EN = {
25
+ badge: "AI answers, grounded in our documentation",
26
+ welcomeTitle: "Ask anything about our products",
27
+ welcomeBody: "Describe what you are trying to do and I will point you at the product, the page and the next step.",
28
+ tryAsking: "Try asking",
29
+ focusProduct: "Focus on a product",
30
+ allProducts: "All products",
31
+ showAll: "All",
32
+ showLess: "Show less",
33
+ sources: "Sources",
34
+ nextYouCouldAsk: "Next you could ask",
35
+ placeholder: "Ask anything about our products\u2026",
36
+ placeholderProduct: "Ask about {product}\u2026",
37
+ send: "Send",
38
+ stop: "Stop",
39
+ newChat: "New chat",
40
+ history: "History",
41
+ clearHistory: "Clear history",
42
+ share: "Share",
43
+ copied: "Copied",
44
+ copying: "Copying\u2026",
45
+ shareUnavailable: "Unavailable",
46
+ disclaimer: "Disclaimer",
47
+ disclaimerShort: "Grounded in our docs \u2014 check anything important.",
48
+ dictate: "Dictate your question",
49
+ stopDictating: "Stop dictating",
50
+ attach: "Attach files",
51
+ attachHint: "Up to {{max}} files, {{size}} MB each",
52
+ removeAttachment: "Remove {{name}}",
53
+ attachmentNameOnly: "name and type only",
54
+ attachmentTooLarge: "{{name}} is larger than {{size}} MB and was not attached.",
55
+ attachmentTooMany: "Only {{max}} files can be attached, so {{name}} was skipped.",
56
+ noAnswer: "I couldn't find this in our documentation, so the answer below is not grounded in a source. Try rephrasing, or",
57
+ askHuman: "ask a human",
58
+ prevSuggestion: "Previous suggestion",
59
+ nextSuggestion: "Next suggestion",
60
+ capabilities: [
61
+ "Grounded in our own docs",
62
+ "Compare across the ecosystem",
63
+ "Straight to the right page"
64
+ ],
65
+ prompts: [
66
+ "What does this product actually do?",
67
+ "Which product fits my team?",
68
+ "How do I get started, step by step?",
69
+ "How much does it cost?"
70
+ ]
71
+ };
72
+ var ZH = {
73
+ badge: "\u57FA\u4E8E\u6211\u4EEC\u6587\u6863\u7684 AI \u56DE\u7B54",
74
+ welcomeTitle: "\u5173\u4E8E\u6211\u4EEC\u7684\u4EA7\u54C1\uFF0C\u968F\u4FBF\u95EE",
75
+ welcomeBody: "\u63CF\u8FF0\u4F60\u60F3\u505A\u7684\u4E8B\uFF0C\u6211\u4F1A\u4E3A\u4F60\u6307\u51FA\u5BF9\u5E94\u7684\u4EA7\u54C1\u3001\u9875\u9762\u548C\u4E0B\u4E00\u6B65\u3002",
76
+ tryAsking: "\u8BD5\u7740\u95EE",
77
+ focusProduct: "\u805A\u7126\u67D0\u4E2A\u4EA7\u54C1",
78
+ allProducts: "\u5168\u90E8\u4EA7\u54C1",
79
+ showAll: "\u5168\u90E8",
80
+ showLess: "\u6536\u8D77",
81
+ sources: "\u6765\u6E90",
82
+ nextYouCouldAsk: "\u4F60\u8FD8\u53EF\u4EE5\u95EE",
83
+ placeholder: "\u5173\u4E8E\u6211\u4EEC\u7684\u4EA7\u54C1\uFF0C\u968F\u4FBF\u95EE\u2026",
84
+ placeholderProduct: "\u8BE2\u95EE\u5173\u4E8E {product} \u7684\u95EE\u9898\u2026",
85
+ send: "\u53D1\u9001",
86
+ stop: "\u505C\u6B62",
87
+ newChat: "\u65B0\u5BF9\u8BDD",
88
+ history: "\u5386\u53F2",
89
+ clearHistory: "\u6E05\u9664\u5386\u53F2",
90
+ share: "\u5206\u4EAB",
91
+ copied: "\u5DF2\u590D\u5236",
92
+ copying: "\u590D\u5236\u4E2D\u2026",
93
+ shareUnavailable: "\u4E0D\u53EF\u7528",
94
+ disclaimer: "\u514D\u8D23\u58F0\u660E",
95
+ disclaimerShort: "\u5185\u5BB9\u57FA\u4E8E\u6211\u4EEC\u7684\u6587\u6863\uFF0C\u91CD\u8981\u4FE1\u606F\u8BF7\u81EA\u884C\u6838\u5BF9\u3002",
96
+ dictate: "\u8BED\u97F3\u8F93\u5165",
97
+ stopDictating: "\u505C\u6B62\u8BED\u97F3\u8F93\u5165",
98
+ attach: "\u6DFB\u52A0\u6587\u4EF6",
99
+ attachHint: "\u6700\u591A {{max}} \u4E2A\u6587\u4EF6\uFF0C\u6BCF\u4E2A\u4E0D\u8D85\u8FC7 {{size}} MB",
100
+ removeAttachment: "\u79FB\u9664 {{name}}",
101
+ attachmentNameOnly: "\u4EC5\u6587\u4EF6\u540D\u548C\u7C7B\u578B",
102
+ attachmentTooLarge: "{{name}} \u8D85\u8FC7 {{size}} MB\uFF0C\u672A\u80FD\u6DFB\u52A0\u3002",
103
+ attachmentTooMany: "\u6700\u591A\u53EA\u80FD\u6DFB\u52A0 {{max}} \u4E2A\u6587\u4EF6\uFF0C\u5DF2\u8DF3\u8FC7 {{name}}\u3002",
104
+ noAnswer: "\u6211\u5728\u6587\u6863\u4E2D\u6CA1\u6709\u627E\u5230\u76F8\u5173\u5185\u5BB9\uFF0C\u4E0B\u9762\u7684\u56DE\u7B54\u6CA1\u6709\u6765\u6E90\u652F\u6301\u3002\u8BF7\u6362\u4E2A\u8BF4\u6CD5\uFF0C\u6216",
105
+ askHuman: "\u8054\u7CFB\u6211\u4EEC",
106
+ prevSuggestion: "\u4E0A\u4E00\u4E2A\u5EFA\u8BAE",
107
+ nextSuggestion: "\u4E0B\u4E00\u4E2A\u5EFA\u8BAE",
108
+ capabilities: ["\u57FA\u4E8E\u6211\u4EEC\u81EA\u5DF1\u7684\u6587\u6863", "\u8DE8\u4EA7\u54C1\u5BF9\u6BD4", "\u76F4\u8FBE\u6B63\u786E\u7684\u9875\u9762"],
109
+ prompts: [
110
+ "\u8FD9\u4E2A\u4EA7\u54C1\u5230\u5E95\u80FD\u505A\u4EC0\u4E48\uFF1F",
111
+ "\u54EA\u4E2A\u4EA7\u54C1\u9002\u5408\u6211\u7684\u56E2\u961F\uFF1F",
112
+ "\u5982\u4F55\u4E00\u6B65\u6B65\u5F00\u59CB\u4F7F\u7528\uFF1F",
113
+ "\u4EF7\u683C\u662F\u591A\u5C11\uFF1F"
114
+ ]
115
+ };
116
+ var HI = {
117
+ badge: "\u0939\u092E\u093E\u0930\u0947 \u0926\u0938\u094D\u0924\u093E\u0935\u0947\u091C\u093C\u094B\u0902 \u092A\u0930 \u0906\u0927\u093E\u0930\u093F\u0924 AI \u0909\u0924\u094D\u0924\u0930",
118
+ welcomeTitle: "\u0939\u092E\u093E\u0930\u0947 \u0909\u0924\u094D\u092A\u093E\u0926\u094B\u0902 \u0915\u0947 \u092C\u093E\u0930\u0947 \u092E\u0947\u0902 \u0915\u0941\u091B \u092D\u0940 \u092A\u0942\u091B\u0947\u0902",
119
+ welcomeBody: "\u092C\u0924\u093E\u0907\u090F \u0906\u092A \u0915\u094D\u092F\u093E \u0915\u0930\u0928\u093E \u091A\u093E\u0939\u0924\u0947 \u0939\u0948\u0902, \u0914\u0930 \u092E\u0948\u0902 \u0906\u092A\u0915\u094B \u0938\u0939\u0940 \u0909\u0924\u094D\u092A\u093E\u0926, \u092A\u0947\u091C \u0914\u0930 \u0905\u0917\u0932\u093E \u0915\u0926\u092E \u092C\u0924\u093E\u090A\u0901\u0917\u093E\u0964",
120
+ tryAsking: "\u092F\u0939 \u092A\u0942\u091B\u0915\u0930 \u0926\u0947\u0916\u0947\u0902",
121
+ focusProduct: "\u0915\u093F\u0938\u0940 \u0909\u0924\u094D\u092A\u093E\u0926 \u092A\u0930 \u0927\u094D\u092F\u093E\u0928 \u0926\u0947\u0902",
122
+ allProducts: "\u0938\u092D\u0940 \u0909\u0924\u094D\u092A\u093E\u0926",
123
+ showAll: "\u0938\u092D\u0940",
124
+ showLess: "\u0915\u092E \u0926\u093F\u0916\u093E\u090F\u0901",
125
+ sources: "\u0938\u094D\u0930\u094B\u0924",
126
+ nextYouCouldAsk: "\u0906\u0917\u0947 \u0906\u092A \u092A\u0942\u091B \u0938\u0915\u0924\u0947 \u0939\u0948\u0902",
127
+ placeholder: "\u0939\u092E\u093E\u0930\u0947 \u0909\u0924\u094D\u092A\u093E\u0926\u094B\u0902 \u0915\u0947 \u092C\u093E\u0930\u0947 \u092E\u0947\u0902 \u0915\u0941\u091B \u092D\u0940 \u092A\u0942\u091B\u0947\u0902\u2026",
128
+ placeholderProduct: "{product} \u0915\u0947 \u092C\u093E\u0930\u0947 \u092E\u0947\u0902 \u092A\u0942\u091B\u0947\u0902\u2026",
129
+ send: "\u092D\u0947\u091C\u0947\u0902",
130
+ stop: "\u0930\u094B\u0915\u0947\u0902",
131
+ newChat: "\u0928\u0908 \u092C\u093E\u0924\u091A\u0940\u0924",
132
+ history: "\u0907\u0924\u093F\u0939\u093E\u0938",
133
+ clearHistory: "\u0907\u0924\u093F\u0939\u093E\u0938 \u092E\u093F\u091F\u093E\u090F\u0901",
134
+ share: "\u0938\u093E\u091D\u093E \u0915\u0930\u0947\u0902",
135
+ copied: "\u0915\u0949\u092A\u0940 \u0939\u094B \u0917\u092F\u093E",
136
+ copying: "\u0915\u0949\u092A\u0940 \u0939\u094B \u0930\u0939\u093E \u0939\u0948\u2026",
137
+ shareUnavailable: "\u0909\u092A\u0932\u092C\u094D\u0927 \u0928\u0939\u0940\u0902",
138
+ disclaimer: "\u0905\u0938\u094D\u0935\u0940\u0915\u0930\u0923",
139
+ disclaimerShort: "\u092F\u0939 \u0939\u092E\u093E\u0930\u0947 \u0926\u0938\u094D\u0924\u093E\u0935\u0947\u091C\u093C\u094B\u0902 \u092A\u0930 \u0906\u0927\u093E\u0930\u093F\u0924 \u0939\u0948 \u2014 \u092E\u0939\u0924\u094D\u0935\u092A\u0942\u0930\u094D\u0923 \u092C\u093E\u0924\u0947\u0902 \u091C\u093C\u0930\u0942\u0930 \u091C\u093E\u0901\u091A \u0932\u0947\u0902\u0964",
140
+ dictate: "\u092C\u094B\u0932\u0915\u0930 \u092A\u0942\u091B\u0947\u0902",
141
+ stopDictating: "\u092C\u094B\u0932\u0928\u093E \u092C\u0902\u0926 \u0915\u0930\u0947\u0902",
142
+ attach: "\u092B\u093C\u093E\u0907\u0932\u0947\u0902 \u091C\u094B\u0921\u093C\u0947\u0902",
143
+ attachHint: "\u0905\u0927\u093F\u0915\u0924\u092E {{max}} \u092B\u093C\u093E\u0907\u0932\u0947\u0902, \u092A\u094D\u0930\u0924\u094D\u092F\u0947\u0915 {{size}} MB \u0924\u0915",
144
+ removeAttachment: "{{name}} \u0939\u091F\u093E\u090F\u0901",
145
+ attachmentNameOnly: "\u0915\u0947\u0935\u0932 \u0928\u093E\u092E \u0914\u0930 \u092A\u094D\u0930\u0915\u093E\u0930",
146
+ attachmentTooLarge: "{{name}} {{size}} MB \u0938\u0947 \u092C\u0921\u093C\u0940 \u0939\u0948, \u0907\u0938\u0932\u093F\u090F \u091C\u094B\u0921\u093C\u0940 \u0928\u0939\u0940\u0902 \u0917\u0908\u0964",
147
+ attachmentTooMany: "\u0915\u0947\u0935\u0932 {{max}} \u092B\u093C\u093E\u0907\u0932\u0947\u0902 \u091C\u094B\u0921\u093C\u0940 \u091C\u093E \u0938\u0915\u0924\u0940 \u0939\u0948\u0902, \u0907\u0938\u0932\u093F\u090F {{name}} \u091B\u094B\u0921\u093C \u0926\u0940 \u0917\u0908\u0964",
148
+ noAnswer: "\u092F\u0939 \u092E\u0941\u091D\u0947 \u0939\u092E\u093E\u0930\u0947 \u0926\u0938\u094D\u0924\u093E\u0935\u0947\u091C\u093C\u094B\u0902 \u092E\u0947\u0902 \u0928\u0939\u0940\u0902 \u092E\u093F\u0932\u093E, \u0907\u0938\u0932\u093F\u090F \u0928\u0940\u091A\u0947 \u0926\u093F\u092F\u093E \u0909\u0924\u094D\u0924\u0930 \u0915\u093F\u0938\u0940 \u0938\u094D\u0930\u094B\u0924 \u092A\u0930 \u0906\u0927\u093E\u0930\u093F\u0924 \u0928\u0939\u0940\u0902 \u0939\u0948\u0964 \u0926\u0942\u0938\u0930\u0947 \u0936\u092C\u094D\u0926\u094B\u0902 \u092E\u0947\u0902 \u092A\u0942\u091B\u0947\u0902, \u092F\u093E",
149
+ askHuman: "\u0939\u092E\u0938\u0947 \u0938\u0902\u092A\u0930\u094D\u0915 \u0915\u0930\u0947\u0902",
150
+ prevSuggestion: "\u092A\u093F\u091B\u0932\u093E \u0938\u0941\u091D\u093E\u0935",
151
+ nextSuggestion: "\u0905\u0917\u0932\u093E \u0938\u0941\u091D\u093E\u0935",
152
+ capabilities: [
153
+ "\u0939\u092E\u093E\u0930\u0947 \u0905\u092A\u0928\u0947 \u0926\u0938\u094D\u0924\u093E\u0935\u0947\u091C\u093C\u094B\u0902 \u092A\u0930 \u0906\u0927\u093E\u0930\u093F\u0924",
154
+ "\u0938\u092D\u0940 \u0909\u0924\u094D\u092A\u093E\u0926\u094B\u0902 \u0915\u0940 \u0924\u0941\u0932\u0928\u093E \u0915\u0930\u0947\u0902",
155
+ "\u0938\u0940\u0927\u0947 \u0938\u0939\u0940 \u092A\u0947\u091C \u092A\u0930"
156
+ ],
157
+ prompts: [
158
+ "\u092F\u0939 \u0909\u0924\u094D\u092A\u093E\u0926 \u0905\u0938\u0932 \u092E\u0947\u0902 \u0915\u094D\u092F\u093E \u0915\u0930\u0924\u093E \u0939\u0948?",
159
+ "\u092E\u0947\u0930\u0940 \u091F\u0940\u092E \u0915\u0947 \u0932\u093F\u090F \u0915\u094C\u0928 \u0938\u093E \u0909\u0924\u094D\u092A\u093E\u0926 \u0938\u0939\u0940 \u0939\u0948?",
160
+ "\u0936\u0941\u0930\u0941\u0906\u0924 \u0915\u0948\u0938\u0947 \u0915\u0930\u0947\u0902, \u091A\u0930\u0923 \u0926\u0930 \u091A\u0930\u0923?",
161
+ "\u0907\u0938\u0915\u0940 \u0915\u0940\u092E\u0924 \u0915\u093F\u0924\u0928\u0940 \u0939\u0948?"
162
+ ]
163
+ };
164
+ var ES = {
165
+ badge: "Respuestas de IA basadas en nuestra documentaci\xF3n",
166
+ welcomeTitle: "Pregunta lo que quieras sobre nuestros productos",
167
+ welcomeBody: "Cu\xE9ntame qu\xE9 necesitas hacer y te indicar\xE9 el producto, la p\xE1gina y el siguiente paso.",
168
+ tryAsking: "Prueba a preguntar",
169
+ focusProduct: "Centrarse en un producto",
170
+ allProducts: "Todos los productos",
171
+ showAll: "Todos",
172
+ showLess: "Ver menos",
173
+ sources: "Fuentes",
174
+ nextYouCouldAsk: "Tambi\xE9n puedes preguntar",
175
+ placeholder: "Pregunta lo que quieras sobre nuestros productos\u2026",
176
+ placeholderProduct: "Pregunta sobre {product}\u2026",
177
+ send: "Enviar",
178
+ stop: "Detener",
179
+ newChat: "Nueva conversaci\xF3n",
180
+ history: "Historial",
181
+ clearHistory: "Borrar historial",
182
+ share: "Compartir",
183
+ copied: "Copiado",
184
+ copying: "Copiando\u2026",
185
+ shareUnavailable: "No disponible",
186
+ disclaimer: "Aviso",
187
+ disclaimerShort: "Basado en nuestra documentaci\xF3n: comprueba cualquier dato importante.",
188
+ dictate: "Dictar tu pregunta",
189
+ stopDictating: "Dejar de dictar",
190
+ attach: "Adjuntar archivos",
191
+ attachHint: "Hasta {{max}} archivos, {{size}} MB cada uno",
192
+ removeAttachment: "Quitar {{name}}",
193
+ attachmentNameOnly: "solo nombre y tipo",
194
+ attachmentTooLarge: "{{name}} supera los {{size}} MB y no se adjunt\xF3.",
195
+ attachmentTooMany: "Solo se pueden adjuntar {{max}} archivos, as\xED que se omiti\xF3 {{name}}.",
196
+ noAnswer: "No he encontrado esto en nuestra documentaci\xF3n, as\xED que la respuesta de abajo no se apoya en ninguna fuente. Prueba a reformularla, o",
197
+ askHuman: "habla con una persona",
198
+ prevSuggestion: "Sugerencia anterior",
199
+ nextSuggestion: "Sugerencia siguiente",
200
+ capabilities: [
201
+ "Basado en nuestra documentaci\xF3n",
202
+ "Compara todo el ecosistema",
203
+ "Directo a la p\xE1gina correcta"
204
+ ],
205
+ prompts: [
206
+ "\xBFQu\xE9 hace realmente este producto?",
207
+ "\xBFQu\xE9 producto encaja con mi equipo?",
208
+ "\xBFC\xF3mo empiezo, paso a paso?",
209
+ "\xBFCu\xE1nto cuesta?"
210
+ ]
211
+ };
212
+ var AR = {
213
+ badge: "\u0625\u062C\u0627\u0628\u0627\u062A \u0630\u0643\u0627\u0621 \u0627\u0635\u0637\u0646\u0627\u0639\u064A \u0645\u0628\u0646\u064A\u0629 \u0639\u0644\u0649 \u0648\u062B\u0627\u0626\u0642\u0646\u0627",
214
+ welcomeTitle: "\u0627\u0633\u0623\u0644 \u0623\u064A \u0634\u064A\u0621 \u0639\u0646 \u0645\u0646\u062A\u062C\u0627\u062A\u0646\u0627",
215
+ welcomeBody: "\u0635\u0650\u0641 \u0645\u0627 \u062A\u0631\u064A\u062F \u0625\u0646\u062C\u0627\u0632\u0647 \u0648\u0633\u0623\u062F\u0644\u0651\u0643 \u0639\u0644\u0649 \u0627\u0644\u0645\u0646\u062A\u062C \u0648\u0627\u0644\u0635\u0641\u062D\u0629 \u0648\u0627\u0644\u062E\u0637\u0648\u0629 \u0627\u0644\u062A\u0627\u0644\u064A\u0629.",
216
+ tryAsking: "\u062C\u0631\u0651\u0628 \u0623\u0646 \u062A\u0633\u0623\u0644",
217
+ focusProduct: "\u0627\u0644\u062A\u0631\u0643\u064A\u0632 \u0639\u0644\u0649 \u0645\u0646\u062A\u062C",
218
+ allProducts: "\u0643\u0644 \u0627\u0644\u0645\u0646\u062A\u062C\u0627\u062A",
219
+ showAll: "\u0627\u0644\u0643\u0644",
220
+ showLess: "\u0639\u0631\u0636 \u0623\u0642\u0644",
221
+ sources: "\u0627\u0644\u0645\u0635\u0627\u062F\u0631",
222
+ nextYouCouldAsk: "\u064A\u0645\u0643\u0646\u0643 \u0623\u0646 \u062A\u0633\u0623\u0644 \u0628\u0639\u062F \u0630\u0644\u0643",
223
+ placeholder: "\u0627\u0633\u0623\u0644 \u0623\u064A \u0634\u064A\u0621 \u0639\u0646 \u0645\u0646\u062A\u062C\u0627\u062A\u0646\u0627\u2026",
224
+ placeholderProduct: "\u0627\u0633\u0623\u0644 \u0639\u0646 {product}\u2026",
225
+ send: "\u0625\u0631\u0633\u0627\u0644",
226
+ stop: "\u0625\u064A\u0642\u0627\u0641",
227
+ newChat: "\u0645\u062D\u0627\u062F\u062B\u0629 \u062C\u062F\u064A\u062F\u0629",
228
+ history: "\u0627\u0644\u0633\u062C\u0644",
229
+ clearHistory: "\u0645\u0633\u062D \u0627\u0644\u0633\u062C\u0644",
230
+ share: "\u0645\u0634\u0627\u0631\u0643\u0629",
231
+ copied: "\u062A\u0645 \u0627\u0644\u0646\u0633\u062E",
232
+ copying: "\u062C\u0627\u0631\u064D \u0627\u0644\u0646\u0633\u062E\u2026",
233
+ shareUnavailable: "\u063A\u064A\u0631 \u0645\u062A\u0627\u062D",
234
+ disclaimer: "\u0625\u062E\u0644\u0627\u0621 \u0645\u0633\u0624\u0648\u0644\u064A\u0629",
235
+ disclaimerShort: "\u0645\u0628\u0646\u064A \u0639\u0644\u0649 \u0648\u062B\u0627\u0626\u0642\u0646\u0627 \u2014 \u062A\u062D\u0642\u0651\u0642 \u0645\u0646 \u0623\u064A \u0645\u0639\u0644\u0648\u0645\u0629 \u0645\u0647\u0645\u0629.",
236
+ dictate: "\u0623\u0645\u0644\u0650 \u0633\u0624\u0627\u0644\u0643",
237
+ stopDictating: "\u0625\u064A\u0642\u0627\u0641 \u0627\u0644\u0625\u0645\u0644\u0627\u0621",
238
+ attach: "\u0625\u0631\u0641\u0627\u0642 \u0645\u0644\u0641\u0627\u062A",
239
+ attachHint: "\u062D\u062A\u0649 {{max}} \u0645\u0644\u0641\u0627\u062A\u060C \u0628\u062D\u062F \u0623\u0642\u0635\u0649 {{size}} \u0645\u064A\u063A\u0627\u0628\u0627\u064A\u062A \u0644\u0643\u0644 \u0645\u0644\u0641",
240
+ removeAttachment: "\u0625\u0632\u0627\u0644\u0629 {{name}}",
241
+ attachmentNameOnly: "\u0627\u0644\u0627\u0633\u0645 \u0648\u0627\u0644\u0646\u0648\u0639 \u0641\u0642\u0637",
242
+ attachmentTooLarge: "{{name}} \u0623\u0643\u0628\u0631 \u0645\u0646 {{size}} \u0645\u064A\u063A\u0627\u0628\u0627\u064A\u062A \u0648\u0644\u0645 \u064A\u062A\u0645 \u0625\u0631\u0641\u0627\u0642\u0647.",
243
+ attachmentTooMany: "\u064A\u0645\u0643\u0646 \u0625\u0631\u0641\u0627\u0642 {{max}} \u0645\u0644\u0641\u0627\u062A \u0641\u0642\u0637\u060C \u0644\u0630\u0627 \u062A\u0645 \u062A\u062E\u0637\u064A {{name}}.",
244
+ noAnswer: "\u0644\u0645 \u0623\u062C\u062F \u0647\u0630\u0627 \u0641\u064A \u0648\u062B\u0627\u0626\u0642\u0646\u0627\u060C \u0644\u0630\u0627 \u0641\u0627\u0644\u0625\u062C\u0627\u0628\u0629 \u0623\u062F\u0646\u0627\u0647 \u063A\u064A\u0631 \u0645\u0633\u062A\u0646\u062F\u0629 \u0625\u0644\u0649 \u0645\u0635\u062F\u0631. \u062D\u0627\u0648\u0644 \u0625\u0639\u0627\u062F\u0629 \u0627\u0644\u0635\u064A\u0627\u063A\u0629\u060C \u0623\u0648",
245
+ askHuman: "\u062A\u062D\u062F\u0651\u062B \u0625\u0644\u0649 \u0634\u062E\u0635",
246
+ prevSuggestion: "\u0627\u0644\u0627\u0642\u062A\u0631\u0627\u062D \u0627\u0644\u0633\u0627\u0628\u0642",
247
+ nextSuggestion: "\u0627\u0644\u0627\u0642\u062A\u0631\u0627\u062D \u0627\u0644\u062A\u0627\u0644\u064A",
248
+ capabilities: [
249
+ "\u0645\u0628\u0646\u064A \u0639\u0644\u0649 \u0648\u062B\u0627\u0626\u0642\u0646\u0627",
250
+ "\u0642\u0627\u0631\u0646 \u0639\u0628\u0631 \u0627\u0644\u0645\u0646\u0638\u0648\u0645\u0629",
251
+ "\u0645\u0628\u0627\u0634\u0631\u0629\u064B \u0625\u0644\u0649 \u0627\u0644\u0635\u0641\u062D\u0629 \u0627\u0644\u0635\u062D\u064A\u062D\u0629"
252
+ ],
253
+ prompts: [
254
+ "\u0645\u0627 \u0627\u0644\u0630\u064A \u064A\u0641\u0639\u0644\u0647 \u0647\u0630\u0627 \u0627\u0644\u0645\u0646\u062A\u062C \u0641\u0639\u0644\u064A\u064B\u0627\u061F",
255
+ "\u0623\u064A \u0645\u0646\u062A\u062C \u064A\u0646\u0627\u0633\u0628 \u0641\u0631\u064A\u0642\u064A\u061F",
256
+ "\u0643\u064A\u0641 \u0623\u0628\u062F\u0623 \u062E\u0637\u0648\u0629 \u0628\u062E\u0637\u0648\u0629\u061F",
257
+ "\u0643\u0645 \u062A\u0628\u0644\u063A \u0627\u0644\u062A\u0643\u0644\u0641\u0629\u061F"
258
+ ]
259
+ };
260
+ var TA = {
261
+ badge: "\u0B8E\u0B99\u0BCD\u0B95\u0BB3\u0BCD \u0B86\u0BB5\u0BA3\u0B99\u0BCD\u0B95\u0BB3\u0BC8 \u0B85\u0B9F\u0BBF\u0BAA\u0BCD\u0BAA\u0B9F\u0BC8\u0BAF\u0BBE\u0B95\u0B95\u0BCD \u0B95\u0BCA\u0BA3\u0BCD\u0B9F AI \u0BAA\u0BA4\u0BBF\u0BB2\u0BCD\u0B95\u0BB3\u0BCD",
262
+ welcomeTitle: "\u0B8E\u0B99\u0BCD\u0B95\u0BB3\u0BCD \u0BA4\u0BAF\u0BBE\u0BB0\u0BBF\u0BAA\u0BCD\u0BAA\u0BC1\u0B95\u0BB3\u0BCD \u0BAA\u0BB1\u0BCD\u0BB1\u0BBF \u0B8E\u0BA4\u0BC8\u0BAF\u0BC1\u0BAE\u0BCD \u0B95\u0BC7\u0BB3\u0BC1\u0B99\u0BCD\u0B95\u0BB3\u0BCD",
263
+ welcomeBody: "\u0BA8\u0BC0\u0B99\u0BCD\u0B95\u0BB3\u0BCD \u0B8E\u0BA9\u0BCD\u0BA9 \u0B9A\u0BC6\u0BAF\u0BCD\u0BAF \u0BB5\u0BBF\u0BB0\u0BC1\u0BAE\u0BCD\u0BAA\u0BC1\u0B95\u0BBF\u0BB1\u0BC0\u0BB0\u0BCD\u0B95\u0BB3\u0BCD \u0B8E\u0BA9\u0BCD\u0BB1\u0BC1 \u0B9A\u0BCA\u0BB2\u0BCD\u0BB2\u0BC1\u0B99\u0BCD\u0B95\u0BB3\u0BCD; \u0B9A\u0BB0\u0BBF\u0BAF\u0BBE\u0BA9 \u0BA4\u0BAF\u0BBE\u0BB0\u0BBF\u0BAA\u0BCD\u0BAA\u0BC1, \u0BAA\u0B95\u0BCD\u0B95\u0BAE\u0BCD, \u0B85\u0B9F\u0BC1\u0BA4\u0BCD\u0BA4 \u0BAA\u0B9F\u0BBF \u0B86\u0B95\u0BBF\u0BAF\u0BB5\u0BB1\u0BCD\u0BB1\u0BC8\u0B95\u0BCD \u0B95\u0BBE\u0B9F\u0BCD\u0B9F\u0BC1\u0B95\u0BBF\u0BB1\u0BC7\u0BA9\u0BCD.",
264
+ tryAsking: "\u0B87\u0BA4\u0BC8\u0B95\u0BCD \u0B95\u0BC7\u0B9F\u0BCD\u0B9F\u0BC1\u0BAA\u0BCD \u0BAA\u0BBE\u0BB0\u0BC1\u0B99\u0BCD\u0B95\u0BB3\u0BCD",
265
+ focusProduct: "\u0B92\u0BB0\u0BC1 \u0BA4\u0BAF\u0BBE\u0BB0\u0BBF\u0BAA\u0BCD\u0BAA\u0BBF\u0BB2\u0BCD \u0B95\u0BB5\u0BA9\u0BAE\u0BCD",
266
+ allProducts: "\u0B85\u0BA9\u0BC8\u0BA4\u0BCD\u0BA4\u0BC1 \u0BA4\u0BAF\u0BBE\u0BB0\u0BBF\u0BAA\u0BCD\u0BAA\u0BC1\u0B95\u0BB3\u0BCD",
267
+ showAll: "\u0B85\u0BA9\u0BC8\u0BA4\u0BCD\u0BA4\u0BC1\u0BAE\u0BCD",
268
+ showLess: "\u0B95\u0BC1\u0BB1\u0BC8\u0BB5\u0BBE\u0B95\u0B95\u0BCD \u0B95\u0BBE\u0B9F\u0BCD\u0B9F\u0BC1",
269
+ sources: "\u0BAE\u0BC2\u0BB2\u0B99\u0BCD\u0B95\u0BB3\u0BCD",
270
+ nextYouCouldAsk: "\u0B85\u0B9F\u0BC1\u0BA4\u0BCD\u0BA4\u0BC1 \u0BA8\u0BC0\u0B99\u0BCD\u0B95\u0BB3\u0BCD \u0B95\u0BC7\u0B9F\u0BCD\u0B95\u0BB2\u0BBE\u0BAE\u0BCD",
271
+ placeholder: "\u0B8E\u0B99\u0BCD\u0B95\u0BB3\u0BCD \u0BA4\u0BAF\u0BBE\u0BB0\u0BBF\u0BAA\u0BCD\u0BAA\u0BC1\u0B95\u0BB3\u0BCD \u0BAA\u0BB1\u0BCD\u0BB1\u0BBF \u0B8E\u0BA4\u0BC8\u0BAF\u0BC1\u0BAE\u0BCD \u0B95\u0BC7\u0BB3\u0BC1\u0B99\u0BCD\u0B95\u0BB3\u0BCD\u2026",
272
+ placeholderProduct: "{product} \u0BAA\u0BB1\u0BCD\u0BB1\u0BBF\u0B95\u0BCD \u0B95\u0BC7\u0BB3\u0BC1\u0B99\u0BCD\u0B95\u0BB3\u0BCD\u2026",
273
+ send: "\u0B85\u0BA9\u0BC1\u0BAA\u0BCD\u0BAA\u0BC1",
274
+ stop: "\u0BA8\u0BBF\u0BB1\u0BC1\u0BA4\u0BCD\u0BA4\u0BC1",
275
+ newChat: "\u0BAA\u0BC1\u0BA4\u0BBF\u0BAF \u0B89\u0BB0\u0BC8\u0BAF\u0BBE\u0B9F\u0BB2\u0BCD",
276
+ history: "\u0BB5\u0BB0\u0BB2\u0BBE\u0BB1\u0BC1",
277
+ clearHistory: "\u0BB5\u0BB0\u0BB2\u0BBE\u0BB1\u0BCD\u0BB1\u0BC8 \u0B85\u0BB4\u0BBF",
278
+ share: "\u0BAA\u0B95\u0BBF\u0BB0\u0BCD",
279
+ copied: "\u0BA8\u0B95\u0BB2\u0BC6\u0B9F\u0BC1\u0B95\u0BCD\u0B95\u0BAA\u0BCD\u0BAA\u0B9F\u0BCD\u0B9F\u0BA4\u0BC1",
280
+ copying: "\u0BA8\u0B95\u0BB2\u0BC6\u0B9F\u0BC1\u0B95\u0BCD\u0B95\u0BBF\u0BB1\u0BA4\u0BC1\u2026",
281
+ shareUnavailable: "\u0B95\u0BBF\u0B9F\u0BC8\u0B95\u0BCD\u0B95\u0BB5\u0BBF\u0BB2\u0BCD\u0BB2\u0BC8",
282
+ disclaimer: "\u0BAA\u0BCA\u0BB1\u0BC1\u0BAA\u0BCD\u0BAA\u0BC1\u0BA4\u0BCD \u0BA4\u0BC1\u0BB1\u0BAA\u0BCD\u0BAA\u0BC1",
283
+ disclaimerShort: "\u0B8E\u0B99\u0BCD\u0B95\u0BB3\u0BCD \u0B86\u0BB5\u0BA3\u0B99\u0BCD\u0B95\u0BB3\u0BC8 \u0B85\u0B9F\u0BBF\u0BAA\u0BCD\u0BAA\u0B9F\u0BC8\u0BAF\u0BBE\u0B95\u0B95\u0BCD \u0B95\u0BCA\u0BA3\u0BCD\u0B9F\u0BA4\u0BC1 \u2014 \u0BAE\u0BC1\u0B95\u0BCD\u0B95\u0BBF\u0BAF\u0BAE\u0BBE\u0BA9\u0BA4\u0BC8\u0B9A\u0BCD \u0B9A\u0BB0\u0BBF\u0BAA\u0BBE\u0BB0\u0BCD\u0B95\u0BCD\u0B95\u0BB5\u0BC1\u0BAE\u0BCD.",
284
+ dictate: "\u0B89\u0B99\u0BCD\u0B95\u0BB3\u0BCD \u0B95\u0BC7\u0BB3\u0BCD\u0BB5\u0BBF\u0BAF\u0BC8\u0BAA\u0BCD \u0BAA\u0BC7\u0B9A\u0BC1\u0B99\u0BCD\u0B95\u0BB3\u0BCD",
285
+ stopDictating: "\u0BAA\u0BC7\u0B9A\u0BC1\u0BB5\u0BA4\u0BC8 \u0BA8\u0BBF\u0BB1\u0BC1\u0BA4\u0BCD\u0BA4\u0BC1",
286
+ attach: "\u0B95\u0BCB\u0BAA\u0BCD\u0BAA\u0BC1\u0B95\u0BB3\u0BC8 \u0B87\u0BA3\u0BC8\u0B95\u0BCD\u0B95",
287
+ attachHint: "\u0B85\u0BA4\u0BBF\u0B95\u0BAA\u0B9F\u0BCD\u0B9A\u0BAE\u0BCD {{max}} \u0B95\u0BCB\u0BAA\u0BCD\u0BAA\u0BC1\u0B95\u0BB3\u0BCD, \u0B92\u0BB5\u0BCD\u0BB5\u0BCA\u0BA9\u0BCD\u0BB1\u0BC1\u0BAE\u0BCD {{size}} MB \u0BB5\u0BB0\u0BC8",
288
+ removeAttachment: "{{name}} \u0B85\u0B95\u0BB1\u0BCD\u0BB1\u0BC1",
289
+ attachmentNameOnly: "\u0BAA\u0BC6\u0BAF\u0BB0\u0BC1\u0BAE\u0BCD \u0BB5\u0B95\u0BC8\u0BAF\u0BC1\u0BAE\u0BCD \u0BAE\u0B9F\u0BCD\u0B9F\u0BC1\u0BAE\u0BCD",
290
+ attachmentTooLarge: "{{name}} {{size}} MB-\u0B90 \u0BB5\u0BBF\u0B9F \u0BAA\u0BC6\u0BB0\u0BBF\u0BAF\u0BA4\u0BC1, \u0B8E\u0BA9\u0BB5\u0BC7 \u0B87\u0BA3\u0BC8\u0B95\u0BCD\u0B95\u0BAA\u0BCD\u0BAA\u0B9F\u0BB5\u0BBF\u0BB2\u0BCD\u0BB2\u0BC8.",
291
+ attachmentTooMany: "{{max}} \u0B95\u0BCB\u0BAA\u0BCD\u0BAA\u0BC1\u0B95\u0BB3\u0BCD \u0BAE\u0B9F\u0BCD\u0B9F\u0BC1\u0BAE\u0BC7 \u0B87\u0BA3\u0BC8\u0B95\u0BCD\u0B95 \u0BAE\u0BC1\u0B9F\u0BBF\u0BAF\u0BC1\u0BAE\u0BCD, \u0B8E\u0BA9\u0BB5\u0BC7 {{name}} \u0BA4\u0BB5\u0BBF\u0BB0\u0BCD\u0B95\u0BCD\u0B95\u0BAA\u0BCD\u0BAA\u0B9F\u0BCD\u0B9F\u0BA4\u0BC1.",
292
+ noAnswer: "\u0B87\u0BA4\u0BC1 \u0B8E\u0B99\u0BCD\u0B95\u0BB3\u0BCD \u0B86\u0BB5\u0BA3\u0B99\u0BCD\u0B95\u0BB3\u0BBF\u0BB2\u0BCD \u0B95\u0BBF\u0B9F\u0BC8\u0B95\u0BCD\u0B95\u0BB5\u0BBF\u0BB2\u0BCD\u0BB2\u0BC8, \u0B8E\u0BA9\u0BB5\u0BC7 \u0B95\u0BC0\u0BB4\u0BC7 \u0B89\u0BB3\u0BCD\u0BB3 \u0BAA\u0BA4\u0BBF\u0BB2\u0BC1\u0B95\u0BCD\u0B95\u0BC1 \u0BAE\u0BC2\u0BB2\u0BAE\u0BCD \u0B87\u0BB2\u0BCD\u0BB2\u0BC8. \u0BB5\u0BC7\u0BB1\u0BC1 \u0BB5\u0B95\u0BC8\u0BAF\u0BBF\u0BB2\u0BCD \u0B95\u0BC7\u0BB3\u0BC1\u0B99\u0BCD\u0B95\u0BB3\u0BCD, \u0B85\u0BB2\u0BCD\u0BB2\u0BA4\u0BC1",
293
+ askHuman: "\u0B8E\u0B99\u0BCD\u0B95\u0BB3\u0BC8\u0BA4\u0BCD \u0BA4\u0BCA\u0B9F\u0BB0\u0BCD\u0BAA\u0BC1 \u0B95\u0BCA\u0BB3\u0BCD\u0BB3\u0BC1\u0B99\u0BCD\u0B95\u0BB3\u0BCD",
294
+ prevSuggestion: "\u0BAE\u0BC1\u0BA8\u0BCD\u0BA4\u0BC8\u0BAF \u0BAA\u0BB0\u0BBF\u0BA8\u0BCD\u0BA4\u0BC1\u0BB0\u0BC8",
295
+ nextSuggestion: "\u0B85\u0B9F\u0BC1\u0BA4\u0BCD\u0BA4 \u0BAA\u0BB0\u0BBF\u0BA8\u0BCD\u0BA4\u0BC1\u0BB0\u0BC8",
296
+ capabilities: [
297
+ "\u0B8E\u0B99\u0BCD\u0B95\u0BB3\u0BCD \u0B9A\u0BCA\u0BA8\u0BCD\u0BA4 \u0B86\u0BB5\u0BA3\u0B99\u0BCD\u0B95\u0BB3\u0BBF\u0BA9\u0BCD \u0B85\u0B9F\u0BBF\u0BAA\u0BCD\u0BAA\u0B9F\u0BC8\u0BAF\u0BBF\u0BB2\u0BCD",
298
+ "\u0BA4\u0BAF\u0BBE\u0BB0\u0BBF\u0BAA\u0BCD\u0BAA\u0BC1\u0B95\u0BB3\u0BC8 \u0B92\u0BAA\u0BCD\u0BAA\u0BBF\u0B9F\u0BC1\u0B99\u0BCD\u0B95\u0BB3\u0BCD",
299
+ "\u0BA8\u0BC7\u0BB0\u0BBE\u0B95 \u0B9A\u0BB0\u0BBF\u0BAF\u0BBE\u0BA9 \u0BAA\u0B95\u0BCD\u0B95\u0BA4\u0BCD\u0BA4\u0BBF\u0BB1\u0BCD\u0B95\u0BC1"
300
+ ],
301
+ prompts: [
302
+ "\u0B87\u0BA8\u0BCD\u0BA4\u0BA4\u0BCD \u0BA4\u0BAF\u0BBE\u0BB0\u0BBF\u0BAA\u0BCD\u0BAA\u0BC1 \u0B89\u0BA3\u0BCD\u0BAE\u0BC8\u0BAF\u0BBF\u0BB2\u0BCD \u0B8E\u0BA9\u0BCD\u0BA9 \u0B9A\u0BC6\u0BAF\u0BCD\u0B95\u0BBF\u0BB1\u0BA4\u0BC1?",
303
+ "\u0B8E\u0BA9\u0BCD \u0B95\u0BC1\u0BB4\u0BC1\u0BB5\u0BBF\u0BB1\u0BCD\u0B95\u0BC1 \u0B8E\u0BA8\u0BCD\u0BA4\u0BA4\u0BCD \u0BA4\u0BAF\u0BBE\u0BB0\u0BBF\u0BAA\u0BCD\u0BAA\u0BC1 \u0BAA\u0BCA\u0BB0\u0BC1\u0BA8\u0BCD\u0BA4\u0BC1\u0BAE\u0BCD?",
304
+ "\u0BAA\u0B9F\u0BBF\u0BAA\u0BCD\u0BAA\u0B9F\u0BBF\u0BAF\u0BBE\u0B95 \u0B8E\u0BAA\u0BCD\u0BAA\u0B9F\u0BBF\u0BA4\u0BCD \u0BA4\u0BCA\u0B9F\u0B99\u0BCD\u0B95\u0BC1\u0BB5\u0BA4\u0BC1?",
305
+ "\u0B87\u0BA4\u0BA9\u0BCD \u0BB5\u0BBF\u0BB2\u0BC8 \u0B8E\u0BA9\u0BCD\u0BA9?"
306
+ ]
307
+ };
308
+ var STRINGS = {
309
+ en: EN,
310
+ zh: ZH,
311
+ hi: HI,
312
+ es: ES,
313
+ ar: AR,
314
+ ta: TA
315
+ };
316
+ function resolveExploreLocale(explicit) {
317
+ const candidates = [
318
+ explicit,
319
+ typeof document === "undefined" ? void 0 : document.documentElement.lang,
320
+ typeof navigator === "undefined" ? void 0 : navigator.language
321
+ ];
322
+ for (const candidate of candidates) {
323
+ if (!candidate) continue;
324
+ const primary = candidate.toLowerCase().split("-")[0];
325
+ const match = EXPLORE_LOCALES.find((locale) => locale === primary);
326
+ if (match) return match;
327
+ }
328
+ return "en";
329
+ }
330
+ function exploreStrings(locale) {
331
+ return STRINGS[locale] ?? EN;
332
+ }
333
+ function fill(template, values) {
334
+ return template.replace(/\{(\w+)\}/g, (match, key) => values[key] ?? match);
335
+ }
17
336
  var defaultComponents = {
18
337
  a: ({ href, children, ...props }) => {
19
338
  const isExternal = typeof href === "string" && (href.startsWith("http://") || href.startsWith("https://"));
@@ -473,6 +792,12 @@ var EXPLORE_MESSAGE_FIELDS = (
473
792
  }
474
793
  followUps
475
794
  answered
795
+ attachments {
796
+ name
797
+ mimeType
798
+ size
799
+ textExtracted
800
+ }
476
801
  errorCode
477
802
  createdAt
478
803
  completedAt
@@ -558,6 +883,16 @@ var CREATE_EXPLORE_SHARE_LINK_MUTATION = (
558
883
  }
559
884
  `
560
885
  );
886
+ var EXPLORE_SHARED_CONVERSATION_QUERY = (
887
+ /* GraphQL */
888
+ `
889
+ query ExploreSharedConversation($shareToken: String!) {
890
+ exploreSharedConversation(shareToken: $shareToken) {
891
+ ${EXPLORE_MESSAGE_FIELDS}
892
+ }
893
+ }
894
+ `
895
+ );
561
896
 
562
897
  // src/data/products.ts
563
898
  var ECOSYSTEM_PRODUCTS = [
@@ -1008,6 +1343,14 @@ function readPersisted(key) {
1008
1343
  return null;
1009
1344
  }
1010
1345
  }
1346
+ function readShareToken() {
1347
+ if (typeof window === "undefined") return null;
1348
+ try {
1349
+ return new URL(window.location.href).searchParams.get("c");
1350
+ } catch {
1351
+ return null;
1352
+ }
1353
+ }
1011
1354
  function visibleText(message) {
1012
1355
  return message.content || message.partialContent || "";
1013
1356
  }
@@ -1046,10 +1389,18 @@ function useExploreChat(options = {}) {
1046
1389
  const pollGenerationRef = useRef(0);
1047
1390
  const pollTimerRef = useRef(null);
1048
1391
  const conversationTokenRef = useRef(null);
1392
+ const shareTokenRef = useRef(void 0);
1393
+ if (shareTokenRef.current === void 0) {
1394
+ shareTokenRef.current = readShareToken();
1395
+ }
1396
+ const isSharedView = shareTokenRef.current !== null;
1049
1397
  const catalogRef = useRef(fallbackCatalog);
1050
1398
  const turnCountRef = useRef(0);
1051
1399
  const focusProductRef = useRef(null);
1052
1400
  const lastSentTextRef = useRef(null);
1401
+ const lastSentAttachmentsRef = useRef(
1402
+ []
1403
+ );
1053
1404
  const inFlightRef = useRef(false);
1054
1405
  catalogRef.current = catalog;
1055
1406
  const clearPollTimer = useCallback(() => {
@@ -1074,6 +1425,43 @@ function useExploreChat(options = {}) {
1074
1425
  };
1075
1426
  }, []);
1076
1427
  useEffect(() => {
1428
+ const shareToken = shareTokenRef.current;
1429
+ if (!shareToken) return;
1430
+ let cancelled = false;
1431
+ setHydrated(true);
1432
+ void client.query(
1433
+ EXPLORE_SHARED_CONVERSATION_QUERY,
1434
+ { shareToken },
1435
+ { cache: false }
1436
+ ).then((res) => {
1437
+ if (cancelled || !mountedRef.current) return;
1438
+ const shared = res?.data?.exploreSharedConversation;
1439
+ if (shared && shared.length > 0) {
1440
+ setMessages(shared);
1441
+ return;
1442
+ }
1443
+ setError({
1444
+ kind: "unknown",
1445
+ code: "SHARE_NOT_FOUND",
1446
+ message: "That shared conversation could not be found. The link may have expired.",
1447
+ // Nothing to retry: a bad token will stay bad.
1448
+ retryable: false
1449
+ });
1450
+ }).catch(() => {
1451
+ if (cancelled || !mountedRef.current) return;
1452
+ setError({
1453
+ kind: "unknown",
1454
+ code: "SHARE_NOT_FOUND",
1455
+ message: "That shared conversation could not be loaded.",
1456
+ retryable: true
1457
+ });
1458
+ });
1459
+ return () => {
1460
+ cancelled = true;
1461
+ };
1462
+ }, [client]);
1463
+ useEffect(() => {
1464
+ if (shareTokenRef.current !== null) return;
1077
1465
  if (!persist) {
1078
1466
  setHydrated(true);
1079
1467
  return;
@@ -1241,7 +1629,7 @@ function useExploreChat(options = {}) {
1241
1629
  [client, pollIntervalMs, pollTimeoutMs]
1242
1630
  );
1243
1631
  const submit = useCallback(
1244
- async (text, optimisticId, captchaAttempt) => {
1632
+ async (text, optimisticId, captchaAttempt, attachments) => {
1245
1633
  const activeCatalog = catalogRef.current;
1246
1634
  let recaptchaToken;
1247
1635
  if (activeCatalog.captchaRequired && activeCatalog.recaptchaSiteKey) {
@@ -1259,7 +1647,8 @@ function useExploreChat(options = {}) {
1259
1647
  ...focusProductRef.current || productSlug ? { productSlug: focusProductRef.current ?? productSlug } : {},
1260
1648
  ...recaptchaToken ? { recaptchaToken } : {},
1261
1649
  ...locale ? { locale } : {},
1262
- ...pageUrl ? { pageUrl } : {}
1650
+ ...pageUrl ? { pageUrl } : {},
1651
+ ...attachments.length > 0 ? { attachments: [...attachments] } : {}
1263
1652
  };
1264
1653
  const res = await client.mutate(
1265
1654
  SEND_EXPLORE_MESSAGE_MUTATION,
@@ -1273,7 +1662,7 @@ function useExploreChat(options = {}) {
1273
1662
  const code = typeof first?.extensions?.code === "string" ? first.extensions.code : void 0;
1274
1663
  const classified = classifyExploreError(code, first?.message);
1275
1664
  if (classified.kind === "captcha" && captchaAttempt === 0) {
1276
- await submit(text, optimisticId, 1);
1665
+ await submit(text, optimisticId, 1, attachments);
1277
1666
  return;
1278
1667
  }
1279
1668
  inFlightRef.current = false;
@@ -1310,7 +1699,7 @@ function useExploreChat(options = {}) {
1310
1699
  [client, locale, pageUrl, productSlug, startPolling]
1311
1700
  );
1312
1701
  const send = useCallback(
1313
- async (message) => {
1702
+ async (message, attachments = []) => {
1314
1703
  const text = message.trim();
1315
1704
  if (!text) return;
1316
1705
  if (inFlightRef.current) return;
@@ -1340,6 +1729,7 @@ function useExploreChat(options = {}) {
1340
1729
  }
1341
1730
  inFlightRef.current = true;
1342
1731
  lastSentTextRef.current = text;
1732
+ lastSentAttachmentsRef.current = attachments;
1343
1733
  setError(null);
1344
1734
  setPhase("sending");
1345
1735
  cancelPolling();
@@ -1362,7 +1752,7 @@ function useExploreChat(options = {}) {
1362
1752
  setTurnCount(turnCountRef.current);
1363
1753
  onSend?.(text);
1364
1754
  try {
1365
- await submit(text, optimistic.id, 0);
1755
+ await submit(text, optimistic.id, 0, attachments);
1366
1756
  } catch (err) {
1367
1757
  if (!mountedRef.current) return;
1368
1758
  console.error("[WebSDK] Explore send failed", err);
@@ -1411,7 +1801,7 @@ function useExploreChat(options = {}) {
1411
1801
  });
1412
1802
  turnCountRef.current = Math.max(0, turnCountRef.current - 1);
1413
1803
  setTurnCount(turnCountRef.current);
1414
- void send(text);
1804
+ void send(text, lastSentAttachmentsRef.current);
1415
1805
  }, [cancelPolling, send]);
1416
1806
  const reset = useCallback(() => {
1417
1807
  setArchive(
@@ -1425,6 +1815,7 @@ function useExploreChat(options = {}) {
1425
1815
  inFlightRef.current = false;
1426
1816
  conversationTokenRef.current = null;
1427
1817
  lastSentTextRef.current = null;
1818
+ lastSentAttachmentsRef.current = [];
1428
1819
  turnCountRef.current = 0;
1429
1820
  setTurnCount(0);
1430
1821
  setMessages([]);
@@ -1533,7 +1924,8 @@ function useExploreChat(options = {}) {
1533
1924
  deleteConversation,
1534
1925
  clearHistory,
1535
1926
  recordClick,
1536
- createShareLink
1927
+ createShareLink,
1928
+ isSharedView
1537
1929
  };
1538
1930
  }
1539
1931
  var optimisticCounter = 0;
@@ -1759,6 +2151,39 @@ function useSpeechInput({
1759
2151
  );
1760
2152
  return { supported, listening, interim, error, start, stop, toggle };
1761
2153
  }
2154
+ var SWIPE_THRESHOLD = 40;
2155
+ function useSwipe({
2156
+ onSwipeLeft,
2157
+ onSwipeRight,
2158
+ enabled = true
2159
+ }) {
2160
+ const start = useRef(null);
2161
+ const onPointerDown = useCallback(
2162
+ (event) => {
2163
+ if (!enabled) return;
2164
+ start.current = { x: event.clientX, y: event.clientY };
2165
+ },
2166
+ [enabled]
2167
+ );
2168
+ const onPointerUp = useCallback(
2169
+ (event) => {
2170
+ const from = start.current;
2171
+ start.current = null;
2172
+ if (!enabled || !from) return;
2173
+ const dx = event.clientX - from.x;
2174
+ const dy = event.clientY - from.y;
2175
+ if (Math.abs(dx) < SWIPE_THRESHOLD || Math.abs(dx) <= Math.abs(dy))
2176
+ return;
2177
+ if (dx < 0) onSwipeLeft?.();
2178
+ else onSwipeRight?.();
2179
+ },
2180
+ [enabled, onSwipeLeft, onSwipeRight]
2181
+ );
2182
+ const onPointerCancel = useCallback(() => {
2183
+ start.current = null;
2184
+ }, []);
2185
+ return { onPointerDown, onPointerUp, onPointerCancel };
2186
+ }
1762
2187
  function canonicalFromLocation() {
1763
2188
  if (typeof window === "undefined" || !window.location) return void 0;
1764
2189
  const { origin, pathname } = window.location;
@@ -1884,6 +2309,145 @@ var Textarea = React.forwardRef(({ className, ...props }, ref) => {
1884
2309
  );
1885
2310
  });
1886
2311
  Textarea.displayName = "Textarea";
2312
+
2313
+ // src/utils/explore-attachments.ts
2314
+ var MAX_ATTACHMENTS = 5;
2315
+ var MAX_ATTACHMENT_BYTES = 10 * 1024 * 1024;
2316
+ var MAX_TEXT_PER_ATTACHMENT = 2e4;
2317
+ var TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
2318
+ "txt",
2319
+ "md",
2320
+ "markdown",
2321
+ "csv",
2322
+ "tsv",
2323
+ "json",
2324
+ "jsonl",
2325
+ "yaml",
2326
+ "yml",
2327
+ "toml",
2328
+ "ini",
2329
+ "cfg",
2330
+ "conf",
2331
+ "env",
2332
+ "log",
2333
+ "sql",
2334
+ "graphql",
2335
+ "gql",
2336
+ "html",
2337
+ "htm",
2338
+ "xml",
2339
+ "svg",
2340
+ "css",
2341
+ "scss",
2342
+ "js",
2343
+ "jsx",
2344
+ "mjs",
2345
+ "cjs",
2346
+ "ts",
2347
+ "tsx",
2348
+ "py",
2349
+ "rb",
2350
+ "go",
2351
+ "rs",
2352
+ "java",
2353
+ "kt",
2354
+ "c",
2355
+ "h",
2356
+ "cpp",
2357
+ "cs",
2358
+ "php",
2359
+ "sh",
2360
+ "bash",
2361
+ "zsh",
2362
+ "ps1",
2363
+ "dockerfile",
2364
+ "tf",
2365
+ "tfvars"
2366
+ ]);
2367
+ function isTextualMimeType(mimeType) {
2368
+ if (mimeType.startsWith("text/")) return true;
2369
+ return mimeType === "application/json" || mimeType === "application/xml" || mimeType === "application/yaml" || mimeType === "application/x-yaml" || mimeType === "application/javascript" || mimeType === "application/graphql" || mimeType.endsWith("+json") || mimeType.endsWith("+xml");
2370
+ }
2371
+ function extensionOf(name) {
2372
+ const dot = name.lastIndexOf(".");
2373
+ if (dot <= 0 || dot === name.length - 1) return "";
2374
+ return name.slice(dot + 1).toLowerCase();
2375
+ }
2376
+ function looksTextual(name, mimeType) {
2377
+ if (isTextualMimeType(mimeType)) return true;
2378
+ return TEXT_EXTENSIONS.has(extensionOf(name));
2379
+ }
2380
+ function isDecodedTextUsable(decoded) {
2381
+ if (decoded.length === 0) return false;
2382
+ if (decoded.includes("\0")) return false;
2383
+ let replacements = 0;
2384
+ for (const char of decoded) if (char === "\uFFFD") replacements += 1;
2385
+ return replacements / decoded.length < 0.1;
2386
+ }
2387
+ function formatBytes(bytes) {
2388
+ if (bytes < 1024) return `${bytes} B`;
2389
+ if (bytes < 1024 * 1024) return `${Math.round(bytes / 1024)} KB`;
2390
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
2391
+ }
2392
+ var counter = 0;
2393
+ function nextId() {
2394
+ counter += 1;
2395
+ return `att-${counter}`;
2396
+ }
2397
+ async function readArrayBuffer(blob) {
2398
+ if (typeof blob.arrayBuffer === "function") return blob.arrayBuffer();
2399
+ return new Promise((resolve, reject) => {
2400
+ const reader = new FileReader();
2401
+ reader.onload = () => resolve(reader.result);
2402
+ reader.onerror = () => reject(reader.error ?? new Error("file read failed"));
2403
+ reader.readAsArrayBuffer(blob);
2404
+ });
2405
+ }
2406
+ async function readTextPrefix(file) {
2407
+ try {
2408
+ const slice = file.slice(0, MAX_TEXT_PER_ATTACHMENT);
2409
+ const buffer = await readArrayBuffer(slice);
2410
+ const decoded = new TextDecoder("utf-8").decode(buffer);
2411
+ return isDecodedTextUsable(decoded) ? decoded : null;
2412
+ } catch {
2413
+ return null;
2414
+ }
2415
+ }
2416
+ async function stageFiles(files, alreadyStaged) {
2417
+ const accepted = [];
2418
+ const rejected = [];
2419
+ let slots = MAX_ATTACHMENTS - alreadyStaged.length;
2420
+ for (const file of files) {
2421
+ if (slots <= 0) {
2422
+ rejected.push({ name: file.name, reason: "too-many" });
2423
+ continue;
2424
+ }
2425
+ if (file.size > MAX_ATTACHMENT_BYTES) {
2426
+ rejected.push({ name: file.name, reason: "too-large" });
2427
+ continue;
2428
+ }
2429
+ const mimeType = file.type || "application/octet-stream";
2430
+ const textContent = looksTextual(file.name, mimeType) ? await readTextPrefix(file) : null;
2431
+ accepted.push({
2432
+ id: nextId(),
2433
+ name: file.name,
2434
+ mimeType,
2435
+ size: file.size,
2436
+ textContent,
2437
+ textExtracted: textContent !== null
2438
+ });
2439
+ slots -= 1;
2440
+ }
2441
+ return { accepted, rejected };
2442
+ }
2443
+ function toPayload(staged) {
2444
+ return staged.map(({ name, mimeType, size, textContent }) => ({
2445
+ name,
2446
+ mimeType,
2447
+ size,
2448
+ textContent
2449
+ }));
2450
+ }
1887
2451
  var EXPLORE_CSS = `
1888
2452
  @keyframes boff-explore-pulse {
1889
2453
  0%, 80%, 100% { opacity: 0.25; transform: translateY(0); }
@@ -1971,6 +2535,70 @@ var EXPLORE_CSS = `
1971
2535
  max-width: 100%;
1972
2536
  height: auto;
1973
2537
  }
2538
+
2539
+ /* ---- Ambient backdrop -----------------------------------------------------------------
2540
+ Two very low-opacity radial washes behind the welcome state, drifting slowly. Painted on
2541
+ a pseudo-element with pointer-events:none so it can never intercept a click \u2014 a
2542
+ decorative overlay that swallows clicks is a bug we have shipped before.
2543
+ Colours come from the product's own --primary token, so this picks up each site's palette
2544
+ instead of introducing one. */
2545
+ .boff-explore-aura {
2546
+ position: relative;
2547
+ isolation: isolate;
2548
+ }
2549
+ .boff-explore-aura::before {
2550
+ content: "";
2551
+ position: absolute;
2552
+ inset: -10% -20% auto -20%;
2553
+ height: 60%;
2554
+ z-index: -1;
2555
+ pointer-events: none;
2556
+ background:
2557
+ radial-gradient(38% 55% at 22% 30%, hsl(var(--primary) / 0.10), transparent 70%),
2558
+ radial-gradient(32% 48% at 78% 18%, hsl(var(--primary) / 0.07), transparent 72%);
2559
+ filter: blur(6px);
2560
+ animation: boff-explore-drift 26s ease-in-out infinite alternate;
2561
+ }
2562
+ @keyframes boff-explore-drift {
2563
+ from { transform: translate3d(-1.5%, -1%, 0) scale(1); }
2564
+ to { transform: translate3d(1.5%, 1.5%, 0) scale(1.06); }
2565
+ }
2566
+
2567
+ /* Entrance: content settles rather than snapping in. Short, and only once. */
2568
+ @keyframes boff-explore-rise {
2569
+ from { opacity: 0; transform: translateY(6px); }
2570
+ to { opacity: 1; transform: none; }
2571
+ }
2572
+ .boff-explore-rise {
2573
+ animation: boff-explore-rise 380ms cubic-bezier(0.22, 1, 0.36, 1) both;
2574
+ }
2575
+ .boff-explore-rise-1 { animation-delay: 40ms; }
2576
+ .boff-explore-rise-2 { animation-delay: 90ms; }
2577
+ .boff-explore-rise-3 { animation-delay: 140ms; }
2578
+
2579
+ /* A soft sheen that crosses the send button while a turn is in flight \u2014 enough to say
2580
+ "working" without another spinner competing with the thinking dots. */
2581
+ @keyframes boff-explore-sheen {
2582
+ from { transform: translateX(-120%); }
2583
+ to { transform: translateX(220%); }
2584
+ }
2585
+ .boff-explore-busy { position: relative; overflow: hidden; }
2586
+ .boff-explore-busy::after {
2587
+ content: "";
2588
+ position: absolute;
2589
+ inset: 0;
2590
+ pointer-events: none;
2591
+ background: linear-gradient(100deg, transparent 20%, hsl(var(--primary) / 0.22) 50%, transparent 80%);
2592
+ animation: boff-explore-sheen 1.5s ease-in-out infinite;
2593
+ }
2594
+
2595
+ /* Every one of the above is decoration. Reduced motion removes the movement and keeps the
2596
+ final state, rather than leaving content mid-animation and invisible. */
2597
+ @media (prefers-reduced-motion: reduce) {
2598
+ .boff-explore-aura::before,
2599
+ .boff-explore-busy::after { animation: none; }
2600
+ .boff-explore-rise { animation: none; opacity: 1; transform: none; }
2601
+ }
1974
2602
  `;
1975
2603
  function ExploreStyles() {
1976
2604
  return /* @__PURE__ */ jsx("style", { dangerouslySetInnerHTML: { __html: EXPLORE_CSS } });
@@ -2168,17 +2796,48 @@ function ThinkingIndicator({ activity }) {
2168
2796
  }
2169
2797
  );
2170
2798
  }
2171
- function UserBubble({ message }) {
2172
- return /* @__PURE__ */ jsx("div", { className: "flex justify-end", children: /* @__PURE__ */ jsx(
2173
- "div",
2174
- {
2175
- "data-boff-explore": "user",
2176
- 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",
2177
- children: message.content
2178
- }
2179
- ) });
2799
+ function UserBubble({
2800
+ strings: T,
2801
+ message
2802
+ }) {
2803
+ const attachments = message.attachments ?? [];
2804
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-end gap-1.5", children: [
2805
+ /* @__PURE__ */ jsx(
2806
+ "div",
2807
+ {
2808
+ "data-boff-explore": "user",
2809
+ 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",
2810
+ children: message.content
2811
+ }
2812
+ ),
2813
+ attachments.length > 0 ? /* @__PURE__ */ jsx(
2814
+ "ul",
2815
+ {
2816
+ "data-boff-explore": "user-attachments",
2817
+ className: "flex max-w-[85%] flex-wrap justify-end gap-1.5",
2818
+ children: attachments.map((attachment) => /* @__PURE__ */ jsxs(
2819
+ "li",
2820
+ {
2821
+ "data-boff-explore": "user-attachment",
2822
+ "data-text-extracted": attachment.textExtracted ? "true" : "false",
2823
+ 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",
2824
+ children: [
2825
+ /* @__PURE__ */ jsx(Paperclip, { className: "h-3 w-3 shrink-0" }),
2826
+ /* @__PURE__ */ jsx("span", { className: "truncate", title: attachment.name, children: attachment.name }),
2827
+ attachment.textExtracted ? null : /* @__PURE__ */ jsxs("span", { className: "shrink-0", children: [
2828
+ "\xB7 ",
2829
+ T.attachmentNameOnly
2830
+ ] })
2831
+ ]
2832
+ },
2833
+ `${attachment.name}-${attachment.size}`
2834
+ ))
2835
+ }
2836
+ ) : null
2837
+ ] });
2180
2838
  }
2181
2839
  function AssistantBubble({
2840
+ strings: T,
2182
2841
  message,
2183
2842
  activity,
2184
2843
  onNavigate,
@@ -2195,7 +2854,7 @@ function AssistantBubble({
2195
2854
  ref: anchorRef,
2196
2855
  "data-boff-explore": "assistant",
2197
2856
  "data-status": message.status,
2198
- className: "flex scroll-mt-4 gap-3",
2857
+ className: "boff-explore-rise flex scroll-mt-4 gap-3",
2199
2858
  children: [
2200
2859
  /* @__PURE__ */ jsx(
2201
2860
  "span",
@@ -2226,7 +2885,7 @@ function AssistantBubble({
2226
2885
  event.preventDefault();
2227
2886
  onNavigate("/contact");
2228
2887
  },
2229
- children: "ask a human"
2888
+ children: T.askHuman
2230
2889
  }
2231
2890
  ),
2232
2891
  "."
@@ -2241,7 +2900,7 @@ function AssistantBubble({
2241
2900
  streaming ? /* @__PURE__ */ jsx(ThinkingIndicator, { activity }) : null,
2242
2901
  failed && !body ? /* @__PURE__ */ jsx("div", { className: "rounded-2xl rounded-tl-md border border-border bg-muted px-4 py-3 text-sm text-muted-foreground", children: "That answer didn't come through. Try asking again." }) : null,
2243
2902
  message.references.length > 0 ? /* @__PURE__ */ jsxs("div", { children: [
2244
- /* @__PURE__ */ jsx("p", { className: "mb-2 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: "Sources" }),
2903
+ /* @__PURE__ */ jsx("p", { className: "mb-2 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: T.sources }),
2245
2904
  /* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-3", children: message.references.map((reference) => /* @__PURE__ */ jsx(
2246
2905
  ReferenceCard,
2247
2906
  {
@@ -2261,7 +2920,7 @@ function AssistantBubble({
2261
2920
  `${cta.kind}-${cta.url}`
2262
2921
  )) }) : null,
2263
2922
  message.status === "COMPLETED" && (message.followUps?.length ?? 0) > 0 ? /* @__PURE__ */ jsxs("div", { className: "space-y-1.5 pt-0.5", children: [
2264
- /* @__PURE__ */ jsx("p", { className: "text-xs font-medium text-muted-foreground", children: "Next you could ask" }),
2923
+ /* @__PURE__ */ jsx("p", { className: "text-xs font-medium text-muted-foreground", children: T.nextYouCouldAsk }),
2265
2924
  /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1.5", children: (message.followUps ?? []).map((question) => /* @__PURE__ */ jsxs(
2266
2925
  "button",
2267
2926
  {
@@ -2323,6 +2982,7 @@ function ErrorBanner({
2323
2982
  );
2324
2983
  }
2325
2984
  function PromptCarousel({
2985
+ strings: T,
2326
2986
  prompts,
2327
2987
  onPrompt,
2328
2988
  disabled
@@ -2337,6 +2997,11 @@ function PromptCarousel({
2337
2997
  },
2338
2998
  [count]
2339
2999
  );
3000
+ const swipe = useSwipe({
3001
+ onSwipeLeft: () => go(1),
3002
+ onSwipeRight: () => go(-1),
3003
+ enabled: count > 1
3004
+ });
2340
3005
  useEffect(() => {
2341
3006
  if (paused || disabled || count < 2) return;
2342
3007
  if (typeof window !== "undefined" && window.matchMedia?.("(prefers-reduced-motion: reduce)").matches) {
@@ -2349,7 +3014,7 @@ function PromptCarousel({
2349
3014
  return /* @__PURE__ */ jsxs(
2350
3015
  "div",
2351
3016
  {
2352
- className: "flex min-w-0 items-center gap-1.5",
3017
+ className: "flex min-w-0 touch-pan-y items-center gap-1.5",
2353
3018
  role: "group",
2354
3019
  "aria-roledescription": "carousel",
2355
3020
  "aria-label": "Example questions",
@@ -2357,14 +3022,15 @@ function PromptCarousel({
2357
3022
  onMouseLeave: () => setPaused(false),
2358
3023
  onFocusCapture: () => setPaused(true),
2359
3024
  onBlurCapture: () => setPaused(false),
3025
+ ...swipe,
2360
3026
  children: [
2361
3027
  count > 1 ? /* @__PURE__ */ jsx(
2362
3028
  "button",
2363
3029
  {
2364
3030
  type: "button",
2365
- "aria-label": "Previous suggestion",
3031
+ "aria-label": T.prevSuggestion,
2366
3032
  onClick: () => go(-1),
2367
- className: "hidden h-8 w-8 shrink-0 items-center justify-center rounded-full text-muted-foreground transition-colors hover:bg-accent hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring sm:inline-flex",
3033
+ 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",
2368
3034
  children: /* @__PURE__ */ jsx(ChevronLeft, { className: "h-4 w-4" })
2369
3035
  }
2370
3036
  ) : null,
@@ -2391,7 +3057,7 @@ function PromptCarousel({
2391
3057
  "button",
2392
3058
  {
2393
3059
  type: "button",
2394
- "aria-label": "Next suggestion",
3060
+ "aria-label": T.nextSuggestion,
2395
3061
  onClick: () => go(1),
2396
3062
  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",
2397
3063
  children: /* @__PURE__ */ jsx(ChevronRight, { className: "h-4 w-4" })
@@ -2402,6 +3068,7 @@ function PromptCarousel({
2402
3068
  );
2403
3069
  }
2404
3070
  function ProductStrip({
3071
+ strings: T,
2405
3072
  products,
2406
3073
  focusProduct,
2407
3074
  onFocus
@@ -2436,7 +3103,7 @@ function ProductStrip({
2436
3103
  "aria-pressed": focusProduct === null,
2437
3104
  onClick: () => onFocus(null),
2438
3105
  className: chipClass(focusProduct === null),
2439
- children: "All products"
3106
+ children: T.allProducts
2440
3107
  }
2441
3108
  ),
2442
3109
  products.map((product) => /* @__PURE__ */ jsx(
@@ -2465,7 +3132,7 @@ function ProductStrip({
2465
3132
  "aria-expanded": expanded,
2466
3133
  onClick: () => setExpanded((v) => !v),
2467
3134
  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",
2468
- children: expanded ? "Show less" : `All ${products.length}`
3135
+ children: expanded ? T.showLess : `${T.showAll} ${products.length}`
2469
3136
  }
2470
3137
  ) : null
2471
3138
  ]
@@ -2573,6 +3240,7 @@ function DisclaimerDialog({
2573
3240
  );
2574
3241
  }
2575
3242
  function WelcomeState({
3243
+ strings: T,
2576
3244
  title,
2577
3245
  body,
2578
3246
  prompts,
@@ -2582,43 +3250,45 @@ function WelcomeState({
2582
3250
  onFocus,
2583
3251
  disabled
2584
3252
  }) {
2585
- return /* @__PURE__ */ jsxs("div", { className: "mx-auto w-full max-w-3xl px-4 py-8 sm:py-12", children: [
2586
- /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
3253
+ return /* @__PURE__ */ jsxs("div", { className: "boff-explore-aura mx-auto my-auto w-full max-w-3xl px-4 py-6 sm:py-8 lg:py-10", children: [
3254
+ /* @__PURE__ */ jsxs("div", { className: "boff-explore-rise text-center", children: [
2587
3255
  /* @__PURE__ */ jsxs("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", children: [
2588
3256
  /* @__PURE__ */ jsx(Sparkles, { className: "h-3.5 w-3.5" }),
2589
- "AI answers, grounded in our documentation"
3257
+ T.badge
2590
3258
  ] }),
2591
3259
  /* @__PURE__ */ jsx("h1", { className: "mt-4 text-balance break-words text-2xl font-bold tracking-tight sm:text-4xl", children: title }),
2592
3260
  /* @__PURE__ */ jsx("p", { className: "mx-auto mt-2.5 max-w-2xl text-pretty text-sm leading-relaxed text-muted-foreground sm:text-lg", children: body })
2593
3261
  ] }),
2594
- /* @__PURE__ */ jsx("ul", { className: "mt-7 grid gap-2.5 sm:grid-cols-3", children: CAPABILITIES.map(({ icon: Icon, title: capTitle, body: capBody }) => /* @__PURE__ */ jsxs(
3262
+ /* @__PURE__ */ jsx("ul", { className: "boff-explore-rise boff-explore-rise-1 mt-6 grid grid-cols-3 gap-2 sm:mt-7 sm:gap-2.5", children: CAPABILITIES.map(({ icon: Icon, body: capBody }, i) => /* @__PURE__ */ jsxs(
2595
3263
  "li",
2596
3264
  {
2597
- className: "rounded-xl border border-border/70 bg-card/60 p-3.5 text-left transition-colors hover:border-border",
3265
+ className: "rounded-xl border border-border/70 bg-card/60 p-2.5 text-center transition-colors hover:border-border sm:p-3.5 sm:text-left",
2598
3266
  children: [
2599
- /* @__PURE__ */ jsx("span", { className: "mb-2.5 flex h-8 w-8 items-center justify-center rounded-lg bg-primary/10 text-primary", children: /* @__PURE__ */ jsx(Icon, { className: "h-4 w-4" }) }),
2600
- /* @__PURE__ */ jsx("p", { className: "text-sm font-semibold text-card-foreground", children: capTitle }),
2601
- /* @__PURE__ */ jsx("p", { className: "mt-1 text-xs leading-relaxed text-muted-foreground", children: capBody })
3267
+ /* @__PURE__ */ jsx("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.5 sm:h-8 sm:w-8", children: /* @__PURE__ */ jsx(Icon, { className: "h-3.5 w-3.5 sm:h-4 sm:w-4" }) }),
3268
+ /* @__PURE__ */ jsx("p", { className: "text-[11px] font-semibold leading-tight text-card-foreground sm:text-sm sm:leading-normal", children: T.capabilities[i] ?? "" }),
3269
+ /* @__PURE__ */ jsx("p", { className: "mt-1 hidden text-xs leading-relaxed text-muted-foreground sm:block", children: capBody })
2602
3270
  ]
2603
3271
  },
2604
- capTitle
3272
+ i
2605
3273
  )) }),
2606
- prompts.length > 0 ? /* @__PURE__ */ jsxs("div", { className: "mt-8", children: [
2607
- /* @__PURE__ */ jsx("p", { className: "mb-2 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: "Try asking" }),
3274
+ prompts.length > 0 ? /* @__PURE__ */ jsxs("div", { className: "boff-explore-rise boff-explore-rise-2 mt-8", children: [
3275
+ /* @__PURE__ */ jsx("p", { className: "mb-2 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: T.tryAsking }),
2608
3276
  /* @__PURE__ */ jsx(
2609
3277
  PromptCarousel,
2610
3278
  {
3279
+ strings: T,
2611
3280
  prompts,
2612
3281
  onPrompt,
2613
3282
  disabled
2614
3283
  }
2615
3284
  )
2616
3285
  ] }) : null,
2617
- products.length > 0 ? /* @__PURE__ */ jsxs("div", { className: "mt-6", children: [
2618
- /* @__PURE__ */ jsx("p", { className: "mb-2 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: "Focus on a product" }),
3286
+ products.length > 0 ? /* @__PURE__ */ jsxs("div", { className: "boff-explore-rise boff-explore-rise-3 mt-6", children: [
3287
+ /* @__PURE__ */ jsx("p", { className: "mb-2 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: T.focusProduct }),
2619
3288
  /* @__PURE__ */ jsx(
2620
3289
  ProductStrip,
2621
3290
  {
3291
+ strings: T,
2622
3292
  products,
2623
3293
  focusProduct,
2624
3294
  onFocus
@@ -2637,7 +3307,8 @@ function ExplorePage({
2637
3307
  onNavigate,
2638
3308
  onSend,
2639
3309
  welcomeTitle,
2640
- welcomeBody
3310
+ welcomeBody,
3311
+ locale
2641
3312
  }) {
2642
3313
  const pageUrl = useMemo(
2643
3314
  () => typeof window === "undefined" ? void 0 : window.location.href,
@@ -2662,7 +3333,8 @@ function ExplorePage({
2662
3333
  deleteConversation,
2663
3334
  clearHistory,
2664
3335
  recordClick,
2665
- createShareLink
3336
+ createShareLink,
3337
+ isSharedView
2666
3338
  } = useExploreChat({ productSlug, pageUrl, onSend, examplePrompts });
2667
3339
  const [draft, setDraft] = useState("");
2668
3340
  const textareaRef = useRef(null);
@@ -2681,7 +3353,18 @@ function ExplorePage({
2681
3353
  }
2682
3354
  });
2683
3355
  speechStopRef.current = speech.stop;
3356
+ const activeLocale = useMemo(
3357
+ () => resolveExploreLocale(locale),
3358
+ [locale]
3359
+ );
3360
+ const T = useMemo(() => exploreStrings(activeLocale), [activeLocale]);
3361
+ const rtl = isRtlLocale(activeLocale);
2684
3362
  const [disclaimerOpen, setDisclaimerOpen] = useState(false);
3363
+ const [staged, setStaged] = useState([]);
3364
+ const [attachmentNotice, setAttachmentNotice] = useState(null);
3365
+ const fileInputRef = useRef(null);
3366
+ const stagedRef = useRef([]);
3367
+ stagedRef.current = staged;
2685
3368
  const [shareLabel, setShareLabel] = useState("Share");
2686
3369
  const [shareUrl, setShareUrl] = useState(null);
2687
3370
  const scrollRef = useRef(null);
@@ -2758,13 +3441,40 @@ function ExplorePage({
2758
3441
  setShareLabel("Share");
2759
3442
  }
2760
3443
  }, [createShareLink, pageUrl]);
3444
+ const handleFilesPicked = useCallback(
3445
+ async (picked) => {
3446
+ if (!picked || picked.length === 0) return;
3447
+ const { accepted, rejected } = await stageFiles(
3448
+ Array.from(picked),
3449
+ stagedRef.current
3450
+ );
3451
+ setStaged((prev) => [...prev, ...accepted]);
3452
+ const first = rejected[0];
3453
+ setAttachmentNotice(
3454
+ first ? first.reason === "too-large" ? fill(T.attachmentTooLarge, {
3455
+ name: first.name,
3456
+ size: String(MAX_ATTACHMENT_BYTES / (1024 * 1024))
3457
+ }) : fill(T.attachmentTooMany, {
3458
+ name: first.name,
3459
+ max: String(MAX_ATTACHMENTS)
3460
+ }) : null
3461
+ );
3462
+ },
3463
+ [T]
3464
+ );
3465
+ const removeAttachment = useCallback((id) => {
3466
+ setStaged((prev) => prev.filter((entry) => entry.id !== id));
3467
+ setAttachmentNotice(null);
3468
+ }, []);
2761
3469
  const submitDraft = useCallback(() => {
2762
3470
  const text = draft.trim();
2763
3471
  if (!text || overLimit || busy || !canSend) return;
2764
3472
  stopDictation();
2765
3473
  setDraft("");
2766
3474
  stickToBottomRef.current = true;
2767
- void send(text);
3475
+ void send(text, toPayload(stagedRef.current));
3476
+ setStaged([]);
3477
+ setAttachmentNotice(null);
2768
3478
  textareaRef.current?.focus();
2769
3479
  }, [busy, canSend, draft, overLimit, send, stopDictation]);
2770
3480
  const sendPrompt = useCallback(
@@ -2772,7 +3482,9 @@ function ExplorePage({
2772
3482
  if (!canSend || busy) return;
2773
3483
  setDraft("");
2774
3484
  stickToBottomRef.current = true;
2775
- void send(prompt);
3485
+ void send(prompt, toPayload(stagedRef.current));
3486
+ setStaged([]);
3487
+ setAttachmentNotice(null);
2776
3488
  },
2777
3489
  [busy, canSend, send]
2778
3490
  );
@@ -2785,7 +3497,9 @@ function ExplorePage({
2785
3497
  },
2786
3498
  [submitDraft]
2787
3499
  );
2788
- const composerDisabled = phase === "limited" || phase === "disabled" || !catalog.enabled;
3500
+ const composerDisabled = phase === "limited" || phase === "disabled" || !catalog.enabled || // A share token grants read access only — the server would reject a send anyway, so
3501
+ // disable it here rather than letting the visitor type into a dead composer.
3502
+ isSharedView;
2789
3503
  const captchaOn = Boolean(
2790
3504
  catalog.captchaRequired && catalog.recaptchaSiteKey
2791
3505
  );
@@ -2795,6 +3509,8 @@ function ExplorePage({
2795
3509
  {
2796
3510
  "data-boff-explore": "page",
2797
3511
  "data-phase": phase,
3512
+ "data-locale": activeLocale,
3513
+ dir: rtl ? "rtl" : void 0,
2798
3514
  className: cn(
2799
3515
  "flex w-full min-w-0 flex-col overflow-x-hidden bg-background text-foreground",
2800
3516
  heightMode === "auto" && "min-h-[70vh]",
@@ -2956,10 +3672,17 @@ function ExplorePage({
2956
3672
  role: "log",
2957
3673
  "aria-live": "polite",
2958
3674
  "aria-label": "Explore conversation",
2959
- className: "boff-explore-scroll min-h-0 min-w-0 flex-1 overflow-y-auto overflow-x-hidden",
3675
+ className: cn(
3676
+ "boff-explore-scroll min-h-0 min-w-0 flex-1 overflow-y-auto overflow-x-hidden",
3677
+ // Only while the welcome state is showing: a flex column is what lets its
3678
+ // `my-auto` centre the block on a tall screen. The transcript must NOT be a flex
3679
+ // column — that would fight the natural top-down flow of messages.
3680
+ showWelcome && "flex flex-col"
3681
+ ),
2960
3682
  children: showWelcome ? /* @__PURE__ */ jsx(
2961
3683
  WelcomeState,
2962
3684
  {
3685
+ strings: T,
2963
3686
  title: resolvedTitle,
2964
3687
  body: resolvedBody,
2965
3688
  prompts,
@@ -2970,9 +3693,10 @@ function ExplorePage({
2970
3693
  disabled: !canSend || busy
2971
3694
  }
2972
3695
  ) : /* @__PURE__ */ jsx("div", { className: "mx-auto w-full min-w-0 max-w-3xl space-y-6 px-4 py-6", children: messages.map(
2973
- (message) => message.role === "USER" ? /* @__PURE__ */ jsx(UserBubble, { message }, message.id) : /* @__PURE__ */ jsx(
3696
+ (message) => message.role === "USER" ? /* @__PURE__ */ jsx(UserBubble, { strings: T, message }, message.id) : /* @__PURE__ */ jsx(
2974
3697
  AssistantBubble,
2975
3698
  {
3699
+ strings: T,
2976
3700
  message,
2977
3701
  activity,
2978
3702
  onNavigate,
@@ -2993,6 +3717,33 @@ function ExplorePage({
2993
3717
  captchaOn
2994
3718
  }
2995
3719
  ),
3720
+ isSharedView ? /* @__PURE__ */ jsxs(
3721
+ "div",
3722
+ {
3723
+ "data-boff-explore": "shared-banner",
3724
+ className: "mx-auto flex w-full max-w-3xl items-center gap-2 px-4 pb-2 text-xs text-muted-foreground",
3725
+ children: [
3726
+ /* @__PURE__ */ jsx(Link2, { className: "h-3.5 w-3.5 shrink-0" }),
3727
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1", children: "You are viewing a shared conversation. Start your own to ask a question." }),
3728
+ /* @__PURE__ */ jsx(
3729
+ "button",
3730
+ {
3731
+ type: "button",
3732
+ "data-boff-explore": "shared-start-own",
3733
+ onClick: () => {
3734
+ if (typeof window !== "undefined") {
3735
+ const url = new URL(window.location.href);
3736
+ url.searchParams.delete("c");
3737
+ window.location.href = url.toString();
3738
+ }
3739
+ },
3740
+ className: "shrink-0 underline underline-offset-2 hover:text-foreground",
3741
+ children: "New chat"
3742
+ }
3743
+ )
3744
+ ]
3745
+ }
3746
+ ) : null,
2996
3747
  /* @__PURE__ */ jsx("div", { className: "border-t border-border bg-background/85 px-4 pb-[max(1rem,env(safe-area-inset-bottom))] pt-3 backdrop-blur-md", children: /* @__PURE__ */ jsxs(
2997
3748
  "form",
2998
3749
  {
@@ -3004,11 +3755,57 @@ function ExplorePage({
3004
3755
  },
3005
3756
  children: [
3006
3757
  error ? /* @__PURE__ */ jsx(ErrorBanner, { error, onRetry: retry, onReset: reset }) : null,
3758
+ staged.length > 0 ? /* @__PURE__ */ jsx(
3759
+ "ul",
3760
+ {
3761
+ "data-boff-explore": "attachments",
3762
+ className: "mb-2 flex flex-wrap gap-1.5",
3763
+ "aria-label": T.attach,
3764
+ children: staged.map((entry) => /* @__PURE__ */ jsxs(
3765
+ "li",
3766
+ {
3767
+ "data-boff-explore": "attachment",
3768
+ "data-text-extracted": entry.textExtracted ? "true" : "false",
3769
+ 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",
3770
+ children: [
3771
+ /* @__PURE__ */ jsx(Paperclip, { className: "h-3 w-3 shrink-0 text-muted-foreground" }),
3772
+ /* @__PURE__ */ jsx("span", { className: "truncate font-medium", title: entry.name, children: entry.name }),
3773
+ /* @__PURE__ */ jsxs("span", { className: "shrink-0 text-muted-foreground", children: [
3774
+ formatBytes(entry.size),
3775
+ entry.textExtracted ? "" : ` \xB7 ${T.attachmentNameOnly}`
3776
+ ] }),
3777
+ /* @__PURE__ */ jsx(
3778
+ "button",
3779
+ {
3780
+ type: "button",
3781
+ "data-boff-explore": "attachment-remove",
3782
+ onClick: () => removeAttachment(entry.id),
3783
+ "aria-label": fill(T.removeAttachment, { name: entry.name }),
3784
+ 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",
3785
+ children: /* @__PURE__ */ jsx(X, { className: "h-3 w-3" })
3786
+ }
3787
+ )
3788
+ ]
3789
+ },
3790
+ entry.id
3791
+ ))
3792
+ }
3793
+ ) : null,
3794
+ attachmentNotice !== null ? /* @__PURE__ */ jsx(
3795
+ "p",
3796
+ {
3797
+ "data-boff-explore": "attachment-notice",
3798
+ role: "status",
3799
+ className: "mb-2 text-xs text-destructive",
3800
+ children: attachmentNotice
3801
+ }
3802
+ ) : null,
3007
3803
  /* @__PURE__ */ jsxs(
3008
3804
  "div",
3009
3805
  {
3010
3806
  className: cn(
3011
3807
  "flex min-w-0 items-end gap-2 rounded-2xl border bg-card p-2 shadow-sm transition-all",
3808
+ busy && "boff-explore-busy",
3012
3809
  overLimit ? "border-destructive/60" : "border-border focus-within:border-primary/40 focus-within:ring-1 focus-within:ring-ring"
3013
3810
  ),
3014
3811
  children: [
@@ -3028,8 +3825,40 @@ function ExplorePage({
3028
3825
  composingRef.current = false;
3029
3826
  },
3030
3827
  "aria-label": "Ask a question",
3031
- placeholder: composerDisabled ? phase === "limited" ? "Message limit reached \u2014 please try again later" : "Explore is unavailable right now" : focusedProductName ? `Ask about ${focusedProductName}\u2026` : "Ask anything about our products\u2026",
3032
- 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-sm shadow-none focus-visible:ring-0 md:text-sm"
3828
+ placeholder: composerDisabled ? phase === "limited" ? "Message limit reached \u2014 please try again later" : "Explore is unavailable right now" : focusedProductName ? fill(T.placeholderProduct, {
3829
+ product: focusedProductName
3830
+ }) : T.placeholder,
3831
+ 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"
3832
+ }
3833
+ ),
3834
+ /* @__PURE__ */ jsx(
3835
+ "input",
3836
+ {
3837
+ ref: fileInputRef,
3838
+ type: "file",
3839
+ multiple: true,
3840
+ className: "hidden",
3841
+ onChange: (event) => {
3842
+ void handleFilesPicked(event.target.files);
3843
+ event.target.value = "";
3844
+ }
3845
+ }
3846
+ ),
3847
+ /* @__PURE__ */ jsx(
3848
+ Button,
3849
+ {
3850
+ "data-boff-explore": "attach",
3851
+ type: "button",
3852
+ size: "icon",
3853
+ variant: "ghost",
3854
+ disabled: composerDisabled || staged.length >= MAX_ATTACHMENTS,
3855
+ "aria-label": T.attach,
3856
+ title: `${T.attach} \u2014 ${fill(T.attachHint, {
3857
+ max: String(MAX_ATTACHMENTS),
3858
+ size: String(MAX_ATTACHMENT_BYTES / (1024 * 1024))
3859
+ })}`,
3860
+ onClick: () => fileInputRef.current?.click(),
3861
+ children: /* @__PURE__ */ jsx(Paperclip, { className: "h-4 w-4" })
3033
3862
  }
3034
3863
  ),
3035
3864
  speech.supported ? /* @__PURE__ */ jsx(
@@ -3041,9 +3870,9 @@ function ExplorePage({
3041
3870
  size: "icon",
3042
3871
  variant: speech.listening ? "default" : "ghost",
3043
3872
  disabled: composerDisabled,
3044
- "aria-label": speech.listening ? "Stop dictating" : "Dictate your question",
3873
+ "aria-label": speech.listening ? T.stopDictating : T.dictate,
3045
3874
  "aria-pressed": speech.listening,
3046
- title: speech.listening ? "Stop dictating" : "Dictate your question",
3875
+ title: speech.listening ? T.stopDictating : T.dictate,
3047
3876
  onClick: speech.toggle,
3048
3877
  className: cn(speech.listening && "animate-pulse"),
3049
3878
  children: /* @__PURE__ */ jsx(Mic, { className: "h-4 w-4" })
@@ -3143,7 +3972,7 @@ function ExplorePage({
3143
3972
  )
3144
3973
  ] }) : null,
3145
3974
  /* @__PURE__ */ jsxs("div", { className: "mt-2 flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-muted-foreground", children: [
3146
- /* @__PURE__ */ jsx("span", { className: "min-w-0 truncate", children: "Grounded in our docs \u2014 check anything important." }),
3975
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 truncate", children: T.disclaimerShort }),
3147
3976
  /* @__PURE__ */ jsx(
3148
3977
  "button",
3149
3978
  {
@@ -3151,7 +3980,7 @@ function ExplorePage({
3151
3980
  "data-boff-explore": "disclaimer",
3152
3981
  onClick: () => setDisclaimerOpen(true),
3153
3982
  className: "shrink-0 underline underline-offset-2 transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
3154
- children: "Disclaimer"
3983
+ children: T.disclaimer
3155
3984
  }
3156
3985
  )
3157
3986
  ] })