@burdenoff/website-sdk 2026.1021.4 → 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 (69) hide show
  1. package/dist/components/contact.js +2 -1
  2. package/dist/components/contact.js.map +1 -1
  3. package/dist/components/contact.mjs +2 -1
  4. package/dist/components/contact.mjs.map +1 -1
  5. package/dist/components/explore-cta.d.mts +10 -1
  6. package/dist/components/explore-cta.d.ts +10 -1
  7. package/dist/components/explore-cta.js +82 -74
  8. package/dist/components/explore-cta.js.map +1 -1
  9. package/dist/components/explore-cta.mjs +83 -75
  10. package/dist/components/explore-cta.mjs.map +1 -1
  11. package/dist/components/explore.d.mts +2 -2
  12. package/dist/components/explore.d.ts +2 -2
  13. package/dist/components/explore.js +592 -464
  14. package/dist/components/explore.js.map +1 -1
  15. package/dist/components/explore.mjs +593 -465
  16. package/dist/components/explore.mjs.map +1 -1
  17. package/dist/components/newsletter.js +2 -1
  18. package/dist/components/newsletter.js.map +1 -1
  19. package/dist/components/newsletter.mjs +2 -1
  20. package/dist/components/newsletter.mjs.map +1 -1
  21. package/dist/components/partners.js +2 -1
  22. package/dist/components/partners.js.map +1 -1
  23. package/dist/components/partners.mjs +2 -1
  24. package/dist/components/partners.mjs.map +1 -1
  25. package/dist/components/pricing.js +2 -1
  26. package/dist/components/pricing.js.map +1 -1
  27. package/dist/components/pricing.mjs +2 -1
  28. package/dist/components/pricing.mjs.map +1 -1
  29. package/dist/components/unsubscribe.js +2 -1
  30. package/dist/components/unsubscribe.js.map +1 -1
  31. package/dist/components/unsubscribe.mjs +2 -1
  32. package/dist/components/unsubscribe.mjs.map +1 -1
  33. package/dist/components/waitlist.js +2 -1
  34. package/dist/components/waitlist.js.map +1 -1
  35. package/dist/components/waitlist.mjs +2 -1
  36. package/dist/components/waitlist.mjs.map +1 -1
  37. package/dist/content/index.js +2 -1
  38. package/dist/content/index.js.map +1 -1
  39. package/dist/content/index.mjs +2 -1
  40. package/dist/content/index.mjs.map +1 -1
  41. package/dist/{explore-POqE7J8r.d.mts → explore-BRfKFfvI.d.mts} +21 -2
  42. package/dist/{explore-D6kon7uz.d.ts → explore-DkfcKgp6.d.ts} +21 -2
  43. package/dist/{explore-types-BB8HNFzX.d.mts → explore-types-_9UJu6EA.d.mts} +1 -1
  44. package/dist/{explore-types-BB8HNFzX.d.ts → explore-types-_9UJu6EA.d.ts} +1 -1
  45. package/dist/hooks/index.d.mts +2 -2
  46. package/dist/hooks/index.d.ts +2 -2
  47. package/dist/hooks/index.js +15 -9
  48. package/dist/hooks/index.js.map +1 -1
  49. package/dist/hooks/index.mjs +15 -9
  50. package/dist/hooks/index.mjs.map +1 -1
  51. package/dist/index.d.mts +123 -7
  52. package/dist/index.d.ts +123 -7
  53. package/dist/index.js +924 -118
  54. package/dist/index.js.map +1 -1
  55. package/dist/index.mjs +924 -121
  56. package/dist/index.mjs.map +1 -1
  57. package/dist/seo/index.d.mts +11 -1
  58. package/dist/seo/index.d.ts +11 -1
  59. package/dist/seo/index.js +2 -1
  60. package/dist/seo/index.js.map +1 -1
  61. package/dist/seo/index.mjs +2 -1
  62. package/dist/seo/index.mjs.map +1 -1
  63. package/dist/store/index.js +2 -1
  64. package/dist/store/index.js.map +1 -1
  65. package/dist/store/index.mjs +2 -1
  66. package/dist/store/index.mjs.map +1 -1
  67. package/dist/{use-progressive-reveal-Kr6DwGXG.d.mts → use-progressive-reveal-BFPWbEXy.d.mts} +25 -2
  68. package/dist/{use-progressive-reveal-BVJn9NIr.d.ts → use-progressive-reveal-C0hkdu_i.d.ts} +25 -2
  69. 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';
