@burdenoff/website-sdk 2026.1024.1 → 2026.1026.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/dist/components/explore-cta.d.mts +10 -1
  2. package/dist/components/explore-cta.d.ts +10 -1
  3. package/dist/components/explore-cta.js +82 -74
  4. package/dist/components/explore-cta.js.map +1 -1
  5. package/dist/components/explore-cta.mjs +83 -75
  6. package/dist/components/explore-cta.mjs.map +1 -1
  7. package/dist/components/explore.d.mts +2 -2
  8. package/dist/components/explore.d.ts +2 -2
  9. package/dist/components/explore.js +590 -463
  10. package/dist/components/explore.js.map +1 -1
  11. package/dist/components/explore.mjs +591 -464
  12. package/dist/components/explore.mjs.map +1 -1
  13. package/dist/{explore-POqE7J8r.d.mts → explore-BRfKFfvI.d.mts} +21 -2
  14. package/dist/{explore-D6kon7uz.d.ts → explore-DkfcKgp6.d.ts} +21 -2
  15. package/dist/{explore-types-BB8HNFzX.d.mts → explore-types-_9UJu6EA.d.mts} +1 -1
  16. package/dist/{explore-types-BB8HNFzX.d.ts → explore-types-_9UJu6EA.d.ts} +1 -1
  17. package/dist/hooks/index.d.mts +2 -2
  18. package/dist/hooks/index.d.ts +2 -2
  19. package/dist/hooks/index.js +15 -9
  20. package/dist/hooks/index.js.map +1 -1
  21. package/dist/hooks/index.mjs +15 -9
  22. package/dist/hooks/index.mjs.map +1 -1
  23. package/dist/index.d.mts +123 -7
  24. package/dist/index.d.ts +123 -7
  25. package/dist/index.js +922 -117
  26. package/dist/index.js.map +1 -1
  27. package/dist/index.mjs +922 -120
  28. package/dist/index.mjs.map +1 -1
  29. package/dist/{use-progressive-reveal-Kr6DwGXG.d.mts → use-progressive-reveal-BFPWbEXy.d.mts} +25 -2
  30. package/dist/{use-progressive-reveal-BVJn9NIr.d.ts → use-progressive-reveal-C0hkdu_i.d.ts} +25 -2
  31. package/package.json +1 -1
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as React from 'react';
2
- import { createContext, useMemo, useContext, useState, useCallback, useLayoutEffect, useRef, useEffect, useId, version, Children, isValidElement, cloneElement } from 'react';
2
+ import { createContext, forwardRef, useState, useEffect, useMemo, useContext, useCallback, useLayoutEffect, useRef, useId, version, Children, isValidElement, cloneElement } from 'react';
3
3
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
4
- import { Instagram, Youtube, Facebook, Github, Linkedin, Twitter, Mail, Phone, MapPin, Clock, Send, CheckCircle, Upload, Globe, ChevronDown, Search, Rocket, ArrowRight, Download, ImageIcon, ChevronRight, Maximize2, Check, ArrowLeft, Sparkles, RotateCcw, Link2, History, Trash2, Paperclip, X, Mic, Square, ArrowUp, Info, ExternalLink, ChevronLeft, BookOpenText, Layers, TriangleAlert, FileText, Film, Play, Copy, ThumbsUp, ThumbsDown, Minimize, Maximize, VideoOff, Volume2 } from 'lucide-react';
4
+ import { Instagram, Youtube, Facebook, Github, Linkedin, Twitter, Sparkles, Mail, Phone, MapPin, Clock, Send, CheckCircle, Upload, Globe, ChevronDown, Search, Rocket, ArrowRight, Download, ImageIcon, ChevronRight, Maximize2, Check, ArrowLeft, RotateCcw, Link2, History, Trash2, Paperclip, X, Mic, Square, ArrowUp, Minimize2, Info, ExternalLink, ChevronLeft, BookOpenText, Layers, TriangleAlert, FileText, Film, Play, Copy, ThumbsUp, ThumbsDown, Minimize, Maximize, VideoOff, Volume2 } from 'lucide-react';
5
5
  import ReCAPTCHA4 from 'react-google-recaptcha';
6
6
  import { toast } from 'sonner';
7
7
  import { Helmet } from 'react-helmet-async';
