@burdenoff/website-sdk 2026.924.10 → 2026.924.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -9004,6 +9004,45 @@ function buildFallbackCatalog(examplePrompts, welcome) {
9004
9004
  conceptHighlights: []
9005
9005
  };
9006
9006
  }
9007
+ var BAKED_CATALOG_ELEMENT_ID = "boff-explore-catalog";
9008
+ function bakedCatalogLocale() {
9009
+ if (typeof navigator === "undefined") return "";
9010
+ return (navigator.language || "").toLowerCase().split("-")[0] ?? "";
9011
+ }
9012
+ function snapshotBakedElement() {
9013
+ if (typeof document === "undefined") return null;
9014
+ const el = document.getElementById(BAKED_CATALOG_ELEMENT_ID);
9015
+ if (!el || el.tagName !== "SCRIPT" || el.getAttribute("type") !== "application/json")
9016
+ return null;
9017
+ return {
9018
+ product: el.getAttribute("data-product") ?? "",
9019
+ locale: el.getAttribute("data-locale") ?? "",
9020
+ text: el.textContent ?? ""
9021
+ };
9022
+ }
9023
+ var BAKED_AT_LOAD = snapshotBakedElement();
9024
+ function isCatalogShape(value) {
9025
+ if (!value || typeof value !== "object") return false;
9026
+ const c = value;
9027
+ const listOrAbsent = (v) => v === void 0 || v === null || Array.isArray(v);
9028
+ const textOrAbsent = (v) => v === void 0 || v === null || typeof v === "string";
9029
+ return (c["enabled"] === void 0 || typeof c["enabled"] === "boolean") && listOrAbsent(c["products"]) && listOrAbsent(c["examplePrompts"]) && listOrAbsent(c["conceptHighlights"]) && textOrAbsent(c["welcomeTitle"]) && textOrAbsent(c["welcomeBody"]);
9030
+ }
9031
+ function readBakedCatalog(productSlug) {
9032
+ const baked = snapshotBakedElement() ?? BAKED_AT_LOAD;
9033
+ if (!baked) return null;
9034
+ if (baked.product !== (productSlug ?? "")) return null;
9035
+ if (baked.locale && baked.locale !== bakedCatalogLocale()) return null;
9036
+ try {
9037
+ const parsed = JSON.parse(baked.text);
9038
+ return isCatalogShape(parsed) ? parsed : null;
9039
+ } catch {
9040
+ return null;
9041
+ }
9042
+ }
9043
+ function serializeBakedCatalog(raw) {
9044
+ return JSON.stringify(raw).replace(/</g, "\\u003c").replace(/>/g, "\\u003e").replace(/&/g, "\\u0026").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
9045
+ }
9007
9046
  function normalizeCatalog(raw, fallback) {
9008
9047
  return {
9009
9048
  enabled: raw.enabled !== false,
@@ -9253,9 +9292,17 @@ function useExploreChat(options = {}) {
9253
9292
  ),
9254
9293
  [promptKey, welcomeKey]
9255
9294
  );
9256
- const [catalog, setCatalog] = useState(fallbackCatalog);
9295
+ const [bakedRaw] = useState(
9296
+ () => readBakedCatalog(productSlug)
9297
+ );
9298
+ const [catalog, setCatalog] = useState(
9299
+ () => bakedRaw ? normalizeCatalog(bakedRaw, fallbackCatalog) : fallbackCatalog
9300
+ );
9301
+ const [serverCatalogRaw, setServerCatalogRaw] = useState(bakedRaw);
9257
9302
  const [messages, setMessages] = useState([]);
9258
- const [phase, setPhase] = useState("loading");
9303
+ const [phase, setPhase] = useState(
9304
+ () => bakedRaw ? bakedRaw.enabled === false ? "disabled" : "ready" : "loading"
9305
+ );
9259
9306
  const [error, setError] = useState(null);
9260
9307
  const [remainingToday, setRemainingToday] = useState(null);
9261
9308
  const [focusProduct, setFocusProductState] = useState(null);
@@ -9273,7 +9320,7 @@ function useExploreChat(options = {}) {
9273
9320
  shareTokenRef.current = readShareToken();
9274
9321
  }
9275
9322
  const isSharedView = shareTokenRef.current !== null;
9276
- const catalogRef = useRef(fallbackCatalog);
9323
+ const catalogRef = useRef(catalog);
9277
9324
  const turnCountRef = useRef(0);
9278
9325
  const focusProductRef = useRef(null);
9279
9326
  const lastSentTextRef = useRef(null);
@@ -9419,25 +9466,29 @@ function useExploreChat(options = {}) {
9419
9466
  const raw = res.data?.exploreCatalog;
9420
9467
  if (res.errors?.length || !raw) {
9421
9468
  console.warn(
9422
- "[WebSDK] exploreCatalog unavailable \u2014 using the built-in fallback catalog",
9469
+ "[WebSDK] exploreCatalog unavailable \u2014 keeping the catalog the page started with",
9423
9470
  res.errors?.[0]?.message
9424
9471
  );
9425
9472
  setPhase((prev) => prev === "loading" ? "ready" : prev);
9426
9473
  return;
9427
9474
  }
9428
- const next = normalizeCatalog(raw, fallbackCatalog);
9475
+ const next = normalizeCatalog(
9476
+ raw,
9477
+ bakedRaw ? normalizeCatalog(bakedRaw, fallbackCatalog) : fallbackCatalog
9478
+ );
9429
9479
  setCatalog(next);
9480
+ setServerCatalogRaw(raw);
9430
9481
  catalogRef.current = next;
9431
9482
  setPhase((prev) => {
9432
9483
  if (!next.enabled) return "disabled";
9433
- return prev === "loading" ? "ready" : prev;
9484
+ return prev === "loading" || prev === "disabled" ? "ready" : prev;
9434
9485
  });
9435
9486
  };
9436
9487
  void load();
9437
9488
  return () => {
9438
9489
  cancelled = true;
9439
9490
  };
9440
- }, [client, productSlug, fallbackCatalog]);
9491
+ }, [client, productSlug, fallbackCatalog, bakedRaw]);
9441
9492
  const startPolling = useCallback(
9442
9493
  (conversationToken, messageId) => {
9443
9494
  pollGenerationRef.current += 1;
@@ -9905,6 +9956,7 @@ function useExploreChat(options = {}) {
9905
9956
  return {
9906
9957
  phase,
9907
9958
  catalog,
9959
+ serverCatalogRaw,
9908
9960
  messages,
9909
9961
  activity,
9910
9962
  remainingToday,
@@ -10738,6 +10790,48 @@ var EXPLORE_CSS = `
10738
10790
  }
10739
10791
  .boff-explore-strip::-webkit-scrollbar { display: none; }
10740
10792
 
10793
+ /* The product chips run past the edge of their row (there are 38). A hard edge sliced the
10794
+ last visible chip mid-word ("Bi", "BigC") right beside "All 38"; a short fade says "there
10795
+ is more this way" instead. A mask carries only alpha, so the gradient's colour is a token
10796
+ that never shows. Mirrored for right-to-left locales, whose row runs the other way. */
10797
+ .boff-explore-chips-fade {
10798
+ /* Focus scrolling honours scroll-padding, so a tabbed-to chip is brought clear of the fade
10799
+ rather than left half-hidden under it. */
10800
+ scroll-padding-inline-end: 2rem;
10801
+ -webkit-mask-image: linear-gradient(to right, hsl(var(--foreground)) calc(100% - 2rem), hsl(var(--foreground) / 0));
10802
+ mask-image: linear-gradient(to right, hsl(var(--foreground)) calc(100% - 2rem), hsl(var(--foreground) / 0));
10803
+ }
10804
+ /* A fade over a fixed edge would leave the LAST chip under it once the row is scrolled to
10805
+ the end \u2014 the visitor could never read it. A trailing spacer the width of the fade lets
10806
+ the final chip scroll clear of it. A pseudo-element rather than padding: trailing padding
10807
+ on a flex scroll container is not reliably part of its scrollable overflow. */
10808
+ .boff-explore-chips-fade::after {
10809
+ content: "";
10810
+ flex: 0 0 2rem;
10811
+ }
10812
+ [dir="rtl"] .boff-explore-chips-fade {
10813
+ -webkit-mask-image: linear-gradient(to left, hsl(var(--foreground)) calc(100% - 2rem), hsl(var(--foreground) / 0));
10814
+ mask-image: linear-gradient(to left, hsl(var(--foreground)) calc(100% - 2rem), hsl(var(--foreground) / 0));
10815
+ }
10816
+
10817
+ /* The concept rail had the chip row's problem: the card at its edge was cut hard mid-word
10818
+ ("Apparatus Rig", "CONCEPT ILLUST") on a dozen sites. It fades an edge only while there are
10819
+ more cards beyond it \u2014 the same state that lights the arrow on that side \u2014 so a rail
10820
+ scrolled to its end shows its last card whole. Physical edges, because that state is
10821
+ physical: it is measured from the left in either reading direction. */
10822
+ .boff-explore-rail-fade-left {
10823
+ -webkit-mask-image: linear-gradient(to right, hsl(var(--foreground) / 0), hsl(var(--foreground)) 3rem);
10824
+ mask-image: linear-gradient(to right, hsl(var(--foreground) / 0), hsl(var(--foreground)) 3rem);
10825
+ }
10826
+ .boff-explore-rail-fade-right {
10827
+ -webkit-mask-image: linear-gradient(to right, hsl(var(--foreground)) calc(100% - 3rem), hsl(var(--foreground) / 0));
10828
+ mask-image: linear-gradient(to right, hsl(var(--foreground)) calc(100% - 3rem), hsl(var(--foreground) / 0));
10829
+ }
10830
+ .boff-explore-rail-fade-left.boff-explore-rail-fade-right {
10831
+ -webkit-mask-image: linear-gradient(to right, hsl(var(--foreground) / 0), hsl(var(--foreground)) 3rem, hsl(var(--foreground)) calc(100% - 3rem), hsl(var(--foreground) / 0));
10832
+ mask-image: linear-gradient(to right, hsl(var(--foreground) / 0), hsl(var(--foreground)) 3rem, hsl(var(--foreground)) calc(100% - 3rem), hsl(var(--foreground) / 0));
10833
+ }
10834
+
10741
10835
  @keyframes boff-explore-fade-in {
10742
10836
  from { opacity: 0; transform: translateY(2px); }
10743
10837
  to { opacity: 1; transform: none; }
@@ -10814,10 +10908,10 @@ var EXPLORE_CSS = `
10814
10908
  Colour comes from the product's --primary token, so it is whatever that site's palette
10815
10909
  already is, never a colour chosen here. */
10816
10910
  .boff-explore-invite {
10817
- border-color: hsl(var(--primary) / 0.45);
10911
+ border-color: hsl(var(--primary) / 0.6);
10818
10912
  box-shadow:
10819
- 0 0 0 4px hsl(var(--primary) / 0.08),
10820
- 0 8px 24px -12px hsl(var(--primary) / 0.45);
10913
+ 0 0 0 4px hsl(var(--primary) / 0.12),
10914
+ 0 8px 24px -12px hsl(var(--primary) / 0.55);
10821
10915
  animation: boff-explore-breathe 3.2s ease-in-out infinite;
10822
10916
  }
10823
10917
  /* Focus and typing both mean "I have found it", and the hint has done its job. */
@@ -10827,8 +10921,8 @@ var EXPLORE_CSS = `
10827
10921
  box-shadow: 0 0 0 4px hsl(var(--primary) / 0.10);
10828
10922
  }
10829
10923
  @keyframes boff-explore-breathe {
10830
- 0%, 100% { box-shadow: 0 0 0 4px hsl(var(--primary) / 0.07), 0 8px 24px -12px hsl(var(--primary) / 0.40); }
10831
- 50% { box-shadow: 0 0 0 7px hsl(var(--primary) / 0.13), 0 8px 28px -12px hsl(var(--primary) / 0.55); }
10924
+ 0%, 100% { box-shadow: 0 0 0 4px hsl(var(--primary) / 0.10), 0 8px 24px -12px hsl(var(--primary) / 0.50); }
10925
+ 50% { box-shadow: 0 0 0 7px hsl(var(--primary) / 0.18), 0 8px 28px -12px hsl(var(--primary) / 0.65); }
10832
10926
  }
10833
10927
 
10834
10928
  /* Every one of the above is decoration. Reduced motion removes the movement and keeps the
@@ -10916,8 +11010,18 @@ var EXPLORE_CSS = `
10916
11010
  .boff-explore-scroll .boff-explore-capabilities { display: none; }
10917
11011
  }
10918
11012
  @container boff-explore-pane (min-width: ${toRem(WELCOME_FIT_MIN_WIDTH_PX)}) and (max-height: ${toRem(WELCOME_FIT_STEP_PX[1])}) {
10919
- /* Step 2. */
11013
+ /* Step 2. At a 4:1 crop the picture is ~44px tall, and the full-size caveat badge covered
11014
+ half of it \u2014 on ten sites, every card, whenever the consent banner was up. It stays (the
11015
+ picture is still a mockup), just smaller and tucked into the corner. */
10920
11016
  .boff-explore-scroll .boff-explore-concept-media { aspect-ratio: 4 / 1; }
11017
+ .boff-explore-scroll .boff-explore-concept-badge {
11018
+ top: 0.25rem;
11019
+ left: 0.25rem;
11020
+ padding: 0 0.3125rem;
11021
+ font-size: 0.5rem;
11022
+ line-height: 0.75rem;
11023
+ letter-spacing: 0.02em;
11024
+ }
10921
11025
  }
10922
11026
  @container boff-explore-pane (min-width: ${toRem(WELCOME_FIT_MIN_WIDTH_PX)}) and (max-height: ${toRem(WELCOME_FIT_STEP_PX[2])}) {
10923
11027
  /* Step 3. Title-only cards. The "concept illustration" caveat lives on the picture, so it
@@ -12076,6 +12180,7 @@ function ErrorBanner({
12076
12180
  }
12077
12181
  function PromptCarousel({
12078
12182
  strings: T,
12183
+ label,
12079
12184
  prompts,
12080
12185
  onPrompt,
12081
12186
  disabled
@@ -12107,7 +12212,7 @@ function PromptCarousel({
12107
12212
  return /* @__PURE__ */ jsxs(
12108
12213
  "div",
12109
12214
  {
12110
- className: "flex min-w-0 touch-pan-y items-center gap-1.5",
12215
+ className: "grid min-w-0 touch-pan-y grid-cols-[minmax(0,1fr)_auto_auto] items-center gap-x-1.5 gap-y-1.5 sm:grid-cols-[auto_minmax(0,1fr)_auto]",
12111
12216
  role: "group",
12112
12217
  "aria-roledescription": "carousel",
12113
12218
  "aria-label": "Example questions",
@@ -12117,13 +12222,14 @@ function PromptCarousel({
12117
12222
  onBlurCapture: () => setPaused(false),
12118
12223
  ...swipe,
12119
12224
  children: [
12225
+ /* @__PURE__ */ jsx("p", { className: "col-start-1 row-start-1 text-xs font-semibold uppercase tracking-wide text-muted-foreground sm:col-span-3", children: label }),
12120
12226
  count > 1 ? /* @__PURE__ */ jsx(
12121
12227
  "button",
12122
12228
  {
12123
12229
  type: "button",
12124
12230
  "aria-label": T.prevSuggestion,
12125
12231
  onClick: () => go(-1),
12126
- className: "inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-full text-muted-foreground transition-colors hover:bg-accent hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
12232
+ className: "col-start-2 row-start-1 inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-full text-muted-foreground transition-colors hover:bg-accent hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring sm:col-start-1 sm:row-start-2",
12127
12233
  children: /* @__PURE__ */ jsx(ChevronLeft, { className: "h-4 w-4" })
12128
12234
  }
12129
12235
  ) : null,
@@ -12137,14 +12243,23 @@ function PromptCarousel({
12137
12243
  "aria-label": `Ask: ${current}`,
12138
12244
  "aria-live": paused ? "polite" : "off",
12139
12245
  onClick: () => onPrompt(current),
12140
- className: "boff-explore-fade group flex min-w-0 flex-1 items-center gap-2 rounded-full border border-border bg-card px-4 py-2 text-left text-sm text-card-foreground shadow-sm transition-colors hover:border-primary/50 hover:bg-accent disabled:cursor-not-allowed disabled:opacity-50 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
12246
+ className: cn(
12247
+ "group col-span-3 row-start-2 flex min-w-0 items-center gap-2 rounded-full border border-border bg-card px-4 py-2 max-sm:min-h-[3.625rem] max-sm:rounded-2xl text-left text-sm text-card-foreground shadow-sm transition-colors hover:border-primary/50 hover:bg-accent disabled:cursor-not-allowed disabled:opacity-50 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
12248
+ count > 1 ? "sm:col-span-1 sm:col-start-2" : "sm:col-span-3"
12249
+ ),
12141
12250
  children: [
12142
12251
  /* @__PURE__ */ jsx(Sparkles, { className: "h-3.5 w-3.5 shrink-0 text-primary" }),
12143
- /* @__PURE__ */ jsx("span", { className: "truncate", children: current }),
12144
- /* @__PURE__ */ jsx(ArrowUp, { className: "ml-auto h-3.5 w-3.5 shrink-0 rotate-45 text-muted-foreground transition-colors group-hover:text-primary" })
12252
+ /* @__PURE__ */ jsx(
12253
+ "span",
12254
+ {
12255
+ className: "boff-explore-fade min-w-0 max-sm:line-clamp-3 sm:truncate",
12256
+ children: current
12257
+ },
12258
+ current
12259
+ ),
12260
+ /* @__PURE__ */ jsx(ArrowUp, { className: "ml-auto h-3.5 w-3.5 shrink-0 rotate-45 text-muted-foreground transition-colors group-hover:text-primary max-sm:hidden" })
12145
12261
  ]
12146
- },
12147
- current
12262
+ }
12148
12263
  ),
12149
12264
  count > 1 ? /* @__PURE__ */ jsx(
12150
12265
  "button",
@@ -12152,7 +12267,7 @@ function PromptCarousel({
12152
12267
  type: "button",
12153
12268
  "aria-label": T.nextSuggestion,
12154
12269
  onClick: () => go(1),
12155
- className: "inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-full text-muted-foreground transition-colors hover:bg-accent hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
12270
+ className: "col-start-3 row-start-1 inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-full text-muted-foreground transition-colors hover:bg-accent hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring sm:row-start-2",
12156
12271
  children: /* @__PURE__ */ jsx(ChevronRight, { className: "h-4 w-4" })
12157
12272
  }
12158
12273
  ) : null
@@ -12183,7 +12298,7 @@ function ProductStrip({
12183
12298
  {
12184
12299
  className: cn(
12185
12300
  "boff-explore-strip flex min-w-0 flex-1 gap-2",
12186
- expanded ? "flex-wrap" : "flex-nowrap overflow-x-auto"
12301
+ expanded ? "flex-wrap" : "boff-explore-chips-fade flex-nowrap overflow-x-auto"
12187
12302
  ),
12188
12303
  children: [
12189
12304
  /* @__PURE__ */ jsx(
@@ -12251,8 +12366,11 @@ function ConceptStrip({
12251
12366
  const measureRail = useCallback(() => {
12252
12367
  const el = railRef.current;
12253
12368
  if (!el) return;
12254
- setCanLeft(el.scrollLeft > 1);
12255
- setCanRight(el.scrollLeft + el.clientWidth < el.scrollWidth - 1);
12369
+ const max = el.scrollWidth - el.clientWidth;
12370
+ const rtl = typeof getComputedStyle === "function" && getComputedStyle(el).direction === "rtl";
12371
+ const fromLeft = rtl ? max + el.scrollLeft : el.scrollLeft;
12372
+ setCanLeft(fromLeft > 1);
12373
+ setCanRight(fromLeft < max - 1);
12256
12374
  }, []);
12257
12375
  useEffect(() => {
12258
12376
  const el = railRef.current;
@@ -12321,11 +12439,15 @@ function ConceptStrip({
12321
12439
  onScroll: measureRail,
12322
12440
  "data-boff-explore": "concept-strip",
12323
12441
  "aria-label": T.conceptStripLabel,
12324
- className: "boff-explore-strip flex min-w-0 snap-x gap-3 overflow-x-auto pb-1",
12442
+ className: cn(
12443
+ "boff-explore-strip flex min-w-0 snap-x gap-3 overflow-x-auto pb-1 sm:mx-10",
12444
+ canLeft && "boff-explore-rail-fade-left",
12445
+ canRight && "boff-explore-rail-fade-right"
12446
+ ),
12325
12447
  children: visible.map((highlight) => /* @__PURE__ */ jsx(
12326
12448
  "li",
12327
12449
  {
12328
- className: "shrink-0 snap-start",
12450
+ className: "flex shrink-0 snap-start",
12329
12451
  children: /* @__PURE__ */ jsxs(
12330
12452
  "button",
12331
12453
  {
@@ -12361,14 +12483,14 @@ function ConceptStrip({
12361
12483
  "span",
12362
12484
  {
12363
12485
  "aria-hidden": "true",
12364
- className: "pointer-events-none absolute left-1.5 top-1.5 rounded-full border border-border bg-background/90 px-1.5 py-0.5 text-[9px] font-semibold uppercase tracking-wide text-foreground",
12486
+ className: "boff-explore-concept-badge pointer-events-none absolute left-1.5 top-1.5 rounded-full border border-border bg-background/90 px-1.5 py-0.5 text-[9px] font-semibold uppercase tracking-wide text-foreground",
12365
12487
  children: T.conceptIllustration
12366
12488
  }
12367
12489
  )
12368
12490
  ] }),
12369
- /* @__PURE__ */ jsxs("span", { className: "flex min-w-0 flex-col gap-0.5 p-2.5", children: [
12491
+ /* @__PURE__ */ jsxs("span", { className: "flex min-w-0 flex-1 flex-col gap-0.5 p-2.5", children: [
12370
12492
  /* @__PURE__ */ jsx("span", { className: "line-clamp-2 text-xs font-semibold leading-snug text-card-foreground", children: highlight.title }),
12371
- /* @__PURE__ */ jsx("span", { className: "truncate text-[11px] text-muted-foreground", children: highlight.productName })
12493
+ /* @__PURE__ */ jsx("span", { className: "mt-auto truncate text-[11px] text-muted-foreground", children: highlight.productName })
12372
12494
  ] })
12373
12495
  ]
12374
12496
  }
@@ -12516,18 +12638,16 @@ function WelcomeState({
12516
12638
  },
12517
12639
  i
12518
12640
  )) }),
12519
- prompts.length > 0 ? /* @__PURE__ */ jsxs("div", { className: "boff-explore-rise boff-explore-rise-2 mt-4", children: [
12520
- /* @__PURE__ */ jsx("p", { className: "mb-1.5 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: T.tryAsking }),
12521
- /* @__PURE__ */ jsx(
12522
- PromptCarousel,
12523
- {
12524
- strings: T,
12525
- prompts,
12526
- onPrompt,
12527
- disabled
12528
- }
12529
- )
12530
- ] }) : null,
12641
+ prompts.length > 0 ? /* @__PURE__ */ jsx("div", { className: "boff-explore-rise boff-explore-rise-2 mt-4", children: /* @__PURE__ */ jsx(
12642
+ PromptCarousel,
12643
+ {
12644
+ strings: T,
12645
+ label: T.tryAsking,
12646
+ prompts,
12647
+ onPrompt,
12648
+ disabled
12649
+ }
12650
+ ) }) : null,
12531
12651
  products.length > 0 ? /* @__PURE__ */ jsxs("div", { className: "boff-explore-rise boff-explore-rise-3 mt-4", children: [
12532
12652
  /* @__PURE__ */ jsx("p", { className: "mb-1.5 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: T.focusProduct }),
12533
12653
  /* @__PURE__ */ jsx(
@@ -12585,6 +12705,7 @@ function ExplorePage({
12585
12705
  const {
12586
12706
  phase,
12587
12707
  catalog,
12708
+ serverCatalogRaw,
12588
12709
  messages,
12589
12710
  activity,
12590
12711
  remainingToday,
@@ -13016,6 +13137,10 @@ function ExplorePage({
13016
13137
  const captchaOn = Boolean(
13017
13138
  catalog.captchaRequired && catalog.recaptchaSiteKey
13018
13139
  );
13140
+ const bakedCatalogJson = useMemo(
13141
+ () => serverCatalogRaw && serverCatalogRaw.enabled !== false ? serializeBakedCatalog(serverCatalogRaw) : null,
13142
+ [serverCatalogRaw]
13143
+ );
13019
13144
  const rootStyle = {};
13020
13145
  if (heightMode === "viewport") {
13021
13146
  rootStyle["--boff-explore-offset"] = paneOffset === null ? normalizeOffset(viewportOffset) : `${paneOffset}px`;
@@ -13055,6 +13180,16 @@ function ExplorePage({
13055
13180
  ),
13056
13181
  /* @__PURE__ */ jsx(ProseStyles, {}),
13057
13182
  /* @__PURE__ */ jsx(ExploreStyles, {}),
13183
+ bakedCatalogJson ? /* @__PURE__ */ jsx(
13184
+ "script",
13185
+ {
13186
+ id: BAKED_CATALOG_ELEMENT_ID,
13187
+ type: "application/json",
13188
+ "data-product": productSlug ?? "",
13189
+ "data-locale": bakedCatalogLocale(),
13190
+ dangerouslySetInnerHTML: { __html: bakedCatalogJson }
13191
+ }
13192
+ ) : null,
13058
13193
  /* @__PURE__ */ jsx(ExploreAnswerStyles, {}),
13059
13194
  !showWelcome ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2.5 border-b border-border px-4 py-2.5", children: [
13060
13195
  /* @__PURE__ */ jsx(
@@ -13529,7 +13664,7 @@ function ExplorePage({
13529
13664
  )
13530
13665
  ] }) : null,
13531
13666
  /* @__PURE__ */ jsxs("div", { className: "mt-2 flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-muted-foreground", children: [
13532
- /* @__PURE__ */ jsx("span", { className: "min-w-0 truncate", children: T.disclaimerShort }),
13667
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 sm:truncate", children: T.disclaimerShort }),
13533
13668
  /* @__PURE__ */ jsx(
13534
13669
  "button",
13535
13670
  {