@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.d.mts CHANGED
@@ -22,7 +22,7 @@ import { A as AnswerRendererStrings } from './explore-Crc41y0j.mjs';
22
22
  export { E as EXPLORE_PREFILL_MAX_LENGTH, a as ExploreAnswerBody, b as ExploreAnswerBodyProps, c as ExploreAnswerStyles, d as ExplorePage, e as ExplorePageProps, f as answerPlainText, g as answerSpeechText, h as exploreQuestionHref, i as inlineImageOrigins, j as isInlineImageAllowed } from './explore-Crc41y0j.mjs';
23
23
  export { ExploreCta, ExploreCtaProps } from './components/explore-cta.mjs';
24
24
  export { g as ESCALATE_EXPLORE_CONVERSATION_MUTATION, h as EXPLORE_CATALOG_QUERY, i as EXPLORE_CATALOG_QUERY_WITHOUT_HIGHLIGHTS, j as EXPLORE_ESCALATION_NOTE_SOFT_MAX, k as EXPLORE_MESSAGE_QUERY, l as EscalateExploreConversationInput, m as EscalateExploreConversationResult, c as ExploreCatalog, n as ExploreCatalogQueryData, o as ExploreConceptHighlight, p as ExploreConversation, q as ExploreCtaKind, r as ExploreCtaLink, s as ExploreErrorCode, t as ExploreEscalation, b as ExploreLimits, d as ExploreMessage, u as ExploreMessageQueryData, v as ExploreMessageRole, w as ExploreMessageStatus, E as ExploreProduct, a as ExploreReference, S as SEND_EXPLORE_MESSAGE_MUTATION, x as SendExploreMessageInput, y as SendExploreMessageMutationData, z as SendExploreMessageResult, A as looksLikeDeliverableEmail } from './explore-types-B5sdOC5M.mjs';
25
- export { D as DEFAULT_EXPLORE_EXAMPLE_PROMPTS, E as ExploreChatError, a as ExploreChatErrorKind, b as ExploreChatPhase, c as ExploreEscalateOutcome, d as ExploreEscalateResult, F as FALLBACK_EXPLORE_LIMITS, U as UseExploreChatOptions, e as UseExploreChatResult, f as UseSpeechOutputOptions, g as UseSpeechOutputResult, h as classifyExploreError, s as stopSpeaking, u as useExploreChat, i as useProgressiveReveal, j as useSpeechOutput } from './use-progressive-reveal-Cmy8bA7L.mjs';
25
+ export { D as DEFAULT_EXPLORE_EXAMPLE_PROMPTS, E as ExploreChatError, a as ExploreChatErrorKind, b as ExploreChatPhase, c as ExploreEscalateOutcome, d as ExploreEscalateResult, F as FALLBACK_EXPLORE_LIMITS, U as UseExploreChatOptions, e as UseExploreChatResult, f as UseSpeechOutputOptions, g as UseSpeechOutputResult, h as classifyExploreError, s as stopSpeaking, u as useExploreChat, i as useProgressiveReveal, j as useSpeechOutput } from './use-progressive-reveal-BBLRAnbU.mjs';
26
26
  export { RybbitAnalytics, RybbitAnalyticsProps } from './analytics/index.mjs';
27
27
  export { PageHead, PageHeadProps } from './seo/index.mjs';
28
28
  export { ProductData, ProductProvider, ProductProviderProps, useProduct, useProductConfig } from './product/index.mjs';
package/dist/index.d.ts CHANGED
@@ -22,7 +22,7 @@ import { A as AnswerRendererStrings } from './explore-C3SEP5K6.js';
22
22
  export { E as EXPLORE_PREFILL_MAX_LENGTH, a as ExploreAnswerBody, b as ExploreAnswerBodyProps, c as ExploreAnswerStyles, d as ExplorePage, e as ExplorePageProps, f as answerPlainText, g as answerSpeechText, h as exploreQuestionHref, i as inlineImageOrigins, j as isInlineImageAllowed } from './explore-C3SEP5K6.js';
23
23
  export { ExploreCta, ExploreCtaProps } from './components/explore-cta.js';