@@ -6531,6 +6531,14 @@ var EN = {
6531
6531
  closeVideo: "Close video",
6532
6532
  enterFullScreen: "Full screen",
6533
6533
  exitFullScreen: "Exit full screen",
6534
+ panelTitle: "AI assistant",
6535
+ panelViews: "Assistant views",
6536
+ tabChat: "Chat",
6537
+ tabAvatar: "Avatar",
6538
+ closePanel: "Close",
6539
+ liveAvatar: "Live avatar",
6540
+ avatarComingSoon: "Live avatar coming soon",
6541
+ continueInChat: "Continue in Chat",
6534
6542
  videoUnavailable: "This video can't be played right now.",
6535
6543
  groundedIn: "What this answer is based on",
6536
6544
  sourceCountOne: "1 source",
@@ -6639,6 +6647,14 @@ var ZH = {
6639
6647
  closeVideo: "\u5173\u95ED\u89C6\u9891",
6640
6648
  enterFullScreen: "\u5168\u5C4F",
6641
6649
  exitFullScreen: "\u9000\u51FA\u5168\u5C4F",
6650
+ panelTitle: "AI \u52A9\u624B",
6651
+ panelViews: "\u52A9\u624B\u89C6\u56FE",
6652
+ tabChat: "\u804A\u5929",
6653
+ tabAvatar: "\u865A\u62DF\u5F62\u8C61",
6654
+ closePanel: "\u5173\u95ED",
6655
+ liveAvatar: "\u5B9E\u65F6\u865A\u62DF\u5F62\u8C61",
6656
+ avatarComingSoon: "\u5B9E\u65F6\u865A\u62DF\u5F62\u8C61\u5373\u5C06\u63A8\u51FA",
6657
+ continueInChat: "\u5728\u804A\u5929\u4E2D\u7EE7\u7EED",
6642
6658
  videoUnavailable: "\u6682\u65F6\u65E0\u6CD5\u64AD\u653E\u6B64\u89C6\u9891\u3002",
6643
6659
  groundedIn: "\u8FD9\u4E2A\u56DE\u7B54\u7684\u4F9D\u636E",
6644
6660
  sourceCountOne: "1 \u4E2A\u6765\u6E90",
@@ -6743,6 +6759,14 @@ var HI = {
6743
6759
  closeVideo: "\u0935\u0940\u0921\u093F\u092F\u094B \u092C\u0902\u0926 \u0915\u0930\u0947\u0902",
6744
6760
  enterFullScreen: "\u092A\u0942\u0930\u094D\u0923 \u0938\u094D\u0915\u094D\u0930\u0940\u0928",
6745
6761
  exitFullScreen: "\u092A\u0942\u0930\u094D\u0923 \u0938\u094D\u0915\u094D\u0930\u0940\u0928 \u0938\u0947 \u092C\u093E\u0939\u0930 \u0928\u093F\u0915\u0932\u0947\u0902",
6762
+ panelTitle: "AI \u0938\u0939\u093E\u092F\u0915",
6763
+ panelViews: "\u0938\u0939\u093E\u092F\u0915 \u0926\u0943\u0936\u094D\u092F",
6764
+ tabChat: "\u091A\u0948\u091F",
6765
+ tabAvatar: "\u0905\u0935\u0924\u093E\u0930",
6766
+ closePanel: "\u092C\u0902\u0926 \u0915\u0930\u0947\u0902",
6767
+ liveAvatar: "\u0932\u093E\u0907\u0935 \u0905\u0935\u0924\u093E\u0930",
6768
+ avatarComingSoon: "\u0932\u093E\u0907\u0935 \u0905\u0935\u0924\u093E\u0930 \u091C\u0932\u094D\u0926 \u0906 \u0930\u0939\u093E \u0939\u0948",
6769
+ continueInChat: "\u091A\u0948\u091F \u092E\u0947\u0902 \u091C\u093E\u0930\u0940 \u0930\u0916\u0947\u0902",
6746
6770
  videoUnavailable: "\u092F\u0939 \u0935\u0940\u0921\u093F\u092F\u094B \u0905\u092D\u0940 \u0928\u0939\u0940\u0902 \u091A\u0932 \u0938\u0915\u0924\u093E\u0964",
6747
6771
  groundedIn: "\u092F\u0939 \u0909\u0924\u094D\u0924\u0930 \u0915\u093F\u0938 \u092A\u0930 \u0906\u0927\u093E\u0930\u093F\u0924 \u0939\u0948",
6748
6772
  sourceCountOne: "1 \u0938\u094D\u0930\u094B\u0924",
@@ -6851,6 +6875,14 @@ var ES = {
6851
6875
  closeVideo: "Cerrar v\xEDdeo",
6852
6876
  enterFullScreen: "Pantalla completa",
6853
6877
  exitFullScreen: "Salir de pantalla completa",
6878
+ panelTitle: "Asistente de IA",
6879
+ panelViews: "Vistas del asistente",
6880
+ tabChat: "Chat",
6881
+ tabAvatar: "Avatar",
6882
+ closePanel: "Cerrar",
6883
+ liveAvatar: "Avatar en vivo",
6884
+ avatarComingSoon: "Avatar en vivo: pr\xF3ximamente",
6885
+ continueInChat: "Continuar en el chat",
6854
6886
  videoUnavailable: "Ahora mismo no se puede reproducir este v\xEDdeo.",
6855
6887
  groundedIn: "En qu\xE9 se basa esta respuesta",
6856
6888
  sourceCountOne: "1 fuente",
@@ -6959,6 +6991,14 @@ var AR = {
6959
6991
  closeVideo: "\u0625\u063A\u0644\u0627\u0642 \u0627\u0644\u0641\u064A\u062F\u064A\u0648",
6960
6992
  enterFullScreen: "\u0645\u0644\u0621 \u0627\u0644\u0634\u0627\u0634\u0629",
6961
6993
  exitFullScreen: "\u0627\u0644\u062E\u0631\u0648\u062C \u0645\u0646 \u0645\u0644\u0621 \u0627\u0644\u0634\u0627\u0634\u0629",
6994
+ panelTitle: "\u0645\u0633\u0627\u0639\u062F \u0627\u0644\u0630\u0643\u0627\u0621 \u0627\u0644\u0627\u0635\u0637\u0646\u0627\u0639\u064A",
6995
+ panelViews: "\u0637\u0631\u0642 \u0639\u0631\u0636 \u0627\u0644\u0645\u0633\u0627\u0639\u062F",
6996
+ tabChat: "\u062F\u0631\u062F\u0634\u0629",
6997
+ tabAvatar: "\u0627\u0644\u0623\u0641\u0627\u062A\u0627\u0631",
6998
+ closePanel: "\u0625\u063A\u0644\u0627\u0642",
6999
+ liveAvatar: "\u0627\u0644\u0623\u0641\u0627\u062A\u0627\u0631 \u0627\u0644\u0645\u0628\u0627\u0634\u0631",
7000
+ avatarComingSoon: "\u0627\u0644\u0623\u0641\u0627\u062A\u0627\u0631 \u0627\u0644\u0645\u0628\u0627\u0634\u0631 \u0642\u0631\u064A\u0628\u064B\u0627",
7001
+ continueInChat: "\u0627\u0644\u0645\u062A\u0627\u0628\u0639\u0629 \u0641\u064A \u0627\u0644\u062F\u0631\u062F\u0634\u0629",
6962
7002
  videoUnavailable: "\u062A\u0639\u0630\u0651\u0631 \u062A\u0634\u063A\u064A\u0644 \u0647\u0630\u0627 \u0627\u0644\u0641\u064A\u062F\u064A\u0648 \u0627\u0644\u0622\u0646.",
6963
7003
  groundedIn: "\u0639\u0644\u0649 \u0645\u0627\u0630\u0627 \u062A\u0633\u062A\u0646\u062F \u0647\u0630\u0647 \u0627\u0644\u0625\u062C\u0627\u0628\u0629",
6964
7004
  sourceCountOne: "\u0645\u0635\u062F\u0631 \u0648\u0627\u062D\u062F",
@@ -7067,6 +7107,14 @@ var TA = {
7067
7107
  closeVideo: "\u0BB5\u0BC0\u0B9F\u0BBF\u0BAF\u0BCB\u0BB5\u0BC8 \u0BAE\u0BC2\u0B9F\u0BC1",
7068
7108
  enterFullScreen: "\u0BAE\u0BC1\u0BB4\u0BC1\u0BA4\u0BCD \u0BA4\u0BBF\u0BB0\u0BC8",
7069
7109
  exitFullScreen: "\u0BAE\u0BC1\u0BB4\u0BC1\u0BA4\u0BCD \u0BA4\u0BBF\u0BB0\u0BC8\u0BAF\u0BBF\u0BB2\u0BBF\u0BB0\u0BC1\u0BA8\u0BCD\u0BA4\u0BC1 \u0BB5\u0BC6\u0BB3\u0BBF\u0BAF\u0BC7\u0BB1\u0BC1",
7110
+ panelTitle: "AI \u0B89\u0BA4\u0BB5\u0BBF\u0BAF\u0BBE\u0BB3\u0BB0\u0BCD",
7111
+ panelViews: "\u0B89\u0BA4\u0BB5\u0BBF\u0BAF\u0BBE\u0BB3\u0BB0\u0BCD \u0B95\u0BBE\u0B9F\u0BCD\u0B9A\u0BBF\u0B95\u0BB3\u0BCD",
7112
+ tabChat: "\u0B85\u0BB0\u0B9F\u0BCD\u0B9F\u0BC8",
7113
+ tabAvatar: "\u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BCD",
7114
+ closePanel: "\u0BAE\u0BC2\u0B9F\u0BC1",
7115
+ liveAvatar: "\u0BA8\u0BC7\u0BB0\u0BB2\u0BC8 \u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BCD",
7116
+ avatarComingSoon: "\u0BA8\u0BC7\u0BB0\u0BB2\u0BC8 \u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BCD \u0BB5\u0BBF\u0BB0\u0BC8\u0BB5\u0BBF\u0BB2\u0BCD",
7117
+ continueInChat: "\u0B85\u0BB0\u0B9F\u0BCD\u0B9F\u0BC8\u0BAF\u0BBF\u0BB2\u0BCD \u0BA4\u0BCA\u0B9F\u0BB0\u0BB5\u0BC1\u0BAE\u0BCD",
7070
7118
  videoUnavailable: "\u0B87\u0BA8\u0BCD\u0BA4 \u0BB5\u0BC0\u0B9F\u0BBF\u0BAF\u0BCB\u0BB5\u0BC8 \u0B87\u0BAA\u0BCD\u0BAA\u0BCB\u0BA4\u0BC1 \u0B87\u0BAF\u0B95\u0BCD\u0B95 \u0BAE\u0BC1\u0B9F\u0BBF\u0BAF\u0BB5\u0BBF\u0BB2\u0BCD\u0BB2\u0BC8.",
7071
7119
  groundedIn: "\u0B87\u0BA8\u0BCD\u0BA4\u0BAA\u0BCD \u0BAA\u0BA4\u0BBF\u0BB2\u0BCD \u0B8E\u0BA4\u0BC8 \u0B85\u0B9F\u0BBF\u0BAA\u0BCD\u0BAA\u0B9F\u0BC8\u0BAF\u0BBE\u0B95\u0B95\u0BCD \u0B95\u0BCA\u0BA3\u0BCD\u0B9F\u0BA4\u0BC1",
7072
7120
  sourceCountOne: "1 \u0BAE\u0BC2\u0BB2\u0BAE\u0BCD",
@@ -10223,7 +10271,9 @@ function useExploreChat(options = {}) {
10223
10271
  pollTimeoutMs = DEFAULT_POLL_TIMEOUT_MS,
10224
10272
  storageKey = DEFAULT_STORAGE_KEY,
10225
10273
  persist = true,
10226
- onSend
10274
+ onSend,
10275
+ enabled = true,
10276
+ shareToken: shareTokenOption
10227
10277
  } = options;
10228
10278
  const client = useWebSDK();
10229
10279
  const { productId } = useWebSDKConfig();
@@ -10261,7 +10311,7 @@ function useExploreChat(options = {}) {
10261
10311
  const [hasConversation, setHasConversation] = useState(false);
10262
10312
  const shareTokenRef = useRef(void 0);
10263
10313
  if (shareTokenRef.current === void 0) {
10264
- shareTokenRef.current = readShareToken();
10314
+ shareTokenRef.current = shareTokenOption === void 0 ? readShareToken() : shareTokenOption;
10265
10315
  }
10266
10316
  const isSharedView = shareTokenRef.current !== null;
10267
10317
  const catalogRef = useRef(catalog);
@@ -10299,6 +10349,7 @@ function useExploreChat(options = {}) {
10299
10349
  };
10300
10350
  }, []);
10301
10351
  useEffect(() => {
10352
+ if (!enabled) return;
10302
10353
  const shareToken = shareTokenRef.current;
10303
10354
  if (!shareToken) return;
10304
10355
  let cancelled = false;
@@ -10333,8 +10384,9 @@ function useExploreChat(options = {}) {
10333
10384
  return () => {
10334
10385
  cancelled = true;
10335
10386
  };
10336
- }, [client]);
10387
+ }, [client, enabled]);
10337
10388
  useEffect(() => {
10389
+ if (!enabled) return;
10338
10390
  if (shareTokenRef.current !== null) return;
10339
10391
  if (!persist) {
10340
10392
  setHydrated(true);
@@ -10359,9 +10411,10 @@ function useExploreChat(options = {}) {
10359
10411
  setTurnCount(turns);
10360
10412
  }
10361
10413
  setHydrated(true);
10362
- }, [persist, rememberConversationToken, storageKey]);
10414
+ }, [persist, rememberConversationToken, storageKey, enabled]);
10363
10415
  useEffect(() => {
10364
- if (!persist || !hydrated || typeof window === "undefined") return;
10416
+ if (!persist || !hydrated || isSharedView || typeof window === "undefined")
10417
+ return;
10365
10418
  try {
10366
10419
  const payload = {
10367
10420
  conversationToken: conversationTokenRef.current,
@@ -10375,10 +10428,10 @@ function useExploreChat(options = {}) {
10375
10428
  window.localStorage.setItem(storageKey, JSON.stringify(payload));
10376
10429
  } catch {
10377
10430
  }
10378
- }, [persist, hydrated, storageKey, messages, focusProduct]);
10431
+ }, [persist, hydrated, isSharedView, storageKey, messages, focusProduct]);
10379
10432
  useEffect(() => {
10380
10433
  messagesRef.current = messages;
10381
- if (!persist || !hydrated) return;
10434
+ if (!persist || !hydrated || isSharedView) return;
10382
10435
  const settled = messages.some(
10383
10436
  (m) => m.role === "ASSISTANT" && (m.status === "COMPLETED" || m.status === "FAILED")
10384
10437
  );
@@ -10390,8 +10443,9 @@ function useExploreChat(options = {}) {
10390
10443
  focusProduct: focusProductRef.current
10391
10444
  })
10392
10445
  );
10393
- }, [messages, persist, hydrated, storageKey]);
10446
+ }, [messages, persist, hydrated, isSharedView, storageKey]);
10394
10447
  useEffect(() => {
10448
+ if (!enabled) return;
10395
10449
  let cancelled = false;
10396
10450
  const load = async () => {
10397
10451
  const variables = { productSlug: productSlug ?? null };
@@ -10432,7 +10486,7 @@ function useExploreChat(options = {}) {
10432
10486
  return () => {
10433
10487
  cancelled = true;
10434
10488
  };
10435
- }, [client, productSlug, fallbackCatalog, bakedRaw]);
10489
+ }, [client, productSlug, fallbackCatalog, bakedRaw, enabled]);
10436
10490
  const startPolling = useCallback(
10437
10491
  (conversationToken, messageId) => {
10438
10492
  pollGenerationRef.current += 1;
@@ -10929,6 +10983,56 @@ function makeOptimisticId() {
10929
10983
  optimisticCounter += 1;
10930
10984
  return `boff-explore-local-${Date.now()}-${optimisticCounter}`;
10931
10985
  }
10986
+ var ExploreConversationContext = createContext(null);
10987
+ function useExploreConversation(options = {}) {
10988
+ const {
10989
+ productSlug,
10990
+ locale,
10991
+ examplePrompts,
10992
+ onSend,
10993
+ pageUrl,
10994
+ enabled,
10995
+ shareToken
10996
+ } = options;
10997
+ const urlAtMount = useMemo(
10998
+ () => typeof window === "undefined" ? void 0 : window.location.href,
10999
+ []
11000
+ );
11001
+ const T = useMemo(
11002
+ () => exploreStrings(resolveExploreLocale(locale)),
11003
+ [locale]
11004
+ );
11005
+ const chat = useExploreChat({
11006
+ productSlug,
11007
+ pageUrl: pageUrl ?? urlAtMount,
11008
+ onSend,
11009
+ // Locale-aware, so a catalog outage degrades to a translated welcome rather than an English one.
11010
+ examplePrompts: examplePrompts ?? T.prompts,
11011
+ fallbackWelcome: { title: T.welcomeTitle, body: T.welcomeBody },
11012
+ ...enabled === void 0 ? {} : { enabled },
11013
+ ...shareToken === void 0 ? {} : { shareToken }
11014
+ });
11015
+ const [draft, setDraft] = useState("");
11016
+ const [staged, setStaged] = useState([]);
11017
+ return useMemo(
11018
+ () => ({ ...chat, draft, setDraft, staged, setStaged }),
11019
+ [chat, draft, staged]
11020
+ );
11021
+ }
11022
+ function ExploreChatProvider({
11023
+ enabled,
11024
+ children,
11025
+ ...options
11026
+ }) {
11027
+ const [started, setStarted] = useState(enabled);
11028
+ if (enabled && !started) setStarted(true);
11029
+ const conversation = useExploreConversation({
11030
+ ...options,
11031
+ // `enabled` as well as `started`: on the render that first sees `enabled`, the latch above has only been queued.
11032
+ enabled: enabled || started
11033
+ });
11034
+ return /* @__PURE__ */ jsx(ExploreConversationContext.Provider, { value: conversation, children });
11035
+ }
10932
11036
  var DRAIN_TARGET_MS = 1200;
10933
11037
  var MIN_CHARS_PER_SECOND = 90;
10934
11038
  var MAX_CHARS_PER_SECOND = 2200;
@@ -13573,15 +13677,17 @@ function WelcomeState({
13573
13677
  focusProduct,
13574
13678
  onPrompt,
13575
13679
  onFocus,
13576
- disabled
13680
+ disabled,
13681
+ heading = "h1"
13577
13682
  }) {
13683
+ const Heading = heading;
13578
13684
  return /* @__PURE__ */ jsxs("div", { className: "boff-explore-aura mx-auto my-auto w-full max-w-3xl px-4 py-4 sm:py-5", children: [
13579
13685
  /* @__PURE__ */ jsxs("div", { className: "boff-explore-rise text-center", children: [
13580
13686
  /* @__PURE__ */ jsxs("span", { className: "boff-explore-hero-badge inline-flex items-center gap-1.5 rounded-full border border-border bg-muted px-3 py-1 text-xs font-medium text-muted-foreground", children: [
13581
13687
  /* @__PURE__ */ jsx(Sparkles, { className: "h-3.5 w-3.5" }),
13582
13688
  T.badge
13583
13689
  ] }),
13584
- /* @__PURE__ */ jsx("h1", { className: "mt-2 text-balance break-words text-2xl font-bold tracking-tight sm:text-3xl", children: title }),
13690
+ /* @__PURE__ */ jsx(Heading, { className: "mt-2 text-balance break-words text-2xl font-bold tracking-tight sm:text-3xl", children: title }),
13585
13691
  /* @__PURE__ */ jsx("p", { className: "mx-auto mt-2 max-w-2xl text-pretty text-sm leading-relaxed text-muted-foreground", children: body })
13586
13692
  ] }),
13587
13693
  /* @__PURE__ */ jsx("ul", { className: "boff-explore-capabilities boff-explore-rise boff-explore-rise-1 mt-4 grid grid-cols-3 gap-2 sm:gap-2.5", children: CAPABILITIES.map(({ icon: Icon, body: capBody }, i) => /* @__PURE__ */ jsxs(
@@ -13636,19 +13742,36 @@ function exploreQuestionHref(question, base = "/explore") {
13636
13742
  const joiner = base.includes("?") ? "&" : "?";
13637
13743
  return `${base}${joiner}q=${encodeURIComponent(trimmed)}`;
13638
13744
  }
13639
- function ExplorePage({
13745
+ function ExplorePage(props) {
13746
+ const shared = useContext(ExploreConversationContext);
13747
+ return shared ? /* @__PURE__ */ jsx(ExploreView, { ...props, conversation: shared }) : /* @__PURE__ */ jsx(StandaloneExplorePage, { ...props });
13748
+ }
13749
+ function StandaloneExplorePage(props) {
13750
+ const conversation = useExploreConversation({
13751
+ productSlug: props.productSlug,
13752
+ locale: props.locale,
13753
+ examplePrompts: props.examplePrompts,
13754
+ onSend: props.onSend
13755
+ });
13756
+ return /* @__PURE__ */ jsx(ExploreView, { ...props, conversation });
13757
+ }
13758
+ function ExploreView({
13640
13759
  seo,
13641
13760
  productSlug,
13642
- examplePrompts,
13643
13761
  className,
13644
13762
  heightMode = "viewport",
13645
13763
  viewportOffset,
13646
13764
  onNavigate,
13647
- onSend,
13648
13765
  welcomeTitle,
13649
13766
  welcomeBody,
13650
- locale
13767
+ locale,
13768
+ presentation = "page",
13769
+ active = true,
13770
+ explorePath = "/explore",
13771
+ conversation
13651
13772
  }) {
13773
+ const panel = presentation === "panel";
13774
+ const viewportPage = !panel && heightMode === "viewport";
13652
13775
  const pageUrl = useMemo(
13653
13776
  () => typeof window === "undefined" ? void 0 : window.location.href,
13654
13777
  []
@@ -13684,26 +13807,21 @@ function ExplorePage({
13684
13807
  escalate,
13685
13808
  canEscalate,
13686
13809
  createShareLink,
13687
- isSharedView
13688
- } = useExploreChat({
13689
- productSlug,
13690
- pageUrl,
13691
- onSend,
13692
- // Locale-aware, so a catalog outage degrades to a translated welcome rather than an
13693
- // English one. `T.prompts` seeds the chips the same way.
13694
- examplePrompts: examplePrompts ?? T.prompts,
13695
- fallbackWelcome: { title: T.welcomeTitle, body: T.welcomeBody }
13696
- });
13697
- const [draft, setDraft] = useState("");
13810
+ isSharedView,
13811
+ draft,
13812
+ setDraft,
13813
+ staged,
13814
+ setStaged
13815
+ } = conversation;
13698
13816
  const textareaRef = useRef(null);
13699
13817
  useEffect(() => {
13700
- if (typeof window === "undefined") return;
13818
+ if (typeof window === "undefined" || panel) return;
13701
13819
  const params = new URLSearchParams(window.location.search);
13702
13820
  if (params.has("c")) return;
13703
13821
  const question = params.get("q")?.trim();
13704
13822
  if (!question) return;
13705
13823
  setDraft(question.slice(0, EXPLORE_PREFILL_MAX_LENGTH));
13706
- }, []);
13824
+ }, [panel, setDraft]);
13707
13825
  const [historyOpen, setHistoryOpen] = useState(false);
13708
13826
  const speechStopRef = useRef(() => void 0);
13709
13827
  const stopDictation = useCallback(() => {
@@ -13719,8 +13837,12 @@ function ExplorePage({
13719
13837
  }
13720
13838
  });
13721
13839
  speechStopRef.current = speech.stop;
13840
+ useEffect(() => {
13841
+ if (active) return;
13842
+ stopDictation();
13843
+ stopSpeaking();
13844
+ }, [active, stopDictation]);
13722
13845
  const [disclaimerOpen, setDisclaimerOpen] = useState(false);
13723
- const [staged, setStaged] = useState([]);
13724
13846
  const [attachmentNotice, setAttachmentNotice] = useState(null);
13725
13847
  const fileInputRef = useRef(null);
13726
13848
  const stagedRef = useRef([]);
@@ -13773,7 +13895,7 @@ function ExplorePage({
13773
13895
  const [bottomInset, setBottomInset] = useState(0);
13774
13896
  const paneOffsetRef = useRef(0);
13775
13897
  const measurePane = useCallback(() => {
13776
- if (heightMode !== "viewport") return;
13898
+ if (!viewportPage) return;
13777
13899
  const el = rootRef.current;
13778
13900
  if (!el) return;
13779
13901
  const layoutHeight = window.innerHeight;
@@ -13792,7 +13914,7 @@ function ExplorePage({
13792
13914
  paneOffsetRef.current = top;
13793
13915
  setPaneOffset((current) => current === top ? current : top);
13794
13916
  setBottomInset((current) => current === inset ? current : inset);
13795
- }, [heightMode]);
13917
+ }, [viewportPage]);
13796
13918
  const [chromeOverlap, setChromeOverlap] = useState(0);
13797
13919
  const measureChrome = useCallback(() => {
13798
13920
  const root = rootRef.current;
@@ -13817,7 +13939,7 @@ function ExplorePage({
13817
13939
  measureChrome();
13818
13940
  }, [measurePane, measureChrome]);
13819
13941
  useEffect(() => {
13820
- if (typeof window === "undefined") return;
13942
+ if (typeof window === "undefined" || panel) return;
13821
13943
  let frame = 0;
13822
13944
  const run = () => {
13823
13945
  frame = 0;
@@ -13855,12 +13977,12 @@ function ExplorePage({
13855
13977
  setBottomInset(0);
13856
13978
  setChromeOverlap(0);
13857
13979
  };
13858
- }, [remeasure]);
13980
+ }, [remeasure, panel]);
13859
13981
  useEffect(() => {
13860
13982
  measureChrome();
13861
13983
  }, [measureChrome, paneOffset, bottomInset]);
13862
13984
  useEffect(() => {
13863
- if (heightMode !== "viewport" || typeof window === "undefined") return;
13985
+ if (!viewportPage || typeof window === "undefined") return;
13864
13986
  const { history: browserHistory } = window;
13865
13987
  const previousRestoration = "scrollRestoration" in browserHistory ? browserHistory.scrollRestoration : null;
13866
13988
  if (previousRestoration !== null)
@@ -13928,14 +14050,14 @@ function ExplorePage({
13928
14050
  if (previousRestoration !== null)
13929
14051
  browserHistory.scrollRestoration = previousRestoration;
13930
14052
  };
13931
- }, [heightMode, remeasure]);
14053
+ }, [viewportPage, remeasure]);
13932
14054
  const handleScroll = useCallback(() => {
13933
14055
  const el = scrollRef.current;
13934
14056
  if (!el) return;
13935
14057
  stickToBottomRef.current = el.scrollHeight - el.scrollTop - el.clientHeight < 80;
13936
14058
  }, []);
13937
14059
  useEffect(() => {
13938
- if (typeof window === "undefined") return;
14060
+ if (typeof window === "undefined" || panel) return;
13939
14061
  let frame = 0;
13940
14062
  const run = () => {
13941
14063
  frame = 0;
@@ -13958,7 +14080,7 @@ function ExplorePage({
13958
14080
  if (frame) window.cancelAnimationFrame(frame);
13959
14081
  window.removeEventListener("scroll", schedule);
13960
14082
  };
13961
- }, []);
14083
+ }, [panel]);
13962
14084
  const latestAssistantId = useMemo(() => {
13963
14085
  for (let i = messages.length - 1; i >= 0; i -= 1) {
13964
14086
  const message = messages[i];
@@ -13974,7 +14096,7 @@ function ExplorePage({
13974
14096
  if (!stickToBottomRef.current) return;
13975
14097
  if (anchor.offsetHeight === 0) return;
13976
14098
  alignedForRef.current = latestAssistantId;
13977
- if (!pageOwnsScrolling(el)) {
14099
+ if (panel || !pageOwnsScrolling(el)) {
13978
14100
  const delta2 = anchor.getBoundingClientRect().top - el.getBoundingClientRect().top;
13979
14101
  el.scrollTop = Math.max(0, el.scrollTop + delta2 - 12);
13980
14102
  return;
@@ -13983,7 +14105,7 @@ function ExplorePage({
13983
14105
  anchor.getBoundingClientRect().top - paneOffsetRef.current - 12
13984
14106
  );
13985
14107
  if (delta !== 0) window.scrollBy({ top: delta, left: 0, behavior: "auto" });
13986
- }, [latestAssistantId, messages]);
14108
+ }, [latestAssistantId, messages, panel]);
13987
14109
  useEffect(() => {
13988
14110
  if (messages.length === 0) return;
13989
14111
  if (!stickToBottomRef.current) return;
@@ -13991,7 +14113,7 @@ function ExplorePage({
13991
14113
  return;
13992
14114
  const el = scrollRef.current;
13993
14115
  if (!el) return;
13994
- if (!pageOwnsScrolling(el)) {
14116
+ if (panel || !pageOwnsScrolling(el)) {
13995
14117
  el.scrollTop = el.scrollHeight;
13996
14118
  return;
13997
14119
  }
@@ -14000,7 +14122,7 @@ function ExplorePage({
14000
14122
  dock.getBoundingClientRect().bottom - visualViewportHeight()
14001
14123
  );
14002
14124
  if (delta > 0) window.scrollBy({ top: delta, left: 0, behavior: "auto" });
14003
- }, [activity, latestAssistantId, messages]);
14125
+ }, [activity, latestAssistantId, messages, panel]);
14004
14126
  const handleShare = useCallback(async () => {
14005
14127
  setShareLabel(T.copying);
14006
14128
  setShareUrl(null);
@@ -14010,7 +14132,7 @@ function ExplorePage({
14010
14132
  setTimeout(() => setShareLabel(T.share), 2500);
14011
14133
  return;
14012
14134
  }
14013
- const url = new URL(pageUrl ?? window.location.href);
14135
+ const url = panel ? new URL(explorePath, window.location.href) : new URL(pageUrl ?? window.location.href);
14014
14136
  url.search = "";
14015
14137
  url.hash = "";
14016
14138
  url.searchParams.set("c", token);
@@ -14026,6 +14148,8 @@ function ExplorePage({
14026
14148
  }, [
14027
14149
  createShareLink,
14028
14150
  pageUrl,
14151
+ panel,
14152
+ explorePath,
14029
14153
  T.copied,
14030
14154
  T.copying,
14031
14155
  T.share,
@@ -14054,12 +14178,15 @@ function ExplorePage({
14054
14178
  });
14055
14179
  return pickQueueRef.current;
14056
14180
  },
14057
- [T]
14181
+ [T, setStaged]
14182
+ );
14183
+ const removeAttachment = useCallback(
14184
+ (id) => {
14185
+ setStaged((prev) => prev.filter((entry) => entry.id !== id));
14186
+ setAttachmentNotice(null);
14187
+ },
14188
+ [setStaged]
14058
14189
  );
14059
- const removeAttachment = useCallback((id) => {
14060
- setStaged((prev) => prev.filter((entry) => entry.id !== id));
14061
- setAttachmentNotice(null);
14062
- }, []);
14063
14190
  const submitDraft = useCallback(() => {
14064
14191
  const text = draft.trim();
14065
14192
  if (!text || overLimit || busy || !canSend) return;
@@ -14071,7 +14198,16 @@ function ExplorePage({
14071
14198
  setStaged([]);
14072
14199
  setAttachmentNotice(null);
14073
14200
  textareaRef.current?.focus();
14074
- }, [busy, canSend, draft, overLimit, send, stopDictation]);
14201
+ }, [
14202
+ busy,
14203
+ canSend,
14204
+ draft,
14205
+ overLimit,
14206
+ send,
14207
+ setDraft,
14208
+ setStaged,
14209
+ stopDictation
14210
+ ]);
14075
14211
  const sendPrompt = useCallback(
14076
14212
  (prompt) => {
14077
14213
  if (!canSend || busy) return;
@@ -14082,7 +14218,7 @@ function ExplorePage({
14082
14218
  setStaged([]);
14083
14219
  setAttachmentNotice(null);
14084
14220
  },
14085
- [busy, canSend, send]
14221
+ [busy, canSend, send, setDraft, setStaged]
14086
14222
  );
14087
14223
  const handleKeyDown = useCallback(
14088
14224
  (event) => {
@@ -14104,7 +14240,7 @@ function ExplorePage({
14104
14240
  [serverCatalogRaw]
14105
14241
  );
14106
14242
  const rootStyle = {};
14107
- if (heightMode === "viewport") {
14243
+ if (viewportPage) {
14108
14244
  rootStyle["--boff-explore-offset"] = paneOffset === null ? normalizeOffset(viewportOffset) : `${paneOffset}px`;
14109
14245
  if (bottomInset > 0) {
14110
14246
  rootStyle["--boff-explore-inset"] = `${bottomInset}px`;
@@ -14117,19 +14253,19 @@ function ExplorePage({
14117
14253
  "div",
14118
14254
  {
14119
14255
  ref: rootRef,
14120
- "data-boff-explore": "page",
14256
+ "data-boff-explore": panel ? "panel" : "page",
14121
14257
  "data-phase": phase,
14122
14258
  "data-locale": activeLocale,
14123
14259
  dir: rtl ? "rtl" : void 0,
14124
14260
  className: cn(
14125
- "flex w-full min-w-0 flex-col overflow-x-hidden bg-background text-foreground",
14126
- heightMode === "viewport" && "boff-explore-viewport",
14127
- heightMode === "auto" && "min-h-[70vh]",
14261
+ panel ? "boff-explore-panel flex h-full min-h-0 w-full min-w-0 flex-col overflow-hidden bg-background text-foreground" : "flex w-full min-w-0 flex-col overflow-x-hidden bg-background text-foreground",
14262
+ viewportPage && "boff-explore-viewport",
14263
+ !panel && heightMode === "auto" && "min-h-[70vh]",
14128
14264
  className
14129
14265
  ),
14130
- style: rootStyle,
14266
+ style: panel ? void 0 : rootStyle,
14131
14267
  children: [
14132
- /* @__PURE__ */ jsx(
14268
+ panel ? null : /* @__PURE__ */ jsx(
14133
14269
  PageHead,
14134
14270
  {
14135
14271
  title: seo?.title ?? T.seoTitle,
@@ -14142,7 +14278,11 @@ function ExplorePage({
14142
14278
  ),
14143
14279
  /* @__PURE__ */ jsx(ProseStyles, {}),
14144
14280
  /* @__PURE__ */ jsx(ExploreStyles, {}),
14145
- bakedCatalogJson ? /* @__PURE__ */ jsx(
14281
+ panel ? /* @__PURE__ */ jsx("style", { children: `.boff-explore-panel .boff-explore-scroll { container: boff-explore-pane / size; }
14282
+ @container boff-explore-pane (width < ${toRem(WELCOME_FIT_MIN_WIDTH_PX)}) {
14283
+ .boff-explore-panel .boff-explore-scroll .boff-explore-capabilities { display: none; }
14284
+ }` }) : null,
14285
+ !panel && bakedCatalogJson ? /* @__PURE__ */ jsx(
14146
14286
  "script",
14147
14287
  {
14148
14288
  id: BAKED_CATALOG_ELEMENT_ID,
@@ -14162,7 +14302,7 @@ function ExplorePage({
14162
14302
  children: /* @__PURE__ */ jsx(Sparkles, { className: "h-4 w-4" })
14163
14303
  }
14164
14304
  ),
14165
- /* @__PURE__ */ jsx("h1", { className: "truncate text-sm font-semibold", children: resolvedTitle }),
14305
+ panel ? /* @__PURE__ */ jsx("h2", { className: "truncate text-sm font-semibold", children: resolvedTitle }) : /* @__PURE__ */ jsx("h1", { className: "truncate text-sm font-semibold", children: resolvedTitle }),
14166
14306
  focusedProductName ? /* @__PURE__ */ jsx("span", { className: "hidden shrink-0 rounded-full bg-secondary px-2 py-0.5 text-xs font-medium text-secondary-foreground sm:inline", children: focusedProductName }) : null,
14167
14307
  /* @__PURE__ */ jsxs(
14168
14308
  Button,
@@ -14306,6 +14446,7 @@ function ExplorePage({
14306
14446
  children: showWelcome ? /* @__PURE__ */ jsx(
14307
14447
  WelcomeState,
14308
14448
  {
14449
+ heading: panel ? "h2" : "h1",
14309
14450
  strings: T,
14310
14451
  title: resolvedTitle,
14311
14452
  body: resolvedBody,
@@ -14668,77 +14809,738 @@ function samePath(a, b) {
14668
14809
  const norm = (v) => v.length > 1 ? v.replace(/\/+$/, "") : v;
14669
14810
  return norm(a) === norm(b);
14670
14811
  }
14671
- function ExploreCta({
14672
- variant,
14673
- href = "/explore",
14674
- label = "Ask AI",
14675
- className,
14812
+ var ExploreCta = forwardRef(
14813
+ function ExploreCta2({
14814
+ variant,
14815
+ href = "/explore",
14816
+ label = "Ask AI",
14817
+ className,
14818
+ onNavigate,
14819
+ onClick,
14820
+ currentPath,
14821
+ expanded,
14822
+ controls
14823
+ }, ref) {
14824
+ const path = useCurrentPath(currentPath);
14825
+ const isActive = samePath(path, href);
14826
+ if (variant === "floating" && isActive) return null;
14827
+ const handleClick = (event) => {
14828
+ onClick?.();
14829
+ if (!onNavigate) return;
14830
+ if (event.defaultPrevented || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey || event.button !== 0) {
14831
+ return;
14832
+ }
14833
+ event.preventDefault();
14834
+ onNavigate(href);
14835
+ };
14836
+ const classes = {
14837
+ // A quiet icon control, deliberately NOT a second gradient pill: a header should carry one
14838
+ // primary CTA ("Get started"), and a competing coloured button next to it reads as clutter.
14839
+ // This matches the theme toggle's visual weight, so the row scans as [utilities] [CTA].
14840
+ // The prominent, labelled entry point to /explore is the floating bubble, which is visible
14841
+ // on every page without scrolling. `shrink-0` keeps it from squeezing the nav.
14842
+ header: "inline-flex h-9 w-9 shrink-0 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground",
14843
+ mobile: "inline-flex w-full items-center gap-2 rounded-lg border border-border bg-card px-3 py-2 text-sm font-medium text-card-foreground transition-colors hover:bg-accent hover:text-accent-foreground",
14844
+ floating: "fixed bottom-5 right-5 z-40 inline-flex items-center gap-2 rounded-full bg-gradient-to-r from-primary to-primary/70 px-4 py-3 text-sm font-medium text-primary-foreground shadow-lg transition-opacity hover:opacity-90"
14845
+ };
14846
+ const hooks = {
14847
+ header: "cta-header",
14848
+ mobile: "cta-mobile",
14849
+ floating: "cta-floating"
14850
+ };
14851
+ return /* @__PURE__ */ jsxs(
14852
+ "a",
14853
+ {
14854
+ ref,
14855
+ "data-boff-explore": hooks[variant],
14856
+ href,
14857
+ onClick: handleClick,
14858
+ "aria-label": label,
14859
+ "aria-current": isActive ? "page" : void 0,
14860
+ "aria-expanded": expanded,
14861
+ "aria-haspopup": expanded === void 0 ? void 0 : "dialog",
14862
+ "aria-controls": expanded === void 0 ? void 0 : controls,
14863
+ className: cn(
14864
+ classes[variant],
14865
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
14866
+ className
14867
+ ),
14868
+ children: [
14869
+ /* @__PURE__ */ jsx(
14870
+ Sparkles,
14871
+ {
14872
+ className: cn(
14873
+ "shrink-0",
14874
+ variant === "floating" ? "h-4 w-4" : variant === "header" ? "h-5 w-5" : "h-3.5 w-3.5"
14875
+ ),
14876
+ "aria-hidden": "true"
14877
+ }
14878
+ ),
14879
+ /* @__PURE__ */ jsx(
14880
+ "span",
14881
+ {
14882
+ className: cn(
14883
+ variant === "floating" && "hidden sm:inline",
14884
+ // Never labelled in the header — see the class comment above.
14885
+ variant === "header" && "hidden"
14886
+ ),
14887
+ children: label
14888
+ }
14889
+ )
14890
+ ]
14891
+ }
14892
+ );
14893
+ }
14894
+ );
14895
+ var MARK_KEY = "boffExplorePanel";
14896
+ var POS_KEY = "boffExplorePanelPos";
14897
+ var DOC_KEY = "boffExplorePanelDoc";
14898
+ var DOC_ID = `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
14899
+ var lastPos = 0;
14900
+ var hostMode = null;
14901
+ var NARROW_QUERY = "(max-width: 639px)";
14902
+ var TOUCH_FIRST_QUERY = "(hover: none) and (pointer: coarse)";
14903
+ var COMPOSER_FOCUS_TRIES = 15;
14904
+ var PANEL_CSS = `
14905
+ .boff-explore-shell {
14906
+ --boff-explore-shell-lift-at: max(var(--boff-explore-shell-lift, 0px), var(--boff-explore-shell-bottom, 0px));
14907
+ --boff-explore-shell-room-at: var(--boff-explore-shell-room, calc(100vh - var(--boff-explore-shell-bottom, 0px)));
14908
+ position: fixed;
14909
+ z-index: var(--boff-explore-shell-z, 50);
14910
+ display: flex;
14911
+ flex-direction: column;
14912
+ overflow: hidden;
14913
+ overscroll-behavior: contain;
14914
+ inset-inline-end: 1rem;
14915
+ bottom: calc(1rem + var(--boff-explore-shell-lift-at));
14916
+ width: min(26rem, calc(100vw - 2rem));
14917
+ height: min(40rem, calc(var(--boff-explore-shell-room-at) - 6rem));
14918
+ border-width: 1px;
14919
+ border-style: solid;
14920
+ border-radius: 1rem;
14921
+ }
14922
+ @supports (height: 100dvh) {
14923
+ .boff-explore-shell {
14924
+ --boff-explore-shell-room-at: var(--boff-explore-shell-room, calc(100dvh - var(--boff-explore-shell-bottom, 0px)));
14925
+ }
14926
+ }
14927
+ @media (max-width: 639px) {
14928
+ .boff-explore-shell[data-size="compact"] {
14929
+ inset-inline: 0;
14930
+ bottom: var(--boff-explore-shell-lift-at);
14931
+ width: auto;
14932
+ height: min(75vh, calc(var(--boff-explore-shell-room-at) - 4rem));
14933
+ border-width: 1px 0 0;
14934
+ border-radius: 1rem 1rem 0 0;
14935
+ }
14936
+ @supports (height: 100dvh) {
14937
+ .boff-explore-shell[data-size="compact"] {
14938
+ height: min(75dvh, calc(var(--boff-explore-shell-room-at) - 4rem));
14939
+ }
14940
+ }
14941
+ }
14942
+ .boff-explore-shell[data-size="expanded"] {
14943
+ inset: var(--boff-explore-shell-top, 0px) 0 var(--boff-explore-shell-lift-at) 0;
14944
+ width: auto;
14945
+ height: auto;
14946
+ border-width: 0;
14947
+ border-radius: 0;
14948
+ box-shadow: none;
14949
+ }
14950
+ .boff-explore-shell[data-open="false"] {
14951
+ visibility: hidden;
14952
+ content-visibility: hidden;
14953
+ }
14954
+ .boff-explore-shell:focus { outline: none; }
14955
+ `;
14956
+ function stateRecord() {
14957
+ const state = window.history.state;
14958
+ return state !== null && typeof state === "object" ? state : {};
14959
+ }
14960
+ function stampedHere() {
14961
+ return stateRecord()[DOC_KEY] === DOC_ID;
14962
+ }
14963
+ function readMark() {
14964
+ if (typeof window === "undefined" || !stampedHere()) return null;
14965
+ const mark = stateRecord()[MARK_KEY];
14966
+ return mark === "open" || mark === "expanded" ? mark : null;
14967
+ }
14968
+ function readPos() {
14969
+ if (typeof window === "undefined" || !stampedHere()) return null;
14970
+ const pos = stateRecord()[POS_KEY];
14971
+ return typeof pos === "number" ? pos : null;
14972
+ }
14973
+ function stamp() {
14974
+ if (typeof window === "undefined" || readPos() !== null) return;
14975
+ const rest = { ...stateRecord() };
14976
+ delete rest[MARK_KEY];
14977
+ delete rest[POS_KEY];
14978
+ delete rest[DOC_KEY];
14979
+ lastPos += 1;
14980
+ try {
14981
+ window.history.replaceState(
14982
+ { ...rest, [POS_KEY]: lastPos, [DOC_KEY]: DOC_ID },
14983
+ ""
14984
+ );
14985
+ } catch {
14986
+ }
14987
+ }
14988
+ function pushMark(mark) {
14989
+ const { history } = window;
14990
+ const mode = "scrollRestoration" in history ? history.scrollRestoration : null;
14991
+ try {
14992
+ if (mode !== null) history.scrollRestoration = "manual";
14993
+ lastPos += 1;
14994
+ history.pushState(
14995
+ {
14996
+ ...stateRecord(),
14997
+ [MARK_KEY]: mark,
14998
+ [POS_KEY]: lastPos,
14999
+ [DOC_KEY]: DOC_ID
15000
+ },
15001
+ ""
15002
+ );
15003
+ return true;
15004
+ } catch {
15005
+ return false;
15006
+ } finally {
15007
+ if (mode !== null) history.scrollRestoration = mode;
15008
+ }
15009
+ }
15010
+ function restoreScrollMode(mode, then) {
15011
+ const { history } = window;
15012
+ const put = () => {
15013
+ if (history.scrollRestoration === "manual")
15014
+ history.scrollRestoration = mode;
15015
+ then?.();
15016
+ };
15017
+ if (typeof window.requestAnimationFrame !== "function") {
15018
+ window.setTimeout(put, 50);
15019
+ return;
15020
+ }
15021
+ window.requestAnimationFrame(() => window.requestAnimationFrame(put));
15022
+ }
15023
+ function closeInnerDialogs(shell) {
15024
+ let closed = false;
15025
+ document.querySelectorAll(
15026
+ 'dialog[data-boff-explore="video-dialog"]'
15027
+ ).forEach((dialog) => {
15028
+ if (!dialog.open) return;
15029
+ dialog.close();
15030
+ closed = true;
15031
+ });
15032
+ const disclaimer = shell?.querySelector(
15033
+ '[data-boff-explore="disclaimer-dialog"]'
15034
+ );
15035
+ if (disclaimer) {
15036
+ disclaimer.click();
15037
+ closed = true;
15038
+ }
15039
+ return closed;
15040
+ }
15041
+ function marksOnTop(mark) {
15042
+ if (mark === "expanded") return 2;
15043
+ return mark === "open" ? 1 : 0;
15044
+ }
15045
+ function matches(query) {
15046
+ return typeof window !== "undefined" && typeof window.matchMedia === "function" && window.matchMedia(query).matches;
15047
+ }
15048
+ function ExplorePanel({
15049
+ open,
15050
+ onOpenChange,
15051
+ id = "boff-explore-panel",
15052
+ productSlug,
15053
+ locale,
14676
15054
  onNavigate,
14677
- onClick,
14678
- currentPath
15055
+ welcomeTitle,
15056
+ welcomeBody,
15057
+ explorePath,
15058
+ avatar,
15059
+ bottomOffset,
15060
+ zIndex,
15061
+ returnFocusRef,
15062
+ className
14679
15063
  }) {
14680
- const path = useCurrentPath(currentPath);
14681
- const isActive = samePath(path, href);
14682
- if (variant === "floating" && isActive) return null;
14683
- const handleClick = (event) => {
14684
- onClick?.();
14685
- if (!onNavigate) return;
14686
- if (event.defaultPrevented || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey || event.button !== 0) {
15064
+ const resolvedLocale = resolveExploreLocale(locale);
15065
+ const T = useMemo(() => exploreStrings(resolvedLocale), [resolvedLocale]);
15066
+ const rtl = isRtlLocale(resolvedLocale);
15067
+ const uid = useId();
15068
+ const titleId = `${uid}-title`;
15069
+ const chatTabId = `${uid}-chat-tab`;
15070
+ const avatarTabId = `${uid}-avatar-tab`;
15071
+ const chatPaneId = `${uid}-chat`;
15072
+ const avatarPaneId = `${uid}-avatar`;
15073
+ const [mounted, setMounted] = useState(open);
15074
+ const [size, setSize] = useState("compact");
15075
+ const [view, setView] = useState("chat");
15076
+ const [focusRequest, setFocusRequest] = useState(
15077
+ open ? "in" : null
15078
+ );
15079
+ const [wasOpen, setWasOpen] = useState(open);
15080
+ if (open !== wasOpen) {
15081
+ setWasOpen(open);
15082
+ if (open) {
15083
+ setMounted(true);
15084
+ setFocusRequest("in");
15085
+ } else {
15086
+ setSize("compact");
15087
+ setFocusRequest("back");
15088
+ }
15089
+ }
15090
+ const shellRef = useRef(null);
15091
+ const chatPaneRef = useRef(null);
15092
+ const chatTabRef = useRef(null);
15093
+ const avatarTabRef = useRef(null);
15094
+ const ownPopsRef = useRef(0);
15095
+ const settlingRef = useRef(false);
15096
+ const afterPopRef = useRef([]);
15097
+ const markRef = useRef(null);
15098
+ const posRef = useRef(null);
15099
+ const hrefRef = useRef(null);
15100
+ const openRef = useRef(open);
15101
+ const onOpenChangeRef = useRef(onOpenChange);
15102
+ const lookedRef = useRef(false);
15103
+ const traverse = useCallback((delta) => {
15104
+ ownPopsRef.current += 1;
15105
+ window.history.go(delta);
15106
+ }, []);
15107
+ const push = useCallback((mark) => {
15108
+ const { history } = window;
15109
+ if ("scrollRestoration" in history && history.scrollRestoration !== "manual") {
15110
+ hostMode = history.scrollRestoration;
15111
+ }
15112
+ stamp();
15113
+ if (!pushMark(mark)) return false;
15114
+ markRef.current = mark;
15115
+ posRef.current = readPos();
15116
+ hrefRef.current = window.location.href;
15117
+ return true;
15118
+ }, []);
15119
+ const whenSettled = useCallback((work) => {
15120
+ if (ownPopsRef.current > 0 || settlingRef.current) {
15121
+ afterPopRef.current.push(work);
15122
+ } else {
15123
+ work();
15124
+ }
15125
+ }, []);
15126
+ const flush = useCallback(() => {
15127
+ settlingRef.current = false;
15128
+ while (afterPopRef.current.length > 0 && ownPopsRef.current === 0 && !settlingRef.current) {
15129
+ afterPopRef.current.shift()?.();
15130
+ }
15131
+ }, []);
15132
+ useEffect(() => {
15133
+ openRef.current = open;
15134
+ onOpenChangeRef.current = onOpenChange;
15135
+ });
15136
+ useEffect(() => {
15137
+ if (typeof window === "undefined") return;
15138
+ if (ownPopsRef.current > 0 || settlingRef.current) return;
15139
+ const pos = readPos();
15140
+ if (lookedRef.current && pos !== null && pos !== posRef.current) return;
15141
+ lookedRef.current = true;
15142
+ stamp();
15143
+ markRef.current = readMark();
15144
+ posRef.current = readPos();
15145
+ hrefRef.current = window.location.href;
15146
+ });
15147
+ useEffect(() => {
15148
+ if (typeof window === "undefined") return;
15149
+ whenSettled(() => {
15150
+ if (openRef.current) {
15151
+ if (readMark() === null) push("open");
15152
+ return;
15153
+ }
15154
+ closeInnerDialogs(shellRef.current);
15155
+ const count = marksOnTop(readMark());
15156
+ if (count > 0) traverse(-count);
15157
+ });
15158
+ }, [open, push, traverse, whenSettled]);
15159
+ useEffect(() => {
15160
+ if (typeof window === "undefined") return;
15161
+ const onPopState = () => {
15162
+ const open2 = openRef.current;
15163
+ const onOpenChange2 = onOpenChangeRef.current;
15164
+ const leftMark = markRef.current;
15165
+ const leftPos = posRef.current;
15166
+ const leftHref = hrefRef.current;
15167
+ const mark = readMark();
15168
+ const pos = readPos();
15169
+ markRef.current = mark;
15170
+ posRef.current = pos;
15171
+ hrefRef.current = window.location.href;
15172
+ const forward = pos !== null && leftPos !== null && pos > leftPos;
15173
+ const mode = hostMode;
15174
+ const restoring = leftMark !== null && mode !== null;
15175
+ if (ownPopsRef.current > 0) {
15176
+ ownPopsRef.current -= 1;
15177
+ if (ownPopsRef.current > 0) return;
15178
+ if (restoring) {
15179
+ settlingRef.current = true;
15180
+ restoreScrollMode(mode, flush);
15181
+ } else {
15182
+ flush();
15183
+ }
15184
+ return;
15185
+ }
15186
+ if (restoring) restoreScrollMode(mode);
15187
+ if (leftMark !== null && !forward) {
15188
+ if (open2 && closeInnerDialogs(shellRef.current)) {
15189
+ if (readMark() === null) push("open");
15190
+ if (leftMark === "expanded" && readMark() === "open") {
15191
+ push("expanded");
15192
+ }
15193
+ return;
15194
+ }
15195
+ setSize("compact");
15196
+ if (mark === null && open2) onOpenChange2(false);
15197
+ return;
15198
+ }
15199
+ if (leftHref !== null && window.location.href !== leftHref) {
15200
+ closeInnerDialogs(shellRef.current);
15201
+ }
15202
+ if (mark === null) return;
15203
+ if (forward) {
15204
+ setSize(mark === "expanded" ? "expanded" : "compact");
15205
+ if (!open2) onOpenChange2(true);
15206
+ return;
15207
+ }
15208
+ if (!open2) {
15209
+ traverse(-marksOnTop(mark));
15210
+ return;
15211
+ }
15212
+ setSize(mark === "expanded" ? "expanded" : "compact");
15213
+ };
15214
+ window.addEventListener("popstate", onPopState);
15215
+ return () => window.removeEventListener("popstate", onPopState);
15216
+ }, [flush, push, traverse]);
15217
+ useEffect(() => {
15218
+ if (!open || typeof window === "undefined") return;
15219
+ const viewport = window.visualViewport;
15220
+ const shell = shellRef.current;
15221
+ if (!viewport || !shell) return;
15222
+ const clear = () => {
15223
+ shell.style.removeProperty("--boff-explore-shell-lift");
15224
+ shell.style.removeProperty("--boff-explore-shell-room");
15225
+ shell.style.removeProperty("--boff-explore-shell-top");
15226
+ };
15227
+ const apply = () => {
15228
+ const covered = Math.max(
15229
+ 0,
15230
+ Math.round(window.innerHeight - viewport.height - viewport.offsetTop)
15231
+ );
15232
+ const panned = viewport.offsetTop > 1;
15233
+ if (covered <= 1 && !panned) {
15234
+ clear();
15235
+ return;
15236
+ }
15237
+ shell.style.setProperty("--boff-explore-shell-lift", `${covered}px`);
15238
+ shell.style.setProperty(
15239
+ "--boff-explore-shell-room",
15240
+ `calc(${Math.round(viewport.height)}px - max(0px, var(--boff-explore-shell-bottom, 0px) - ${covered}px))`
15241
+ );
15242
+ shell.style.setProperty(
15243
+ "--boff-explore-shell-top",
15244
+ `${Math.max(0, Math.round(viewport.offsetTop))}px`
15245
+ );
15246
+ };
15247
+ apply();
15248
+ viewport.addEventListener("resize", apply);
15249
+ viewport.addEventListener("scroll", apply);
15250
+ return () => {
15251
+ viewport.removeEventListener("resize", apply);
15252
+ viewport.removeEventListener("scroll", apply);
15253
+ clear();
15254
+ };
15255
+ }, [open]);
15256
+ const focusComposerSoon = useCallback((from) => {
15257
+ let tries = 0;
15258
+ const next = (attempt2) => {
15259
+ if (typeof window.requestAnimationFrame === "function") {
15260
+ window.requestAnimationFrame(attempt2);
15261
+ } else {
15262
+ window.setTimeout(attempt2, 16);
15263
+ }
15264
+ };
15265
+ const attempt = () => {
15266
+ if (document.activeElement !== from) return;
15267
+ const composer = chatPaneRef.current?.querySelector(
15268
+ "textarea:not(:disabled)"
15269
+ );
15270
+ if (!composer) return;
15271
+ composer.focus();
15272
+ tries += 1;
15273
+ if (document.activeElement !== composer && tries < COMPOSER_FOCUS_TRIES) {
15274
+ next(attempt);
15275
+ }
15276
+ };
15277
+ next(attempt);
15278
+ }, []);
15279
+ useEffect(() => {
15280
+ if (focusRequest === null) return;
15281
+ setFocusRequest(null);
15282
+ const shell = shellRef.current;
15283
+ if (focusRequest === "back") {
15284
+ const active = document.activeElement;
15285
+ if (active === null || active === document.body || shell?.contains(active)) {
15286
+ returnFocusRef?.current?.focus();
15287
+ }
14687
15288
  return;
14688
15289
  }
14689
- event.preventDefault();
14690
- onNavigate(href);
14691
- };
14692
- const classes = {
14693
- // A quiet icon control, deliberately NOT a second gradient pill: a header should carry one
14694
- // primary CTA ("Get started"), and a competing coloured button next to it reads as clutter.
14695
- // This matches the theme toggle's visual weight, so the row scans as [utilities] [CTA].
14696
- // The prominent, labelled entry point to /explore is the floating bubble, which is visible
14697
- // on every page without scrolling. `shrink-0` keeps it from squeezing the nav.
14698
- header: "inline-flex h-9 w-9 shrink-0 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground",
14699
- mobile: "inline-flex w-full items-center gap-2 rounded-lg border border-border bg-card px-3 py-2 text-sm font-medium text-card-foreground transition-colors hover:bg-accent hover:text-accent-foreground",
14700
- floating: "fixed bottom-5 right-5 z-40 inline-flex items-center gap-2 rounded-full bg-gradient-to-r from-primary to-primary/70 px-4 py-3 text-sm font-medium text-primary-foreground shadow-lg transition-opacity hover:opacity-90"
14701
- };
14702
- const hooks = {
14703
- header: "cta-header",
14704
- mobile: "cta-mobile",
14705
- floating: "cta-floating"
15290
+ if (!shell) return;
15291
+ shell.focus();
15292
+ if (view === "chat" && !matches(TOUCH_FIRST_QUERY)) {
15293
+ focusComposerSoon(shell);
15294
+ }
15295
+ }, [focusComposerSoon, focusRequest, returnFocusRef, view]);
15296
+ const close = useCallback(() => onOpenChange(false), [onOpenChange]);
15297
+ const expand = useCallback(() => {
15298
+ setSize("expanded");
15299
+ whenSettled(() => {
15300
+ if (!openRef.current) return;
15301
+ if (readMark() === null) push("open");
15302
+ if (readMark() === "open") push("expanded");
15303
+ });
15304
+ }, [push, whenSettled]);
15305
+ const restore = useCallback(() => {
15306
+ setSize("compact");
15307
+ whenSettled(() => {
15308
+ if (readMark() === "expanded") traverse(-1);
15309
+ });
15310
+ }, [traverse, whenSettled]);
15311
+ const onKeyDown = useCallback(
15312
+ (event) => {
15313
+ if (event.key !== "Escape" || event.defaultPrevented) return;
15314
+ if (event.nativeEvent.isComposing || event.keyCode === 229) return;
15315
+ const shell = shellRef.current;
15316
+ if (!shell || !(event.target instanceof Node) || !shell.contains(event.target)) {
15317
+ return;
15318
+ }
15319
+ if (shell.querySelector('dialog[open], [role="dialog"][aria-modal="true"]')) {
15320
+ return;
15321
+ }
15322
+ event.preventDefault();
15323
+ if (size === "expanded") restore();
15324
+ else close();
15325
+ },
15326
+ [close, restore, size]
15327
+ );
15328
+ const navigate = useCallback(
15329
+ (path) => {
15330
+ if (!onNavigate) return;
15331
+ setSize("compact");
15332
+ const stayOpen = !matches(NARROW_QUERY);
15333
+ if (!stayOpen) onOpenChange(false);
15334
+ whenSettled(() => {
15335
+ const go = () => {
15336
+ onNavigate(path);
15337
+ if (stayOpen && openRef.current && readMark() === null) {
15338
+ push("open");
15339
+ }
15340
+ };
15341
+ const count = marksOnTop(readMark());
15342
+ if (count === 0) {
15343
+ go();
15344
+ return;
15345
+ }
15346
+ afterPopRef.current.push(go);
15347
+ traverse(-count);
15348
+ });
15349
+ },
15350
+ [onNavigate, onOpenChange, push, traverse, whenSettled]
15351
+ );
15352
+ const selectView = useCallback((next) => {
15353
+ setView(next);
15354
+ (next === "chat" ? chatTabRef : avatarTabRef).current?.focus();
15355
+ }, []);
15356
+ const continueInChat = useCallback(() => {
15357
+ setView("chat");
15358
+ const tab = chatTabRef.current;
15359
+ tab?.focus();
15360
+ focusComposerSoon(tab);
15361
+ }, [focusComposerSoon]);
15362
+ const onTabKeyDown = useCallback(
15363
+ (event) => {
15364
+ const other = view === "chat" ? "avatar" : "chat";
15365
+ const next = {
15366
+ ArrowLeft: other,
15367
+ ArrowRight: other,
15368
+ Home: "chat",
15369
+ End: "avatar"
15370
+ };
15371
+ const target = next[event.key];
15372
+ if (!target) return;
15373
+ event.preventDefault();
15374
+ selectView(target);
15375
+ },
15376
+ [selectView, view]
15377
+ );
15378
+ if (!mounted) return null;
15379
+ const style = {
15380
+ "--boff-explore-shell-bottom": bottomOffset ?? "0px",
15381
+ ...zIndex === void 0 ? {} : { "--boff-explore-shell-z": String(zIndex) }
14706
15382
  };
15383
+ const iconButton = "inline-flex h-9 w-9 shrink-0 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring";
15384
+ const tabButton = "rounded-md px-3 py-1.5 text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring";
15385
+ const expanded = size === "expanded";
15386
+ const sizeLabel = expanded ? T.exitFullScreen : T.enterFullScreen;
15387
+ const tabs = [
15388
+ { key: "chat", id: chatTabId, pane: chatPaneId, label: T.tabChat },
15389
+ { key: "avatar", id: avatarTabId, pane: avatarPaneId, label: T.tabAvatar }
15390
+ ];
14707
15391
  return /* @__PURE__ */ jsxs(
14708
- "a",
15392
+ "div",
14709
15393
  {
14710
- "data-boff-explore": hooks[variant],
14711
- href,
14712
- onClick: handleClick,
14713
- "aria-label": label,
14714
- "aria-current": isActive ? "page" : void 0,
15394
+ ref: shellRef,
15395
+ id,
15396
+ role: "dialog",
15397
+ "aria-modal": "false",
15398
+ "aria-labelledby": titleId,
15399
+ tabIndex: -1,
15400
+ "data-boff-explore": "panel-shell",
15401
+ "data-open": open ? "true" : "false",
15402
+ "data-size": size,
15403
+ dir: rtl ? "rtl" : void 0,
14715
15404
  className: cn(
14716
- classes[variant],
14717
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
15405
+ "boff-explore-shell border-border bg-background text-foreground shadow-2xl",
14718
15406
  className
14719
15407
  ),
15408
+ style,
15409
+ onKeyDown,
14720
15410
  children: [
14721
- /* @__PURE__ */ jsx(
14722
- Sparkles,
14723
- {
14724
- className: cn(
14725
- "shrink-0",
14726
- variant === "floating" ? "h-4 w-4" : variant === "header" ? "h-5 w-5" : "h-3.5 w-3.5"
14727
- ),
14728
- "aria-hidden": "true"
14729
- }
14730
- ),
14731
- /* @__PURE__ */ jsx(
14732
- "span",
14733
- {
14734
- className: cn(
14735
- variant === "floating" && "hidden sm:inline",
14736
- // Never labelled in the header — see the class comment above.
14737
- variant === "header" && "hidden"
15411
+ /* @__PURE__ */ jsx("style", { children: PANEL_CSS }),
15412
+ /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center gap-2 border-b border-border px-3 py-2", children: [
15413
+ /* @__PURE__ */ jsx(
15414
+ "span",
15415
+ {
15416
+ id: titleId,
15417
+ className: "min-w-0 flex-1 truncate text-sm font-semibold",
15418
+ children: T.panelTitle
15419
+ }
15420
+ ),
15421
+ avatar ? /* @__PURE__ */ jsx(
15422
+ "div",
15423
+ {
15424
+ role: "tablist",
15425
+ "aria-label": T.panelViews,
15426
+ className: "inline-flex shrink-0 rounded-lg bg-muted p-0.5",
15427
+ children: tabs.map((tab) => /* @__PURE__ */ jsx(
15428
+ "button",
15429
+ {
15430
+ ref: tab.key === "chat" ? chatTabRef : avatarTabRef,
15431
+ type: "button",
15432
+ role: "tab",
15433
+ id: tab.id,
15434
+ "aria-selected": view === tab.key,
15435
+ "aria-controls": tab.pane,
15436
+ tabIndex: view === tab.key ? 0 : -1,
15437
+ "data-boff-explore": `panel-tab-${tab.key}`,
15438
+ className: cn(
15439
+ tabButton,
15440
+ view === tab.key ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"
15441
+ ),
15442
+ onClick: () => selectView(tab.key),
15443
+ onKeyDown: onTabKeyDown,
15444
+ children: tab.label
15445
+ },
15446
+ tab.key
15447
+ ))
15448
+ }
15449
+ ) : null,
15450
+ /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center gap-1", children: [
15451
+ /* @__PURE__ */ jsx(
15452
+ "button",
15453
+ {
15454
+ type: "button",
15455
+ "data-boff-explore": expanded ? "panel-restore" : "panel-expand",
15456
+ "aria-label": sizeLabel,
15457
+ title: sizeLabel,
15458
+ className: iconButton,
15459
+ onClick: expanded ? restore : expand,
15460
+ children: expanded ? /* @__PURE__ */ jsx(Minimize2, { className: "h-4 w-4", "aria-hidden": "true" }) : /* @__PURE__ */ jsx(Maximize2, { className: "h-4 w-4", "aria-hidden": "true" })
15461
+ }
14738
15462
  ),
14739
- children: label
14740
- }
14741
- )
15463
+ /* @__PURE__ */ jsx(
15464
+ "button",
15465
+ {
15466
+ type: "button",
15467
+ "data-boff-explore": "panel-close",
15468
+ "aria-label": T.closePanel,
15469
+ title: T.closePanel,
15470
+ className: iconButton,
15471
+ onClick: close,
15472
+ children: /* @__PURE__ */ jsx(X, { className: "h-4 w-4", "aria-hidden": "true" })
15473
+ }
15474
+ )
15475
+ ] })
15476
+ ] }),
15477
+ /* @__PURE__ */ jsxs("div", { className: "relative flex min-h-0 flex-1 flex-col", children: [
15478
+ /* @__PURE__ */ jsx(
15479
+ "div",
15480
+ {
15481
+ ref: chatPaneRef,
15482
+ id: chatPaneId,
15483
+ role: avatar ? "tabpanel" : void 0,
15484
+ "aria-labelledby": avatar ? chatTabId : void 0,
15485
+ "data-boff-explore": "panel-chat",
15486
+ className: cn(
15487
+ "flex min-h-0 flex-1 flex-col",
15488
+ view === "avatar" && "invisible"
15489
+ ),
15490
+ children: /* @__PURE__ */ jsx(
15491
+ ExplorePage,
15492
+ {
15493
+ presentation: "panel",
15494
+ active: open && view === "chat",
15495
+ productSlug,
15496
+ locale,
15497
+ onNavigate: onNavigate ? navigate : void 0,
15498
+ welcomeTitle,
15499
+ welcomeBody,
15500
+ explorePath
15501
+ }
15502
+ )
15503
+ }
15504
+ ),
15505
+ avatar ? /* @__PURE__ */ jsxs(
15506
+ "div",
15507
+ {
15508
+ id: avatarPaneId,
15509
+ role: "tabpanel",
15510
+ "aria-labelledby": avatarTabId,
15511
+ "data-boff-explore": "panel-avatar",
15512
+ className: cn(
15513
+ "absolute inset-0 flex-col items-center justify-center gap-4 overflow-y-auto bg-background p-6 text-center",
15514
+ view === "avatar" ? "flex" : "hidden"
15515
+ ),
15516
+ children: [
15517
+ /* @__PURE__ */ jsx(
15518
+ "img",
15519
+ {
15520
+ src: avatar.src,
15521
+ alt: avatar.name ? `${avatar.name}, ${T.liveAvatar}` : T.liveAvatar,
15522
+ loading: "lazy",
15523
+ decoding: "async",
15524
+ width: 128,
15525
+ height: 128,
15526
+ className: "h-32 w-32 rounded-full border border-border object-cover shadow-sm"
15527
+ }
15528
+ ),
15529
+ /* @__PURE__ */ jsx("p", { className: "text-base font-semibold", children: T.avatarComingSoon }),
15530
+ /* @__PURE__ */ jsx(
15531
+ "button",
15532
+ {
15533
+ type: "button",
15534
+ "data-boff-explore": "panel-continue-chat",
15535
+ className: "inline-flex items-center justify-center rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground transition-opacity hover:opacity-90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
15536
+ onClick: continueInChat,
15537
+ children: T.continueInChat
15538
+ }
15539
+ )
15540
+ ]
15541
+ }
15542
+ ) : null
15543
+ ] })
14742
15544
  ]
14743
15545
  }
14744
15546
  );
@@ -19526,6 +20328,6 @@ function shouldRenderSiteFooter(pathname) {
19526
20328
  return !isFooterlessPath(pathname);
19527
20329
  }
19528
20330
 
19529
- export { ANSWERS_PATH, ANSWER_HEADING_SHIFT, ANSWER_PATH_PREFIX, AnswerDetailPage, AnswersPage, BlogListPage, BlogPostPage, Button, CONCEPTS_PATH, CONCEPT_ILLUSTRATION_NOTICE, CONCEPT_PATH_PREFIX, CONCEPT_WORKFLOW_NOTICE, CareersApplyForm, CareersSubmissionForm, CaseStudiesListPage, CaseStudyPage, ChangelogPage, ConceptDetailPage, ConceptsPage, ContactPage, ContentRenderer, ContractsPage, DEFAULT_CONTACT_CATEGORIES, DEFAULT_EXPLORE_EXAMPLE_PROMPTS, DOMAINS_URL, ECOSYSTEM_PRODUCTS, ESCALATE_EXPLORE_CONVERSATION_MUTATION, EXPLORE_CATALOG_QUERY, EXPLORE_CATALOG_QUERY_WITHOUT_HIGHLIGHTS, EXPLORE_ESCALATION_NOTE_SOFT_MAX, EXPLORE_LOCALES, EXPLORE_MESSAGE_QUERY, EXPLORE_PREFILL_MAX_LENGTH, EXPLORE_RECAPTCHA_ACTION, ElectronDownloadLink, ExploreAnswerBody, ExploreAnswerStyles, ExploreCta, ExplorePage, FALLBACK_EXPLORE_LIMITS, FOOTERLESS_ROUTES, Input, LEGAL_DOCUMENTS, LEGAL_DOCUMENT_KEYS, Label, LaunchCountdown, LegalPage, Markdown, NewsletterForm, NewsletterPage, PRODUCT_SLUG_ALIASES, PRODUCT_SLUG_EMIT, PRODUCT_SLUG_RENAMES, PUBLISHED_ANSWER_FIELDS, PageHead, PartnersPage, PressKitPage, PricingPage, PricingProductKeyError, PricingSection, ProblemsSolvedSection, ProductCard, ProductProvider, ResourceLinks, RybbitAnalytics, SEND_EXPLORE_MESSAGE_MUTATION, Select, SocialLinks, StarRating, StoreBrowsePage, StoreHomePage, StoreProductDetailPage, Textarea, TypeBadge, UnsubscribePage, WaitlistForm, WaitlistPage, WebSDKClient, WebSDKProvider, WebsiteSwitcher, answerPath, answerPlainText, answerSourceHost, answerSpeechText, answerStrings, availablePlanCurrencies, buttonVariants, classifyExploreError, cleanPlanDisplayName, cn, conceptPath, detectElectronPlatform, emitProductSlug, exploreQuestionHref, fetchLegalContent, fetchLegalContentPage, fetchPublicJobPosting, fetchPublicJobPostings, fetchPublicJobPostingsForSubmission, fetchPublicProduct, findLegalDocument, formatAnswerDate, formatDownloads, formatLegalDate, formatPrice2 as formatPrice, getAnswerBySlug, getConceptBySlug, getRecaptchaV3Token, inlineImageOrigins, isFooterlessPath, isInlineImageAllowed, isInlineVideoAllowed, isPublishedSourceUrl, isSameProductSlug, isUuidLike, isValidUrl, legacyProductSlug, loadRecaptchaV3, looksLikeDeliverableEmail, normalizeProductSlug, normalizeRoutePath, planPriceIn, productSlugVariants, productSlugsByOrigin, resolvePricingProductKey, shouldRenderSiteFooter, speechLocaleOf, splitLeadingHeading, stopSpeaking, useContentPage, useContentPages, useExploreChat, useProduct, useProductConfig, useProgressiveReveal, usePublicJobPosting, usePublicJobPostings, usePublicJobPostingsForSubmission, useSpeechOutput, useWebSDK, useWebSDKConfig };
20331
+ export { ANSWERS_PATH, ANSWER_HEADING_SHIFT, ANSWER_PATH_PREFIX, AnswerDetailPage, AnswersPage, BlogListPage, BlogPostPage, Button, CONCEPTS_PATH, CONCEPT_ILLUSTRATION_NOTICE, CONCEPT_PATH_PREFIX, CONCEPT_WORKFLOW_NOTICE, CareersApplyForm, CareersSubmissionForm, CaseStudiesListPage, CaseStudyPage, ChangelogPage, ConceptDetailPage, ConceptsPage, ContactPage, ContentRenderer, ContractsPage, DEFAULT_CONTACT_CATEGORIES, DEFAULT_EXPLORE_EXAMPLE_PROMPTS, DOMAINS_URL, ECOSYSTEM_PRODUCTS, ESCALATE_EXPLORE_CONVERSATION_MUTATION, EXPLORE_CATALOG_QUERY, EXPLORE_CATALOG_QUERY_WITHOUT_HIGHLIGHTS, EXPLORE_ESCALATION_NOTE_SOFT_MAX, EXPLORE_LOCALES, EXPLORE_MESSAGE_QUERY, EXPLORE_PREFILL_MAX_LENGTH, EXPLORE_RECAPTCHA_ACTION, ElectronDownloadLink, ExploreAnswerBody, ExploreAnswerStyles, ExploreChatProvider, ExploreCta, ExplorePage, ExplorePanel, FALLBACK_EXPLORE_LIMITS, FOOTERLESS_ROUTES, Input, LEGAL_DOCUMENTS, LEGAL_DOCUMENT_KEYS, Label, LaunchCountdown, LegalPage, Markdown, NewsletterForm, NewsletterPage, PRODUCT_SLUG_ALIASES, PRODUCT_SLUG_EMIT, PRODUCT_SLUG_RENAMES, PUBLISHED_ANSWER_FIELDS, PageHead, PartnersPage, PressKitPage, PricingPage, PricingProductKeyError, PricingSection, ProblemsSolvedSection, ProductCard, ProductProvider, ResourceLinks, RybbitAnalytics, SEND_EXPLORE_MESSAGE_MUTATION, Select, SocialLinks, StarRating, StoreBrowsePage, StoreHomePage, StoreProductDetailPage, Textarea, TypeBadge, UnsubscribePage, WaitlistForm, WaitlistPage, WebSDKClient, WebSDKProvider, WebsiteSwitcher, answerPath, answerPlainText, answerSourceHost, answerSpeechText, answerStrings, availablePlanCurrencies, buttonVariants, classifyExploreError, cleanPlanDisplayName, cn, conceptPath, detectElectronPlatform, emitProductSlug, exploreQuestionHref, fetchLegalContent, fetchLegalContentPage, fetchPublicJobPosting, fetchPublicJobPostings, fetchPublicJobPostingsForSubmission, fetchPublicProduct, findLegalDocument, formatAnswerDate, formatDownloads, formatLegalDate, formatPrice2 as formatPrice, getAnswerBySlug, getConceptBySlug, getRecaptchaV3Token, inlineImageOrigins, isFooterlessPath, isInlineImageAllowed, isInlineVideoAllowed, isPublishedSourceUrl, isSameProductSlug, isUuidLike, isValidUrl, legacyProductSlug, loadRecaptchaV3, looksLikeDeliverableEmail, normalizeProductSlug, normalizeRoutePath, planPriceIn, productSlugVariants, productSlugsByOrigin, resolvePricingProductKey, shouldRenderSiteFooter, speechLocaleOf, splitLeadingHeading, stopSpeaking, useContentPage, useContentPages, useExploreChat, useExploreConversation, useProduct, useProductConfig, useProgressiveReveal, usePublicJobPosting, usePublicJobPostings, usePublicJobPostingsForSubmission, useSpeechOutput, useWebSDK, useWebSDKConfig };
19530
20332
  //# sourceMappingURL=index.mjs.map
19531
20333
  //# sourceMappingURL=index.mjs.map