@@ -557,6 +557,7 @@ function PageHead({
557
557
  locale = "en_US",
558
558
  twitterHandle,
559
559
  themeColor = "#000000",
560
+ author,
560
561
  structuredData,
561
562
  additionalMeta
562
563
  }) {
@@ -569,7 +570,7 @@ function PageHead({
569
570
  /* @__PURE__ */ jsx("meta", { name: "title", content: fullTitle }),
570
571
  description && /* @__PURE__ */ jsx("meta", { name: "description", content: description }),
571
572
  keywords && /* @__PURE__ */ jsx("meta", { name: "keywords", content: keywords }),
572
- /* @__PURE__ */ jsx("meta", { name: "author", content: "Burdenoff Consultancy Services Pvt Ltd" }),
573
+ author && /* @__PURE__ */ jsx("meta", { name: "author", content: author }),
573
574
  /* @__PURE__ */ jsx("meta", { name: "robots", content: robots }),
574
575
  resolvedUrl && /* @__PURE__ */ jsx("link", { rel: "canonical", href: resolvedUrl }),
575
576
  favicon && /* @__PURE__ */ jsx("link", { rel: "icon", href: favicon }),
@@ -6530,6 +6531,14 @@ var EN = {
6530
6531
  closeVideo: "Close video",
6531
6532
  enterFullScreen: "Full screen",
6532
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",
6533
6542
  videoUnavailable: "This video can't be played right now.",
6534
6543
  groundedIn: "What this answer is based on",
6535
6544
  sourceCountOne: "1 source",
@@ -6638,6 +6647,14 @@ var ZH = {
6638
6647
  closeVideo: "\u5173\u95ED\u89C6\u9891",
6639
6648
  enterFullScreen: "\u5168\u5C4F",
6640
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",
6641
6658
  videoUnavailable: "\u6682\u65F6\u65E0\u6CD5\u64AD\u653E\u6B64\u89C6\u9891\u3002",
6642
6659
  groundedIn: "\u8FD9\u4E2A\u56DE\u7B54\u7684\u4F9D\u636E",
6643
6660
  sourceCountOne: "1 \u4E2A\u6765\u6E90",
@@ -6742,6 +6759,14 @@ var HI = {
6742
6759
  closeVideo: "\u0935\u0940\u0921\u093F\u092F\u094B \u092C\u0902\u0926 \u0915\u0930\u0947\u0902",
6743
6760
  enterFullScreen: "\u092A\u0942\u0930\u094D\u0923 \u0938\u094D\u0915\u094D\u0930\u0940\u0928",
6744
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",
6745
6770
  videoUnavailable: "\u092F\u0939 \u0935\u0940\u0921\u093F\u092F\u094B \u0905\u092D\u0940 \u0928\u0939\u0940\u0902 \u091A\u0932 \u0938\u0915\u0924\u093E\u0964",
6746
6771
  groundedIn: "\u092F\u0939 \u0909\u0924\u094D\u0924\u0930 \u0915\u093F\u0938 \u092A\u0930 \u0906\u0927\u093E\u0930\u093F\u0924 \u0939\u0948",
6747
6772
  sourceCountOne: "1 \u0938\u094D\u0930\u094B\u0924",
@@ -6850,6 +6875,14 @@ var ES = {
6850
6875
  closeVideo: "Cerrar v\xEDdeo",
6851
6876
  enterFullScreen: "Pantalla completa",
6852
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",
6853
6886
  videoUnavailable: "Ahora mismo no se puede reproducir este v\xEDdeo.",
6854
6887
  groundedIn: "En qu\xE9 se basa esta respuesta",
6855
6888
  sourceCountOne: "1 fuente",
@@ -6958,6 +6991,14 @@ var AR = {
6958
6991
  closeVideo: "\u0625\u063A\u0644\u0627\u0642 \u0627\u0644\u0641\u064A\u062F\u064A\u0648",
6959
6992
  enterFullScreen: "\u0645\u0644\u0621 \u0627\u0644\u0634\u0627\u0634\u0629",
6960
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",
6961
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.",
6962
7003
  groundedIn: "\u0639\u0644\u0649 \u0645\u0627\u0630\u0627 \u062A\u0633\u062A\u0646\u062F \u0647\u0630\u0647 \u0627\u0644\u0625\u062C\u0627\u0628\u0629",
6963
7004
  sourceCountOne: "\u0645\u0635\u062F\u0631 \u0648\u0627\u062D\u062F",
@@ -7066,6 +7107,14 @@ var TA = {
7066
7107
  closeVideo: "\u0BB5\u0BC0\u0B9F\u0BBF\u0BAF\u0BCB\u0BB5\u0BC8 \u0BAE\u0BC2\u0B9F\u0BC1",
7067
7108
  enterFullScreen: "\u0BAE\u0BC1\u0BB4\u0BC1\u0BA4\u0BCD \u0BA4\u0BBF\u0BB0\u0BC8",
7068
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",
7069
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.",
7070
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",
7071
7120
  sourceCountOne: "1 \u0BAE\u0BC2\u0BB2\u0BAE\u0BCD",
@@ -10222,7 +10271,9 @@ function useExploreChat(options = {}) {
10222
10271
  pollTimeoutMs = DEFAULT_POLL_TIMEOUT_MS,
10223
10272
  storageKey = DEFAULT_STORAGE_KEY,
10224
10273
  persist = true,
10225
- onSend
10274
+ onSend,
10275
+ enabled = true,
10276
+ shareToken: shareTokenOption
10226
10277
  } = options;
10227
10278
  const client = useWebSDK();
10228
10279
  const { productId } = useWebSDKConfig();
@@ -10260,7 +10311,7 @@ function useExploreChat(options = {}) {
10260
10311
  const [hasConversation, setHasConversation] = useState(false);
10261
10312
  const shareTokenRef = useRef(void 0);
10262
10313
  if (shareTokenRef.current === void 0) {
10263
- shareTokenRef.current = readShareToken();
10314
+ shareTokenRef.current = shareTokenOption === void 0 ? readShareToken() : shareTokenOption;
10264
10315
  }
10265
10316
  const isSharedView = shareTokenRef.current !== null;
10266
10317
  const catalogRef = useRef(catalog);
@@ -10298,6 +10349,7 @@ function useExploreChat(options = {}) {
10298
10349
  };
10299
10350
  }, []);
10300
10351
  useEffect(() => {
10352
+ if (!enabled) return;
10301
10353
  const shareToken = shareTokenRef.current;
10302
10354
  if (!shareToken) return;
10303
10355
  let cancelled = false;
@@ -10332,8 +10384,9 @@ function useExploreChat(options = {}) {
10332
10384
  return () => {
10333
10385
  cancelled = true;
10334
10386
  };
10335
- }, [client]);
10387
+ }, [client, enabled]);
10336
10388
  useEffect(() => {
10389
+ if (!enabled) return;
10337
10390
  if (shareTokenRef.current !== null) return;
10338
10391
  if (!persist) {
10339
10392
  setHydrated(true);
@@ -10358,9 +10411,10 @@ function useExploreChat(options = {}) {
10358
10411
  setTurnCount(turns);
10359
10412
  }
10360
10413
  setHydrated(true);
10361
- }, [persist, rememberConversationToken, storageKey]);
10414
+ }, [persist, rememberConversationToken, storageKey, enabled]);
10362
10415
  useEffect(() => {
10363
- if (!persist || !hydrated || typeof window === "undefined") return;
10416
+ if (!persist || !hydrated || isSharedView || typeof window === "undefined")
10417
+ return;
10364
10418
  try {
10365
10419
  const payload = {
10366
10420
  conversationToken: conversationTokenRef.current,
@@ -10374,10 +10428,10 @@ function useExploreChat(options = {}) {
10374
10428
  window.localStorage.setItem(storageKey, JSON.stringify(payload));
10375
10429
  } catch {
10376
10430
  }
10377
- }, [persist, hydrated, storageKey, messages, focusProduct]);
10431
+ }, [persist, hydrated, isSharedView, storageKey, messages, focusProduct]);
10378
10432
  useEffect(() => {
10379
10433
  messagesRef.current = messages;
10380
- if (!persist || !hydrated) return;
10434
+ if (!persist || !hydrated || isSharedView) return;
10381
10435
  const settled = messages.some(
10382
10436
  (m) => m.role === "ASSISTANT" && (m.status === "COMPLETED" || m.status === "FAILED")
10383
10437
  );
@@ -10389,8 +10443,9 @@ function useExploreChat(options = {}) {
10389
10443
  focusProduct: focusProductRef.current
10390
10444
  })
10391
10445
  );
10392
- }, [messages, persist, hydrated, storageKey]);
10446
+ }, [messages, persist, hydrated, isSharedView, storageKey]);
10393
10447
  useEffect(() => {
10448
+ if (!enabled) return;
10394
10449
  let cancelled = false;
10395
10450
  const load = async () => {
10396
10451
  const variables = { productSlug: productSlug ?? null };
@@ -10431,7 +10486,7 @@ function useExploreChat(options = {}) {
10431
10486
  return () => {
10432
10487
  cancelled = true;
10433
10488
  };
10434
- }, [client, productSlug, fallbackCatalog, bakedRaw]);
10489
+ }, [client, productSlug, fallbackCatalog, bakedRaw, enabled]);
10435
10490
  const startPolling = useCallback(
10436
10491
  (conversationToken, messageId) => {
10437
10492
  pollGenerationRef.current += 1;
@@ -10928,6 +10983,56 @@ function makeOptimisticId() {
10928
10983
  optimisticCounter += 1;
10929
10984
  return `boff-explore-local-${Date.now()}-${optimisticCounter}`;
10930
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
+ }
10931
11036
  var DRAIN_TARGET_MS = 1200;
10932
11037
  var MIN_CHARS_PER_SECOND = 90;
10933
11038
  var MAX_CHARS_PER_SECOND = 2200;
@@ -13572,15 +13677,17 @@ function WelcomeState({
13572
13677
  focusProduct,
13573
13678
  onPrompt,
13574
13679
  onFocus,
13575
- disabled
13680
+ disabled,
13681
+ heading = "h1"
13576
13682
  }) {
13683
+ const Heading = heading;
13577
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: [
13578
13685
  /* @__PURE__ */ jsxs("div", { className: "boff-explore-rise text-center", children: [
13579
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: [
13580
13687
  /* @__PURE__ */ jsx(Sparkles, { className: "h-3.5 w-3.5" }),
13581
13688
  T.badge
13582
13689
  ] }),
13583
- /* @__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 }),
13584
13691
  /* @__PURE__ */ jsx("p", { className: "mx-auto mt-2 max-w-2xl text-pretty text-sm leading-relaxed text-muted-foreground", children: body })
13585
13692
  ] }),
13586
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(
@@ -13635,19 +13742,36 @@ function exploreQuestionHref(question, base = "/explore") {
13635
13742
  const joiner = base.includes("?") ? "&" : "?";
13636
13743
  return `${base}${joiner}q=${encodeURIComponent(trimmed)}`;
13637
13744
  }
13638
- 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({
13639
13759
  seo,
13640
13760
  productSlug,
13641
- examplePrompts,
13642
13761
  className,
13643
13762
  heightMode = "viewport",
13644
13763
  viewportOffset,
13645
13764
  onNavigate,
13646
- onSend,
13647
13765
  welcomeTitle,
13648
13766
  welcomeBody,
13649
- locale
13767
+ locale,
13768
+ presentation = "page",
13769
+ active = true,
13770
+ explorePath = "/explore",
13771
+ conversation
13650
13772
  }) {
13773
+ const panel = presentation === "panel";
13774
+ const viewportPage = !panel && heightMode === "viewport";
13651
13775
  const pageUrl = useMemo(
13652
13776
  () => typeof window === "undefined" ? void 0 : window.location.href,
13653
13777
  []
@@ -13683,26 +13807,21 @@ function ExplorePage({
13683
13807
  escalate,
13684
13808
  canEscalate,
13685
13809
  createShareLink,
13686
- isSharedView
13687
- } = useExploreChat({
13688
- productSlug,
13689
- pageUrl,
13690
- onSend,
13691
- // Locale-aware, so a catalog outage degrades to a translated welcome rather than an
13692
- // English one. `T.prompts` seeds the chips the same way.
13693
- examplePrompts: examplePrompts ?? T.prompts,
13694
- fallbackWelcome: { title: T.welcomeTitle, body: T.welcomeBody }
13695
- });
13696
- const [draft, setDraft] = useState("");
13810
+ isSharedView,
13811
+ draft,
13812
+ setDraft,
13813
+ staged,
13814
+ setStaged
13815
+ } = conversation;
13697
13816
  const textareaRef = useRef(null);
13698
13817
  useEffect(() => {
13699
- if (typeof window === "undefined") return;
13818
+ if (typeof window === "undefined" || panel) return;
13700
13819
  const params = new URLSearchParams(window.location.search);
13701
13820
  if (params.has("c")) return;
13702
13821
  const question = params.get("q")?.trim();
13703
13822
  if (!question) return;
13704
13823
  setDraft(question.slice(0, EXPLORE_PREFILL_MAX_LENGTH));
13705
- }, []);
13824
+ }, [panel, setDraft]);
13706
13825
  const [historyOpen, setHistoryOpen] = useState(false);
13707
13826
  const speechStopRef = useRef(() => void 0);
13708
13827
  const stopDictation = useCallback(() => {
@@ -13718,8 +13837,12 @@ function ExplorePage({
13718
13837
  }
13719
13838
  });
13720
13839
  speechStopRef.current = speech.stop;
13840
+ useEffect(() => {
13841
+ if (active) return;
13842
+ stopDictation();
13843
+ stopSpeaking();
13844
+ }, [active, stopDictation]);
13721
13845
  const [disclaimerOpen, setDisclaimerOpen] = useState(false);
13722
- const [staged, setStaged] = useState([]);
13723
13846
  const [attachmentNotice, setAttachmentNotice] = useState(null);
13724
13847
  const fileInputRef = useRef(null);
13725
13848
  const stagedRef = useRef([]);
@@ -13772,7 +13895,7 @@ function ExplorePage({
13772
13895
  const [bottomInset, setBottomInset] = useState(0);
13773
13896
  const paneOffsetRef = useRef(0);
13774
13897
  const measurePane = useCallback(() => {
13775
- if (heightMode !== "viewport") return;
13898
+ if (!viewportPage) return;
13776
13899
  const el = rootRef.current;
13777
13900
  if (!el) return;
13778
13901
  const layoutHeight = window.innerHeight;
@@ -13791,7 +13914,7 @@ function ExplorePage({
13791
13914
  paneOffsetRef.current = top;
13792
13915
  setPaneOffset((current) => current === top ? current : top);
13793
13916
  setBottomInset((current) => current === inset ? current : inset);
13794
- }, [heightMode]);
13917
+ }, [viewportPage]);
13795
13918
  const [chromeOverlap, setChromeOverlap] = useState(0);
13796
13919
  const measureChrome = useCallback(() => {
13797
13920
  const root = rootRef.current;
@@ -13816,7 +13939,7 @@ function ExplorePage({
13816
13939
  measureChrome();
13817
13940
  }, [measurePane, measureChrome]);
13818
13941
  useEffect(() => {
13819
- if (typeof window === "undefined") return;
13942
+ if (typeof window === "undefined" || panel) return;
13820
13943
  let frame = 0;
13821
13944
  const run = () => {
13822
13945
  frame = 0;
@@ -13854,12 +13977,12 @@ function ExplorePage({
13854
13977
  setBottomInset(0);
13855
13978
  setChromeOverlap(0);
13856
13979
  };
13857
- }, [remeasure]);
13980
+ }, [remeasure, panel]);
13858
13981
  useEffect(() => {
13859
13982
  measureChrome();
13860
13983
  }, [measureChrome, paneOffset, bottomInset]);
13861
13984
  useEffect(() => {
13862
- if (heightMode !== "viewport" || typeof window === "undefined") return;
13985
+ if (!viewportPage || typeof window === "undefined") return;
13863
13986
  const { history: browserHistory } = window;
13864
13987
  const previousRestoration = "scrollRestoration" in browserHistory ? browserHistory.scrollRestoration : null;
13865
13988
  if (previousRestoration !== null)
@@ -13927,14 +14050,14 @@ function ExplorePage({
13927
14050
  if (previousRestoration !== null)
13928
14051
  browserHistory.scrollRestoration = previousRestoration;
13929
14052
  };
13930
- }, [heightMode, remeasure]);
14053
+ }, [viewportPage, remeasure]);
13931
14054
  const handleScroll = useCallback(() => {
13932
14055
  const el = scrollRef.current;
13933
14056
  if (!el) return;
13934
14057
  stickToBottomRef.current = el.scrollHeight - el.scrollTop - el.clientHeight < 80;
13935
14058
  }, []);
13936
14059
  useEffect(() => {
13937
- if (typeof window === "undefined") return;
14060
+ if (typeof window === "undefined" || panel) return;
13938
14061
  let frame = 0;
13939
14062
  const run = () => {
13940
14063
  frame = 0;
@@ -13957,7 +14080,7 @@ function ExplorePage({
13957
14080
  if (frame) window.cancelAnimationFrame(frame);
13958
14081
  window.removeEventListener("scroll", schedule);
13959
14082
  };
13960
- }, []);
14083
+ }, [panel]);
13961
14084
  const latestAssistantId = useMemo(() => {
13962
14085
  for (let i = messages.length - 1; i >= 0; i -= 1) {
13963
14086
  const message = messages[i];
@@ -13973,7 +14096,7 @@ function ExplorePage({
13973
14096
  if (!stickToBottomRef.current) return;
13974
14097
  if (anchor.offsetHeight === 0) return;
13975
14098
  alignedForRef.current = latestAssistantId;
13976
- if (!pageOwnsScrolling(el)) {
14099
+ if (panel || !pageOwnsScrolling(el)) {
13977
14100
  const delta2 = anchor.getBoundingClientRect().top - el.getBoundingClientRect().top;
13978
14101
  el.scrollTop = Math.max(0, el.scrollTop + delta2 - 12);
13979
14102
  return;
@@ -13982,7 +14105,7 @@ function ExplorePage({
13982
14105
  anchor.getBoundingClientRect().top - paneOffsetRef.current - 12
13983
14106
  );
13984
14107
  if (delta !== 0) window.scrollBy({ top: delta, left: 0, behavior: "auto" });
13985
- }, [latestAssistantId, messages]);
14108
+ }, [latestAssistantId, messages, panel]);
13986
14109
  useEffect(() => {
13987
14110
  if (messages.length === 0) return;
13988
14111
  if (!stickToBottomRef.current) return;
@@ -13990,7 +14113,7 @@ function ExplorePage({
13990
14113
  return;
13991
14114
  const el = scrollRef.current;
13992
14115
  if (!el) return;
13993
- if (!pageOwnsScrolling(el)) {
14116
+ if (panel || !pageOwnsScrolling(el)) {
13994
14117
  el.scrollTop = el.scrollHeight;
13995
14118
  return;
13996
14119
  }
@@ -13999,7 +14122,7 @@ function ExplorePage({
13999
14122
  dock.getBoundingClientRect().bottom - visualViewportHeight()
14000
14123
  );
14001
14124
  if (delta > 0) window.scrollBy({ top: delta, left: 0, behavior: "auto" });
14002
- }, [activity, latestAssistantId, messages]);
14125
+ }, [activity, latestAssistantId, messages, panel]);
14003
14126
  const handleShare = useCallback(async () => {
14004
14127
  setShareLabel(T.copying);
14005
14128
  setShareUrl(null);
@@ -14009,7 +14132,7 @@ function ExplorePage({
14009
14132
  setTimeout(() => setShareLabel(T.share), 2500);
14010
14133
  return;
14011
14134
  }
14012
- const url = new URL(pageUrl ?? window.location.href);
14135
+ const url = panel ? new URL(explorePath, window.location.href) : new URL(pageUrl ?? window.location.href);
14013
14136
  url.search = "";
14014
14137
  url.hash = "";
14015
14138
  url.searchParams.set("c", token);
@@ -14025,6 +14148,8 @@ function ExplorePage({
14025
14148
  }, [
14026
14149
  createShareLink,
14027
14150
  pageUrl,
14151
+ panel,
14152
+ explorePath,
14028
14153
  T.copied,
14029
14154
  T.copying,
14030
14155
  T.share,
@@ -14053,12 +14178,15 @@ function ExplorePage({
14053
14178
  });
14054
14179
  return pickQueueRef.current;
14055
14180
  },
14056
- [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]
14057
14189
  );
14058
- const removeAttachment = useCallback((id) => {
14059
- setStaged((prev) => prev.filter((entry) => entry.id !== id));
14060
- setAttachmentNotice(null);
14061
- }, []);
14062
14190
  const submitDraft = useCallback(() => {
14063
14191
  const text = draft.trim();
14064
14192
  if (!text || overLimit || busy || !canSend) return;
@@ -14070,7 +14198,16 @@ function ExplorePage({
14070
14198
  setStaged([]);
14071
14199
  setAttachmentNotice(null);
14072
14200
  textareaRef.current?.focus();
14073
- }, [busy, canSend, draft, overLimit, send, stopDictation]);
14201
+ }, [
14202
+ busy,
14203
+ canSend,
14204
+ draft,
14205
+ overLimit,
14206
+ send,
14207
+ setDraft,
14208
+ setStaged,
14209
+ stopDictation
14210
+ ]);
14074
14211
  const sendPrompt = useCallback(
14075
14212
  (prompt) => {
14076
14213
  if (!canSend || busy) return;
@@ -14081,7 +14218,7 @@ function ExplorePage({
14081
14218
  setStaged([]);
14082
14219
  setAttachmentNotice(null);
14083
14220
  },
14084
- [busy, canSend, send]
14221
+ [busy, canSend, send, setDraft, setStaged]
14085
14222
  );
14086
14223
  const handleKeyDown = useCallback(
14087
14224
  (event) => {
@@ -14103,7 +14240,7 @@ function ExplorePage({
14103
14240
  [serverCatalogRaw]
14104
14241
  );
14105
14242
  const rootStyle = {};
14106
- if (heightMode === "viewport") {
14243
+ if (viewportPage) {
14107
14244
  rootStyle["--boff-explore-offset"] = paneOffset === null ? normalizeOffset(viewportOffset) : `${paneOffset}px`;
14108
14245
  if (bottomInset > 0) {
14109
14246
  rootStyle["--boff-explore-inset"] = `${bottomInset}px`;
@@ -14116,19 +14253,19 @@ function ExplorePage({
14116
14253
  "div",
14117
14254
  {
14118
14255
  ref: rootRef,
14119
- "data-boff-explore": "page",
14256
+ "data-boff-explore": panel ? "panel" : "page",
14120
14257
  "data-phase": phase,
14121
14258
  "data-locale": activeLocale,
14122
14259
  dir: rtl ? "rtl" : void 0,
14123
14260
  className: cn(
14124
- "flex w-full min-w-0 flex-col overflow-x-hidden bg-background text-foreground",
14125
- heightMode === "viewport" && "boff-explore-viewport",
14126
- 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]",
14127
14264
  className
14128
14265
  ),
14129
- style: rootStyle,
14266
+ style: panel ? void 0 : rootStyle,
14130
14267
  children: [
14131
- /* @__PURE__ */ jsx(
14268
+ panel ? null : /* @__PURE__ */ jsx(
14132
14269
  PageHead,
14133
14270
  {
14134
14271
  title: seo?.title ?? T.seoTitle,
@@ -14141,7 +14278,11 @@ function ExplorePage({
14141
14278
  ),
14142
14279
  /* @__PURE__ */ jsx(ProseStyles, {}),
14143
14280
  /* @__PURE__ */ jsx(ExploreStyles, {}),
14144
- 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(
14145
14286
  "script",
14146
14287
  {
14147
14288
  id: BAKED_CATALOG_ELEMENT_ID,
@@ -14161,7 +14302,7 @@ function ExplorePage({
14161
14302
  children: /* @__PURE__ */ jsx(Sparkles, { className: "h-4 w-4" })
14162
14303
  }
14163
14304
  ),
14164
- /* @__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 }),
14165
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,
14166
14307
  /* @__PURE__ */ jsxs(
14167
14308
  Button,
@@ -14305,6 +14446,7 @@ function ExplorePage({
14305
14446
  children: showWelcome ? /* @__PURE__ */ jsx(
14306
14447
  WelcomeState,
14307
14448
  {
14449
+ heading: panel ? "h2" : "h1",
14308
14450
  strings: T,
14309
14451
  title: resolvedTitle,
14310
14452
  body: resolvedBody,
@@ -14667,77 +14809,738 @@ function samePath(a, b) {
14667
14809
  const norm = (v) => v.length > 1 ? v.replace(/\/+$/, "") : v;
14668
14810
  return norm(a) === norm(b);
14669
14811
  }
14670
- function ExploreCta({
14671
- variant,
14672
- href = "/explore",
14673
- label = "Ask AI",
14674
- 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,
14675
15054
  onNavigate,
14676
- onClick,
14677
- currentPath
15055
+ welcomeTitle,
15056
+ welcomeBody,
15057
+ explorePath,
15058
+ avatar,
15059
+ bottomOffset,
15060
+ zIndex,
15061
+ returnFocusRef,
15062
+ className
14678
15063
  }) {
14679
- const path = useCurrentPath(currentPath);
14680
- const isActive = samePath(path, href);
14681
- if (variant === "floating" && isActive) return null;
14682
- const handleClick = (event) => {
14683
- onClick?.();
14684
- if (!onNavigate) return;
14685
- 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
+ }
14686
15288
  return;
14687
15289
  }
14688
- event.preventDefault();
14689
- onNavigate(href);
14690
- };
14691
- const classes = {
14692
- // A quiet icon control, deliberately NOT a second gradient pill: a header should carry one
14693
- // primary CTA ("Get started"), and a competing coloured button next to it reads as clutter.
14694
- // This matches the theme toggle's visual weight, so the row scans as [utilities] [CTA].
14695
- // The prominent, labelled entry point to /explore is the floating bubble, which is visible
14696
- // on every page without scrolling. `shrink-0` keeps it from squeezing the nav.
14697
- 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",
14698
- 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",
14699
- 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"
14700
- };
14701
- const hooks = {
14702
- header: "cta-header",
14703
- mobile: "cta-mobile",
14704
- 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) }
14705
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
+ ];
14706
15391
  return /* @__PURE__ */ jsxs(
14707
- "a",
15392
+ "div",
14708
15393
  {
14709
- "data-boff-explore": hooks[variant],
14710
- href,
14711
- onClick: handleClick,
14712
- "aria-label": label,
14713
- "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,
14714
15404
  className: cn(
14715
- classes[variant],
14716
- "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",
14717
15406
  className
14718
15407
  ),
15408
+ style,
15409
+ onKeyDown,
14719
15410
  children: [
14720
- /* @__PURE__ */ jsx(
14721
- Sparkles,
14722
- {
14723
- className: cn(
14724
- "shrink-0",
14725
- variant === "floating" ? "h-4 w-4" : variant === "header" ? "h-5 w-5" : "h-3.5 w-3.5"
14726
- ),
14727
- "aria-hidden": "true"
14728
- }
14729
- ),
14730
- /* @__PURE__ */ jsx(
14731
- "span",
14732
- {
14733
- className: cn(
14734
- variant === "floating" && "hidden sm:inline",
14735
- // Never labelled in the header — see the class comment above.
14736
- 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
+ }
14737
15462
  ),
14738
- children: label
14739
- }
14740
- )
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
+ ] })
14741
15544
  ]
14742
15545
  }
14743
15546
  );
@@ -19525,6 +20328,6 @@ function shouldRenderSiteFooter(pathname) {
19525
20328
  return !isFooterlessPath(pathname);
19526
20329
  }
19527
20330
 
19528
- 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 };
19529
20332
  //# sourceMappingURL=index.mjs.map
19530
20333
  //# sourceMappingURL=index.mjs.map