@burdenoff/website-sdk 2026.830.1 → 2026.922.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 (60) hide show
  1. package/README.md +114 -3
  2. package/dist/components/contact.js +4 -1
  3. package/dist/components/contact.js.map +1 -1
  4. package/dist/components/contact.mjs +4 -1
  5. package/dist/components/contact.mjs.map +1 -1
  6. package/dist/components/explore.d.mts +24 -3
  7. package/dist/components/explore.d.ts +24 -3
  8. package/dist/components/explore.js +690 -236
  9. package/dist/components/explore.js.map +1 -1
  10. package/dist/components/explore.mjs +690 -238
  11. package/dist/components/explore.mjs.map +1 -1
  12. package/dist/components/newsletter.js +4 -1
  13. package/dist/components/newsletter.js.map +1 -1
  14. package/dist/components/newsletter.mjs +4 -1
  15. package/dist/components/newsletter.mjs.map +1 -1
  16. package/dist/components/partners.js +23 -13
  17. package/dist/components/partners.js.map +1 -1
  18. package/dist/components/partners.mjs +23 -13
  19. package/dist/components/partners.mjs.map +1 -1
  20. package/dist/components/pricing.js +4 -1
  21. package/dist/components/pricing.js.map +1 -1
  22. package/dist/components/pricing.mjs +4 -1
  23. package/dist/components/pricing.mjs.map +1 -1
  24. package/dist/components/unsubscribe.js +4 -1
  25. package/dist/components/unsubscribe.js.map +1 -1
  26. package/dist/components/unsubscribe.mjs +4 -1
  27. package/dist/components/unsubscribe.mjs.map +1 -1
  28. package/dist/components/waitlist.js +4 -1
  29. package/dist/components/waitlist.js.map +1 -1
  30. package/dist/components/waitlist.mjs +4 -1
  31. package/dist/components/waitlist.mjs.map +1 -1
  32. package/dist/content/index.js +23 -13
  33. package/dist/content/index.js.map +1 -1
  34. package/dist/content/index.mjs +23 -13
  35. package/dist/content/index.mjs.map +1 -1
  36. package/dist/{use-explore-chat-B8xKGid5.d.mts → explore-types-CLw19R76.d.mts} +1 -143
  37. package/dist/{use-explore-chat-B8xKGid5.d.ts → explore-types-CLw19R76.d.ts} +1 -143
  38. package/dist/hooks/index.d.mts +2 -1
  39. package/dist/hooks/index.d.ts +2 -1
  40. package/dist/hooks/index.js +4 -1
  41. package/dist/hooks/index.js.map +1 -1
  42. package/dist/hooks/index.mjs +4 -1
  43. package/dist/hooks/index.mjs.map +1 -1
  44. package/dist/index.d.mts +141 -2
  45. package/dist/index.d.ts +141 -2
  46. package/dist/index.js +2025 -400
  47. package/dist/index.js.map +1 -1
  48. package/dist/index.mjs +2021 -403
  49. package/dist/index.mjs.map +1 -1
  50. package/dist/seo/index.js +4 -1
  51. package/dist/seo/index.js.map +1 -1
  52. package/dist/seo/index.mjs +4 -1
  53. package/dist/seo/index.mjs.map +1 -1
  54. package/dist/store/index.js +23 -13
  55. package/dist/store/index.js.map +1 -1
  56. package/dist/store/index.mjs +23 -13
  57. package/dist/store/index.mjs.map +1 -1
  58. package/dist/use-explore-chat-CvW-kyIm.d.mts +145 -0
  59. package/dist/use-explore-chat-DdGBimiz.d.ts +145 -0
  60. 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 } from 'react';
2
+ import { createContext, useMemo, useContext, useState, useCallback, useLayoutEffect, useRef, useEffect, useId, version } 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, Sparkles, RotateCcw, Link2, History, Trash2, Paperclip, X, Mic, Square, ArrowUp, BookOpenText, Layers, TriangleAlert, ChevronLeft, ChevronRight, FileText, ExternalLink } from 'lucide-react';
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, ChevronLeft, BookOpenText, Layers, TriangleAlert, FileText, ExternalLink } 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';
@@ -477,6 +477,9 @@ function resolveImageUrl(image, base) {
477
477
  return image;
478
478
  }
479
479
  }
480
+ function serializeJsonLd(data) {
481
+ return JSON.stringify(data).replace(/</g, "\\u003c").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
482
+ }
480
483
  function PageHead({
481
484
  title,
482
485
  description,
@@ -518,7 +521,7 @@ function PageHead({
518
521
  fullImageUrl && /* @__PURE__ */ jsx("meta", { name: "twitter:image", content: fullImageUrl }),
519
522
  twitterHandle && /* @__PURE__ */ jsx("meta", { name: "twitter:creator", content: twitterHandle }),
520
523
  /* @__PURE__ */ jsx("meta", { name: "theme-color", content: themeColor }),
521
- structuredDataItems.map((data, index) => /* @__PURE__ */ jsx("script", { type: "application/ld+json", children: JSON.stringify(data) }, `ld-${index}`)),
524
+ structuredDataItems.map((data, index) => /* @__PURE__ */ jsx("script", { type: "application/ld+json", children: serializeJsonLd(data) }, `ld-${index}`)),
522
525
  additionalMeta?.map((meta, index) => /* @__PURE__ */ jsx(
523
526
  "meta",
524
527
  {
@@ -1078,19 +1081,26 @@ function ContactPage({
1078
1081
  ] }) })
1079
1082
  ] });
1080
1083
  }
1084
+ function MarkdownLink({
1085
+ href,
1086
+ children,
1087
+ // react-markdown passes the hast node to every override; it is not a DOM attribute.
1088
+ node: _node,
1089
+ ...props
1090
+ }) {
1091
+ const isExternal = typeof href === "string" && (href.startsWith("http://") || href.startsWith("https://"));
1092
+ return /* @__PURE__ */ jsx(
1093
+ "a",
1094
+ {
1095
+ href,
1096
+ ...props,
1097
+ ...isExternal ? { target: "_blank", rel: "noopener noreferrer" } : { rel: "noopener noreferrer" },
1098
+ children
1099
+ }
1100
+ );
1101
+ }
1081
1102
  var defaultComponents = {
1082
- a: ({ href, children, ...props }) => {
1083
- const isExternal = typeof href === "string" && (href.startsWith("http://") || href.startsWith("https://"));
1084
- return /* @__PURE__ */ jsx(
1085
- "a",
1086
- {
1087
- href,
1088
- ...props,
1089
- ...isExternal ? { target: "_blank", rel: "noopener noreferrer" } : { rel: "noopener noreferrer" },
1090
- children
1091
- }
1092
- );
1093
- }
1103
+ a: MarkdownLink
1094
1104
  };
1095
1105
  function Markdown({
1096
1106
  children,
@@ -4736,171 +4746,1343 @@ function ElectronDownloadLink({
4736
4746
  );
4737
4747
  }
4738
4748
 
4739
- // src/components/explore-i18n.ts
4740
- var EXPLORE_LOCALES = ["en", "zh", "hi", "es", "ar", "ta"];
4741
- var RTL_LOCALES = /* @__PURE__ */ new Set(["ar"]);
4742
- function isRtlLocale(locale) {
4743
- return RTL_LOCALES.has(locale);
4749
+ // src/components/concepts-types.ts
4750
+ var CONCEPT_ILLUSTRATION_NOTICE = "These images are illustrations of the concept, not screenshots of the actual product.";
4751
+ var CONCEPTS_PATH = "/concepts";
4752
+ var CONCEPT_PATH_PREFIX = "/concept";
4753
+ function conceptPath(slug) {
4754
+ return `${CONCEPT_PATH_PREFIX}/${encodeURIComponent(slug)}`;
4755
+ }
4756
+ function getConceptBySlug(concepts, slug) {
4757
+ if (!slug) return void 0;
4758
+ const wanted = slug.trim().toLowerCase();
4759
+ if (!wanted) return void 0;
4760
+ return concepts.find((concept) => concept.slug === wanted);
4761
+ }
4762
+ var NAV_BUTTON = "inline-flex h-11 w-11 items-center justify-center rounded-full border border-border bg-card text-foreground shadow-md transition-colors hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring";
4763
+ function ConceptLightbox({
4764
+ images,
4765
+ index,
4766
+ conceptTitle,
4767
+ onIndexChange,
4768
+ onClose
4769
+ }) {
4770
+ const dialogRef = useRef(null);
4771
+ const closeRef = useRef(null);
4772
+ const nativeModalRef = useRef(false);
4773
+ const titleId = useId();
4774
+ const count = images.length;
4775
+ const position = count > 0 ? (index % count + count) % count : 0;
4776
+ const image = images[position];
4777
+ useEffect(() => {
4778
+ const dialog = dialogRef.current;
4779
+ if (!dialog) return;
4780
+ if (typeof dialog.showModal === "function") {
4781
+ if (!dialog.open) dialog.showModal();
4782
+ nativeModalRef.current = true;
4783
+ } else {
4784
+ dialog.setAttribute("open", "");
4785
+ nativeModalRef.current = false;
4786
+ }
4787
+ closeRef.current?.focus();
4788
+ return () => {
4789
+ if (dialog.open && typeof dialog.close === "function") dialog.close();
4790
+ };
4791
+ }, []);
4792
+ const go = useCallback(
4793
+ (delta) => {
4794
+ if (count < 2) return;
4795
+ onIndexChange((position + delta + count) % count);
4796
+ },
4797
+ [count, onIndexChange, position]
4798
+ );
4799
+ const handleClose = useCallback(
4800
+ (event) => {
4801
+ if (event.currentTarget.open) return;
4802
+ onClose();
4803
+ },
4804
+ [onClose]
4805
+ );
4806
+ const handleKeyDown = useCallback(
4807
+ (event) => {
4808
+ if (event.key === "ArrowRight") {
4809
+ event.preventDefault();
4810
+ go(1);
4811
+ } else if (event.key === "ArrowLeft") {
4812
+ event.preventDefault();
4813
+ go(-1);
4814
+ } else if (event.key === "Escape" && !nativeModalRef.current) {
4815
+ event.preventDefault();
4816
+ onClose();
4817
+ }
4818
+ },
4819
+ [go, onClose]
4820
+ );
4821
+ const handleStageClick = useCallback(
4822
+ (event) => {
4823
+ if (event.target === event.currentTarget) onClose();
4824
+ },
4825
+ [onClose]
4826
+ );
4827
+ if (!image) return null;
4828
+ return /* @__PURE__ */ jsx(
4829
+ "dialog",
4830
+ {
4831
+ ref: dialogRef,
4832
+ "data-concepts": "lightbox",
4833
+ "aria-labelledby": titleId,
4834
+ onClose: handleClose,
4835
+ onKeyDown: handleKeyDown,
4836
+ className: "fixed inset-0 z-50 m-0 h-full max-h-none w-full max-w-none overflow-y-auto overscroll-contain border-0 bg-background/95 p-0 text-foreground backdrop-blur-sm",
4837
+ children: /* @__PURE__ */ jsxs("div", { className: "flex min-h-full flex-col", children: [
4838
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-4 border-b border-border px-4 py-3 sm:px-6", children: [
4839
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
4840
+ /* @__PURE__ */ jsxs("p", { className: "truncate text-xs font-medium uppercase tracking-wide text-muted-foreground", children: [
4841
+ conceptTitle,
4842
+ count > 1 ? ` \xB7 ${position + 1} / ${count}` : null
4843
+ ] }),
4844
+ /* @__PURE__ */ jsx(
4845
+ "h2",
4846
+ {
4847
+ id: titleId,
4848
+ className: "truncate text-base font-semibold text-foreground sm:text-lg",
4849
+ children: image.title
4850
+ }
4851
+ )
4852
+ ] }),
4853
+ /* @__PURE__ */ jsx(
4854
+ "button",
4855
+ {
4856
+ ref: closeRef,
4857
+ type: "button",
4858
+ onClick: onClose,
4859
+ "aria-label": "Close",
4860
+ "data-concepts": "lightbox-close",
4861
+ className: "inline-flex h-10 w-10 shrink-0 items-center justify-center rounded-full border border-border bg-card text-foreground transition-colors hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
4862
+ children: /* @__PURE__ */ jsx(X, { "aria-hidden": "true", className: "h-5 w-5" })
4863
+ }
4864
+ )
4865
+ ] }),
4866
+ /* @__PURE__ */ jsxs(
4867
+ "div",
4868
+ {
4869
+ className: "relative flex flex-1 items-center justify-center px-4 py-4 sm:px-20",
4870
+ onClick: handleStageClick,
4871
+ children: [
4872
+ /* @__PURE__ */ jsx(
4873
+ "img",
4874
+ {
4875
+ src: image.src,
4876
+ alt: image.alt,
4877
+ width: image.width,
4878
+ height: image.height,
4879
+ decoding: "async",
4880
+ className: "h-auto max-h-[calc(100vh-14rem)] w-auto max-w-full rounded-lg border border-border bg-muted object-contain shadow-lg"
4881
+ },
4882
+ image.key
4883
+ ),
4884
+ count > 1 ? /* @__PURE__ */ jsxs(Fragment, { children: [
4885
+ /* @__PURE__ */ jsx(
4886
+ "button",
4887
+ {
4888
+ type: "button",
4889
+ onClick: () => go(-1),
4890
+ "aria-label": "Previous illustration",
4891
+ "data-concepts": "lightbox-prev",
4892
+ className: `absolute left-2 top-1/2 -translate-y-1/2 sm:left-4 ${NAV_BUTTON}`,
4893
+ children: /* @__PURE__ */ jsx(ChevronLeft, { "aria-hidden": "true", className: "h-5 w-5" })
4894
+ }
4895
+ ),
4896
+ /* @__PURE__ */ jsx(
4897
+ "button",
4898
+ {
4899
+ type: "button",
4900
+ onClick: () => go(1),
4901
+ "aria-label": "Next illustration",
4902
+ "data-concepts": "lightbox-next",
4903
+ className: `absolute right-2 top-1/2 -translate-y-1/2 sm:right-4 ${NAV_BUTTON}`,
4904
+ children: /* @__PURE__ */ jsx(ChevronRight, { "aria-hidden": "true", className: "h-5 w-5" })
4905
+ }
4906
+ )
4907
+ ] }) : null
4908
+ ]
4909
+ }
4910
+ ),
4911
+ /* @__PURE__ */ jsxs("div", { className: "border-t border-border px-4 py-3 sm:px-6", children: [
4912
+ /* @__PURE__ */ jsx("p", { className: "text-sm leading-relaxed text-foreground", children: image.caption }),
4913
+ /* @__PURE__ */ jsxs("p", { className: "mt-1.5 flex items-start gap-1.5 text-xs leading-relaxed text-muted-foreground", children: [
4914
+ /* @__PURE__ */ jsx(Info, { "aria-hidden": "true", className: "mt-0.5 h-3.5 w-3.5 shrink-0" }),
4915
+ /* @__PURE__ */ jsx("span", { children: CONCEPT_ILLUSTRATION_NOTICE })
4916
+ ] })
4917
+ ] })
4918
+ ] })
4919
+ }
4920
+ );
4744
4921
  }