24
24
  export { g as ESCALATE_EXPLORE_CONVERSATION_MUTATION, h as EXPLORE_CATALOG_QUERY, i as EXPLORE_CATALOG_QUERY_WITHOUT_HIGHLIGHTS, j as EXPLORE_ESCALATION_NOTE_SOFT_MAX, k as EXPLORE_MESSAGE_QUERY, l as EscalateExploreConversationInput, m as EscalateExploreConversationResult, c as ExploreCatalog, n as ExploreCatalogQueryData, o as ExploreConceptHighlight, p as ExploreConversation, q as ExploreCtaKind, r as ExploreCtaLink, s as ExploreErrorCode, t as ExploreEscalation, b as ExploreLimits, d as ExploreMessage, u as ExploreMessageQueryData, v as ExploreMessageRole, w as ExploreMessageStatus, E as ExploreProduct, a as ExploreReference, S as SEND_EXPLORE_MESSAGE_MUTATION, x as SendExploreMessageInput, y as SendExploreMessageMutationData, z as SendExploreMessageResult, A as looksLikeDeliverableEmail } from './explore-types-B5sdOC5M.js';
25
- export { D as DEFAULT_EXPLORE_EXAMPLE_PROMPTS, E as ExploreChatError, a as ExploreChatErrorKind, b as ExploreChatPhase, c as ExploreEscalateOutcome, d as ExploreEscalateResult, F as FALLBACK_EXPLORE_LIMITS, U as UseExploreChatOptions, e as UseExploreChatResult, f as UseSpeechOutputOptions, g as UseSpeechOutputResult, h as classifyExploreError, s as stopSpeaking, u as useExploreChat, i as useProgressiveReveal, j as useSpeechOutput } from './use-progressive-reveal-DHPGGxZu.js';
25
+ export { D as DEFAULT_EXPLORE_EXAMPLE_PROMPTS, E as ExploreChatError, a as ExploreChatErrorKind, b as ExploreChatPhase, c as ExploreEscalateOutcome, d as ExploreEscalateResult, F as FALLBACK_EXPLORE_LIMITS, U as UseExploreChatOptions, e as UseExploreChatResult, f as UseSpeechOutputOptions, g as UseSpeechOutputResult, h as classifyExploreError, s as stopSpeaking, u as useExploreChat, i as useProgressiveReveal, j as useSpeechOutput } from './use-progressive-reveal-myNKWb6S.js';
26
26
  export { RybbitAnalytics, RybbitAnalyticsProps } from './analytics/index.js';
27
27
  export { PageHead, PageHeadProps } from './seo/index.js';
28
28
  export { ProductData, ProductProvider, ProductProviderProps, useProduct, useProductConfig } from './product/index.js';
package/dist/index.js CHANGED
@@ -9034,6 +9034,45 @@ function buildFallbackCatalog(examplePrompts, welcome) {
9034
9034
  conceptHighlights: []
9035
9035
  };
9036
9036
  }
9037
+ var BAKED_CATALOG_ELEMENT_ID = "boff-explore-catalog";
9038
+ function bakedCatalogLocale() {
9039
+ if (typeof navigator === "undefined") return "";
9040
+ return (navigator.language || "").toLowerCase().split("-")[0] ?? "";
9041
+ }
9042
+ function snapshotBakedElement() {
9043
+ if (typeof document === "undefined") return null;
9044
+ const el = document.getElementById(BAKED_CATALOG_ELEMENT_ID);
9045
+ if (!el || el.tagName !== "SCRIPT" || el.getAttribute("type") !== "application/json")
9046
+ return null;
9047
+ return {
9048
+ product: el.getAttribute("data-product") ?? "",
9049
+ locale: el.getAttribute("data-locale") ?? "",
9050
+ text: el.textContent ?? ""
9051
+ };
9052
+ }
9053
+ var BAKED_AT_LOAD = snapshotBakedElement();
9054
+ function isCatalogShape(value) {
9055
+ if (!value || typeof value !== "object") return false;
9056
+ const c = value;
9057
+ const listOrAbsent = (v) => v === void 0 || v === null || Array.isArray(v);
9058
+ const textOrAbsent = (v) => v === void 0 || v === null || typeof v === "string";
9059
+ return (c["enabled"] === void 0 || typeof c["enabled"] === "boolean") && listOrAbsent(c["products"]) && listOrAbsent(c["examplePrompts"]) && listOrAbsent(c["conceptHighlights"]) && textOrAbsent(c["welcomeTitle"]) && textOrAbsent(c["welcomeBody"]);
9060
+ }
9061
+ function readBakedCatalog(productSlug) {
9062
+ const baked = snapshotBakedElement() ?? BAKED_AT_LOAD;
9063
+ if (!baked) return null;
9064
+ if (baked.product !== (productSlug ?? "")) return null;
9065
+ if (baked.locale && baked.locale !== bakedCatalogLocale()) return null;
9066
+ try {
9067
+ const parsed = JSON.parse(baked.text);
9068
+ return isCatalogShape(parsed) ? parsed : null;
9069
+ } catch {
9070
+ return null;
9071
+ }
9072
+ }
9073
+ function serializeBakedCatalog(raw) {
9074
+ return JSON.stringify(raw).replace(/</g, "\\u003c").replace(/>/g, "\\u003e").replace(/&/g, "\\u0026").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
9075
+ }
9037
9076
  function normalizeCatalog(raw, fallback) {
9038
9077
  return {
9039
9078
  enabled: raw.enabled !== false,
@@ -9283,9 +9322,17 @@ function useExploreChat(options = {}) {
9283
9322
  ),
9284
9323
  [promptKey, welcomeKey]
9285
9324
  );
9286
- const [catalog, setCatalog] = React.useState(fallbackCatalog);
9325
+ const [bakedRaw] = React.useState(
9326
+ () => readBakedCatalog(productSlug)
9327
+ );
9328
+ const [catalog, setCatalog] = React.useState(
9329
+ () => bakedRaw ? normalizeCatalog(bakedRaw, fallbackCatalog) : fallbackCatalog
9330
+ );
9331
+ const [serverCatalogRaw, setServerCatalogRaw] = React.useState(bakedRaw);
9287
9332
  const [messages, setMessages] = React.useState([]);
9288
- const [phase, setPhase] = React.useState("loading");
9333
+ const [phase, setPhase] = React.useState(
9334
+ () => bakedRaw ? bakedRaw.enabled === false ? "disabled" : "ready" : "loading"
9335
+ );
9289
9336
  const [error, setError] = React.useState(null);
9290
9337
  const [remainingToday, setRemainingToday] = React.useState(null);
9291
9338
  const [focusProduct, setFocusProductState] = React.useState(null);
@@ -9303,7 +9350,7 @@ function useExploreChat(options = {}) {
9303
9350
  shareTokenRef.current = readShareToken();
9304
9351
  }
9305
9352
  const isSharedView = shareTokenRef.current !== null;
9306
- const catalogRef = React.useRef(fallbackCatalog);
9353
+ const catalogRef = React.useRef(catalog);
9307
9354
  const turnCountRef = React.useRef(0);
9308
9355
  const focusProductRef = React.useRef(null);
9309
9356
  const lastSentTextRef = React.useRef(null);
@@ -9449,25 +9496,29 @@ function useExploreChat(options = {}) {
9449
9496
  const raw = res.data?.exploreCatalog;
9450
9497
  if (res.errors?.length || !raw) {
9451
9498
  console.warn(
9452
- "[WebSDK] exploreCatalog unavailable \u2014 using the built-in fallback catalog",
9499
+ "[WebSDK] exploreCatalog unavailable \u2014 keeping the catalog the page started with",
9453
9500
  res.errors?.[0]?.message
9454
9501
  );
9455
9502
  setPhase((prev) => prev === "loading" ? "ready" : prev);
9456
9503
  return;
9457
9504
  }
9458
- const next = normalizeCatalog(raw, fallbackCatalog);
9505
+ const next = normalizeCatalog(
9506
+ raw,
9507
+ bakedRaw ? normalizeCatalog(bakedRaw, fallbackCatalog) : fallbackCatalog
9508
+ );
9459
9509
  setCatalog(next);
9510
+ setServerCatalogRaw(raw);
9460
9511
  catalogRef.current = next;
9461
9512
  setPhase((prev) => {
9462
9513
  if (!next.enabled) return "disabled";
9463
- return prev === "loading" ? "ready" : prev;
9514
+ return prev === "loading" || prev === "disabled" ? "ready" : prev;
9464
9515
  });
9465
9516
  };
9466
9517
  void load();
9467
9518
  return () => {
9468
9519
  cancelled = true;
9469
9520
  };
9470
- }, [client, productSlug, fallbackCatalog]);
9521
+ }, [client, productSlug, fallbackCatalog, bakedRaw]);
9471
9522
  const startPolling = React.useCallback(
9472
9523
  (conversationToken, messageId) => {
9473
9524
  pollGenerationRef.current += 1;
@@ -9935,6 +9986,7 @@ function useExploreChat(options = {}) {
9935
9986
  return {
9936
9987
  phase,
9937
9988
  catalog,
9989
+ serverCatalogRaw,
9938
9990
  messages,
9939
9991
  activity,
9940
9992
  remainingToday,
@@ -10768,6 +10820,48 @@ var EXPLORE_CSS = `
10768
10820
  }
10769
10821
  .boff-explore-strip::-webkit-scrollbar { display: none; }
10770
10822
 
10823
+ /* The product chips run past the edge of their row (there are 38). A hard edge sliced the
10824
+ last visible chip mid-word ("Bi", "BigC") right beside "All 38"; a short fade says "there
10825
+ is more this way" instead. A mask carries only alpha, so the gradient's colour is a token
10826
+ that never shows. Mirrored for right-to-left locales, whose row runs the other way. */
10827
+ .boff-explore-chips-fade {
10828
+ /* Focus scrolling honours scroll-padding, so a tabbed-to chip is brought clear of the fade
10829
+ rather than left half-hidden under it. */
10830
+ scroll-padding-inline-end: 2rem;
10831
+ -webkit-mask-image: linear-gradient(to right, hsl(var(--foreground)) calc(100% - 2rem), hsl(var(--foreground) / 0));
10832
+ mask-image: linear-gradient(to right, hsl(var(--foreground)) calc(100% - 2rem), hsl(var(--foreground) / 0));
10833
+ }
10834
+ /* A fade over a fixed edge would leave the LAST chip under it once the row is scrolled to
10835
+ the end \u2014 the visitor could never read it. A trailing spacer the width of the fade lets
10836
+ the final chip scroll clear of it. A pseudo-element rather than padding: trailing padding
10837
+ on a flex scroll container is not reliably part of its scrollable overflow. */
10838
+ .boff-explore-chips-fade::after {
10839
+ content: "";
10840
+ flex: 0 0 2rem;
10841
+ }
10842
+ [dir="rtl"] .boff-explore-chips-fade {
10843
+ -webkit-mask-image: linear-gradient(to left, hsl(var(--foreground)) calc(100% - 2rem), hsl(var(--foreground) / 0));
10844
+ mask-image: linear-gradient(to left, hsl(var(--foreground)) calc(100% - 2rem), hsl(var(--foreground) / 0));
10845
+ }
10846
+
10847
+ /* The concept rail had the chip row's problem: the card at its edge was cut hard mid-word
10848
+ ("Apparatus Rig", "CONCEPT ILLUST") on a dozen sites. It fades an edge only while there are
10849
+ more cards beyond it \u2014 the same state that lights the arrow on that side \u2014 so a rail
10850
+ scrolled to its end shows its last card whole. Physical edges, because that state is
10851
+ physical: it is measured from the left in either reading direction. */
10852
+ .boff-explore-rail-fade-left {
10853
+ -webkit-mask-image: linear-gradient(to right, hsl(var(--foreground) / 0), hsl(var(--foreground)) 3rem);
10854
+ mask-image: linear-gradient(to right, hsl(var(--foreground) / 0), hsl(var(--foreground)) 3rem);
10855
+ }
10856
+ .boff-explore-rail-fade-right {
10857
+ -webkit-mask-image: linear-gradient(to right, hsl(var(--foreground)) calc(100% - 3rem), hsl(var(--foreground) / 0));
10858
+ mask-image: linear-gradient(to right, hsl(var(--foreground)) calc(100% - 3rem), hsl(var(--foreground) / 0));
10859
+ }
10860
+ .boff-explore-rail-fade-left.boff-explore-rail-fade-right {
10861
+ -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));
10862
+ mask-image: linear-gradient(to right, hsl(var(--foreground) / 0), hsl(var(--foreground)) 3rem, hsl(var(--foreground)) calc(100% - 3rem), hsl(var(--foreground) / 0));
10863
+ }
10864
+
10771
10865
  @keyframes boff-explore-fade-in {
10772
10866
  from { opacity: 0; transform: translateY(2px); }
10773
10867
  to { opacity: 1; transform: none; }
@@ -10844,10 +10938,10 @@ var EXPLORE_CSS = `
10844
10938
  Colour comes from the product's --primary token, so it is whatever that site's palette
10845
10939
  already is, never a colour chosen here. */
10846
10940
  .boff-explore-invite {
10847
- border-color: hsl(var(--primary) / 0.45);
10941
+ border-color: hsl(var(--primary) / 0.6);
10848
10942
  box-shadow:
10849
- 0 0 0 4px hsl(var(--primary) / 0.08),
10850
- 0 8px 24px -12px hsl(var(--primary) / 0.45);
10943
+ 0 0 0 4px hsl(var(--primary) / 0.12),
10944
+ 0 8px 24px -12px hsl(var(--primary) / 0.55);
10851
10945
  animation: boff-explore-breathe 3.2s ease-in-out infinite;
10852
10946
  }
10853
10947
  /* Focus and typing both mean "I have found it", and the hint has done its job. */
@@ -10857,8 +10951,8 @@ var EXPLORE_CSS = `
10857
10951
  box-shadow: 0 0 0 4px hsl(var(--primary) / 0.10);
10858
10952
  }
10859
10953
  @keyframes boff-explore-breathe {
10860
- 0%, 100% { box-shadow: 0 0 0 4px hsl(var(--primary) / 0.07), 0 8px 24px -12px hsl(var(--primary) / 0.40); }
10861
- 50% { box-shadow: 0 0 0 7px hsl(var(--primary) / 0.13), 0 8px 28px -12px hsl(var(--primary) / 0.55); }
10954
+ 0%, 100% { box-shadow: 0 0 0 4px hsl(var(--primary) / 0.10), 0 8px 24px -12px hsl(var(--primary) / 0.50); }
10955
+ 50% { box-shadow: 0 0 0 7px hsl(var(--primary) / 0.18), 0 8px 28px -12px hsl(var(--primary) / 0.65); }
10862
10956
  }
10863
10957
 
10864
10958
  /* Every one of the above is decoration. Reduced motion removes the movement and keeps the
@@ -10946,8 +11040,18 @@ var EXPLORE_CSS = `
10946
11040
  .boff-explore-scroll .boff-explore-capabilities { display: none; }
10947
11041
  }
10948
11042
  @container boff-explore-pane (min-width: ${toRem(WELCOME_FIT_MIN_WIDTH_PX)}) and (max-height: ${toRem(WELCOME_FIT_STEP_PX[1])}) {
10949
- /* Step 2. */
11043
+ /* Step 2. At a 4:1 crop the picture is ~44px tall, and the full-size caveat badge covered
11044
+ half of it \u2014 on ten sites, every card, whenever the consent banner was up. It stays (the
11045
+ picture is still a mockup), just smaller and tucked into the corner. */
10950
11046
  .boff-explore-scroll .boff-explore-concept-media { aspect-ratio: 4 / 1; }
11047
+ .boff-explore-scroll .boff-explore-concept-badge {
11048
+ top: 0.25rem;
11049
+ left: 0.25rem;
11050
+ padding: 0 0.3125rem;
11051
+ font-size: 0.5rem;
11052
+ line-height: 0.75rem;
11053
+ letter-spacing: 0.02em;
11054
+ }
10951
11055
  }
10952
11056
  @container boff-explore-pane (min-width: ${toRem(WELCOME_FIT_MIN_WIDTH_PX)}) and (max-height: ${toRem(WELCOME_FIT_STEP_PX[2])}) {
10953
11057
  /* Step 3. Title-only cards. The "concept illustration" caveat lives on the picture, so it
@@ -12106,6 +12210,7 @@ function ErrorBanner({
12106
12210
  }
12107
12211
  function PromptCarousel({
12108
12212
  strings: T,
12213
+ label,
12109
12214
  prompts,
12110
12215
  onPrompt,
12111
12216
  disabled
@@ -12137,7 +12242,7 @@ function PromptCarousel({
12137
12242
  return /* @__PURE__ */ jsxRuntime.jsxs(
12138
12243
  "div",
12139
12244
  {
12140
- className: "flex min-w-0 touch-pan-y items-center gap-1.5",
12245
+ 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]",
12141
12246
  role: "group",
12142
12247
  "aria-roledescription": "carousel",
12143
12248
  "aria-label": "Example questions",
@@ -12147,13 +12252,14 @@ function PromptCarousel({
12147
12252
  onBlurCapture: () => setPaused(false),
12148
12253
  ...swipe,
12149
12254
  children: [
12255
+ /* @__PURE__ */ jsxRuntime.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 }),
12150
12256
  count > 1 ? /* @__PURE__ */ jsxRuntime.jsx(
12151
12257
  "button",
12152
12258
  {
12153
12259
  type: "button",
12154
12260
  "aria-label": T.prevSuggestion,
12155
12261
  onClick: () => go(-1),
12156
- 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",
12262
+ 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",
12157
12263
  children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronLeft, { className: "h-4 w-4" })
12158
12264
  }
12159
12265
  ) : null,
@@ -12167,14 +12273,23 @@ function PromptCarousel({
12167
12273
  "aria-label": `Ask: ${current}`,
12168
12274
  "aria-live": paused ? "polite" : "off",
12169
12275
  onClick: () => onPrompt(current),
12170
- 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",
12276
+ className: cn(
12277
+ "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",
12278
+ count > 1 ? "sm:col-span-1 sm:col-start-2" : "sm:col-span-3"
12279
+ ),
12171
12280
  children: [
12172
12281
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Sparkles, { className: "h-3.5 w-3.5 shrink-0 text-primary" }),
12173
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: current }),
12174
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUp, { className: "ml-auto h-3.5 w-3.5 shrink-0 rotate-45 text-muted-foreground transition-colors group-hover:text-primary" })
12282
+ /* @__PURE__ */ jsxRuntime.jsx(
12283
+ "span",
12284
+ {
12285
+ className: "boff-explore-fade min-w-0 max-sm:line-clamp-3 sm:truncate",
12286
+ children: current
12287
+ },
12288
+ current
12289
+ ),
12290
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.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" })
12175
12291
  ]
12176
- },
12177
- current
12292
+ }
12178
12293
  ),