4745
- var EN = {
4746
- badge: "AI answers, grounded in our documentation",
4747
- welcomeTitle: "Ask anything about our products",
4748
- welcomeBody: "Describe what you are trying to do and I will point you at the product, the page and the next step.",
4749
- tryAsking: "Try asking",
4750
- focusProduct: "Focus on a product",
4751
- allProducts: "All products",
4752
- showAll: "All",
4753
- showLess: "Show less",
4754
- sources: "Sources",
4755
- nextYouCouldAsk: "Next you could ask",
4756
- placeholder: "Ask anything about our products\u2026",
4757
- placeholderProduct: "Ask about {product}\u2026",
4758
- send: "Send",
4759
- stop: "Stop",
4760
- newChat: "New chat",
4761
- history: "History",
4762
- clearHistory: "Clear history",
4763
- share: "Share",
4764
- copied: "Copied",
4765
- copying: "Copying\u2026",
4766
- shareUnavailable: "Unavailable",
4767
- disclaimer: "Disclaimer",
4768
- disclaimerShort: "Grounded in our docs \u2014 check anything important.",
4769
- dictate: "Dictate your question",
4770
- stopDictating: "Stop dictating",
4771
- attach: "Attach files",
4772
- attachHint: "Up to {{max}} files, {{size}} MB each",
4773
- removeAttachment: "Remove {{name}}",
4774
- attachmentNameOnly: "name and type only",
4775
- attachmentTooLarge: "{{name}} is larger than {{size}} MB and was not attached.",
4776
- attachmentTooMany: "Only {{max}} files can be attached, so {{name}} was skipped.",
4777
- noAnswer: "I couldn't find this in our documentation, so the answer below is not grounded in a source. Try rephrasing, or",
4778
- answerDidNotArrive: "That answer didn't come through. Try asking again.",
4779
- askHuman: "ask a human",
4780
- prevSuggestion: "Previous suggestion",
4781
- nextSuggestion: "Next suggestion",
4782
- capabilities: [
4783
- "Grounded in our own docs",
4784
- "Compare across the ecosystem",
4785
- "Straight to the right page"
4786
- ],
4787
- prompts: [
4788
- "What does this product actually do?",
4789
- "Which product fits my team?",
4790
- "How do I get started, step by step?",
4791
- "How much does it cost?"
4792
- ]
4793
- };
4794
- var ZH = {
4795
- badge: "\u57FA\u4E8E\u6211\u4EEC\u6587\u6863\u7684 AI \u56DE\u7B54",
4796
- welcomeTitle: "\u5173\u4E8E\u6211\u4EEC\u7684\u4EA7\u54C1\uFF0C\u968F\u4FBF\u95EE",
4797
- welcomeBody: "\u63CF\u8FF0\u4F60\u60F3\u505A\u7684\u4E8B\uFF0C\u6211\u4F1A\u4E3A\u4F60\u6307\u51FA\u5BF9\u5E94\u7684\u4EA7\u54C1\u3001\u9875\u9762\u548C\u4E0B\u4E00\u6B65\u3002",
4798
- tryAsking: "\u8BD5\u7740\u95EE",
4799
- focusProduct: "\u805A\u7126\u67D0\u4E2A\u4EA7\u54C1",
4800
- allProducts: "\u5168\u90E8\u4EA7\u54C1",
4801
- showAll: "\u5168\u90E8",
4802
- showLess: "\u6536\u8D77",
4803
- sources: "\u6765\u6E90",
4804
- nextYouCouldAsk: "\u4F60\u8FD8\u53EF\u4EE5\u95EE",
4805
- placeholder: "\u5173\u4E8E\u6211\u4EEC\u7684\u4EA7\u54C1\uFF0C\u968F\u4FBF\u95EE\u2026",
4806
- placeholderProduct: "\u8BE2\u95EE\u5173\u4E8E {product} \u7684\u95EE\u9898\u2026",
4807
- send: "\u53D1\u9001",
4808
- stop: "\u505C\u6B62",
4809
- newChat: "\u65B0\u5BF9\u8BDD",
4810
- history: "\u5386\u53F2",
4811
- clearHistory: "\u6E05\u9664\u5386\u53F2",
4812
- share: "\u5206\u4EAB",
4813
- copied: "\u5DF2\u590D\u5236",
4814
- copying: "\u590D\u5236\u4E2D\u2026",
4815
- shareUnavailable: "\u4E0D\u53EF\u7528",
4816
- disclaimer: "\u514D\u8D23\u58F0\u660E",
4817
- disclaimerShort: "\u5185\u5BB9\u57FA\u4E8E\u6211\u4EEC\u7684\u6587\u6863\uFF0C\u91CD\u8981\u4FE1\u606F\u8BF7\u81EA\u884C\u6838\u5BF9\u3002",
4818
- dictate: "\u8BED\u97F3\u8F93\u5165",
4819
- stopDictating: "\u505C\u6B62\u8BED\u97F3\u8F93\u5165",
4820
- attach: "\u6DFB\u52A0\u6587\u4EF6",
4821
- attachHint: "\u6700\u591A {{max}} \u4E2A\u6587\u4EF6\uFF0C\u6BCF\u4E2A\u4E0D\u8D85\u8FC7 {{size}} MB",
4822
- removeAttachment: "\u79FB\u9664 {{name}}",
4823
- attachmentNameOnly: "\u4EC5\u6587\u4EF6\u540D\u548C\u7C7B\u578B",
4824
- attachmentTooLarge: "{{name}} \u8D85\u8FC7 {{size}} MB\uFF0C\u672A\u80FD\u6DFB\u52A0\u3002",
4825
- attachmentTooMany: "\u6700\u591A\u53EA\u80FD\u6DFB\u52A0 {{max}} \u4E2A\u6587\u4EF6\uFF0C\u5DF2\u8DF3\u8FC7 {{name}}\u3002",
4826
- noAnswer: "\u6211\u5728\u6587\u6863\u4E2D\u6CA1\u6709\u627E\u5230\u76F8\u5173\u5185\u5BB9\uFF0C\u4E0B\u9762\u7684\u56DE\u7B54\u6CA1\u6709\u6765\u6E90\u652F\u6301\u3002\u8BF7\u6362\u4E2A\u8BF4\u6CD5\uFF0C\u6216",
4827
- answerDidNotArrive: "\u8FD9\u6761\u56DE\u7B54\u6CA1\u6709\u8FD4\u56DE\u3002\u8BF7\u518D\u95EE\u4E00\u6B21\u3002",
4828
- askHuman: "\u8054\u7CFB\u6211\u4EEC",
4829
- prevSuggestion: "\u4E0A\u4E00\u4E2A\u5EFA\u8BAE",
4830
- nextSuggestion: "\u4E0B\u4E00\u4E2A\u5EFA\u8BAE",
4831
- capabilities: ["\u57FA\u4E8E\u6211\u4EEC\u81EA\u5DF1\u7684\u6587\u6863", "\u8DE8\u4EA7\u54C1\u5BF9\u6BD4", "\u76F4\u8FBE\u6B63\u786E\u7684\u9875\u9762"],
4832
- prompts: [
4833
- "\u8FD9\u4E2A\u4EA7\u54C1\u5230\u5E95\u80FD\u505A\u4EC0\u4E48\uFF1F",
4834
- "\u54EA\u4E2A\u4EA7\u54C1\u9002\u5408\u6211\u7684\u56E2\u961F\uFF1F",
4835
- "\u5982\u4F55\u4E00\u6B65\u6B65\u5F00\u59CB\u4F7F\u7528\uFF1F",
4836
- "\u4EF7\u683C\u662F\u591A\u5C11\uFF1F"
4837
- ]
4838
- };
4839
- var HI = {
4840
- badge: "\u0939\u092E\u093E\u0930\u0947 \u0926\u0938\u094D\u0924\u093E\u0935\u0947\u091C\u093C\u094B\u0902 \u092A\u0930 \u0906\u0927\u093E\u0930\u093F\u0924 AI \u0909\u0924\u094D\u0924\u0930",
4841
- welcomeTitle: "\u0939\u092E\u093E\u0930\u0947 \u0909\u0924\u094D\u092A\u093E\u0926\u094B\u0902 \u0915\u0947 \u092C\u093E\u0930\u0947 \u092E\u0947\u0902 \u0915\u0941\u091B \u092D\u0940 \u092A\u0942\u091B\u0947\u0902",
4842
- welcomeBody: "\u092C\u0924\u093E\u0907\u090F \u0906\u092A \u0915\u094D\u092F\u093E \u0915\u0930\u0928\u093E \u091A\u093E\u0939\u0924\u0947 \u0939\u0948\u0902, \u0914\u0930 \u092E\u0948\u0902 \u0906\u092A\u0915\u094B \u0938\u0939\u0940 \u0909\u0924\u094D\u092A\u093E\u0926, \u092A\u0947\u091C \u0914\u0930 \u0905\u0917\u0932\u093E \u0915\u0926\u092E \u092C\u0924\u093E\u090A\u0901\u0917\u093E\u0964",
4843
- tryAsking: "\u092F\u0939 \u092A\u0942\u091B\u0915\u0930 \u0926\u0947\u0916\u0947\u0902",
4844
- focusProduct: "\u0915\u093F\u0938\u0940 \u0909\u0924\u094D\u092A\u093E\u0926 \u092A\u0930 \u0927\u094D\u092F\u093E\u0928 \u0926\u0947\u0902",
4845
- allProducts: "\u0938\u092D\u0940 \u0909\u0924\u094D\u092A\u093E\u0926",
4846
- showAll: "\u0938\u092D\u0940",
4847
- showLess: "\u0915\u092E \u0926\u093F\u0916\u093E\u090F\u0901",
4848
- sources: "\u0938\u094D\u0930\u094B\u0924",
4849
- nextYouCouldAsk: "\u0906\u0917\u0947 \u0906\u092A \u092A\u0942\u091B \u0938\u0915\u0924\u0947 \u0939\u0948\u0902",
4850
- placeholder: "\u0939\u092E\u093E\u0930\u0947 \u0909\u0924\u094D\u092A\u093E\u0926\u094B\u0902 \u0915\u0947 \u092C\u093E\u0930\u0947 \u092E\u0947\u0902 \u0915\u0941\u091B \u092D\u0940 \u092A\u0942\u091B\u0947\u0902\u2026",
4851
- placeholderProduct: "{product} \u0915\u0947 \u092C\u093E\u0930\u0947 \u092E\u0947\u0902 \u092A\u0942\u091B\u0947\u0902\u2026",
4852
- send: "\u092D\u0947\u091C\u0947\u0902",
4853
- stop: "\u0930\u094B\u0915\u0947\u0902",
4854
- newChat: "\u0928\u0908 \u092C\u093E\u0924\u091A\u0940\u0924",
4855
- history: "\u0907\u0924\u093F\u0939\u093E\u0938",
4856
- clearHistory: "\u0907\u0924\u093F\u0939\u093E\u0938 \u092E\u093F\u091F\u093E\u090F\u0901",
4857
- share: "\u0938\u093E\u091D\u093E \u0915\u0930\u0947\u0902",
4858
- copied: "\u0915\u0949\u092A\u0940 \u0939\u094B \u0917\u092F\u093E",
4859
- copying: "\u0915\u0949\u092A\u0940 \u0939\u094B \u0930\u0939\u093E \u0939\u0948\u2026",
4860
- shareUnavailable: "\u0909\u092A\u0932\u092C\u094D\u0927 \u0928\u0939\u0940\u0902",
4861
- disclaimer: "\u0905\u0938\u094D\u0935\u0940\u0915\u0930\u0923",
4862
- disclaimerShort: "\u092F\u0939 \u0939\u092E\u093E\u0930\u0947 \u0926\u0938\u094D\u0924\u093E\u0935\u0947\u091C\u093C\u094B\u0902 \u092A\u0930 \u0906\u0927\u093E\u0930\u093F\u0924 \u0939\u0948 \u2014 \u092E\u0939\u0924\u094D\u0935\u092A\u0942\u0930\u094D\u0923 \u092C\u093E\u0924\u0947\u0902 \u091C\u093C\u0930\u0942\u0930 \u091C\u093E\u0901\u091A \u0932\u0947\u0902\u0964",
4863
- dictate: "\u092C\u094B\u0932\u0915\u0930 \u092A\u0942\u091B\u0947\u0902",
4864
- stopDictating: "\u092C\u094B\u0932\u0928\u093E \u092C\u0902\u0926 \u0915\u0930\u0947\u0902",
4865
- attach: "\u092B\u093C\u093E\u0907\u0932\u0947\u0902 \u091C\u094B\u0921\u093C\u0947\u0902",
4866
- attachHint: "\u0905\u0927\u093F\u0915\u0924\u092E {{max}} \u092B\u093C\u093E\u0907\u0932\u0947\u0902, \u092A\u094D\u0930\u0924\u094D\u092F\u0947\u0915 {{size}} MB \u0924\u0915",
4867
- removeAttachment: "{{name}} \u0939\u091F\u093E\u090F\u0901",
4868
- attachmentNameOnly: "\u0915\u0947\u0935\u0932 \u0928\u093E\u092E \u0914\u0930 \u092A\u094D\u0930\u0915\u093E\u0930",
4869
- attachmentTooLarge: "{{name}} {{size}} MB \u0938\u0947 \u092C\u0921\u093C\u0940 \u0939\u0948, \u0907\u0938\u0932\u093F\u090F \u091C\u094B\u0921\u093C\u0940 \u0928\u0939\u0940\u0902 \u0917\u0908\u0964",
4870
- attachmentTooMany: "\u0915\u0947\u0935\u0932 {{max}} \u092B\u093C\u093E\u0907\u0932\u0947\u0902 \u091C\u094B\u0921\u093C\u0940 \u091C\u093E \u0938\u0915\u0924\u0940 \u0939\u0948\u0902, \u0907\u0938\u0932\u093F\u090F {{name}} \u091B\u094B\u0921\u093C \u0926\u0940 \u0917\u0908\u0964",
4871
- noAnswer: "\u092F\u0939 \u092E\u0941\u091D\u0947 \u0939\u092E\u093E\u0930\u0947 \u0926\u0938\u094D\u0924\u093E\u0935\u0947\u091C\u093C\u094B\u0902 \u092E\u0947\u0902 \u0928\u0939\u0940\u0902 \u092E\u093F\u0932\u093E, \u0907\u0938\u0932\u093F\u090F \u0928\u0940\u091A\u0947 \u0926\u093F\u092F\u093E \u0909\u0924\u094D\u0924\u0930 \u0915\u093F\u0938\u0940 \u0938\u094D\u0930\u094B\u0924 \u092A\u0930 \u0906\u0927\u093E\u0930\u093F\u0924 \u0928\u0939\u0940\u0902 \u0939\u0948\u0964 \u0926\u0942\u0938\u0930\u0947 \u0936\u092C\u094D\u0926\u094B\u0902 \u092E\u0947\u0902 \u092A\u0942\u091B\u0947\u0902, \u092F\u093E",
4872
- answerDidNotArrive: "\u0935\u0939 \u0909\u0924\u094D\u0924\u0930 \u0928\u0939\u0940\u0902 \u0906 \u0938\u0915\u093E\u0964 \u0915\u0943\u092A\u092F\u093E \u0926\u094B\u092C\u093E\u0930\u093E \u092A\u0942\u091B\u0947\u0902\u0964",
4873
- askHuman: "\u0939\u092E\u0938\u0947 \u0938\u0902\u092A\u0930\u094D\u0915 \u0915\u0930\u0947\u0902",
4874
- prevSuggestion: "\u092A\u093F\u091B\u0932\u093E \u0938\u0941\u091D\u093E\u0935",
4875
- nextSuggestion: "\u0905\u0917\u0932\u093E \u0938\u0941\u091D\u093E\u0935",
4876
- capabilities: [
4877
- "\u0939\u092E\u093E\u0930\u0947 \u0905\u092A\u0928\u0947 \u0926\u0938\u094D\u0924\u093E\u0935\u0947\u091C\u093C\u094B\u0902 \u092A\u0930 \u0906\u0927\u093E\u0930\u093F\u0924",
4878
- "\u0938\u092D\u0940 \u0909\u0924\u094D\u092A\u093E\u0926\u094B\u0902 \u0915\u0940 \u0924\u0941\u0932\u0928\u093E \u0915\u0930\u0947\u0902",
4879
- "\u0938\u0940\u0927\u0947 \u0938\u0939\u0940 \u092A\u0947\u091C \u092A\u0930"
4880
- ],
4881
- prompts: [
4882
- "\u092F\u0939 \u0909\u0924\u094D\u092A\u093E\u0926 \u0905\u0938\u0932 \u092E\u0947\u0902 \u0915\u094D\u092F\u093E \u0915\u0930\u0924\u093E \u0939\u0948?",
4883
- "\u092E\u0947\u0930\u0940 \u091F\u0940\u092E \u0915\u0947 \u0932\u093F\u090F \u0915\u094C\u0928 \u0938\u093E \u0909\u0924\u094D\u092A\u093E\u0926 \u0938\u0939\u0940 \u0939\u0948?",
4884
- "\u0936\u0941\u0930\u0941\u0906\u0924 \u0915\u0948\u0938\u0947 \u0915\u0930\u0947\u0902, \u091A\u0930\u0923 \u0926\u0930 \u091A\u0930\u0923?",
4885
- "\u0907\u0938\u0915\u0940 \u0915\u0940\u092E\u0924 \u0915\u093F\u0924\u0928\u0940 \u0939\u0948?"
4886
- ]
4887
- };
4888
- var ES = {
4889
- badge: "Respuestas de IA basadas en nuestra documentaci\xF3n",
4890
- welcomeTitle: "Pregunta lo que quieras sobre nuestros productos",
4891
- welcomeBody: "Cu\xE9ntame qu\xE9 necesitas hacer y te indicar\xE9 el producto, la p\xE1gina y el siguiente paso.",
4892
- tryAsking: "Prueba a preguntar",
4893
- focusProduct: "Centrarse en un producto",
4894
- allProducts: "Todos los productos",
4895
- showAll: "Todos",
4896
- showLess: "Ver menos",
4897
- sources: "Fuentes",
4898
- nextYouCouldAsk: "Tambi\xE9n puedes preguntar",
4899
- placeholder: "Pregunta lo que quieras sobre nuestros productos\u2026",
4900
- placeholderProduct: "Pregunta sobre {product}\u2026",
4901
- send: "Enviar",
4902
- stop: "Detener",
4903
- newChat: "Nueva conversaci\xF3n",
4922
+ var META_DESCRIPTION_LIMIT = 160;
4923
+ var RELATED_LIMIT = 4;
4924
+ var HERO_FETCH_PRIORITY = Number.parseInt(version, 10) >= 19 ? { fetchPriority: "high" } : { fetchpriority: "high" };
4925
+ function normaliseSiteUrl(siteUrl) {
4926
+ return siteUrl.trim().replace(/\/+$/, "");
4927
+ }
4928
+ function absoluteUrl(base, path) {
4929
+ if (/^https?:\/\//i.test(path)) return path;
4930
+ return `${base}${path.startsWith("/") ? path : `/${path}`}`;
4931
+ }
4932
+ function sortByOrder(concepts) {
4933
+ return [...concepts].sort(
4934
+ (a, b) => a.order - b.order || a.slug.localeCompare(b.slug)
4935
+ );
4936
+ }
4937
+ function plural(count, singular, pluralForm) {
4938
+ return `${count} ${count === 1 ? singular : pluralForm}`;
4939
+ }
4940
+ function illustrationCount(count) {
4941
+ return plural(count, "illustration", "illustrations");
4942
+ }
4943
+ function listSentence(items) {
4944
+ if (items.length <= 1) return items.join("");
4945
+ return `${items.slice(0, -1).join(", ")} and ${items[items.length - 1]}`;
4946
+ }
4947
+ function clampText(text, limit) {
4948
+ if (text.length <= limit) return text;
4949
+ const cut = text.slice(0, limit - 1);
4950
+ const lastSpace = cut.lastIndexOf(" ");
4951
+ return `${(lastSpace > 0 ? cut.slice(0, lastSpace) : cut).replace(/[\s,;:—–-]+$/, "")}\u2026`;
4952
+ }
4953
+ function defaultLandingDescription(productName, conceptTotal, imageTotal, categoryNames) {
4954
+ if (conceptTotal === 0) {
4955
+ return clampText(
4956
+ `Concepts of how ${productName} works, each a feature or flow explained with illustrations.`,
4957
+ META_DESCRIPTION_LIMIT
4958
+ );
4959
+ }
4960
+ const head = `Explore ${plural(conceptTotal, `${productName} concept`, `${productName} concepts`)} with ${illustrationCount(imageTotal)}`;
4961
+ for (let take = Math.min(categoryNames.length, 4); take >= 1; take -= 1) {
4962
+ const more = categoryNames.length > take ? " and more" : "";
4963
+ const text = `${head} across ${listSentence(categoryNames.slice(0, take))}${more}.`;
4964
+ if (text.length <= META_DESCRIPTION_LIMIT) return text;
4965
+ }
4966
+ return clampText(`${head} of how the product works.`, META_DESCRIPTION_LIMIT);
4967
+ }
4968
+ function slugifyAnchor(value) {
4969
+ return value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
4970
+ }
4971
+ function groupByCategory(ordered, categories) {
4972
+ const byName = /* @__PURE__ */ new Map();
4973
+ for (const concept of ordered) {
4974
+ const list = byName.get(concept.category);
4975
+ if (list) list.push(concept);
4976
+ else byName.set(concept.category, [concept]);
4977
+ }
4978
+ const described = [];
4979
+ for (const category of categories ?? []) {
4980
+ const list = byName.get(category.name);
4981
+ if (!list) continue;
4982
+ described.push({
4983
+ name: category.name,
4984
+ description: category.description,
4985
+ concepts: list
4986
+ });
4987
+ byName.delete(category.name);
4988
+ }
4989
+ for (const [name, list] of byName) {
4990
+ described.push({ name, description: "", concepts: list });
4991
+ }
4992
+ const used = /* @__PURE__ */ new Set();
4993
+ return described.map((group) => {
4994
+ const base = `concepts-${slugifyAnchor(group.name) || "category"}`;
4995
+ let anchor = base;
4996
+ for (let n = 2; used.has(anchor); n += 1) anchor = `${base}-${n}`;
4997
+ used.add(anchor);
4998
+ return { ...group, anchor };
4999
+ });
5000
+ }
5001
+ function searchTokens(query) {
5002
+ return query.toLowerCase().split(/\s+/).filter(Boolean);
5003
+ }
5004
+ function matchesSearch(concept, tokens) {
5005
+ if (tokens.length === 0) return true;
5006
+ const haystack = [
5007
+ concept.title,
5008
+ concept.tagline,
5009
+ concept.category,
5010
+ ...concept.keywords
5011
+ ].join(" ").toLowerCase();
5012
+ return tokens.every((token) => haystack.includes(token));
5013
+ }
5014
+ function isPortrait(width, height) {
5015
+ return height > width;
5016
+ }
5017
+ function copyKey(index, text) {
5018
+ return `${index}-${text}`;
5019
+ }
5020
+ function DefaultConceptLink({
5021
+ href,
5022
+ className,
5023
+ children,
5024
+ "aria-label": ariaLabel
5025
+ }) {
5026
+ return /* @__PURE__ */ jsx("a", { href, className, "aria-label": ariaLabel, children });
5027
+ }
5028
+ function IllustrationNotice({ className }) {
5029
+ return /* @__PURE__ */ jsxs(
5030
+ "div",
5031
+ {
5032
+ role: "note",
5033
+ "data-concepts": "notice",
5034
+ "data-concepts-notice": "",
5035
+ className: cn(
5036
+ "flex items-start gap-3 rounded-xl border border-primary/30 bg-primary/10 px-4 py-3 text-sm leading-relaxed text-foreground",
5037
+ className
5038
+ ),
5039
+ children: [
5040
+ /* @__PURE__ */ jsx(
5041
+ Info,
5042
+ {
5043
+ "aria-hidden": "true",
5044
+ className: "mt-0.5 h-4 w-4 shrink-0 text-primary"
5045
+ }
5046
+ ),
5047
+ /* @__PURE__ */ jsx("p", { children: CONCEPT_ILLUSTRATION_NOTICE })
5048
+ ]
5049
+ }
5050
+ );
5051
+ }
5052
+ function IllustrationBadge({ className }) {
5053
+ return /* @__PURE__ */ jsx(
5054
+ "span",
5055
+ {
5056
+ "aria-hidden": "true",
5057
+ className: cn(
5058
+ "pointer-events-none absolute left-2 top-2 inline-flex items-center rounded-full border border-border bg-background/90 px-2 py-0.5 text-[11px] font-semibold uppercase tracking-wide text-foreground shadow-sm",
5059
+ className
5060
+ ),
5061
+ children: "Illustration"
5062
+ }
5063
+ );
5064
+ }
5065
+ function ConceptCard({
5066
+ concept,
5067
+ Link
5068
+ }) {
5069
+ const image = concept.images[0];
5070
+ const portrait = image ? isPortrait(image.thumbWidth, image.thumbHeight) : false;
5071
+ return /* @__PURE__ */ jsxs(
5072
+ Link,
5073
+ {
5074
+ href: conceptPath(concept.slug),
5075
+ className: "group flex h-full flex-col overflow-hidden rounded-2xl border border-border bg-card text-card-foreground shadow-sm transition hover:-translate-y-0.5 hover:border-primary/40 hover:shadow-md focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring motion-reduce:transform-none motion-reduce:transition-none",
5076
+ children: [
5077
+ /* @__PURE__ */ jsxs("div", { className: "relative aspect-[16/10] overflow-hidden border-b border-border bg-muted", children: [
5078
+ image ? /* @__PURE__ */ jsx(
5079
+ "img",
5080
+ {
5081
+ src: image.thumb,
5082
+ alt: "",
5083
+ width: image.thumbWidth,
5084
+ height: image.thumbHeight,
5085
+ loading: "lazy",
5086
+ decoding: "async",
5087
+ className: cn(
5088
+ "h-full w-full",
5089
+ portrait ? "object-contain p-3" : "object-cover object-top"
5090
+ )
5091
+ }
5092
+ ) : null,
5093
+ /* @__PURE__ */ jsx(IllustrationBadge, {})
5094
+ ] }),
5095
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col gap-2 p-4", children: [
5096
+ /* @__PURE__ */ jsx("h3", { className: "text-base font-semibold leading-snug text-card-foreground transition-colors group-hover:text-primary", children: concept.title }),
5097
+ /* @__PURE__ */ jsx("p", { className: "line-clamp-3 text-sm leading-relaxed text-muted-foreground", children: concept.tagline }),
5098
+ /* @__PURE__ */ jsxs("span", { className: "mt-auto inline-flex items-center gap-1.5 pt-1 text-xs font-medium text-muted-foreground", children: [
5099
+ /* @__PURE__ */ jsx(ImageIcon, { "aria-hidden": "true", className: "h-3.5 w-3.5" }),
5100
+ illustrationCount(concept.images.length)
5101
+ ] })
5102
+ ] })
5103
+ ]
5104
+ }
5105
+ );
5106
+ }
5107
+ function FilterChip({
5108
+ label,
5109
+ count,
5110
+ active,
5111
+ category,
5112
+ onSelect
5113
+ }) {
5114
+ return /* @__PURE__ */ jsxs(
5115
+ "button",
5116
+ {
5117
+ type: "button",
5118
+ "aria-pressed": active,
5119
+ "data-category": category,
5120
+ onClick: onSelect,
5121
+ className: cn(
5122
+ "inline-flex items-center gap-2 rounded-full border px-3 py-1.5 text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
5123
+ active ? "border-primary bg-primary text-primary-foreground" : "border-border bg-card text-foreground hover:border-primary/40 hover:bg-muted"
5124
+ ),
5125
+ children: [
5126
+ /* @__PURE__ */ jsx("span", { children: label }),
5127
+ /* @__PURE__ */ jsx(
5128
+ "span",
5129
+ {
5130
+ className: cn(
5131
+ "rounded-full px-1.5 text-xs tabular-nums",
5132
+ active ? "bg-primary-foreground/20 text-primary-foreground" : "bg-muted text-muted-foreground"
5133
+ ),
5134
+ children: count
5135
+ }
5136
+ )
5137
+ ]
5138
+ }
5139
+ );
5140
+ }
5141
+ function ConceptsPage({
5142
+ productName,
5143
+ siteUrl,
5144
+ concepts,
5145
+ categories,
5146
+ cta,
5147
+ linkComponent,
5148
+ title,
5149
+ description,
5150
+ className
5151
+ }) {
5152
+ const Link = linkComponent ?? DefaultConceptLink;
5153
+ const base = normaliseSiteUrl(siteUrl);
5154
+ const searchId = useId();
5155
+ const ordered = useMemo(() => sortByOrder(concepts), [concepts]);
5156
+ const groups = useMemo(
5157
+ () => groupByCategory(ordered, categories),
5158
+ [ordered, categories]
5159
+ );
5160
+ const imageTotal = useMemo(
5161
+ () => ordered.reduce((sum, concept) => sum + concept.images.length, 0),
5162
+ [ordered]
5163
+ );
5164
+ const [query, setQuery] = useState("");
5165
+ const [activeCategory, setActiveCategory] = useState(null);
5166
+ const hasConcepts = ordered.length > 0;
5167
+ const tokens = useMemo(() => searchTokens(query), [query]);
5168
+ const searched = useMemo(
5169
+ () => ordered.filter((concept) => matchesSearch(concept, tokens)),
5170
+ [ordered, tokens]
5171
+ );
5172
+ const countsByCategory = useMemo(() => {
5173
+ const counts = /* @__PURE__ */ new Map();
5174
+ for (const concept of searched) {
5175
+ counts.set(concept.category, (counts.get(concept.category) ?? 0) + 1);
5176
+ }
5177
+ return counts;
5178
+ }, [searched]);
5179
+ const visibleGroups = useMemo(() => {
5180
+ const visible = new Set(
5181
+ searched.filter(
5182
+ (concept) => activeCategory === null || concept.category === activeCategory
5183
+ )
5184
+ );
5185
+ return groups.map((group) => ({
5186
+ ...group,
5187
+ concepts: group.concepts.filter((concept) => visible.has(concept))
5188
+ })).filter((group) => group.concepts.length > 0);
5189
+ }, [groups, searched, activeCategory]);
5190
+ const visibleTotal = visibleGroups.reduce(
5191
+ (sum, group) => sum + group.concepts.length,
5192
+ 0
5193
+ );
5194
+ const filtering = tokens.length > 0 || activeCategory !== null;
5195
+ const clearFilters = useCallback(() => {
5196
+ setQuery("");
5197
+ setActiveCategory(null);
5198
+ }, []);
5199
+ const heading = title ?? `${productName} concepts`;
5200
+ const metaDescription = description ?? defaultLandingDescription(
5201
+ productName,
5202
+ ordered.length,
5203
+ imageTotal,
5204
+ groups.map((group) => group.name)
5205
+ );
5206
+ const lead = description ?? `A guided tour of ${productName}, one concept at a time. Each concept groups the illustrations of a feature or flow and explains what it does, how it works and who it is for.`;
5207
+ const canonical = `${base}${CONCEPTS_PATH}`;
5208
+ const firstImage = ordered.find((concept) => concept.images[0])?.images[0];
5209
+ const structuredData = useMemo(
5210
+ () => [
5211
+ {
5212
+ "@context": "https://schema.org",
5213
+ "@type": "CollectionPage",
5214
+ name: heading,
5215
+ description: metaDescription,
5216
+ url: canonical,
5217
+ isPartOf: { "@type": "WebSite", name: productName, url: `${base}/` },
5218
+ mainEntity: {
5219
+ "@type": "ItemList",
5220
+ numberOfItems: ordered.length,
5221
+ itemListElement: ordered.map((concept, index) => {
5222
+ const image = concept.images[0];
5223
+ return {
5224
+ "@type": "ListItem",
5225
+ position: index + 1,
5226
+ url: absoluteUrl(base, conceptPath(concept.slug)),
5227
+ name: concept.title,
5228
+ ...image ? { image: absoluteUrl(base, image.src) } : {}
5229
+ };
5230
+ })
5231
+ }
5232
+ },
5233
+ {
5234
+ "@context": "https://schema.org",
5235
+ "@type": "BreadcrumbList",
5236
+ itemListElement: [
5237
+ { "@type": "ListItem", position: 1, name: "Home", item: `${base}/` },
5238
+ {
5239
+ "@type": "ListItem",
5240
+ position: 2,
5241
+ name: "Concepts",
5242
+ item: canonical
5243
+ }
5244
+ ]
5245
+ }
5246
+ ],
5247
+ [base, canonical, heading, metaDescription, ordered, productName]
5248
+ );
5249
+ return /* @__PURE__ */ jsxs(
5250
+ "div",
5251
+ {
5252
+ "data-concepts": "landing",
5253
+ className: cn("bg-background text-foreground", className),
5254
+ children: [
5255
+ /* @__PURE__ */ jsx(
5256
+ PageHead,
5257
+ {
5258
+ title: "Concepts",
5259
+ description: metaDescription,
5260
+ productName,
5261
+ keywords: [
5262
+ `${productName} concepts`,
5263
+ `${productName} illustrations`,
5264
+ ...groups.map((group) => group.name)
5265
+ ].join(", "),
5266
+ image: firstImage ? absoluteUrl(base, firstImage.src) : void 0,
5267
+ url: canonical,
5268
+ structuredData
5269
+ }
5270
+ ),
5271
+ /* @__PURE__ */ jsx("section", { className: "border-b border-border bg-muted/30", children: /* @__PURE__ */ jsxs("div", { className: "mx-auto max-w-6xl px-4 py-14 sm:px-6 sm:py-20 lg:px-8", children: [
5272
+ /* @__PURE__ */ jsx("p", { className: "text-xs font-semibold uppercase tracking-[0.2em] text-primary", children: "Concepts" }),
5273
+ /* @__PURE__ */ jsx("h1", { className: "mt-3 max-w-3xl text-4xl font-bold tracking-tight text-foreground sm:text-5xl", children: heading }),
5274
+ /* @__PURE__ */ jsx("p", { className: "mt-4 max-w-2xl text-lg leading-relaxed text-muted-foreground", children: lead }),
5275
+ hasConcepts ? /* @__PURE__ */ jsxs("p", { className: "mt-6 flex flex-wrap gap-x-6 gap-y-2 text-sm text-muted-foreground", children: [
5276
+ /* @__PURE__ */ jsxs("span", { children: [
5277
+ /* @__PURE__ */ jsx("strong", { className: "text-lg font-semibold text-foreground", children: ordered.length }),
5278
+ " ",
5279
+ ordered.length === 1 ? "concept" : "concepts"
5280
+ ] }),
5281
+ /* @__PURE__ */ jsxs("span", { children: [
5282
+ /* @__PURE__ */ jsx("strong", { className: "text-lg font-semibold text-foreground", children: imageTotal }),
5283
+ " ",
5284
+ imageTotal === 1 ? "illustration" : "illustrations"
5285
+ ] })
5286
+ ] }) : null,
5287
+ /* @__PURE__ */ jsx(IllustrationNotice, { className: "mt-6 max-w-2xl" }),
5288
+ cta ? /* @__PURE__ */ jsx("div", { className: "mt-8 flex flex-wrap gap-3", children: cta }) : null
5289
+ ] }) }),
5290
+ /* @__PURE__ */ jsx("div", { className: "mx-auto max-w-6xl px-4 pb-20 sm:px-6 lg:px-8", children: hasConcepts ? /* @__PURE__ */ jsxs(Fragment, { children: [
5291
+ /* @__PURE__ */ jsxs(
5292
+ "div",
5293
+ {
5294
+ role: "search",
5295
+ "data-concepts": "filter",
5296
+ className: "flex flex-col gap-4 py-8",
5297
+ children: [
5298
+ /* @__PURE__ */ jsxs("div", { className: "relative w-full max-w-md", children: [
5299
+ /* @__PURE__ */ jsx(
5300
+ Search,
5301
+ {
5302
+ "aria-hidden": "true",
5303
+ className: "pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground"
5304
+ }
5305
+ ),
5306
+ /* @__PURE__ */ jsx("label", { htmlFor: searchId, className: "sr-only", children: "Search concepts" }),
5307
+ /* @__PURE__ */ jsx(
5308
+ "input",
5309
+ {
5310
+ id: searchId,
5311
+ type: "search",
5312
+ value: query,
5313
+ onChange: (event) => setQuery(event.target.value),
5314
+ placeholder: "Search concepts",
5315
+ autoComplete: "off",
5316
+ className: "h-10 w-full rounded-lg border border-border bg-background pl-9 pr-3 text-sm text-foreground shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
5317
+ }
5318
+ )
5319
+ ] }),
5320
+ /* @__PURE__ */ jsxs(
5321
+ "div",
5322
+ {
5323
+ role: "group",
5324
+ "aria-label": "Filter by category",
5325
+ className: "flex flex-wrap gap-2",
5326
+ children: [
5327
+ /* @__PURE__ */ jsx(
5328
+ FilterChip,
5329
+ {
5330
+ label: "All",
5331
+ category: "all",
5332
+ count: searched.length,
5333
+ active: activeCategory === null,
5334
+ onSelect: () => setActiveCategory(null)
5335
+ }
5336
+ ),
5337
+ groups.map((group) => /* @__PURE__ */ jsx(
5338
+ FilterChip,
5339
+ {
5340
+ label: group.name,
5341
+ category: group.name,
5342
+ count: countsByCategory.get(group.name) ?? 0,
5343
+ active: activeCategory === group.name,
5344
+ onSelect: () => setActiveCategory(
5345
+ (current) => current === group.name ? null : group.name
5346
+ )
5347
+ },
5348
+ group.anchor
5349
+ ))
5350
+ ]
5351
+ }
5352
+ ),
5353
+ /* @__PURE__ */ jsxs(
5354
+ "p",
5355
+ {
5356
+ "aria-live": "polite",
5357
+ className: filtering ? "text-sm text-muted-foreground" : "sr-only",
5358
+ children: [
5359
+ "Showing ",
5360
+ visibleTotal,
5361
+ " of ",
5362
+ ordered.length,
5363
+ " ",
5364
+ ordered.length === 1 ? "concept" : "concepts"
5365
+ ]
5366
+ }
5367
+ )
5368
+ ]
5369
+ }
5370
+ ),
5371
+ visibleTotal === 0 ? /* @__PURE__ */ jsxs(
5372
+ "div",
5373
+ {
5374
+ "data-concepts": "empty",
5375
+ className: "rounded-2xl border border-dashed border-border bg-muted/30 px-6 py-14 text-center",
5376
+ children: [
5377
+ /* @__PURE__ */ jsx(
5378
+ Search,
5379
+ {
5380
+ "aria-hidden": "true",
5381
+ className: "mx-auto h-8 w-8 text-muted-foreground"
5382
+ }
5383
+ ),
5384
+ /* @__PURE__ */ jsx("h2", { className: "mt-4 text-lg font-semibold text-foreground", children: "No concepts match your filters" }),
5385
+ /* @__PURE__ */ jsx("p", { className: "mt-2 text-sm text-muted-foreground", children: "Try a different search, or show every category." }),
5386
+ /* @__PURE__ */ jsx(
5387
+ "button",
5388
+ {
5389
+ type: "button",
5390
+ onClick: clearFilters,
5391
+ className: "mt-6 inline-flex items-center rounded-full border border-border bg-card px-4 py-2 text-sm font-medium text-foreground transition-colors hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
5392
+ children: "Clear filters"
5393
+ }
5394
+ )
5395
+ ]
5396
+ }
5397
+ ) : /* @__PURE__ */ jsx("div", { className: "space-y-14", children: visibleGroups.map((group) => /* @__PURE__ */ jsxs("section", { "aria-labelledby": group.anchor, children: [
5398
+ /* @__PURE__ */ jsxs("div", { className: "max-w-3xl", children: [
5399
+ /* @__PURE__ */ jsx(
5400
+ "h2",
5401
+ {
5402
+ id: group.anchor,
5403
+ className: "scroll-mt-24 text-2xl font-semibold tracking-tight text-foreground",
5404
+ children: group.name
5405
+ }
5406
+ ),
5407
+ group.description ? /* @__PURE__ */ jsx("p", { className: "mt-2 leading-relaxed text-muted-foreground", children: group.description }) : null
5408
+ ] }),
5409
+ /* @__PURE__ */ jsx(
5410
+ "ul",
5411
+ {
5412
+ role: "list",
5413
+ className: "mt-6 grid grid-cols-1 gap-5 sm:grid-cols-2 lg:grid-cols-3",
5414
+ children: group.concepts.map((concept) => /* @__PURE__ */ jsx(
5415
+ "li",
5416
+ {
5417
+ "data-concepts": "card",
5418
+ "data-slug": concept.slug,
5419
+ children: /* @__PURE__ */ jsx(ConceptCard, { concept, Link })
5420
+ },
5421
+ concept.slug
5422
+ ))
5423
+ }
5424
+ )
5425
+ ] }, group.anchor)) })
5426
+ ] }) : (
5427
+ // Nothing published yet: no filter bar with an "All 0" chip, and no empty state
5428
+ // that blames filters the visitor never set.
5429
+ /* @__PURE__ */ jsxs(
5430
+ "div",
5431
+ {
5432
+ "data-concepts": "none",
5433
+ className: "mt-10 rounded-2xl border border-dashed border-border bg-muted/30 px-6 py-14 text-center",
5434
+ children: [
5435
+ /* @__PURE__ */ jsx(
5436
+ ImageIcon,
5437
+ {
5438
+ "aria-hidden": "true",
5439
+ className: "mx-auto h-8 w-8 text-muted-foreground"
5440
+ }
5441
+ ),
5442
+ /* @__PURE__ */ jsx("h2", { className: "mt-4 text-lg font-semibold text-foreground", children: "No concepts published yet" }),
5443
+ /* @__PURE__ */ jsxs("p", { className: "mt-2 text-sm text-muted-foreground", children: [
5444
+ productName,
5445
+ " concepts will appear here as they are published."
5446
+ ] })
5447
+ ]
5448
+ }
5449
+ )
5450
+ ) })
5451
+ ]
5452
+ }
5453
+ );
5454
+ }
5455
+ var SECTION_HEADING = "scroll-mt-24 text-2xl font-semibold tracking-tight text-foreground";
5456
+ var CHIP = "inline-flex items-center rounded-full border border-border bg-muted/50 px-3 py-1 text-sm text-foreground";
5457
+ function IllustrationFigure({
5458
+ image,
5459
+ onOpen
5460
+ }) {
5461
+ const portrait = isPortrait(image.width, image.height);
5462
+ return (
5463
+ // The block the llms extractor reads: title, image line, caption, description — in
5464
+ // that order and with nothing in between. The description sits outside <figure>
5465
+ // because a <figcaption> must be the figure's first or last child.
5466
+ /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
5467
+ /* @__PURE__ */ jsxs("figure", { id: `illustration-${image.key}`, className: "scroll-mt-24", children: [
5468
+ /* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold text-foreground", children: image.title }),
5469
+ /* @__PURE__ */ jsxs(
5470
+ "button",
5471
+ {
5472
+ type: "button",
5473
+ onClick: (event) => onOpen(event.currentTarget),
5474
+ "data-concepts": "illustration",
5475
+ className: cn(
5476
+ "group relative mt-3 block w-full overflow-hidden rounded-2xl border border-border shadow-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
5477
+ portrait ? "bg-muted p-4 sm:p-6" : "bg-muted"
5478
+ ),
5479
+ children: [
5480
+ /* @__PURE__ */ jsx(
5481
+ "img",
5482
+ {
5483
+ "data-llms-image": "",
5484
+ src: image.src,
5485
+ alt: image.alt,
5486
+ width: image.width,
5487
+ height: image.height,
5488
+ loading: "lazy",
5489
+ decoding: "async",
5490
+ className: "mx-auto block h-auto max-h-[80vh] w-auto max-w-full"
5491
+ }
5492
+ ),
5493
+ /* @__PURE__ */ jsx(IllustrationBadge, { className: "left-3 top-3" }),
5494
+ /* @__PURE__ */ jsx(
5495
+ "span",
5496
+ {
5497
+ "aria-hidden": "true",
5498
+ className: "absolute bottom-3 right-3 inline-flex h-8 w-8 items-center justify-center rounded-full border border-border bg-background/90 text-foreground shadow-sm transition-opacity group-hover:opacity-100 sm:opacity-80",
5499
+ children: /* @__PURE__ */ jsx(Maximize2, { className: "h-4 w-4" })
5500
+ }
5501
+ ),
5502
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Enlarge illustration" })
5503
+ ]
5504
+ }
5505
+ ),
5506
+ /* @__PURE__ */ jsx("figcaption", { className: "mt-3 text-sm font-medium text-foreground", children: image.caption })
5507
+ ] }),
5508
+ /* @__PURE__ */ jsx("p", { className: "leading-relaxed text-muted-foreground", children: image.description })
5509
+ ] })
5510
+ );
5511
+ }
5512
+ function ConceptDetailPage(props) {
5513
+ return /* @__PURE__ */ jsx(ConceptDetail, { ...props }, props.concept.slug);
5514
+ }
5515
+ function ConceptDetail({
5516
+ productName,
5517
+ siteUrl,
5518
+ concept,
5519
+ concepts,
5520
+ categories,
5521
+ cta,
5522
+ linkComponent,
5523
+ className
5524
+ }) {
5525
+ const Link = linkComponent ?? DefaultConceptLink;
5526
+ const base = normaliseSiteUrl(siteUrl);
5527
+ const headingId = useId();
5528
+ const ordered = useMemo(() => sortByOrder(concepts), [concepts]);
5529
+ const position = ordered.findIndex((item) => item.slug === concept.slug);
5530
+ const previous = position > 0 ? ordered[position - 1] : void 0;
5531
+ const next = position >= 0 && position < ordered.length - 1 ? ordered[position + 1] : void 0;
5532
+ const related = useMemo(() => {
5533
+ const bySlug = new Map(ordered.map((item) => [item.slug, item]));
5534
+ const curated = [...new Set(concept.related)].map((slug) => bySlug.get(slug)).filter(
5535
+ (item) => item !== void 0 && item.slug !== concept.slug
5536
+ );
5537
+ const list = curated.length > 0 ? curated : ordered.filter(
5538
+ (item) => item.category === concept.category && item.slug !== concept.slug
5539
+ );
5540
+ return list.slice(0, RELATED_LIMIT);
5541
+ }, [concept, ordered]);
5542
+ const relatedIsCurated = concept.related.some(
5543
+ (slug) => related.some((item) => item.slug === slug)
5544
+ );
5545
+ const categoryDescription = categories?.find(
5546
+ (category) => category.name === concept.category
5547
+ )?.description;
5548
+ const [lightboxIndex, setLightboxIndex] = useState(null);
5549
+ const triggerRef = useRef(null);
5550
+ const openLightbox = useCallback((index, trigger) => {
5551
+ triggerRef.current = trigger;
5552
+ setLightboxIndex(index);
5553
+ }, []);
5554
+ const closeLightbox = useCallback(() => setLightboxIndex(null), []);
5555
+ useEffect(() => {
5556
+ if (lightboxIndex !== null) return;
5557
+ const trigger = triggerRef.current;
5558
+ if (!trigger) return;
5559
+ triggerRef.current = null;
5560
+ if (trigger.isConnected) trigger.focus();
5561
+ }, [lightboxIndex]);
5562
+ const canonical = absoluteUrl(base, conceptPath(concept.slug));
5563
+ const hero = concept.images[0];
5564
+ const imageTotal = concept.images.length;
5565
+ const structuredData = useMemo(
5566
+ () => [
5567
+ {
5568
+ "@context": "https://schema.org",
5569
+ "@type": "ImageGallery",
5570
+ name: concept.title,
5571
+ description: concept.metaDescription,
5572
+ url: canonical,
5573
+ keywords: concept.keywords.join(", "),
5574
+ about: { "@type": "Thing", name: productName },
5575
+ image: concept.images.map((image) => ({
5576
+ "@type": "ImageObject",
5577
+ contentUrl: absoluteUrl(base, image.src),
5578
+ thumbnailUrl: absoluteUrl(base, image.thumb),
5579
+ name: image.title,
5580
+ caption: image.caption,
5581
+ description: image.description,
5582
+ width: image.width,
5583
+ height: image.height
5584
+ }))
5585
+ },
5586
+ {
5587
+ "@context": "https://schema.org",
5588
+ "@type": "BreadcrumbList",
5589
+ itemListElement: [
5590
+ { "@type": "ListItem", position: 1, name: "Home", item: `${base}/` },
5591
+ {
5592
+ "@type": "ListItem",
5593
+ position: 2,
5594
+ name: "Concepts",
5595
+ item: `${base}${CONCEPTS_PATH}`
5596
+ },
5597
+ {
5598
+ "@type": "ListItem",
5599
+ position: 3,
5600
+ name: concept.title,
5601
+ item: canonical
5602
+ }
5603
+ ]
5604
+ }
5605
+ ],
5606
+ [base, canonical, concept, productName]
5607
+ );
5608
+ return /* @__PURE__ */ jsxs(
5609
+ "article",
5610
+ {
5611
+ "data-concepts": "detail",
5612
+ "data-slug": concept.slug,
5613
+ "aria-labelledby": headingId,
5614
+ className: cn("bg-background text-foreground", className),
5615
+ children: [
5616
+ /* @__PURE__ */ jsx(
5617
+ PageHead,
5618
+ {
5619
+ title: `${concept.title} \u2014 Concept`,
5620
+ description: concept.metaDescription,
5621
+ productName,
5622
+ keywords: concept.keywords.join(", "),
5623
+ image: hero ? absoluteUrl(base, hero.src) : void 0,
5624
+ url: canonical,
5625
+ structuredData
5626
+ }
5627
+ ),
5628
+ /* @__PURE__ */ jsx("header", { className: "border-b border-border bg-muted/30", children: /* @__PURE__ */ jsxs("div", { className: "mx-auto max-w-6xl px-4 pb-10 pt-8 sm:px-6 lg:px-8", children: [
5629
+ /* @__PURE__ */ jsx("nav", { "aria-label": "Breadcrumb", children: /* @__PURE__ */ jsxs("ol", { className: "flex flex-wrap items-center gap-1.5 text-sm text-muted-foreground", children: [
5630
+ /* @__PURE__ */ jsxs("li", { className: "inline-flex items-center gap-1.5", children: [
5631
+ /* @__PURE__ */ jsx(
5632
+ Link,
5633
+ {
5634
+ href: "/",
5635
+ className: "rounded hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
5636
+ children: "Home"
5637
+ }
5638
+ ),
5639
+ /* @__PURE__ */ jsx(ChevronRight, { "aria-hidden": "true", className: "h-3.5 w-3.5" })
5640
+ ] }),
5641
+ /* @__PURE__ */ jsxs("li", { className: "inline-flex items-center gap-1.5", children: [
5642
+ /* @__PURE__ */ jsx(
5643
+ Link,
5644
+ {
5645
+ href: CONCEPTS_PATH,
5646
+ className: "rounded hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
5647
+ children: "Concepts"
5648
+ }
5649
+ ),
5650
+ /* @__PURE__ */ jsx(ChevronRight, { "aria-hidden": "true", className: "h-3.5 w-3.5" })
5651
+ ] }),
5652
+ /* @__PURE__ */ jsx(
5653
+ "li",
5654
+ {
5655
+ "aria-current": "page",
5656
+ className: "min-w-0 truncate text-foreground",
5657
+ children: concept.title
5658
+ }
5659
+ )
5660
+ ] }) }),
5661
+ /* @__PURE__ */ jsxs("div", { className: "mt-6 flex flex-wrap items-center gap-2", children: [
5662
+ /* @__PURE__ */ jsx(
5663
+ "span",
5664
+ {
5665
+ "data-concepts": "category",
5666
+ title: categoryDescription,
5667
+ className: "inline-flex items-center rounded-full border border-primary/30 bg-primary/10 px-3 py-1 text-xs font-semibold text-primary",
5668
+ children: concept.category
5669
+ }
5670
+ ),
5671
+ /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1.5 rounded-full border border-border bg-background px-3 py-1 text-xs font-medium text-muted-foreground", children: [
5672
+ /* @__PURE__ */ jsx(ImageIcon, { "aria-hidden": "true", className: "h-3.5 w-3.5" }),
5673
+ illustrationCount(imageTotal)
5674
+ ] })
5675
+ ] }),
5676
+ /* @__PURE__ */ jsx(
5677
+ "h1",
5678
+ {
5679
+ id: headingId,
5680
+ className: "mt-4 max-w-4xl text-3xl font-bold tracking-tight text-foreground sm:text-4xl lg:text-5xl",
5681
+ children: concept.title
5682
+ }
5683
+ ),
5684
+ /* @__PURE__ */ jsx("p", { className: "mt-4 max-w-3xl text-lg leading-relaxed text-muted-foreground", children: concept.tagline }),
5685
+ /* @__PURE__ */ jsx(IllustrationNotice, { className: "mt-6 max-w-3xl" })
5686
+ ] }) }),
5687
+ hero ? /* @__PURE__ */ jsx("div", { className: "mx-auto max-w-6xl px-4 pt-10 sm:px-6 lg:px-8", children: /* @__PURE__ */ jsx("figure", { "data-concepts": "hero", children: /* @__PURE__ */ jsxs(
5688
+ "button",
5689
+ {
5690
+ type: "button",
5691
+ onClick: (event) => openLightbox(0, event.currentTarget),
5692
+ className: cn(
5693
+ "group relative block w-full overflow-hidden rounded-2xl border border-border bg-muted shadow-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
5694
+ isPortrait(hero.width, hero.height) && "p-4 sm:p-6"
5695
+ ),
5696
+ children: [
5697
+ /* @__PURE__ */ jsx(
5698
+ "img",
5699
+ {
5700
+ src: hero.src,
5701
+ alt: hero.alt,
5702
+ width: hero.width,
5703
+ height: hero.height,
5704
+ loading: "eager",
5705
+ ...HERO_FETCH_PRIORITY,
5706
+ className: "mx-auto block h-auto max-h-[75vh] w-auto max-w-full"
5707
+ }
5708
+ ),
5709
+ /* @__PURE__ */ jsx(IllustrationBadge, { className: "left-3 top-3" }),
5710
+ /* @__PURE__ */ jsxs(
5711
+ "span",
5712
+ {
5713
+ "aria-hidden": "true",
5714
+ className: "absolute bottom-3 right-3 inline-flex items-center gap-1.5 rounded-full border border-border bg-background/90 px-3 py-1 text-xs font-medium text-foreground shadow-sm",
5715
+ children: [
5716
+ /* @__PURE__ */ jsx(Maximize2, { className: "h-3.5 w-3.5" }),
5717
+ "Enlarge"
5718
+ ]
5719
+ }
5720
+ ),
5721
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Enlarge illustration" })
5722
+ ]
5723
+ }
5724
+ ) }) }) : null,
5725
+ /* @__PURE__ */ jsxs("div", { className: "mx-auto max-w-6xl px-4 py-14 sm:px-6 lg:px-8", children: [
5726
+ /* @__PURE__ */ jsxs("div", { className: "max-w-3xl space-y-12", children: [
5727
+ concept.overview.length > 0 ? /* @__PURE__ */ jsxs("section", { "aria-labelledby": `${headingId}-overview`, children: [
5728
+ /* @__PURE__ */ jsx("h2", { id: `${headingId}-overview`, className: SECTION_HEADING, children: "Overview" }),
5729
+ /* @__PURE__ */ jsx("div", { className: "mt-4 space-y-4 text-base leading-relaxed text-foreground", children: concept.overview.map((paragraph, index) => /* @__PURE__ */ jsx("p", { children: paragraph }, copyKey(index, paragraph))) })
5730
+ ] }) : null,
5731
+ concept.highlights.length > 0 ? /* @__PURE__ */ jsxs("section", { "aria-labelledby": `${headingId}-highlights`, children: [
5732
+ /* @__PURE__ */ jsx("h2", { id: `${headingId}-highlights`, className: SECTION_HEADING, children: "What this concept shows" }),
5733
+ /* @__PURE__ */ jsx("ul", { role: "list", className: "mt-4 space-y-3", children: concept.highlights.map((highlight, index) => /* @__PURE__ */ jsxs(
5734
+ "li",
5735
+ {
5736
+ className: "flex items-start gap-3 leading-relaxed text-foreground",
5737
+ children: [
5738
+ /* @__PURE__ */ jsx(
5739
+ "span",
5740
+ {
5741
+ "aria-hidden": "true",
5742
+ className: "mt-0.5 inline-flex h-5 w-5 shrink-0 items-center justify-center rounded-full bg-primary/10 text-primary",
5743
+ children: /* @__PURE__ */ jsx(Check, { className: "h-3.5 w-3.5" })
5744
+ }
5745
+ ),
5746
+ /* @__PURE__ */ jsx("span", { children: highlight })
5747
+ ]
5748
+ },
5749
+ copyKey(index, highlight)
5750
+ )) })
5751
+ ] }) : null,
5752
+ concept.workflow.length > 0 ? /* @__PURE__ */ jsxs("section", { "aria-labelledby": `${headingId}-workflow`, children: [
5753
+ /* @__PURE__ */ jsx("h2", { id: `${headingId}-workflow`, className: SECTION_HEADING, children: "How it works" }),
5754
+ /* @__PURE__ */ jsx("ol", { role: "list", className: "mt-4 space-y-4", children: concept.workflow.map((step, index) => /* @__PURE__ */ jsxs(
5755
+ "li",
5756
+ {
5757
+ className: "flex items-start gap-4",
5758
+ children: [
5759
+ /* @__PURE__ */ jsx(
5760
+ "span",
5761
+ {
5762
+ "aria-hidden": "true",
5763
+ className: "inline-flex h-7 w-7 shrink-0 items-center justify-center rounded-full border border-border bg-card text-sm font-semibold tabular-nums text-foreground",
5764
+ children: index + 1
5765
+ }
5766
+ ),
5767
+ /* @__PURE__ */ jsx("span", { className: "pt-0.5 leading-relaxed text-foreground", children: step })
5768
+ ]
5769
+ },
5770
+ copyKey(index, step)
5771
+ )) })
5772
+ ] }) : null,
5773
+ concept.audience.length > 0 ? /* @__PURE__ */ jsxs("section", { "aria-labelledby": `${headingId}-audience`, children: [
5774
+ /* @__PURE__ */ jsx("h2", { id: `${headingId}-audience`, className: SECTION_HEADING, children: "Who it's for" }),
5775
+ /* @__PURE__ */ jsx("ul", { role: "list", className: "mt-4 flex flex-wrap gap-2", children: concept.audience.map((who, index) => /* @__PURE__ */ jsx("li", { className: CHIP, children: who }, copyKey(index, who))) })
5776
+ ] }) : null
5777
+ ] }),
5778
+ imageTotal > 0 ? /* @__PURE__ */ jsxs(
5779
+ "section",
5780
+ {
5781
+ "aria-labelledby": `${headingId}-illustrations`,
5782
+ className: "mt-16",
5783
+ children: [
5784
+ /* @__PURE__ */ jsxs("div", { className: "max-w-3xl", children: [
5785
+ /* @__PURE__ */ jsx("h2", { id: `${headingId}-illustrations`, className: SECTION_HEADING, children: "Illustrations" }),
5786
+ /* @__PURE__ */ jsxs("p", { className: "mt-2 text-muted-foreground", children: [
5787
+ illustrationCount(imageTotal),
5788
+ " of this concept. Select one to view it full size."
5789
+ ] })
5790
+ ] }),
5791
+ /* @__PURE__ */ jsx("div", { className: "mt-8 space-y-14", children: concept.images.map((image, index) => /* @__PURE__ */ jsx(
5792
+ IllustrationFigure,
5793
+ {
5794
+ image,
5795
+ onOpen: (trigger) => openLightbox(index, trigger)
5796
+ },
5797
+ image.key
5798
+ )) })
5799
+ ]
5800
+ }
5801
+ ) : null,
5802
+ concept.keywords.length > 0 ? /* @__PURE__ */ jsxs("section", { "aria-labelledby": `${headingId}-topics`, className: "mt-16", children: [
5803
+ /* @__PURE__ */ jsx("h2", { id: `${headingId}-topics`, className: SECTION_HEADING, children: "Topics" }),
5804
+ /* @__PURE__ */ jsx("ul", { role: "list", className: "mt-4 flex flex-wrap gap-2", children: concept.keywords.map((keyword, index) => /* @__PURE__ */ jsx("li", { className: CHIP, children: keyword }, copyKey(index, keyword))) })
5805
+ ] }) : null,
5806
+ related.length > 0 ? /* @__PURE__ */ jsxs(
5807
+ "section",
5808
+ {
5809
+ "aria-labelledby": `${headingId}-related`,
5810
+ "data-concepts": "related",
5811
+ className: "mt-16",
5812
+ children: [
5813
+ /* @__PURE__ */ jsx("h2", { id: `${headingId}-related`, className: SECTION_HEADING, children: relatedIsCurated ? "Related concepts" : `More in ${concept.category}` }),
5814
+ /* @__PURE__ */ jsx(
5815
+ "ul",
5816
+ {
5817
+ role: "list",
5818
+ className: cn(
5819
+ "mt-6 grid grid-cols-1 gap-5 sm:grid-cols-2",
5820
+ related.length >= 4 ? "lg:grid-cols-4" : "lg:grid-cols-3"
5821
+ ),
5822
+ children: related.map((item) => /* @__PURE__ */ jsx("li", { "data-concepts": "card", "data-slug": item.slug, children: /* @__PURE__ */ jsx(ConceptCard, { concept: item, Link }) }, item.slug))
5823
+ }
5824
+ )
5825
+ ]
5826
+ }
5827
+ ) : null,
5828
+ previous || next ? /* @__PURE__ */ jsxs(
5829
+ "nav",
5830
+ {
5831
+ "aria-label": "Previous and next concepts",
5832
+ "data-concepts": "pager",
5833
+ className: "mt-16 grid gap-4 sm:grid-cols-2",
5834
+ children: [
5835
+ previous ? /* @__PURE__ */ jsxs(
5836
+ Link,
5837
+ {
5838
+ href: conceptPath(previous.slug),
5839
+ className: "group flex items-center gap-3 rounded-2xl border border-border bg-card p-4 text-card-foreground transition-colors hover:border-primary/40 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
5840
+ children: [
5841
+ /* @__PURE__ */ jsx(
5842
+ ArrowLeft,
5843
+ {
5844
+ "aria-hidden": "true",
5845
+ className: "h-5 w-5 shrink-0 text-muted-foreground transition-colors group-hover:text-primary"
5846
+ }
5847
+ ),
5848
+ /* @__PURE__ */ jsxs("span", { className: "min-w-0", children: [
5849
+ /* @__PURE__ */ jsx("span", { className: "block text-xs font-medium uppercase tracking-wide text-muted-foreground", children: "Previous concept" }),
5850
+ /* @__PURE__ */ jsx("span", { className: "block truncate font-semibold", children: previous.title })
5851
+ ] })
5852
+ ]
5853
+ }
5854
+ ) : /* @__PURE__ */ jsx("span", { className: "hidden sm:block" }),
5855
+ next ? /* @__PURE__ */ jsxs(
5856
+ Link,
5857
+ {
5858
+ href: conceptPath(next.slug),
5859
+ className: "group flex items-center justify-end gap-3 rounded-2xl border border-border bg-card p-4 text-right text-card-foreground transition-colors hover:border-primary/40 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
5860
+ children: [
5861
+ /* @__PURE__ */ jsxs("span", { className: "min-w-0", children: [
5862
+ /* @__PURE__ */ jsx("span", { className: "block text-xs font-medium uppercase tracking-wide text-muted-foreground", children: "Next concept" }),
5863
+ /* @__PURE__ */ jsx("span", { className: "block truncate font-semibold", children: next.title })
5864
+ ] }),
5865
+ /* @__PURE__ */ jsx(
5866
+ ArrowRight,
5867
+ {
5868
+ "aria-hidden": "true",
5869
+ className: "h-5 w-5 shrink-0 text-muted-foreground transition-colors group-hover:text-primary"
5870
+ }
5871
+ )
5872
+ ]
5873
+ }
5874
+ ) : null
5875
+ ]
5876
+ }
5877
+ ) : null,
5878
+ /* @__PURE__ */ jsx("div", { className: "mt-10", children: /* @__PURE__ */ jsxs(
5879
+ Link,
5880
+ {
5881
+ href: CONCEPTS_PATH,
5882
+ className: "inline-flex items-center gap-2 rounded text-sm font-medium text-primary hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
5883
+ children: [
5884
+ /* @__PURE__ */ jsx(ArrowLeft, { "aria-hidden": "true", className: "h-4 w-4" }),
5885
+ "All ",
5886
+ productName,
5887
+ " concepts"
5888
+ ]
5889
+ }
5890
+ ) })
5891
+ ] }),
5892
+ cta ? /* @__PURE__ */ jsx(
5893
+ "section",
5894
+ {
5895
+ "data-concepts": "cta",
5896
+ className: "border-t border-border bg-muted/30",
5897
+ children: /* @__PURE__ */ jsx("div", { className: "mx-auto flex max-w-6xl flex-wrap items-center gap-4 px-4 py-12 sm:px-6 lg:px-8", children: cta })
5898
+ }
5899
+ ) : null,
5900
+ lightboxIndex !== null ? /* @__PURE__ */ jsx(
5901
+ ConceptLightbox,
5902
+ {
5903
+ images: concept.images,
5904
+ index: lightboxIndex,
5905
+ conceptTitle: concept.title,
5906
+ onIndexChange: setLightboxIndex,
5907
+ onClose: closeLightbox
5908
+ }
5909
+ ) : null
5910
+ ]
5911
+ }
5912
+ );
5913
+ }
5914
+
5915
+ // src/components/explore-i18n.ts
5916
+ var EXPLORE_LOCALES = ["en", "zh", "hi", "es", "ar", "ta"];
5917
+ var RTL_LOCALES = /* @__PURE__ */ new Set(["ar"]);
5918
+ function isRtlLocale(locale) {
5919
+ return RTL_LOCALES.has(locale);
5920
+ }
5921
+ var EN = {
5922
+ badge: "AI answers, grounded in our documentation",
5923
+ welcomeTitle: "Ask anything about our products",
5924
+ welcomeBody: "Describe what you are trying to do and I will point you at the product, the page and the next step.",
5925
+ tryAsking: "Try asking",
5926
+ focusProduct: "Focus on a product",
5927
+ allProducts: "All products",
5928
+ showAll: "All",
5929
+ showLess: "Show less",
5930
+ sources: "Sources",
5931
+ nextYouCouldAsk: "Next you could ask",
5932
+ placeholder: "Ask anything about our products\u2026",
5933
+ placeholderProduct: "Ask about {product}\u2026",
5934
+ send: "Send",
5935
+ stop: "Stop",
5936
+ newChat: "New chat",
5937
+ history: "History",
5938
+ clearHistory: "Clear history",
5939
+ share: "Share",
5940
+ copied: "Copied",
5941
+ copying: "Copying\u2026",
5942
+ shareUnavailable: "Unavailable",
5943
+ disclaimer: "Disclaimer",
5944
+ disclaimerShort: "Grounded in our docs \u2014 check anything important.",
5945
+ dictate: "Dictate your question",
5946
+ stopDictating: "Stop dictating",
5947
+ attach: "Attach files",
5948
+ attachHint: "Up to {{max}} files, {{size}} MB each",
5949
+ removeAttachment: "Remove {{name}}",
5950
+ attachmentNameOnly: "name and type only",
5951
+ attachmentTooLarge: "{{name}} is larger than {{size}} MB and was not attached.",
5952
+ attachmentTooMany: "Only {{max}} files can be attached, so {{name}} was skipped.",
5953
+ noAnswer: "I couldn't find this in our documentation, so the answer below is not grounded in a source. Try rephrasing, or",
5954
+ answerDidNotArrive: "That answer didn't come through. Try asking again.",
5955
+ askHuman: "ask a human",
5956
+ prevSuggestion: "Previous suggestion",
5957
+ nextSuggestion: "Next suggestion",
5958
+ conceptIllustration: "Concept illustration",
5959
+ opensInNewTab: "opens in a new tab",
5960
+ capabilities: [
5961
+ "Grounded in our own docs",
5962
+ "Compare across the ecosystem",
5963
+ "Straight to the right page"
5964
+ ],
5965
+ prompts: [
5966
+ "What does this product actually do?",
5967
+ "Which product fits my team?",
5968
+ "How do I get started, step by step?",
5969
+ "How much does it cost?"
5970
+ ]
5971
+ };
5972
+ var ZH = {
5973
+ badge: "\u57FA\u4E8E\u6211\u4EEC\u6587\u6863\u7684 AI \u56DE\u7B54",
5974
+ welcomeTitle: "\u5173\u4E8E\u6211\u4EEC\u7684\u4EA7\u54C1\uFF0C\u968F\u4FBF\u95EE",
5975
+ welcomeBody: "\u63CF\u8FF0\u4F60\u60F3\u505A\u7684\u4E8B\uFF0C\u6211\u4F1A\u4E3A\u4F60\u6307\u51FA\u5BF9\u5E94\u7684\u4EA7\u54C1\u3001\u9875\u9762\u548C\u4E0B\u4E00\u6B65\u3002",
5976
+ tryAsking: "\u8BD5\u7740\u95EE",
5977
+ focusProduct: "\u805A\u7126\u67D0\u4E2A\u4EA7\u54C1",
5978
+ allProducts: "\u5168\u90E8\u4EA7\u54C1",
5979
+ showAll: "\u5168\u90E8",
5980
+ showLess: "\u6536\u8D77",
5981
+ sources: "\u6765\u6E90",
5982
+ nextYouCouldAsk: "\u4F60\u8FD8\u53EF\u4EE5\u95EE",
5983
+ placeholder: "\u5173\u4E8E\u6211\u4EEC\u7684\u4EA7\u54C1\uFF0C\u968F\u4FBF\u95EE\u2026",
5984
+ placeholderProduct: "\u8BE2\u95EE\u5173\u4E8E {product} \u7684\u95EE\u9898\u2026",
5985
+ send: "\u53D1\u9001",
5986
+ stop: "\u505C\u6B62",
5987
+ newChat: "\u65B0\u5BF9\u8BDD",
5988
+ history: "\u5386\u53F2",
5989
+ clearHistory: "\u6E05\u9664\u5386\u53F2",
5990
+ share: "\u5206\u4EAB",
5991
+ copied: "\u5DF2\u590D\u5236",
5992
+ copying: "\u590D\u5236\u4E2D\u2026",
5993
+ shareUnavailable: "\u4E0D\u53EF\u7528",
5994
+ disclaimer: "\u514D\u8D23\u58F0\u660E",
5995
+ disclaimerShort: "\u5185\u5BB9\u57FA\u4E8E\u6211\u4EEC\u7684\u6587\u6863\uFF0C\u91CD\u8981\u4FE1\u606F\u8BF7\u81EA\u884C\u6838\u5BF9\u3002",
5996
+ dictate: "\u8BED\u97F3\u8F93\u5165",
5997
+ stopDictating: "\u505C\u6B62\u8BED\u97F3\u8F93\u5165",
5998
+ attach: "\u6DFB\u52A0\u6587\u4EF6",
5999
+ attachHint: "\u6700\u591A {{max}} \u4E2A\u6587\u4EF6\uFF0C\u6BCF\u4E2A\u4E0D\u8D85\u8FC7 {{size}} MB",
6000
+ removeAttachment: "\u79FB\u9664 {{name}}",
6001
+ attachmentNameOnly: "\u4EC5\u6587\u4EF6\u540D\u548C\u7C7B\u578B",
6002
+ attachmentTooLarge: "{{name}} \u8D85\u8FC7 {{size}} MB\uFF0C\u672A\u80FD\u6DFB\u52A0\u3002",
6003
+ attachmentTooMany: "\u6700\u591A\u53EA\u80FD\u6DFB\u52A0 {{max}} \u4E2A\u6587\u4EF6\uFF0C\u5DF2\u8DF3\u8FC7 {{name}}\u3002",
6004
+ noAnswer: "\u6211\u5728\u6587\u6863\u4E2D\u6CA1\u6709\u627E\u5230\u76F8\u5173\u5185\u5BB9\uFF0C\u4E0B\u9762\u7684\u56DE\u7B54\u6CA1\u6709\u6765\u6E90\u652F\u6301\u3002\u8BF7\u6362\u4E2A\u8BF4\u6CD5\uFF0C\u6216",
6005
+ answerDidNotArrive: "\u8FD9\u6761\u56DE\u7B54\u6CA1\u6709\u8FD4\u56DE\u3002\u8BF7\u518D\u95EE\u4E00\u6B21\u3002",
6006
+ askHuman: "\u8054\u7CFB\u6211\u4EEC",
6007
+ prevSuggestion: "\u4E0A\u4E00\u4E2A\u5EFA\u8BAE",
6008
+ nextSuggestion: "\u4E0B\u4E00\u4E2A\u5EFA\u8BAE",
6009
+ conceptIllustration: "\u6982\u5FF5\u793A\u610F\u56FE",
6010
+ opensInNewTab: "\u5728\u65B0\u6807\u7B7E\u9875\u4E2D\u6253\u5F00",
6011
+ capabilities: ["\u57FA\u4E8E\u6211\u4EEC\u81EA\u5DF1\u7684\u6587\u6863", "\u8DE8\u4EA7\u54C1\u5BF9\u6BD4", "\u76F4\u8FBE\u6B63\u786E\u7684\u9875\u9762"],
6012
+ prompts: [
6013
+ "\u8FD9\u4E2A\u4EA7\u54C1\u5230\u5E95\u80FD\u505A\u4EC0\u4E48\uFF1F",
6014
+ "\u54EA\u4E2A\u4EA7\u54C1\u9002\u5408\u6211\u7684\u56E2\u961F\uFF1F",
6015
+ "\u5982\u4F55\u4E00\u6B65\u6B65\u5F00\u59CB\u4F7F\u7528\uFF1F",
6016
+ "\u4EF7\u683C\u662F\u591A\u5C11\uFF1F"
6017
+ ]
6018
+ };
6019
+ var HI = {
6020
+ badge: "\u0939\u092E\u093E\u0930\u0947 \u0926\u0938\u094D\u0924\u093E\u0935\u0947\u091C\u093C\u094B\u0902 \u092A\u0930 \u0906\u0927\u093E\u0930\u093F\u0924 AI \u0909\u0924\u094D\u0924\u0930",
6021
+ welcomeTitle: "\u0939\u092E\u093E\u0930\u0947 \u0909\u0924\u094D\u092A\u093E\u0926\u094B\u0902 \u0915\u0947 \u092C\u093E\u0930\u0947 \u092E\u0947\u0902 \u0915\u0941\u091B \u092D\u0940 \u092A\u0942\u091B\u0947\u0902",
6022
+ welcomeBody: "\u092C\u0924\u093E\u0907\u090F \u0906\u092A \u0915\u094D\u092F\u093E \u0915\u0930\u0928\u093E \u091A\u093E\u0939\u0924\u0947 \u0939\u0948\u0902, \u0914\u0930 \u092E\u0948\u0902 \u0906\u092A\u0915\u094B \u0938\u0939\u0940 \u0909\u0924\u094D\u092A\u093E\u0926, \u092A\u0947\u091C \u0914\u0930 \u0905\u0917\u0932\u093E \u0915\u0926\u092E \u092C\u0924\u093E\u090A\u0901\u0917\u093E\u0964",
6023
+ tryAsking: "\u092F\u0939 \u092A\u0942\u091B\u0915\u0930 \u0926\u0947\u0916\u0947\u0902",
6024
+ focusProduct: "\u0915\u093F\u0938\u0940 \u0909\u0924\u094D\u092A\u093E\u0926 \u092A\u0930 \u0927\u094D\u092F\u093E\u0928 \u0926\u0947\u0902",
6025
+ allProducts: "\u0938\u092D\u0940 \u0909\u0924\u094D\u092A\u093E\u0926",
6026
+ showAll: "\u0938\u092D\u0940",
6027
+ showLess: "\u0915\u092E \u0926\u093F\u0916\u093E\u090F\u0901",
6028
+ sources: "\u0938\u094D\u0930\u094B\u0924",
6029
+ nextYouCouldAsk: "\u0906\u0917\u0947 \u0906\u092A \u092A\u0942\u091B \u0938\u0915\u0924\u0947 \u0939\u0948\u0902",
6030
+ placeholder: "\u0939\u092E\u093E\u0930\u0947 \u0909\u0924\u094D\u092A\u093E\u0926\u094B\u0902 \u0915\u0947 \u092C\u093E\u0930\u0947 \u092E\u0947\u0902 \u0915\u0941\u091B \u092D\u0940 \u092A\u0942\u091B\u0947\u0902\u2026",
6031
+ placeholderProduct: "{product} \u0915\u0947 \u092C\u093E\u0930\u0947 \u092E\u0947\u0902 \u092A\u0942\u091B\u0947\u0902\u2026",
6032
+ send: "\u092D\u0947\u091C\u0947\u0902",
6033
+ stop: "\u0930\u094B\u0915\u0947\u0902",
6034
+ newChat: "\u0928\u0908 \u092C\u093E\u0924\u091A\u0940\u0924",
6035
+ history: "\u0907\u0924\u093F\u0939\u093E\u0938",
6036
+ clearHistory: "\u0907\u0924\u093F\u0939\u093E\u0938 \u092E\u093F\u091F\u093E\u090F\u0901",
6037
+ share: "\u0938\u093E\u091D\u093E \u0915\u0930\u0947\u0902",
6038
+ copied: "\u0915\u0949\u092A\u0940 \u0939\u094B \u0917\u092F\u093E",
6039
+ copying: "\u0915\u0949\u092A\u0940 \u0939\u094B \u0930\u0939\u093E \u0939\u0948\u2026",
6040
+ shareUnavailable: "\u0909\u092A\u0932\u092C\u094D\u0927 \u0928\u0939\u0940\u0902",
6041
+ disclaimer: "\u0905\u0938\u094D\u0935\u0940\u0915\u0930\u0923",
6042
+ disclaimerShort: "\u092F\u0939 \u0939\u092E\u093E\u0930\u0947 \u0926\u0938\u094D\u0924\u093E\u0935\u0947\u091C\u093C\u094B\u0902 \u092A\u0930 \u0906\u0927\u093E\u0930\u093F\u0924 \u0939\u0948 \u2014 \u092E\u0939\u0924\u094D\u0935\u092A\u0942\u0930\u094D\u0923 \u092C\u093E\u0924\u0947\u0902 \u091C\u093C\u0930\u0942\u0930 \u091C\u093E\u0901\u091A \u0932\u0947\u0902\u0964",
6043
+ dictate: "\u092C\u094B\u0932\u0915\u0930 \u092A\u0942\u091B\u0947\u0902",
6044
+ stopDictating: "\u092C\u094B\u0932\u0928\u093E \u092C\u0902\u0926 \u0915\u0930\u0947\u0902",
6045
+ attach: "\u092B\u093C\u093E\u0907\u0932\u0947\u0902 \u091C\u094B\u0921\u093C\u0947\u0902",
6046
+ attachHint: "\u0905\u0927\u093F\u0915\u0924\u092E {{max}} \u092B\u093C\u093E\u0907\u0932\u0947\u0902, \u092A\u094D\u0930\u0924\u094D\u092F\u0947\u0915 {{size}} MB \u0924\u0915",
6047
+ removeAttachment: "{{name}} \u0939\u091F\u093E\u090F\u0901",
6048
+ attachmentNameOnly: "\u0915\u0947\u0935\u0932 \u0928\u093E\u092E \u0914\u0930 \u092A\u094D\u0930\u0915\u093E\u0930",
6049
+ attachmentTooLarge: "{{name}} {{size}} MB \u0938\u0947 \u092C\u0921\u093C\u0940 \u0939\u0948, \u0907\u0938\u0932\u093F\u090F \u091C\u094B\u0921\u093C\u0940 \u0928\u0939\u0940\u0902 \u0917\u0908\u0964",
6050
+ attachmentTooMany: "\u0915\u0947\u0935\u0932 {{max}} \u092B\u093C\u093E\u0907\u0932\u0947\u0902 \u091C\u094B\u0921\u093C\u0940 \u091C\u093E \u0938\u0915\u0924\u0940 \u0939\u0948\u0902, \u0907\u0938\u0932\u093F\u090F {{name}} \u091B\u094B\u0921\u093C \u0926\u0940 \u0917\u0908\u0964",
6051
+ noAnswer: "\u092F\u0939 \u092E\u0941\u091D\u0947 \u0939\u092E\u093E\u0930\u0947 \u0926\u0938\u094D\u0924\u093E\u0935\u0947\u091C\u093C\u094B\u0902 \u092E\u0947\u0902 \u0928\u0939\u0940\u0902 \u092E\u093F\u0932\u093E, \u0907\u0938\u0932\u093F\u090F \u0928\u0940\u091A\u0947 \u0926\u093F\u092F\u093E \u0909\u0924\u094D\u0924\u0930 \u0915\u093F\u0938\u0940 \u0938\u094D\u0930\u094B\u0924 \u092A\u0930 \u0906\u0927\u093E\u0930\u093F\u0924 \u0928\u0939\u0940\u0902 \u0939\u0948\u0964 \u0926\u0942\u0938\u0930\u0947 \u0936\u092C\u094D\u0926\u094B\u0902 \u092E\u0947\u0902 \u092A\u0942\u091B\u0947\u0902, \u092F\u093E",
6052
+ answerDidNotArrive: "\u0935\u0939 \u0909\u0924\u094D\u0924\u0930 \u0928\u0939\u0940\u0902 \u0906 \u0938\u0915\u093E\u0964 \u0915\u0943\u092A\u092F\u093E \u0926\u094B\u092C\u093E\u0930\u093E \u092A\u0942\u091B\u0947\u0902\u0964",
6053
+ askHuman: "\u0939\u092E\u0938\u0947 \u0938\u0902\u092A\u0930\u094D\u0915 \u0915\u0930\u0947\u0902",
6054
+ prevSuggestion: "\u092A\u093F\u091B\u0932\u093E \u0938\u0941\u091D\u093E\u0935",
6055
+ nextSuggestion: "\u0905\u0917\u0932\u093E \u0938\u0941\u091D\u093E\u0935",
6056
+ conceptIllustration: "\u0905\u0935\u0927\u093E\u0930\u0923\u093E \u091A\u093F\u0924\u094D\u0930\u0923",
6057
+ opensInNewTab: "\u0928\u090F \u091F\u0948\u092C \u092E\u0947\u0902 \u0916\u0941\u0932\u0924\u093E \u0939\u0948",
6058
+ capabilities: [
6059
+ "\u0939\u092E\u093E\u0930\u0947 \u0905\u092A\u0928\u0947 \u0926\u0938\u094D\u0924\u093E\u0935\u0947\u091C\u093C\u094B\u0902 \u092A\u0930 \u0906\u0927\u093E\u0930\u093F\u0924",
6060
+ "\u0938\u092D\u0940 \u0909\u0924\u094D\u092A\u093E\u0926\u094B\u0902 \u0915\u0940 \u0924\u0941\u0932\u0928\u093E \u0915\u0930\u0947\u0902",
6061
+ "\u0938\u0940\u0927\u0947 \u0938\u0939\u0940 \u092A\u0947\u091C \u092A\u0930"
6062
+ ],
6063
+ prompts: [
6064
+ "\u092F\u0939 \u0909\u0924\u094D\u092A\u093E\u0926 \u0905\u0938\u0932 \u092E\u0947\u0902 \u0915\u094D\u092F\u093E \u0915\u0930\u0924\u093E \u0939\u0948?",
6065
+ "\u092E\u0947\u0930\u0940 \u091F\u0940\u092E \u0915\u0947 \u0932\u093F\u090F \u0915\u094C\u0928 \u0938\u093E \u0909\u0924\u094D\u092A\u093E\u0926 \u0938\u0939\u0940 \u0939\u0948?",
6066
+ "\u0936\u0941\u0930\u0941\u0906\u0924 \u0915\u0948\u0938\u0947 \u0915\u0930\u0947\u0902, \u091A\u0930\u0923 \u0926\u0930 \u091A\u0930\u0923?",
6067
+ "\u0907\u0938\u0915\u0940 \u0915\u0940\u092E\u0924 \u0915\u093F\u0924\u0928\u0940 \u0939\u0948?"
6068
+ ]
6069
+ };
6070
+ var ES = {
6071
+ badge: "Respuestas de IA basadas en nuestra documentaci\xF3n",
6072
+ welcomeTitle: "Pregunta lo que quieras sobre nuestros productos",
6073
+ welcomeBody: "Cu\xE9ntame qu\xE9 necesitas hacer y te indicar\xE9 el producto, la p\xE1gina y el siguiente paso.",
6074
+ tryAsking: "Prueba a preguntar",
6075
+ focusProduct: "Centrarse en un producto",
6076
+ allProducts: "Todos los productos",
6077
+ showAll: "Todos",
6078
+ showLess: "Ver menos",
6079
+ sources: "Fuentes",
6080
+ nextYouCouldAsk: "Tambi\xE9n puedes preguntar",
6081
+ placeholder: "Pregunta lo que quieras sobre nuestros productos\u2026",
6082
+ placeholderProduct: "Pregunta sobre {product}\u2026",
6083
+ send: "Enviar",
6084
+ stop: "Detener",
6085
+ newChat: "Nueva conversaci\xF3n",
4904
6086
  history: "Historial",
4905
6087
  clearHistory: "Borrar historial",
4906
6088
  share: "Compartir",
@@ -4922,6 +6104,8 @@ var ES = {
4922
6104
  askHuman: "habla con una persona",
4923
6105
  prevSuggestion: "Sugerencia anterior",
4924
6106
  nextSuggestion: "Sugerencia siguiente",
6107
+ conceptIllustration: "Ilustraci\xF3n del concepto",
6108
+ opensInNewTab: "se abre en una pesta\xF1a nueva",
4925
6109
  capabilities: [
4926
6110
  "Basado en nuestra documentaci\xF3n",
4927
6111
  "Compara todo el ecosistema",
@@ -4971,6 +6155,8 @@ var AR = {
4971
6155
  askHuman: "\u062A\u062D\u062F\u0651\u062B \u0625\u0644\u0649 \u0634\u062E\u0635",
4972
6156
  prevSuggestion: "\u0627\u0644\u0627\u0642\u062A\u0631\u0627\u062D \u0627\u0644\u0633\u0627\u0628\u0642",
4973
6157
  nextSuggestion: "\u0627\u0644\u0627\u0642\u062A\u0631\u0627\u062D \u0627\u0644\u062A\u0627\u0644\u064A",
6158
+ conceptIllustration: "\u0631\u0633\u0645 \u062A\u0648\u0636\u064A\u062D\u064A \u0644\u0644\u0645\u0641\u0647\u0648\u0645",
6159
+ opensInNewTab: "\u064A\u064F\u0641\u062A\u062D \u0641\u064A \u0639\u0644\u0627\u0645\u0629 \u062A\u0628\u0648\u064A\u0628 \u062C\u062F\u064A\u062F\u0629",
4974
6160
  capabilities: [
4975
6161
  "\u0645\u0628\u0646\u064A \u0639\u0644\u0649 \u0648\u062B\u0627\u0626\u0642\u0646\u0627",
4976
6162
  "\u0642\u0627\u0631\u0646 \u0639\u0628\u0631 \u0627\u0644\u0645\u0646\u0638\u0648\u0645\u0629",
@@ -5020,6 +6206,8 @@ var TA = {
5020
6206
  askHuman: "\u0B8E\u0B99\u0BCD\u0B95\u0BB3\u0BC8\u0BA4\u0BCD \u0BA4\u0BCA\u0B9F\u0BB0\u0BCD\u0BAA\u0BC1 \u0B95\u0BCA\u0BB3\u0BCD\u0BB3\u0BC1\u0B99\u0BCD\u0B95\u0BB3\u0BCD",
5021
6207
  prevSuggestion: "\u0BAE\u0BC1\u0BA8\u0BCD\u0BA4\u0BC8\u0BAF \u0BAA\u0BB0\u0BBF\u0BA8\u0BCD\u0BA4\u0BC1\u0BB0\u0BC8",
5022
6208
  nextSuggestion: "\u0B85\u0B9F\u0BC1\u0BA4\u0BCD\u0BA4 \u0BAA\u0BB0\u0BBF\u0BA8\u0BCD\u0BA4\u0BC1\u0BB0\u0BC8",
6209
+ conceptIllustration: "\u0B95\u0BB0\u0BC1\u0BA4\u0BCD\u0BA4\u0BC1 \u0BB5\u0BBF\u0BB3\u0B95\u0BCD\u0B95\u0BAA\u0BCD\u0BAA\u0B9F\u0BAE\u0BCD",
6210
+ opensInNewTab: "\u0BAA\u0BC1\u0BA4\u0BBF\u0BAF \u0BA4\u0BBE\u0BB5\u0BB2\u0BBF\u0BB2\u0BCD \u0BA4\u0BBF\u0BB1\u0B95\u0BCD\u0B95\u0BC1\u0BAE\u0BCD",
5023
6211
  capabilities: [
5024
6212
  "\u0B8E\u0B99\u0BCD\u0B95\u0BB3\u0BCD \u0B9A\u0BCA\u0BA8\u0BCD\u0BA4 \u0B86\u0BB5\u0BA3\u0B99\u0BCD\u0B95\u0BB3\u0BBF\u0BA9\u0BCD \u0B85\u0B9F\u0BBF\u0BAA\u0BCD\u0BAA\u0B9F\u0BC8\u0BAF\u0BBF\u0BB2\u0BCD",
5025
6213
  "\u0BA4\u0BAF\u0BBE\u0BB0\u0BBF\u0BAA\u0BCD\u0BAA\u0BC1\u0B95\u0BB3\u0BC8 \u0B92\u0BAA\u0BCD\u0BAA\u0BBF\u0B9F\u0BC1\u0B99\u0BCD\u0B95\u0BB3\u0BCD",
@@ -5378,10 +6566,13 @@ var ECOSYSTEM_PRODUCTS = [
5378
6566
  name: "VibeControls",
5379
6567
  websiteUrl: "https://vibecontrols.com"
5380
6568
  },
6569
+ // FluidGrids ships on www.fluidgrids.ai — fluidgrids.com only redirects there. The explore
6570
+ // catalog and the site's own sitemap use this origin, and so must the fallback catalog
6571
+ // built from this list, or /explore rejects FluidGrids concept images until it loads.
5381
6572
  {
5382
6573
  slug: "fluidgrids",
5383
6574
  name: "FluidGrids",
5384
- websiteUrl: "https://fluidgrids.com"
6575
+ websiteUrl: "https://www.fluidgrids.ai"
5385
6576
  },
5386
6577
  // Botlit ships on botlit.ai — botlit.com does not resolve.
5387
6578
  { slug: "botlit", name: "Botlit", websiteUrl: "https://www.botlit.ai" },
@@ -6808,6 +7999,7 @@ function toPayload(staged) {
6808
7999
  textContent
6809
8000
  }));
6810
8001
  }
8002
+ var SHORT_VIEWPORT_PX = 420;
6811
8003
  var EXPLORE_CSS = `
6812
8004
  @keyframes boff-explore-pulse {
6813
8005
  0%, 80%, 100% { opacity: 0.25; transform: translateY(0); }
@@ -6842,6 +8034,12 @@ var EXPLORE_CSS = `
6842
8034
  .boff-explore-scroll {
6843
8035
  scrollbar-width: thin;
6844
8036
  scrollbar-color: hsl(var(--border)) transparent;
8037
+ /* Stop the transcript handing its scroll to the page. Without this, the first
8038
+ swipe that exhausts the transcript chains to the document \u2014 and on a host site
8039
+ that is 65-70% footer, which is how a phone ends up showing nothing but the
8040
+ footer. Engines that do not support this property ignore the line and keep
8041
+ today's behaviour; the scroll correction above covers them. */
8042
+ overscroll-behavior: contain;
6845
8043
  }
6846
8044
  .boff-explore-scroll::-webkit-scrollbar { width: 10px; }
6847
8045
  .boff-explore-scroll::-webkit-scrollbar-track { background: transparent; }
@@ -6959,6 +8157,68 @@ var EXPLORE_CSS = `
6959
8157
  .boff-explore-busy::after { animation: none; }
6960
8158
  .boff-explore-rise { animation: none; opacity: 1; transform: none; }
6961
8159
  }
8160
+
8161
+ /* ---- Pane height ----------------------------------------------------------------------
8162
+ This used to be one inline declaration, \`height: calc(100dvh - 64px)\`, and it carried two
8163
+ defects. An inline style cannot carry a fallback, so every engine without \`dvh\` (iOS
8164
+ Safari < 15.4, Chrome/WebView < 108, Samsung Internet < 21, Firefox < 101) dropped it
8165
+ whole; and the 64px came from a prop hard-coded to 64 on all 41 host pages that matches
8166
+ none of them \u2014 the burdenoff/algoshred chrome is 80px, the sticky-header sites are 65.
8167
+
8168
+ A class plus custom properties lets the cascade do the work: \`vh\` is the floor and \`dvh\`
8169
+ an upgrade where it exists, while the two measured values stay *lengths*, never a height.
8170
+ That distinction is the whole prerender contract. The host sites snapshot \`/explore\` by
8171
+ loading the built SPA in headless Chromium and writing the POST-HYDRATION DOM to
8172
+ dist/explore/index.html, so every attribute and inline value this component sets after
8173
+ mount IS the static HTML CloudFront serves. A measured pixel *height* would therefore
8174
+ hand every phone the prerender viewport's height until the bundle executes; a measured
8175
+ *offset* is a site-header height, which is the same on every device to within a few
8176
+ pixels, and the height built from it stays viewport-relative on the visitor's own screen.
8177
+
8178
+ --boff-explore-offset chrome above the pane (measured root top; the prop pre-measure)
8179
+ --boff-explore-inset the slice of the layout viewport hidden below the visible area \u2014
8180
+ the on-screen keyboard, which \`dvh\` does not track. Zero unless
8181
+ something is actually covering the bottom, so a snapshot taken
8182
+ with no keyboard open never carries it. */
8183
+ .boff-explore-viewport {
8184
+ height: calc(100vh - var(--boff-explore-offset, 0px) - var(--boff-explore-inset, 0px));
8185
+ }
8186
+ @supports (height: 100dvh) {
8187
+ .boff-explore-viewport {
8188
+ height: calc(100dvh - var(--boff-explore-offset, 0px) - var(--boff-explore-inset, 0px));
8189
+ }
8190
+ }
8191
+
8192
+ /* Landscape phones and other short viewports: a one-screen pane leaves a ~124px transcript
8193
+ sliver under ~610px of chrome and content. At or below the threshold the pane stops
8194
+ pretending to be a window and lets the page's own scrolling carry the transcript. The
8195
+ min-height is the available height rather than a fixed rem value, so the fallback can
8196
+ never be taller than the screen it is rescuing. */
8197
+ @media (max-height: ${SHORT_VIEWPORT_PX}px) {
8198
+ .boff-explore-viewport {
8199
+ height: auto;
8200
+ min-height: calc(100vh - var(--boff-explore-offset, 0px));
8201
+ }
8202
+ }
8203
+ @supports (height: 100dvh) {
8204
+ @media (max-height: ${SHORT_VIEWPORT_PX}px) {
8205
+ .boff-explore-viewport {
8206
+ min-height: calc(100dvh - var(--boff-explore-offset, 0px));
8207
+ }
8208
+ }
8209
+ }
8210
+
8211
+ /* ---- Composer dock --------------------------------------------------------------------
8212
+ Three declarations, each the fallback for the one after it: a plain 1rem where \`max()\`
8213
+ is unknown, then the measured overlap of any FOREIGN fixed chrome sitting over the
8214
+ composer (the host sites' cookie banner is 229px tall and lands exactly there), then the
8215
+ same plus the home-indicator inset. \`--boff-explore-chrome\` is set on the root only once
8216
+ an overlap has actually been measured, so everywhere else this collapses to 1rem. */
8217
+ .boff-explore-composer {
8218
+ padding-bottom: 1rem;
8219
+ padding-bottom: max(1rem, var(--boff-explore-chrome, 0px));
8220
+ padding-bottom: max(1rem, env(safe-area-inset-bottom), var(--boff-explore-chrome, 0px));
8221
+ }
6962
8222
  `;
6963
8223
  function ExploreStyles() {
6964
8224
  return /* @__PURE__ */ jsx("style", { dangerouslySetInnerHTML: { __html: EXPLORE_CSS } });
@@ -6980,6 +8240,8 @@ var CAPABILITIES = [
6980
8240
  body: "Get the sources and next steps \u2014 pricing, docs, a demo \u2014 without hunting."
6981
8241
  }
6982
8242
  ];
8243
+ var MIN_VISIBLE_FRACTION = 0.25;
8244
+ var SDK_OVERLAY_SELECTOR = "[data-boff-explore]";
6983
8245
  var CTA_VARIANTS = {
6984
8246
  CONTACT: "default",
6985
8247
  WAITLIST: "default",
@@ -6995,6 +8257,28 @@ function normalizeOffset(offset) {
6995
8257
  if (offset === void 0) return "0px";
6996
8258
  return typeof offset === "number" ? `${offset}px` : offset;
6997
8259
  }
8260
+ function isOwnElement(el, root) {
8261
+ if (el === document.body || el === document.documentElement) return true;
8262
+ if (root.contains(el)) return true;
8263
+ return el.closest(SDK_OVERLAY_SELECTOR) !== null;
8264
+ }
8265
+ function visualViewportHeight() {
8266
+ return window.visualViewport?.height ?? window.innerHeight;
8267
+ }
8268
+ function clamp(value, min, max) {
8269
+ return Math.min(Math.max(value, min), max);
8270
+ }
8271
+ function isRestoredNavigation() {
8272
+ const entries = window.performance?.getEntriesByType?.("navigation");
8273
+ const entry = entries?.[0];
8274
+ if (!entry) return true;
8275
+ const navigation = entry;
8276
+ return navigation.type === "reload" || navigation.type === "back_forward";
8277
+ }
8278
+ function pageOwnsScrolling(el) {
8279
+ if (window.innerHeight > SHORT_VIEWPORT_PX) return false;
8280
+ return el.scrollHeight - el.clientHeight <= 1;
8281
+ }
6998
8282
  function isInternalPath(url) {
6999
8283
  return url.startsWith("/") && !url.startsWith("//");
7000
8284
  }
@@ -7018,6 +8302,93 @@ function logoUrlOf(url) {
7018
8302
  return null;
7019
8303
  }
7020
8304
  }
8305
+ function inlineImageOrigins(products) {
8306
+ const origins = /* @__PURE__ */ new Set();
8307
+ for (const product of products) {
8308
+ let url;
8309
+ try {
8310
+ url = new URL(product.website);
8311
+ } catch {
8312
+ continue;
8313
+ }
8314
+ if (url.protocol !== "https:") continue;
8315
+ const apex = url.hostname.replace(/^www\./, "");
8316
+ const port = url.port ? `:${url.port}` : "";
8317
+ origins.add(`https://${apex}${port}`);
8318
+ origins.add(`https://www.${apex}${port}`);
8319
+ }
8320
+ return origins;
8321
+ }
8322
+ function isInlineImageAllowed(src, origins) {
8323
+ if (typeof src !== "string" || src === "") return false;
8324
+ let url;
8325
+ try {
8326
+ url = new URL(src);
8327
+ } catch {
8328
+ return false;
8329
+ }
8330
+ if (url.protocol !== "https:" || url.username || url.password) return false;
8331
+ return origins.has(url.origin);
8332
+ }
8333
+ var InlineImageScopeContext = createContext(null);
8334
+ var InsideLinkContext = createContext(false);
8335
+ function AnswerLink(props) {
8336
+ return /* @__PURE__ */ jsx(InsideLinkContext.Provider, { value: true, children: /* @__PURE__ */ jsx(MarkdownLink, { ...props }) });
8337
+ }
8338
+ var INLINE_IMAGE_FRAME = "relative inline-block max-w-full overflow-hidden rounded-xl border border-border bg-muted align-top shadow-sm";
8339
+ function InlineConceptImage({ src, alt }) {
8340
+ const scope = useContext(InlineImageScopeContext);
8341
+ const insideLink = useContext(InsideLinkContext);
8342
+ if (!scope || !scope.enabled || !isInlineImageAllowed(src, scope.origins) || scope.failed.has(src)) {
8343
+ return null;
8344
+ }
8345
+ const { strings: T, onFailed } = scope;
8346
+ const picture = /* @__PURE__ */ jsxs(Fragment, { children: [
8347
+ /* @__PURE__ */ jsx(
8348
+ "img",
8349
+ {
8350
+ src,
8351
+ alt: alt ?? "",
8352
+ loading: "lazy",
8353
+ decoding: "async",
8354
+ onError: () => onFailed(src),
8355
+ className: "block h-auto max-h-80 w-auto max-w-full object-contain"
8356
+ }
8357
+ ),
8358
+ /* @__PURE__ */ jsx(
8359
+ "span",
8360
+ {
8361
+ "aria-hidden": "true",
8362
+ className: "pointer-events-none absolute left-2 top-2 rounded-full border border-border bg-background/90 px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide text-foreground shadow-sm",
8363
+ children: T.conceptIllustration
8364
+ }
8365
+ )
8366
+ ] });
8367
+ return /* @__PURE__ */ jsx("span", { "data-boff-explore": "inline-image", className: "my-3 block", children: insideLink ? /* @__PURE__ */ jsx("span", { className: INLINE_IMAGE_FRAME, children: picture }) : /* @__PURE__ */ jsxs(
8368
+ "a",
8369
+ {
8370
+ href: src,
8371
+ target: "_blank",
8372
+ rel: "noopener noreferrer",
8373
+ className: cn(
8374
+ INLINE_IMAGE_FRAME,
8375
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
8376
+ ),
8377
+ children: [
8378
+ picture,
8379
+ /* @__PURE__ */ jsxs("span", { className: "sr-only", children: [
8380
+ "(",
8381
+ T.opensInNewTab,
8382
+ ")"
8383
+ ] })
8384
+ ]
8385
+ }
8386
+ ) });
8387
+ }
8388
+ var ANSWER_MARKDOWN_COMPONENTS = {
8389
+ a: AnswerLink,
8390
+ img: InlineConceptImage
8391
+ };
7021
8392
  function ReferenceCard({
7022
8393
  reference,
7023
8394
  onFollow
@@ -7200,6 +8571,7 @@ function AssistantBubble({
7200
8571
  strings: T,
7201
8572
  message,
7202
8573
  activity,
8574
+ imageOrigins,
7203
8575
  onNavigate,
7204
8576
  anchorRef,
7205
8577
  onFollow,
@@ -7208,6 +8580,25 @@ function AssistantBubble({
7208
8580
  const streaming = message.status === "PENDING" || message.status === "RUNNING";
7209
8581
  const body = message.content || message.partialContent || "";
7210
8582
  const failed = message.status === "FAILED";
8583
+ const completed = message.status === "COMPLETED";
8584
+ const [failedImages, setFailedImages] = useState(
8585
+ () => /* @__PURE__ */ new Set()
8586
+ );
8587
+ const markImageFailed = useCallback((src) => {
8588
+ setFailedImages(
8589
+ (current) => current.has(src) ? current : new Set(current).add(src)
8590
+ );
8591
+ }, []);
8592
+ const imageScope = useMemo(
8593
+ () => ({
8594
+ strings: T,
8595
+ enabled: completed,
8596
+ origins: imageOrigins,
8597
+ failed: failedImages,
8598
+ onFailed: markImageFailed
8599
+ }),
8600
+ [T, completed, imageOrigins, failedImages, markImageFailed]
8601
+ );
7211
8602
  return /* @__PURE__ */ jsxs(
7212
8603
  "div",
7213
8604
  {
@@ -7254,7 +8645,7 @@ function AssistantBubble({
7254
8645
  }
7255
8646
  ) : null,
7256
8647
  body ? /* @__PURE__ */ jsxs("div", { className: "rounded-2xl rounded-tl-md border border-border bg-card px-4 py-3 shadow-sm", children: [
7257
- /* @__PURE__ */ jsx("div", { className: "boff-prose boff-prose-sm boff-explore-body min-w-0 text-card-foreground", children: /* @__PURE__ */ jsx(Markdown, { children: body }) }),
8648
+ /* @__PURE__ */ jsx("div", { className: "boff-prose boff-prose-sm boff-explore-body min-w-0 text-card-foreground", children: /* @__PURE__ */ jsx(InlineImageScopeContext.Provider, { value: imageScope, children: /* @__PURE__ */ jsx(Markdown, { components: ANSWER_MARKDOWN_COMPONENTS, children: body }) }) }),
7258
8649
  streaming ? /* @__PURE__ */ jsx("span", { className: "boff-explore-caret", "aria-hidden": "true" }) : null
7259
8650
  ] }) : null,
7260
8651
  streaming ? /* @__PURE__ */ jsx(ThinkingIndicator, { activity }) : null,
@@ -7736,6 +9127,8 @@ function ExplorePage({
7736
9127
  const pickQueueRef = useRef(Promise.resolve());
7737
9128
  const [shareLabel, setShareLabel] = useState(T.share);
7738
9129
  const [shareUrl, setShareUrl] = useState(null);
9130
+ const rootRef = useRef(null);
9131
+ const composerRef = useRef(null);
7739
9132
  const scrollRef = useRef(null);
7740
9133
  const latestAssistantRef = useRef(null);
7741
9134
  const alignedForRef = useRef(null);
@@ -7753,17 +9146,206 @@ function ExplorePage({
7753
9146
  () => catalog.products.find((p) => p.slug === focusProduct)?.name ?? null,
7754
9147
  [catalog.products, focusProduct]
7755
9148
  );
9149
+ const imageOrigins = useMemo(
9150
+ () => inlineImageOrigins(catalog.products),
9151
+ [catalog.products]
9152
+ );
7756
9153
  useEffect(() => {
7757
9154
  const el = textareaRef.current;
7758
9155
  if (!el) return;
7759
9156
  el.style.height = "auto";
7760
9157
  el.style.height = `${Math.min(el.scrollHeight, 200)}px`;
7761
9158
  }, [draft]);
9159
+ const [paneOffset, setPaneOffset] = useState(null);
9160
+ const [bottomInset, setBottomInset] = useState(0);
9161
+ const paneOffsetRef = useRef(0);
9162
+ const measurePane = useCallback(() => {
9163
+ if (heightMode !== "viewport") return;
9164
+ const el = rootRef.current;
9165
+ if (!el) return;
9166
+ const layoutHeight = window.innerHeight;
9167
+ if (layoutHeight === 0) return;
9168
+ const top = Math.round(
9169
+ clamp(el.getBoundingClientRect().top, 0, layoutHeight)
9170
+ );
9171
+ const viewport = window.visualViewport;
9172
+ const inset = viewport ? Math.round(
9173
+ clamp(
9174
+ layoutHeight - viewport.height - viewport.offsetTop,
9175
+ 0,
9176
+ layoutHeight
9177
+ )
9178
+ ) : 0;
9179
+ paneOffsetRef.current = top;
9180
+ setPaneOffset((current) => current === top ? current : top);
9181
+ setBottomInset((current) => current === inset ? current : inset);
9182
+ }, [heightMode]);
9183
+ const [chromeOverlap, setChromeOverlap] = useState(0);
9184
+ const measureChrome = useCallback(() => {
9185
+ const root = rootRef.current;
9186
+ const dock = composerRef.current;
9187
+ if (!root || !dock) return;
9188
+ if (typeof document.elementFromPoint !== "function") return;
9189
+ const viewportHeight = visualViewportHeight();
9190
+ const rect = dock.getBoundingClientRect();
9191
+ if (rect.width === 0 || viewportHeight === 0) return;
9192
+ if (rect.bottom <= 0 || rect.top >= viewportHeight) return;
9193
+ const edge = Math.min(rect.bottom, viewportHeight);
9194
+ const hit = document.elementFromPoint(rect.left + rect.width / 2, edge - 1);
9195
+ if (!hit || isOwnElement(hit, root)) {
9196
+ setChromeOverlap(0);
9197
+ return;
9198
+ }
9199
+ const overlap = Math.round(edge - hit.getBoundingClientRect().top);
9200
+ setChromeOverlap(overlap > 0 && overlap < viewportHeight ? overlap : 0);
9201
+ }, []);
9202
+ const remeasure = useCallback(() => {
9203
+ measurePane();
9204
+ measureChrome();
9205
+ }, [measurePane, measureChrome]);
9206
+ useEffect(() => {
9207
+ if (typeof window === "undefined") return;
9208
+ let frame = 0;
9209
+ const run = () => {
9210
+ frame = 0;
9211
+ remeasure();
9212
+ };
9213
+ const schedule = () => {
9214
+ if (frame) return;
9215
+ if (typeof window.requestAnimationFrame !== "function") {
9216
+ remeasure();
9217
+ return;
9218
+ }
9219
+ frame = window.requestAnimationFrame(run);
9220
+ };
9221
+ remeasure();
9222
+ const viewport = window.visualViewport;
9223
+ window.addEventListener("resize", schedule);
9224
+ window.addEventListener("orientationchange", schedule);
9225
+ viewport?.addEventListener("resize", schedule);
9226
+ viewport?.addEventListener("scroll", schedule);
9227
+ const observer = typeof MutationObserver === "function" ? new MutationObserver((records) => {
9228
+ const el = rootRef.current;
9229
+ if (el && records.every((record) => el.contains(record.target)))
9230
+ return;
9231
+ schedule();
9232
+ }) : null;
9233
+ observer?.observe(document.body, { childList: true, subtree: true });
9234
+ return () => {
9235
+ if (frame) window.cancelAnimationFrame(frame);
9236
+ window.removeEventListener("resize", schedule);
9237
+ window.removeEventListener("orientationchange", schedule);
9238
+ viewport?.removeEventListener("resize", schedule);
9239
+ viewport?.removeEventListener("scroll", schedule);
9240
+ observer?.disconnect();
9241
+ setPaneOffset(null);
9242
+ setBottomInset(0);
9243
+ setChromeOverlap(0);
9244
+ };
9245
+ }, [remeasure]);
9246
+ useEffect(() => {
9247
+ measureChrome();
9248
+ }, [measureChrome, paneOffset, bottomInset]);
9249
+ useEffect(() => {
9250
+ if (heightMode !== "viewport" || typeof window === "undefined") return;
9251
+ const { history: browserHistory } = window;
9252
+ const previousRestoration = "scrollRestoration" in browserHistory ? browserHistory.scrollRestoration : null;
9253
+ if (previousRestoration !== null)
9254
+ browserHistory.scrollRestoration = "manual";
9255
+ let frame = 0;
9256
+ let visitorMoved = false;
9257
+ const onVisitorMove = () => {
9258
+ visitorMoved = true;
9259
+ };
9260
+ const align = () => {
9261
+ if (visitorMoved) return;
9262
+ const el = rootRef.current;
9263
+ if (!el) return;
9264
+ const viewportHeight = visualViewportHeight();
9265
+ const rect = el.getBoundingClientRect();
9266
+ if (rect.height === 0 || viewportHeight === 0) return;
9267
+ const visible = Math.min(rect.bottom, viewportHeight) - Math.max(rect.top, 0);
9268
+ const reachable = Math.min(rect.height, viewportHeight);
9269
+ if (visible >= reachable * MIN_VISIBLE_FRACTION) return;
9270
+ window.scrollTo({
9271
+ top: Math.max(0, window.scrollY + rect.top),
9272
+ left: window.scrollX,
9273
+ behavior: "auto"
9274
+ });
9275
+ if (typeof document.elementFromPoint === "function") {
9276
+ const probe = document.elementFromPoint(
9277
+ Math.max(0, rect.left + rect.width / 2),
9278
+ 1
9279
+ );
9280
+ if (probe && !isOwnElement(probe, el)) {
9281
+ const chrome = probe.getBoundingClientRect().bottom;
9282
+ if (chrome > 0 && chrome < viewportHeight / 2) {
9283
+ window.scrollBy({ top: -chrome, left: 0, behavior: "auto" });
9284
+ }
9285
+ }
9286
+ }
9287
+ remeasure();
9288
+ };
9289
+ const alignIfRestored = () => {
9290
+ if (!isRestoredNavigation()) return;
9291
+ align();
9292
+ };
9293
+ alignIfRestored();
9294
+ if (typeof window.requestAnimationFrame === "function") {
9295
+ frame = window.requestAnimationFrame(alignIfRestored);
9296
+ }
9297
+ const onPageShow = (event) => {
9298
+ if (!event.persisted) {
9299
+ alignIfRestored();
9300
+ return;
9301
+ }
9302
+ visitorMoved = false;
9303
+ align();
9304
+ };
9305
+ window.addEventListener("pageshow", onPageShow);
9306
+ window.addEventListener("wheel", onVisitorMove, { passive: true });
9307
+ window.addEventListener("touchmove", onVisitorMove, { passive: true });
9308
+ window.addEventListener("keydown", onVisitorMove, { passive: true });
9309
+ return () => {
9310
+ if (frame) window.cancelAnimationFrame(frame);
9311
+ window.removeEventListener("pageshow", onPageShow);
9312
+ window.removeEventListener("wheel", onVisitorMove);
9313
+ window.removeEventListener("touchmove", onVisitorMove);
9314
+ window.removeEventListener("keydown", onVisitorMove);
9315
+ if (previousRestoration !== null)
9316
+ browserHistory.scrollRestoration = previousRestoration;
9317
+ };
9318
+ }, [heightMode, remeasure]);
7762
9319
  const handleScroll = useCallback(() => {
7763
9320
  const el = scrollRef.current;
7764
9321
  if (!el) return;
7765
9322
  stickToBottomRef.current = el.scrollHeight - el.scrollTop - el.clientHeight < 80;
7766
9323
  }, []);
9324
+ useEffect(() => {
9325
+ if (typeof window === "undefined") return;
9326
+ let frame = 0;
9327
+ const run = () => {
9328
+ frame = 0;
9329
+ const el = scrollRef.current;
9330
+ const dock = composerRef.current;
9331
+ if (!el || !dock) return;
9332
+ if (!pageOwnsScrolling(el)) return;
9333
+ stickToBottomRef.current = dock.getBoundingClientRect().bottom - visualViewportHeight() < 80;
9334
+ };
9335
+ const schedule = () => {
9336
+ if (frame) return;
9337
+ if (typeof window.requestAnimationFrame !== "function") {
9338
+ run();
9339
+ return;
9340
+ }
9341
+ frame = window.requestAnimationFrame(run);
9342
+ };
9343
+ window.addEventListener("scroll", schedule, { passive: true });
9344
+ return () => {
9345
+ if (frame) window.cancelAnimationFrame(frame);
9346
+ window.removeEventListener("scroll", schedule);
9347
+ };
9348
+ }, []);
7767
9349
  const latestAssistantId = useMemo(() => {
7768
9350
  for (let i = messages.length - 1; i >= 0; i -= 1) {
7769
9351
  const message = messages[i];
@@ -7779,16 +9361,32 @@ function ExplorePage({
7779
9361
  if (!stickToBottomRef.current) return;
7780
9362
  if (anchor.offsetHeight === 0) return;
7781
9363
  alignedForRef.current = latestAssistantId;
7782
- const delta = anchor.getBoundingClientRect().top - el.getBoundingClientRect().top;
7783
- el.scrollTop = Math.max(0, el.scrollTop + delta - 12);
9364
+ if (!pageOwnsScrolling(el)) {
9365
+ const delta2 = anchor.getBoundingClientRect().top - el.getBoundingClientRect().top;
9366
+ el.scrollTop = Math.max(0, el.scrollTop + delta2 - 12);
9367
+ return;
9368
+ }
9369
+ const delta = Math.round(
9370
+ anchor.getBoundingClientRect().top - paneOffsetRef.current - 12
9371
+ );
9372
+ if (delta !== 0) window.scrollBy({ top: delta, left: 0, behavior: "auto" });
7784
9373
  }, [latestAssistantId, messages]);
7785
9374
  useEffect(() => {
9375
+ if (messages.length === 0) return;
7786
9376
  if (!stickToBottomRef.current) return;
7787
9377
  if (latestAssistantId && alignedForRef.current === latestAssistantId)
7788
9378
  return;
7789
9379
  const el = scrollRef.current;
7790
9380
  if (!el) return;
7791
- el.scrollTop = el.scrollHeight;
9381
+ if (!pageOwnsScrolling(el)) {
9382
+ el.scrollTop = el.scrollHeight;
9383
+ return;
9384
+ }
9385
+ const dock = composerRef.current ?? el;
9386
+ const delta = Math.round(
9387
+ dock.getBoundingClientRect().bottom - visualViewportHeight()
9388
+ );
9389
+ if (delta > 0) window.scrollBy({ top: delta, left: 0, behavior: "auto" });
7792
9390
  }, [activity, latestAssistantId, messages]);
7793
9391
  const handleShare = useCallback(async () => {
7794
9392
  setShareLabel(T.copying);
@@ -7886,16 +9484,27 @@ function ExplorePage({
7886
9484
  const captchaOn = Boolean(
7887
9485
  catalog.captchaRequired && catalog.recaptchaSiteKey
7888
9486
  );
7889
- const rootStyle = heightMode === "viewport" ? { height: `calc(100dvh - ${normalizeOffset(viewportOffset)})` } : void 0;
9487
+ const rootStyle = {};
9488
+ if (heightMode === "viewport") {
9489
+ rootStyle["--boff-explore-offset"] = paneOffset === null ? normalizeOffset(viewportOffset) : `${paneOffset}px`;
9490
+ if (bottomInset > 0) {
9491
+ rootStyle["--boff-explore-inset"] = `${bottomInset}px`;
9492
+ }
9493
+ }
9494
+ if (chromeOverlap > 0) {
9495
+ rootStyle["--boff-explore-chrome"] = `${chromeOverlap}px`;
9496
+ }
7890
9497
  return /* @__PURE__ */ jsxs(
7891
9498
  "div",
7892
9499
  {
9500
+ ref: rootRef,
7893
9501
  "data-boff-explore": "page",
7894
9502
  "data-phase": phase,
7895
9503
  "data-locale": activeLocale,
7896
9504
  dir: rtl ? "rtl" : void 0,
7897
9505
  className: cn(
7898
9506
  "flex w-full min-w-0 flex-col overflow-x-hidden bg-background text-foreground",
9507
+ heightMode === "viewport" && "boff-explore-viewport",
7899
9508
  heightMode === "auto" && "min-h-[70vh]",
7900
9509
  className
7901
9510
  ),
@@ -8083,6 +9692,7 @@ function ExplorePage({
8083
9692
  strings: T,
8084
9693
  message,
8085
9694
  activity,
9695
+ imageOrigins,
8086
9696
  onNavigate,
8087
9697
  anchorRef: message.id === latestAssistantId ? latestAssistantRef : void 0,
8088
9698
  onFollow: (kind, url) => recordClick(message.id, kind, url),
@@ -8128,249 +9738,257 @@ function ExplorePage({
8128
9738
  ]
8129
9739
  }
8130
9740
  ) : null,
8131
- /* @__PURE__ */ jsx("div", { className: "border-t border-border bg-background/85 px-4 pb-[max(1rem,env(safe-area-inset-bottom))] pt-3 backdrop-blur-md", children: /* @__PURE__ */ jsxs(
8132
- "form",
9741
+ /* @__PURE__ */ jsx(
9742
+ "div",
8133
9743
  {
8134
- "data-boff-explore": "composer",
8135
- className: "mx-auto w-full max-w-3xl",
8136
- onSubmit: (event) => {
8137
- event.preventDefault();
8138
- submitDraft();
8139
- },
8140
- children: [
8141
- error ? /* @__PURE__ */ jsx(ErrorBanner, { error, onRetry: retry, onReset: reset }) : null,
8142
- staged.length > 0 ? /* @__PURE__ */ jsx(
8143
- "ul",
8144
- {
8145
- "data-boff-explore": "attachments",
8146
- className: "mb-2 flex flex-wrap gap-1.5",
8147
- "aria-label": T.attach,
8148
- children: staged.map((entry) => /* @__PURE__ */ jsxs(
8149
- "li",
9744
+ ref: composerRef,
9745
+ "data-boff-explore": "composer-dock",
9746
+ className: "boff-explore-composer border-t border-border bg-background/85 px-4 pt-3 backdrop-blur-md",
9747
+ children: /* @__PURE__ */ jsxs(
9748
+ "form",
9749
+ {
9750
+ "data-boff-explore": "composer",
9751
+ className: "mx-auto w-full max-w-3xl",
9752
+ onSubmit: (event) => {
9753
+ event.preventDefault();
9754
+ submitDraft();
9755
+ },
9756
+ children: [
9757
+ error ? /* @__PURE__ */ jsx(ErrorBanner, { error, onRetry: retry, onReset: reset }) : null,
9758
+ staged.length > 0 ? /* @__PURE__ */ jsx(
9759
+ "ul",
9760
+ {
9761
+ "data-boff-explore": "attachments",
9762
+ className: "mb-2 flex flex-wrap gap-1.5",
9763
+ "aria-label": T.attach,
9764
+ children: staged.map((entry) => /* @__PURE__ */ jsxs(
9765
+ "li",
9766
+ {
9767
+ "data-boff-explore": "attachment",
9768
+ "data-text-extracted": entry.textExtracted ? "true" : "false",
9769
+ className: "flex max-w-full items-center gap-1.5 rounded-full border border-border bg-muted/60 py-1 pl-2.5 pr-1 text-xs",
9770
+ children: [
9771
+ /* @__PURE__ */ jsx(Paperclip, { className: "h-3 w-3 shrink-0 text-muted-foreground" }),
9772
+ /* @__PURE__ */ jsx("span", { className: "truncate font-medium", title: entry.name, children: entry.name }),
9773
+ /* @__PURE__ */ jsxs("span", { className: "shrink-0 text-muted-foreground", children: [
9774
+ formatBytes(entry.size),
9775
+ entry.textExtracted ? "" : ` \xB7 ${T.attachmentNameOnly}`
9776
+ ] }),
9777
+ /* @__PURE__ */ jsx(
9778
+ "button",
9779
+ {
9780
+ type: "button",
9781
+ "data-boff-explore": "attachment-remove",
9782
+ onClick: () => removeAttachment(entry.id),
9783
+ "aria-label": fill(T.removeAttachment, { name: entry.name }),
9784
+ className: "ml-0.5 flex h-5 w-5 shrink-0 items-center justify-center rounded-full text-muted-foreground transition-colors hover:bg-background hover:text-foreground",
9785
+ children: /* @__PURE__ */ jsx(X, { className: "h-3 w-3" })
9786
+ }
9787
+ )
9788
+ ]
9789
+ },
9790
+ entry.id
9791
+ ))
9792
+ }
9793
+ ) : null,
9794
+ attachmentNotice !== null ? /* @__PURE__ */ jsx(
9795
+ "p",
9796
+ {
9797
+ "data-boff-explore": "attachment-notice",
9798
+ role: "status",
9799
+ className: "mb-2 text-xs text-destructive",
9800
+ children: attachmentNotice
9801
+ }
9802
+ ) : null,
9803
+ /* @__PURE__ */ jsxs(
9804
+ "div",
8150
9805
  {
8151
- "data-boff-explore": "attachment",
8152
- "data-text-extracted": entry.textExtracted ? "true" : "false",
8153
- className: "flex max-w-full items-center gap-1.5 rounded-full border border-border bg-muted/60 py-1 pl-2.5 pr-1 text-xs",
9806
+ className: cn(
9807
+ "flex min-w-0 items-end gap-2 rounded-2xl border bg-card p-2 shadow-sm transition-all",
9808
+ busy && "boff-explore-busy",
9809
+ overLimit ? "border-destructive/60" : "border-border focus-within:border-primary/40 focus-within:ring-1 focus-within:ring-ring"
9810
+ ),
8154
9811
  children: [
8155
- /* @__PURE__ */ jsx(Paperclip, { className: "h-3 w-3 shrink-0 text-muted-foreground" }),
8156
- /* @__PURE__ */ jsx("span", { className: "truncate font-medium", title: entry.name, children: entry.name }),
8157
- /* @__PURE__ */ jsxs("span", { className: "shrink-0 text-muted-foreground", children: [
8158
- formatBytes(entry.size),
8159
- entry.textExtracted ? "" : ` \xB7 ${T.attachmentNameOnly}`
8160
- ] }),
8161
9812
  /* @__PURE__ */ jsx(
8162
- "button",
9813
+ Textarea,
9814
+ {
9815
+ ref: textareaRef,
9816
+ value: draft,
9817
+ rows: 1,
9818
+ disabled: composerDisabled,
9819
+ onChange: (event) => setDraft(event.target.value),
9820
+ onKeyDown: handleKeyDown,
9821
+ onCompositionStart: () => {
9822
+ composingRef.current = true;
9823
+ },
9824
+ onCompositionEnd: () => {
9825
+ composingRef.current = false;
9826
+ },
9827
+ "aria-label": "Ask a question",
9828
+ placeholder: composerDisabled ? phase === "limited" ? "Message limit reached \u2014 please try again later" : "Explore is unavailable right now" : focusedProductName ? fill(T.placeholderProduct, {
9829
+ product: focusedProductName
9830
+ }) : T.placeholder,
9831
+ className: "max-h-[200px] min-h-[44px] w-full min-w-0 flex-1 resize-none border-0 bg-transparent px-2 py-2.5 text-base shadow-none focus-visible:ring-0 sm:text-sm"
9832
+ }
9833
+ ),
9834
+ /* @__PURE__ */ jsx(
9835
+ "input",
9836
+ {
9837
+ ref: fileInputRef,
9838
+ type: "file",
9839
+ multiple: true,
9840
+ className: "hidden",
9841
+ onChange: (event) => {
9842
+ void handleFilesPicked(event.target.files);
9843
+ event.target.value = "";
9844
+ }
9845
+ }
9846
+ ),
9847
+ /* @__PURE__ */ jsx(
9848
+ Button,
9849
+ {
9850
+ "data-boff-explore": "attach",
9851
+ type: "button",
9852
+ size: "icon",
9853
+ variant: "ghost",
9854
+ disabled: composerDisabled || staged.length >= MAX_ATTACHMENTS,
9855
+ "aria-label": T.attach,
9856
+ title: `${T.attach} \u2014 ${fill(T.attachHint, {
9857
+ max: String(MAX_ATTACHMENTS),
9858
+ size: String(MAX_ATTACHMENT_BYTES / (1024 * 1024))
9859
+ })}`,
9860
+ onClick: () => fileInputRef.current?.click(),
9861
+ children: /* @__PURE__ */ jsx(Paperclip, { className: "h-4 w-4" })
9862
+ }
9863
+ ),
9864
+ speech.supported ? /* @__PURE__ */ jsx(
9865
+ Button,
9866
+ {
9867
+ "data-boff-explore": "mic",
9868
+ "data-listening": speech.listening ? "true" : "false",
9869
+ type: "button",
9870
+ size: "icon",
9871
+ variant: speech.listening ? "default" : "ghost",
9872
+ disabled: composerDisabled,
9873
+ "aria-label": speech.listening ? T.stopDictating : T.dictate,
9874
+ "aria-pressed": speech.listening,
9875
+ title: speech.listening ? T.stopDictating : T.dictate,
9876
+ onClick: speech.toggle,
9877
+ className: cn(speech.listening && "animate-pulse"),
9878
+ children: /* @__PURE__ */ jsx(Mic, { className: "h-4 w-4" })
9879
+ }
9880
+ ) : null,
9881
+ busy ? /* @__PURE__ */ jsx(
9882
+ Button,
8163
9883
  {
9884
+ "data-boff-explore": "stop",
8164
9885
  type: "button",
8165
- "data-boff-explore": "attachment-remove",
8166
- onClick: () => removeAttachment(entry.id),
8167
- "aria-label": fill(T.removeAttachment, { name: entry.name }),
8168
- className: "ml-0.5 flex h-5 w-5 shrink-0 items-center justify-center rounded-full text-muted-foreground transition-colors hover:bg-background hover:text-foreground",
8169
- children: /* @__PURE__ */ jsx(X, { className: "h-3 w-3" })
9886
+ size: "icon",
9887
+ variant: "secondary",
9888
+ "aria-label": T.stop,
9889
+ onClick: stop,
9890
+ children: /* @__PURE__ */ jsx(Square, { className: "h-4 w-4" })
9891
+ }
9892
+ ) : /* @__PURE__ */ jsx(
9893
+ Button,
9894
+ {
9895
+ "data-boff-explore": "send",
9896
+ type: "submit",
9897
+ size: "icon",
9898
+ disabled: !canSubmit,
9899
+ "aria-label": T.send,
9900
+ children: /* @__PURE__ */ jsx(ArrowUp, { className: "h-4 w-4" })
8170
9901
  }
8171
9902
  )
8172
9903
  ]
8173
- },
8174
- entry.id
8175
- ))
8176
- }
8177
- ) : null,
8178
- attachmentNotice !== null ? /* @__PURE__ */ jsx(
8179
- "p",
8180
- {
8181
- "data-boff-explore": "attachment-notice",
8182
- role: "status",
8183
- className: "mb-2 text-xs text-destructive",
8184
- children: attachmentNotice
8185
- }
8186
- ) : null,
8187
- /* @__PURE__ */ jsxs(
8188
- "div",
8189
- {
8190
- className: cn(
8191
- "flex min-w-0 items-end gap-2 rounded-2xl border bg-card p-2 shadow-sm transition-all",
8192
- busy && "boff-explore-busy",
8193
- overLimit ? "border-destructive/60" : "border-border focus-within:border-primary/40 focus-within:ring-1 focus-within:ring-ring"
9904
+ }
8194
9905
  ),
8195
- children: [
8196
- /* @__PURE__ */ jsx(
8197
- Textarea,
9906
+ speech.listening || speech.interim !== "" ? /* @__PURE__ */ jsxs(
9907
+ "p",
9908
+ {
9909
+ "data-boff-explore": "dictation",
9910
+ className: "mt-2 flex items-center gap-2 text-xs text-muted-foreground",
9911
+ "aria-live": "polite",
9912
+ children: [
9913
+ /* @__PURE__ */ jsxs("span", { className: "relative flex h-2 w-2 shrink-0", children: [
9914
+ /* @__PURE__ */ jsx("span", { className: "absolute inline-flex h-full w-full animate-ping rounded-full bg-primary opacity-75" }),
9915
+ /* @__PURE__ */ jsx("span", { className: "relative inline-flex h-2 w-2 rounded-full bg-primary" })
9916
+ ] }),
9917
+ /* @__PURE__ */ jsx("span", { className: "italic", children: speech.interim !== "" ? speech.interim : "Listening\u2026" })
9918
+ ]
9919
+ }
9920
+ ) : null,
9921
+ speech.error !== null ? /* @__PURE__ */ jsx(
9922
+ "p",
9923
+ {
9924
+ "data-boff-explore": "dictation-error",
9925
+ className: "mt-2 text-xs text-destructive",
9926
+ children: speech.error
9927
+ }
9928
+ ) : null,
9929
+ /* @__PURE__ */ jsxs("div", { className: "mt-2 flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-muted-foreground", children: [
9930
+ /* @__PURE__ */ jsx("span", { className: "hidden sm:inline", children: "Enter to send \xB7 Shift + Enter for a new line" }),
9931
+ remainingToday !== null ? /* @__PURE__ */ jsxs("span", { "data-boff-explore": "remaining", children: [
9932
+ remainingToday,
9933
+ " message",
9934
+ remainingToday === 1 ? "" : "s",
9935
+ " left today"
9936
+ ] }) : null,
9937
+ /* @__PURE__ */ jsxs(
9938
+ "span",
8198
9939
  {
8199
- ref: textareaRef,
8200
- value: draft,
8201
- rows: 1,
8202
- disabled: composerDisabled,
8203
- onChange: (event) => setDraft(event.target.value),
8204
- onKeyDown: handleKeyDown,
8205
- onCompositionStart: () => {
8206
- composingRef.current = true;
8207
- },
8208
- onCompositionEnd: () => {
8209
- composingRef.current = false;
8210
- },
8211
- "aria-label": "Ask a question",
8212
- placeholder: composerDisabled ? phase === "limited" ? "Message limit reached \u2014 please try again later" : "Explore is unavailable right now" : focusedProductName ? fill(T.placeholderProduct, {
8213
- product: focusedProductName
8214
- }) : T.placeholder,
8215
- className: "max-h-[200px] min-h-[44px] w-full min-w-0 flex-1 resize-none border-0 bg-transparent px-2 py-2.5 text-base shadow-none focus-visible:ring-0 sm:text-sm"
9940
+ className: cn(
9941
+ "ml-auto tabular-nums",
9942
+ overLimit && "font-medium text-destructive"
9943
+ ),
9944
+ children: [
9945
+ draft.length.toLocaleString(),
9946
+ " / ",
9947
+ maxLength.toLocaleString()
9948
+ ]
8216
9949
  }
8217
- ),
9950
+ )
9951
+ ] }),
9952
+ shareUrl ? /* @__PURE__ */ jsxs("div", { className: "mt-2 flex items-center gap-2", children: [
8218
9953
  /* @__PURE__ */ jsx(
8219
9954
  "input",
8220
9955
  {
8221
- ref: fileInputRef,
8222
- type: "file",
8223
- multiple: true,
8224
- className: "hidden",
8225
- onChange: (event) => {
8226
- void handleFilesPicked(event.target.files);
8227
- event.target.value = "";
8228
- }
9956
+ "data-boff-explore": "share-url",
9957
+ readOnly: true,
9958
+ value: shareUrl,
9959
+ "aria-label": "Read-only link to this conversation",
9960
+ onFocus: (event) => event.currentTarget.select(),
9961
+ className: "min-w-0 flex-1 rounded-md border border-border bg-muted px-2 py-1 text-xs text-muted-foreground"
8229
9962
  }
8230
9963
  ),
8231
9964
  /* @__PURE__ */ jsx(
8232
- Button,
8233
- {
8234
- "data-boff-explore": "attach",
8235
- type: "button",
8236
- size: "icon",
8237
- variant: "ghost",
8238
- disabled: composerDisabled || staged.length >= MAX_ATTACHMENTS,
8239
- "aria-label": T.attach,
8240
- title: `${T.attach} \u2014 ${fill(T.attachHint, {
8241
- max: String(MAX_ATTACHMENTS),
8242
- size: String(MAX_ATTACHMENT_BYTES / (1024 * 1024))
8243
- })}`,
8244
- onClick: () => fileInputRef.current?.click(),
8245
- children: /* @__PURE__ */ jsx(Paperclip, { className: "h-4 w-4" })
8246
- }
8247
- ),
8248
- speech.supported ? /* @__PURE__ */ jsx(
8249
- Button,
9965
+ "button",
8250
9966
  {
8251
- "data-boff-explore": "mic",
8252
- "data-listening": speech.listening ? "true" : "false",
8253
9967
  type: "button",
8254
- size: "icon",
8255
- variant: speech.listening ? "default" : "ghost",
8256
- disabled: composerDisabled,
8257
- "aria-label": speech.listening ? T.stopDictating : T.dictate,
8258
- "aria-pressed": speech.listening,
8259
- title: speech.listening ? T.stopDictating : T.dictate,
8260
- onClick: speech.toggle,
8261
- className: cn(speech.listening && "animate-pulse"),
8262
- children: /* @__PURE__ */ jsx(Mic, { className: "h-4 w-4" })
9968
+ className: "shrink-0 text-xs underline underline-offset-2",
9969
+ onClick: () => setShareUrl(null),
9970
+ children: "Done"
8263
9971
  }
8264
- ) : null,
8265
- busy ? /* @__PURE__ */ jsx(
8266
- Button,
9972
+ )
9973
+ ] }) : null,
9974
+ /* @__PURE__ */ jsxs("div", { className: "mt-2 flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-muted-foreground", children: [
9975
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 truncate", children: T.disclaimerShort }),
9976
+ /* @__PURE__ */ jsx(
9977
+ "button",
8267
9978
  {
8268
- "data-boff-explore": "stop",
8269
9979
  type: "button",
8270
- size: "icon",
8271
- variant: "secondary",
8272
- "aria-label": T.stop,
8273
- onClick: stop,
8274
- children: /* @__PURE__ */ jsx(Square, { className: "h-4 w-4" })
8275
- }
8276
- ) : /* @__PURE__ */ jsx(
8277
- Button,
8278
- {
8279
- "data-boff-explore": "send",
8280
- type: "submit",
8281
- size: "icon",
8282
- disabled: !canSubmit,
8283
- "aria-label": T.send,
8284
- children: /* @__PURE__ */ jsx(ArrowUp, { className: "h-4 w-4" })
9980
+ "data-boff-explore": "disclaimer",
9981
+ onClick: () => setDisclaimerOpen(true),
9982
+ className: "shrink-0 underline underline-offset-2 transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
9983
+ children: T.disclaimer
8285
9984
  }
8286
9985
  )
8287
- ]
8288
- }
8289
- ),
8290
- speech.listening || speech.interim !== "" ? /* @__PURE__ */ jsxs(
8291
- "p",
8292
- {
8293
- "data-boff-explore": "dictation",
8294
- className: "mt-2 flex items-center gap-2 text-xs text-muted-foreground",
8295
- "aria-live": "polite",
8296
- children: [
8297
- /* @__PURE__ */ jsxs("span", { className: "relative flex h-2 w-2 shrink-0", children: [
8298
- /* @__PURE__ */ jsx("span", { className: "absolute inline-flex h-full w-full animate-ping rounded-full bg-primary opacity-75" }),
8299
- /* @__PURE__ */ jsx("span", { className: "relative inline-flex h-2 w-2 rounded-full bg-primary" })
8300
- ] }),
8301
- /* @__PURE__ */ jsx("span", { className: "italic", children: speech.interim !== "" ? speech.interim : "Listening\u2026" })
8302
- ]
8303
- }
8304
- ) : null,
8305
- speech.error !== null ? /* @__PURE__ */ jsx(
8306
- "p",
8307
- {
8308
- "data-boff-explore": "dictation-error",
8309
- className: "mt-2 text-xs text-destructive",
8310
- children: speech.error
8311
- }
8312
- ) : null,
8313
- /* @__PURE__ */ jsxs("div", { className: "mt-2 flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-muted-foreground", children: [
8314
- /* @__PURE__ */ jsx("span", { className: "hidden sm:inline", children: "Enter to send \xB7 Shift + Enter for a new line" }),
8315
- remainingToday !== null ? /* @__PURE__ */ jsxs("span", { "data-boff-explore": "remaining", children: [
8316
- remainingToday,
8317
- " message",
8318
- remainingToday === 1 ? "" : "s",
8319
- " left today"
8320
- ] }) : null,
8321
- /* @__PURE__ */ jsxs(
8322
- "span",
8323
- {
8324
- className: cn(
8325
- "ml-auto tabular-nums",
8326
- overLimit && "font-medium text-destructive"
8327
- ),
8328
- children: [
8329
- draft.length.toLocaleString(),
8330
- " / ",
8331
- maxLength.toLocaleString()
8332
- ]
8333
- }
8334
- )
8335
- ] }),
8336
- shareUrl ? /* @__PURE__ */ jsxs("div", { className: "mt-2 flex items-center gap-2", children: [
8337
- /* @__PURE__ */ jsx(
8338
- "input",
8339
- {
8340
- "data-boff-explore": "share-url",
8341
- readOnly: true,
8342
- value: shareUrl,
8343
- "aria-label": "Read-only link to this conversation",
8344
- onFocus: (event) => event.currentTarget.select(),
8345
- className: "min-w-0 flex-1 rounded-md border border-border bg-muted px-2 py-1 text-xs text-muted-foreground"
8346
- }
8347
- ),
8348
- /* @__PURE__ */ jsx(
8349
- "button",
8350
- {
8351
- type: "button",
8352
- className: "shrink-0 text-xs underline underline-offset-2",
8353
- onClick: () => setShareUrl(null),
8354
- children: "Done"
8355
- }
8356
- )
8357
- ] }) : null,
8358
- /* @__PURE__ */ jsxs("div", { className: "mt-2 flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-muted-foreground", children: [
8359
- /* @__PURE__ */ jsx("span", { className: "min-w-0 truncate", children: T.disclaimerShort }),
8360
- /* @__PURE__ */ jsx(
8361
- "button",
8362
- {
8363
- type: "button",
8364
- "data-boff-explore": "disclaimer",
8365
- onClick: () => setDisclaimerOpen(true),
8366
- className: "shrink-0 underline underline-offset-2 transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
8367
- children: T.disclaimer
8368
- }
8369
- )
8370
- ] })
8371
- ]
9986
+ ] })
9987
+ ]
9988
+ }
9989
+ )
8372
9990
  }
8373
- ) })
9991
+ )
8374
9992
  ]
8375
9993
  }
8376
9994
  );
@@ -13035,6 +14653,6 @@ function StoreProductDetailPage({
13035
14653
  ] });
13036
14654
  }
13037
14655
 
13038
- export { BlogListPage, BlogPostPage, Button, CareersApplyForm, CareersSubmissionForm, CaseStudiesListPage, CaseStudyPage, ChangelogPage, ContactPage, ContentRenderer, ContractsPage, DEFAULT_CONTACT_CATEGORIES, DEFAULT_EXPLORE_EXAMPLE_PROMPTS, ECOSYSTEM_PRODUCTS, EXPLORE_CATALOG_QUERY, EXPLORE_LOCALES, EXPLORE_MESSAGE_QUERY, EXPLORE_RECAPTCHA_ACTION, ElectronDownloadLink, ExploreCta, ExplorePage, FALLBACK_EXPLORE_LIMITS, Input, Label, LaunchCountdown, Markdown, NewsletterForm, NewsletterPage, PageHead, PartnersPage, PressKitPage, PricingPage, PricingSection, ProblemsSolvedSection, ProductCard, ProductProvider, ResourceLinks, RybbitAnalytics, SEND_EXPLORE_MESSAGE_MUTATION, Select, SocialLinks, StarRating, StoreBrowsePage, StoreHomePage, StoreProductDetailPage, Textarea, TypeBadge, UnsubscribePage, WaitlistForm, WaitlistPage, WebSDKClient, WebSDKProvider, WebsiteSwitcher, buttonVariants, classifyExploreError, cn, detectElectronPlatform, fetchPublicJobPosting, fetchPublicJobPostings, fetchPublicJobPostingsForSubmission, formatDownloads, formatPrice2 as formatPrice, getRecaptchaV3Token, isValidUrl, loadRecaptchaV3, useContentPage, useContentPages, useExploreChat, useProduct, useProductConfig, usePublicJobPosting, usePublicJobPostings, usePublicJobPostingsForSubmission, useWebSDK, useWebSDKConfig };
14656
+ export { BlogListPage, BlogPostPage, Button, CONCEPTS_PATH, CONCEPT_ILLUSTRATION_NOTICE, CONCEPT_PATH_PREFIX, CareersApplyForm, CareersSubmissionForm, CaseStudiesListPage, CaseStudyPage, ChangelogPage, ConceptDetailPage, ConceptsPage, ContactPage, ContentRenderer, ContractsPage, DEFAULT_CONTACT_CATEGORIES, DEFAULT_EXPLORE_EXAMPLE_PROMPTS, ECOSYSTEM_PRODUCTS, EXPLORE_CATALOG_QUERY, EXPLORE_LOCALES, EXPLORE_MESSAGE_QUERY, EXPLORE_RECAPTCHA_ACTION, ElectronDownloadLink, ExploreCta, ExplorePage, FALLBACK_EXPLORE_LIMITS, Input, Label, LaunchCountdown, Markdown, NewsletterForm, NewsletterPage, PageHead, PartnersPage, PressKitPage, PricingPage, PricingSection, ProblemsSolvedSection, ProductCard, ProductProvider, ResourceLinks, RybbitAnalytics, SEND_EXPLORE_MESSAGE_MUTATION, Select, SocialLinks, StarRating, StoreBrowsePage, StoreHomePage, StoreProductDetailPage, Textarea, TypeBadge, UnsubscribePage, WaitlistForm, WaitlistPage, WebSDKClient, WebSDKProvider, WebsiteSwitcher, buttonVariants, classifyExploreError, cn, conceptPath, detectElectronPlatform, fetchPublicJobPosting, fetchPublicJobPostings, fetchPublicJobPostingsForSubmission, formatDownloads, formatPrice2 as formatPrice, getConceptBySlug, getRecaptchaV3Token, isValidUrl, loadRecaptchaV3, useContentPage, useContentPages, useExploreChat, useProduct, useProductConfig, usePublicJobPosting, usePublicJobPostings, usePublicJobPostingsForSubmission, useWebSDK, useWebSDKConfig };
13039
14657
  //# sourceMappingURL=index.mjs.map
13040
14658
  //# sourceMappingURL=index.mjs.map