12179
12294
  count > 1 ? /* @__PURE__ */ jsxRuntime.jsx(
12180
12295
  "button",
@@ -12182,7 +12297,7 @@ function PromptCarousel({
12182
12297
  type: "button",
12183
12298
  "aria-label": T.nextSuggestion,
12184
12299
  onClick: () => go(1),
12185
- 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",
12300
+ 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",
12186
12301
  children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "h-4 w-4" })
12187
12302
  }
12188
12303
  ) : null
@@ -12213,7 +12328,7 @@ function ProductStrip({
12213
12328
  {
12214
12329
  className: cn(
12215
12330
  "boff-explore-strip flex min-w-0 flex-1 gap-2",
12216
- expanded ? "flex-wrap" : "flex-nowrap overflow-x-auto"
12331
+ expanded ? "flex-wrap" : "boff-explore-chips-fade flex-nowrap overflow-x-auto"
12217
12332
  ),
12218
12333
  children: [
12219
12334
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -12281,8 +12396,11 @@ function ConceptStrip({
12281
12396
  const measureRail = React.useCallback(() => {
12282
12397
  const el = railRef.current;
12283
12398
  if (!el) return;
12284
- setCanLeft(el.scrollLeft > 1);
12285
- setCanRight(el.scrollLeft + el.clientWidth < el.scrollWidth - 1);
12399
+ const max = el.scrollWidth - el.clientWidth;
12400
+ const rtl = typeof getComputedStyle === "function" && getComputedStyle(el).direction === "rtl";
12401
+ const fromLeft = rtl ? max + el.scrollLeft : el.scrollLeft;
12402
+ setCanLeft(fromLeft > 1);
12403
+ setCanRight(fromLeft < max - 1);
12286
12404
  }, []);
12287
12405
  React.useEffect(() => {
12288
12406
  const el = railRef.current;
@@ -12351,11 +12469,15 @@ function ConceptStrip({
12351
12469
  onScroll: measureRail,
12352
12470
  "data-boff-explore": "concept-strip",
12353
12471
  "aria-label": T.conceptStripLabel,
12354
- className: "boff-explore-strip flex min-w-0 snap-x gap-3 overflow-x-auto pb-1",
12472
+ className: cn(
12473
+ "boff-explore-strip flex min-w-0 snap-x gap-3 overflow-x-auto pb-1 sm:mx-10",
12474
+ canLeft && "boff-explore-rail-fade-left",
12475
+ canRight && "boff-explore-rail-fade-right"
12476
+ ),
12355
12477
  children: visible.map((highlight) => /* @__PURE__ */ jsxRuntime.jsx(
12356
12478
  "li",
12357
12479
  {
12358
- className: "shrink-0 snap-start",
12480
+ className: "flex shrink-0 snap-start",
12359
12481
  children: /* @__PURE__ */ jsxRuntime.jsxs(
12360
12482
  "button",
12361
12483
  {
@@ -12391,14 +12513,14 @@ function ConceptStrip({
12391
12513
  "span",
12392
12514
  {
12393
12515
  "aria-hidden": "true",
12394
- 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",
12516
+ 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",
12395
12517
  children: T.conceptIllustration
12396
12518
  }
12397
12519
  )
12398
12520
  ] }),
12399
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 flex-col gap-0.5 p-2.5", children: [
12521
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 flex-1 flex-col gap-0.5 p-2.5", children: [
12400
12522
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "line-clamp-2 text-xs font-semibold leading-snug text-card-foreground", children: highlight.title }),
12401
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-[11px] text-muted-foreground", children: highlight.productName })
12523
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mt-auto truncate text-[11px] text-muted-foreground", children: highlight.productName })
12402
12524
  ] })
12403
12525
  ]
12404
12526
  }
@@ -12546,18 +12668,16 @@ function WelcomeState({
12546
12668
  },
12547
12669
  i
12548
12670
  )) }),
12549
- prompts.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "boff-explore-rise boff-explore-rise-2 mt-4", children: [
12550
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mb-1.5 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: T.tryAsking }),
12551
- /* @__PURE__ */ jsxRuntime.jsx(
12552
- PromptCarousel,
12553
- {
12554
- strings: T,
12555
- prompts,
12556
- onPrompt,
12557
- disabled
12558
- }
12559
- )
12560
- ] }) : null,
12671
+ prompts.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "boff-explore-rise boff-explore-rise-2 mt-4", children: /* @__PURE__ */ jsxRuntime.jsx(
12672
+ PromptCarousel,
12673
+ {
12674
+ strings: T,
12675
+ label: T.tryAsking,
12676
+ prompts,
12677
+ onPrompt,
12678
+ disabled
12679
+ }
12680
+ ) }) : null,
12561
12681
  products.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "boff-explore-rise boff-explore-rise-3 mt-4", children: [
12562
12682
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mb-1.5 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: T.focusProduct }),
12563
12683
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -12615,6 +12735,7 @@ function ExplorePage({
12615
12735
  const {
12616
12736
  phase,
12617
12737
  catalog,
12738
+ serverCatalogRaw,
12618
12739
  messages,
12619
12740
  activity,
12620
12741
  remainingToday,
@@ -13046,6 +13167,10 @@ function ExplorePage({
13046
13167
  const captchaOn = Boolean(
13047
13168
  catalog.captchaRequired && catalog.recaptchaSiteKey
13048
13169
  );
13170
+ const bakedCatalogJson = React.useMemo(
13171
+ () => serverCatalogRaw && serverCatalogRaw.enabled !== false ? serializeBakedCatalog(serverCatalogRaw) : null,
13172
+ [serverCatalogRaw]
13173
+ );
13049
13174
  const rootStyle = {};
13050
13175
  if (heightMode === "viewport") {
13051
13176
  rootStyle["--boff-explore-offset"] = paneOffset === null ? normalizeOffset(viewportOffset) : `${paneOffset}px`;
@@ -13085,6 +13210,16 @@ function ExplorePage({
13085
13210
  ),
13086
13211
  /* @__PURE__ */ jsxRuntime.jsx(ProseStyles, {}),
13087
13212
  /* @__PURE__ */ jsxRuntime.jsx(ExploreStyles, {}),
13213
+ bakedCatalogJson ? /* @__PURE__ */ jsxRuntime.jsx(
13214
+ "script",
13215
+ {
13216
+ id: BAKED_CATALOG_ELEMENT_ID,
13217
+ type: "application/json",
13218
+ "data-product": productSlug ?? "",
13219
+ "data-locale": bakedCatalogLocale(),
13220
+ dangerouslySetInnerHTML: { __html: bakedCatalogJson }
13221
+ }
13222
+ ) : null,
13088
13223
  /* @__PURE__ */ jsxRuntime.jsx(ExploreAnswerStyles, {}),
13089
13224
  !showWelcome ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2.5 border-b border-border px-4 py-2.5", children: [
13090
13225
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -13559,7 +13694,7 @@ function ExplorePage({
13559
13694
  )
13560
13695
  ] }) : null,
13561
13696
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-2 flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-muted-foreground", children: [
13562
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 truncate", children: T.disclaimerShort }),
13697
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 sm:truncate", children: T.disclaimerShort }),
13563
13698
  /* @__PURE__ */ jsxRuntime.jsx(
13564
13699
  "button",
13565
13700
  {