@riverbankcms/sdk 0.140.0 → 0.141.0

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 (112) hide show
  1. package/dist/{PreviewEditorSidebar-CUyTzd5z.mjs → PreviewEditorSidebar-Q-fy9GYw.mjs} +3 -3
  2. package/dist/{PreviewEditorUI-Agkw4v5i.mjs → PreviewEditorUI-LYGzgk85.mjs} +2 -2
  3. package/dist/{SdkPreviewModeRuntime-DdbeAdS8.mjs → SdkPreviewModeRuntime-CoPYI5Jq.mjs} +72 -46
  4. package/dist/{SiteChromeCustomizeContext-CqGOz-Kv.mjs → SiteChromeCustomizeContext-D8LePX8x.mjs} +681 -196
  5. package/dist/_dts/api/src/contentRuntime.d.ts +12 -31
  6. package/dist/_dts/api/src/domainConnection.d.ts +4 -0
  7. package/dist/_dts/api/src/footerCompositionContracts.d.ts +25 -0
  8. package/dist/_dts/api/src/index.d.ts +1 -1
  9. package/dist/_dts/api/src/launchReadiness.d.ts +1 -0
  10. package/dist/_dts/api/src/navigation/dashboardSiteNav.d.ts +2 -1
  11. package/dist/_dts/api/src/siteManagementEndpoints.d.ts +3 -26
  12. package/dist/_dts/api/src/siteOnboarding.d.ts +7 -0
  13. package/dist/_dts/billing/src/site-arrangements.d.ts +12 -3
  14. package/dist/_dts/blocks/src/contracts/proof-block-islands.d.ts +4 -0
  15. package/dist/_dts/blocks/src/pageRendererContracts.d.ts +2 -0
  16. package/dist/_dts/blocks/src/system/blocks/events/event-calendar.d.ts +2 -0
  17. package/dist/_dts/blocks/src/system/blocks/events/eventSelectionFields.d.ts +122 -0
  18. package/dist/_dts/blocks/src/system/blocks/events/shared/calendarWindow.d.ts +2 -1
  19. package/dist/_dts/blocks/src/system/blocks/events/shared/eventSelection.d.ts +11 -0
  20. package/dist/_dts/blocks/src/system/blocks/location-map.d.ts +2 -2
  21. package/dist/_dts/blocks/src/system/blocks/media-text.d.ts +47 -47
  22. package/dist/_dts/blocks/src/system/data/prefetchBlockData.d.ts +5 -0
  23. package/dist/_dts/blocks/src/system/data/utils.d.ts +1 -1
  24. package/dist/_dts/blocks/src/system/manifest/schema.d.ts +27 -1
  25. package/dist/_dts/blocks/src/system/runtime/components/registry.client.d.ts +12 -180
  26. package/dist/_dts/blocks/src/system/runtime/components/runtime-backed-blocks.d.ts +6 -90
  27. package/dist/_dts/blocks/src/system/runtime/hooks/useEventFilters.d.ts +2 -1
  28. package/dist/_dts/blocks/src/system/runtime/nodes/appointment-services.d.ts +5 -1
  29. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/hooks.d.ts +4 -0
  30. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/hooks.state.d.ts +5 -0
  31. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useDiscountCodeUi.d.ts +3 -0
  32. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useDiscountCodeUi.state.d.ts +10 -3
  33. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventCheckoutHandoffRestore.d.ts +9 -0
  34. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventRegistrationWizard.d.ts +4 -5
  35. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useSettledCommerceView.d.ts +37 -0
  36. package/dist/_dts/blocks/src/system/runtime/nodes/events/EventCombined.client.d.ts +4 -3
  37. package/dist/_dts/blocks/src/system/runtime/nodes/events/EventCombined.interactive.d.ts +3 -0
  38. package/dist/_dts/blocks/src/system/runtime/nodes/events/EventListing.interactive.d.ts +11 -101
  39. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/eventCollectionContract.d.ts +7 -2
  40. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/listOptions.d.ts +2 -0
  41. package/dist/_dts/blocks/src/system/transforms/registry/eventCalendar.d.ts +12 -0
  42. package/dist/_dts/commerce/src/purchase/bookingInstalmentSchedule.d.ts +4 -0
  43. package/dist/_dts/db/src/generated/supabase/database.types.d.ts +3 -0
  44. package/dist/_dts/editor-blocks/src/widgets/site-option-picker/loaders.d.ts +27 -1
  45. package/dist/_dts/sdk/src/public-api/contracts.d.ts +1 -1
  46. package/dist/_dts/sdk/src/version.d.ts +1 -1
  47. package/dist/_dts/theme-core/src/ThemeFontLoader.d.ts +17 -1
  48. package/dist/_dts/theme-core/src/buttons/affordanceSuppression.d.ts +17 -0
  49. package/dist/_dts/theme-core/src/buttons/buttonColourContract.d.ts +1 -1
  50. package/dist/_dts/theme-core/src/buttons/classNames.d.ts +16 -0
  51. package/dist/_dts/theme-core/src/buttons/generateButtonCss.d.ts +0 -6
  52. package/dist/_dts/theme-core/src/buttons/resolvedButtonCss.d.ts +4 -4
  53. package/dist/_dts/theme-core/src/generated/containerResponsiveThemeCss.d.ts +1 -1
  54. package/dist/_dts/theme-core/src/hosted-booking-appearance.d.ts +54 -12
  55. package/dist/_dts/theme-core/src/index.d.ts +1 -1
  56. package/dist/client/{BookingConsentAgreement-CuKa82V4.mjs → BookingConsentAgreement-xJeYNdnb.mjs} +2 -2
  57. package/dist/client/{DiscountCodeDisclosure-BbYieKWB.mjs → DiscountCodeDisclosure-DdT6uzl9.mjs} +1 -1
  58. package/dist/client/{EventCombined.client-LTfR1Aby.mjs → EventCombined.client-Cp28uYuM.mjs} +11 -15
  59. package/dist/client/{EventListing.client-DUHpYSuo.mjs → EventListing.client-CD6AJsMr.mjs} +4 -17
  60. package/dist/client/{LeafletStaticMap-CHRupL6m.mjs → LeafletStaticMap-DBsAi9-e.mjs} +1 -1
  61. package/dist/client/{accordion-6HiIFxNL.mjs → accordion-6dwbOKYR.mjs} +1 -1
  62. package/dist/client/{bookingForm-Dlmid43H.mjs → bookingForm-CZE9_qPQ.mjs} +5 -5
  63. package/dist/client/bookings.mjs +175 -93
  64. package/dist/client/{carousel-DmkZRRq_.mjs → carousel-7VHGQARz.mjs} +1 -1
  65. package/dist/client/{cart-CIC24330.mjs → cart-Qg_mvQhh.mjs} +3 -3
  66. package/dist/client/{checkout-D1Zw9imo.mjs → checkout-D84rpgdr.mjs} +3 -3
  67. package/dist/client/client.mjs +602 -139
  68. package/dist/client/{context-Cy1OayHx.mjs → context-Ctp3T0Wr.mjs} +1 -1
  69. package/dist/client/{dates-aDcfoLHr.mjs → dates-DJKFcI_N.mjs} +2 -2
  70. package/dist/client/{eventCalendar-FQxMPAjf.mjs → eventCalendar-CK31z3vs.mjs} +11 -7
  71. package/dist/client/{eventCombined-Dr3ac6Hb.mjs → eventCombined-DiXd-ewn.mjs} +3 -3
  72. package/dist/client/{eventDetails-D-AzUHFQ.mjs → eventDetails-CTRgt2DK.mjs} +4 -4
  73. package/dist/client/{eventListing-B3XxBf3i.mjs → eventListing-Dy9vi_j_.mjs} +3 -3
  74. package/dist/client/{eventRegistration-I6EaokFD.mjs → eventRegistration-CnalYMr2.mjs} +124 -31
  75. package/dist/client/{form-BbWckVWY.mjs → form-eUiMveTT.mjs} +2 -2
  76. package/dist/client/{headerSection-C9qU4Y7x.mjs → headerSection-Dy9kQpB1.mjs} +2 -2
  77. package/dist/client/hooks.mjs +247 -32
  78. package/dist/client/{locationMap-CLCShvlG.mjs → locationMap-DalCmWU0.mjs} +2 -2
  79. package/dist/client/{newsletterForm-Briukxzi.mjs → newsletterForm-SDDPvhS0.mjs} +23 -10
  80. package/dist/client/{pricing-Copadu-2.mjs → pricing-OcMz4SnX.mjs} +1 -1
  81. package/dist/client/{productDetail-oujlRd-r.mjs → productDetail-BQrgHElM.mjs} +3 -3
  82. package/dist/client/{productList-BRiIRUcd.mjs → productList-OnPn_UJj.mjs} +3 -3
  83. package/dist/client/{propsDecoder-CB2KS_ko.mjs → propsDecoder-zBdsnS-N.mjs} +38 -8
  84. package/dist/client/rendering/client.mjs +446 -121
  85. package/dist/client/rendering/islands.mjs +17 -17
  86. package/dist/client/rendering.mjs +601 -138
  87. package/dist/client/{scrollToBlock-B1IS1_ua.mjs → scrollToBlock-BNM4Ob2Y.mjs} +28 -11
  88. package/dist/client/{shop-Vn6yNFED.mjs → shop-Bv1fPTwQ.mjs} +6 -6
  89. package/dist/client/{shop-commerce-BVTqipYp.mjs → shop-commerce-D4KNGaW8.mjs} +5 -5
  90. package/dist/client/{shop-commerce-store-BVnJVy7v.mjs → shop-commerce-store-2N5EV0Rc.mjs} +1 -1
  91. package/dist/client/{shopShared-COIeK77T.mjs → shopShared-DvJGdHTV.mjs} +3 -3
  92. package/dist/client/{useEventFilters-DzIUcS9n.mjs → useEventFilters-BBBvGDHQ.mjs} +17 -11
  93. package/dist/preview-next/client/runtime.mjs +3 -3
  94. package/dist/preview-next/editor-chrome.css +4 -8
  95. package/dist/{sdk-runtime-CnCLvZRv.mjs → sdk-runtime-Defnbfzw.mjs} +1 -1
  96. package/dist/{separator-DKDRJ1oH.mjs → separator-CZXO3Sb0.mjs} +1 -1
  97. package/dist/server/components.mjs +384 -62
  98. package/dist/server/config-validation.mjs +232 -26
  99. package/dist/server/config.mjs +232 -26
  100. package/dist/server/data.mjs +247 -32
  101. package/dist/server/index.mjs +1 -1
  102. package/dist/server/next.mjs +400 -69
  103. package/dist/server/page-converter.mjs +189 -25
  104. package/dist/server/prebuild.mjs +1 -1
  105. package/dist/server/rendering/server.mjs +399 -68
  106. package/dist/server/rendering.mjs +399 -68
  107. package/dist/server/routing.mjs +261 -33
  108. package/dist/server/server.mjs +248 -33
  109. package/dist/server/theme-bridge.mjs +47 -15
  110. package/dist/server/theme.mjs +1 -1
  111. package/dist/styles/index.css +28 -2
  112. package/package.json +1 -1
@@ -4760,7 +4760,7 @@ const BUTTON_CONTRAST_POLICY = {
4760
4760
  nonTextMinimumRatio: 3,
4761
4761
  gradientSamplesPerSegment: 20,
4762
4762
  alphaBackgrounds: "reject-without-known-surface",
4763
- disabled: "retain-full-colour-contract"
4763
+ disabled: "validated-colour-pair-with-muted-control-opacity"
4764
4764
  };
4765
4765
  function formatButtonColourContractError(error) {
4766
4766
  switch (error.tag) {
@@ -5348,6 +5348,25 @@ function parseThemeForPersistence(value) {
5348
5348
  };
5349
5349
  }
5350
5350
  //#endregion
5351
+ //#region ../theme-core/src/buttons/affordanceSuppression.ts
5352
+ /**
5353
+ * Internal: the opt-out the generated affordance rule is written against.
5354
+ *
5355
+ * A button style may declare a trailing `affordance`, which the theme renders as
5356
+ * a CSS `::after` on every button of that variant. An authored button that
5357
+ * renders its own trailing icon must not also receive the theme's, or it shows
5358
+ * two.
5359
+ *
5360
+ * Deliberately not exported from `./index`. This used to be public, and two
5361
+ * block components reached past the theme to draw arrows of their own — one of
5362
+ * them doubling up on the styles that declare an affordance, both of them
5363
+ * overriding the twelve styles that deliberately declare none. Whether a button
5364
+ * carries a trailing affordance is the style's decision; the only caller that
5365
+ * legitimately opts out is the authored-button renderer, which reaches it
5366
+ * through `themeButtonClassNameWithTrailingIcon`.
5367
+ */
5368
+ const AFFORDANCE_SUPPRESS_CLASS = "rb-affordance-off";
5369
+ //#endregion
5351
5370
  //#region ../theme-core/src/buttons/classNames.ts
5352
5371
  /**
5353
5372
  * Parse content/runtime variant identifiers into the closed theme-button class
@@ -5380,6 +5399,27 @@ function themeButtonClassName(spec) {
5380
5399
  spec.extraClassName
5381
5400
  ].filter(Boolean).join(" ");
5382
5401
  }
5402
+ /**
5403
+ * Button classes for an authored button that renders its own trailing icon.
5404
+ *
5405
+ * A separate function rather than a flag on `themeButtonClassName`, because
5406
+ * there is exactly one caller and it should stay visible in a diff. The name
5407
+ * states what the caller knows to be true of its own markup — that it renders a
5408
+ * trailing icon — rather than what the theme does about it. The consequence is
5409
+ * the theme's to decide and to change; a caller naming the consequence would be
5410
+ * asserting a policy it does not own, and would quietly become a lie the moment
5411
+ * that policy moved.
5412
+ *
5413
+ * Do not reach for this to remove an arrow you simply do not want. A trailing
5414
+ * affordance is declared by the button style, and a block overriding that is the
5415
+ * defect this replaced.
5416
+ */
5417
+ function themeButtonClassNameWithTrailingIcon(spec) {
5418
+ return themeButtonClassName({
5419
+ ...spec,
5420
+ extraClassName: [spec.extraClassName, AFFORDANCE_SUPPRESS_CLASS].filter(Boolean).join(" ")
5421
+ });
5422
+ }
5383
5423
  const defaultThemeTokens = {
5384
5424
  color: {
5385
5425
  "background/base": "#ffffff",
@@ -7798,26 +7838,19 @@ function resolvedButtonFocusDeclarations(indicator, role) {
7798
7838
  ] : [["outline", value("outline", `3px solid ${indicator.colorCss}`)], ["outline-offset", value("outline-offset", "3px")]];
7799
7839
  }
7800
7840
  /**
7801
- * Disabled buttons retain their validated colour pair and add a non-layout
7802
- * visual affordance. `currentColor` keeps the cue inside the same contrast
7803
- * relationship, while retaining pointer events lets the not-allowed cursor
7804
- * remain observable.
7841
+ * Disabled buttons are deliberately muted as unavailable controls. Native
7842
+ * disabled controls are exempt from active-control contrast requirements;
7843
+ * opacity distinguishes the state without introducing a focus-like outline.
7844
+ * Retaining pointer events lets the not-allowed cursor remain observable.
7805
7845
  */
7806
7846
  const RESOLVED_BUTTON_DISABLED_DECLARATIONS = [
7807
7847
  ["cursor", "not-allowed"],
7808
7848
  ["transform", "none"],
7809
7849
  ["box-shadow", "none"],
7810
- ["outline", "2px dashed currentColor"],
7811
- ["outline-offset", "-4px"]
7850
+ ["opacity", "0.55"]
7812
7851
  ];
7813
7852
  //#endregion
7814
7853
  //#region ../theme-core/src/buttons/generateButtonCss.ts
7815
- /**
7816
- * Class the `button` runtime node adds when it renders its own trailing icon,
7817
- * so a node-level icon suppresses the theme's CSS `::after` affordance.
7818
- * Shared so generator and renderer can't drift.
7819
- */
7820
- const AFFORDANCE_SUPPRESS_CLASS = "rb-affordance-off";
7821
7854
  const BUTTON_SIZE_NAMES = buttonSizeNameSchema.options;
7822
7855
  /**
7823
7856
  * Letter spacing token → CSS value.
@@ -10611,14 +10644,12 @@ function generateVariantCSS(variant, themeId, cardClasses, tokens, theme) {
10611
10644
  const shadowValue = generateShadowValue(shadow);
10612
10645
  rules.push(`box-shadow: ${shadowValue}`);
10613
10646
  }
10614
- rules.push(`display: flex`);
10615
- rules.push(`flex-direction: column`);
10616
- rules.push(`position: relative`);
10617
- rules.push(`overflow: visible`);
10647
+ const structureSelector = cardClasses.map((cardClass) => `:where([data-theme-scope="${themeId}"]) :where(.${cardClass})`).join(",\n");
10618
10648
  const mediaRadius = MEDIA_CORNER_MAP[corners];
10619
10649
  const mediaRules = [`border-top-left-radius: ${mediaRadius}`, `border-top-right-radius: ${mediaRadius}`];
10620
10650
  const contentRules = [`padding: ${resolveContentPadding(variant)}`];
10621
10651
  return [
10652
+ `${structureSelector} {\n display: flex;\n flex-direction: column;\n position: relative;\n overflow: visible;\n}`,
10622
10653
  `${containerSelector} {\n ${rules.join(";\n ")};\n}`,
10623
10654
  ...cardDecorationPseudoRules(containerSelectors, variant.decorations, resolveColor),
10624
10655
  `${fallbackBackgroundSelector} {\n background: transparent;\n}`,
@@ -13470,6 +13501,7 @@ const calendarWindowQuerySchema = z$1.object({
13470
13501
  eventSurface: z$1.enum(eventSurfaceScopeValues).optional(),
13471
13502
  eventPresets: z$1.string().optional(),
13472
13503
  scheduleScope: z$1.enum(eventScheduleScopeValues).optional(),
13504
+ seriesIds: z$1.string().optional(),
13473
13505
  categoryIds: z$1.string().optional(),
13474
13506
  venueId: z$1.string().transform(normalizeCalendarFilterId).optional(),
13475
13507
  staffMemberId: z$1.string().transform(normalizeCalendarFilterId).optional()
@@ -23298,6 +23330,7 @@ function isDisplayMediaKind$2(kind) {
23298
23330
  }
23299
23331
  const siteOptionSources = [
23300
23332
  "eventCategories",
23333
+ "eventSeries",
23301
23334
  "venues",
23302
23335
  "staffMembers"
23303
23336
  ];
@@ -27666,6 +27699,35 @@ function buildBookingFormInteractiveIslandProps(props) {
27666
27699
  });
27667
27700
  }
27668
27701
  //#endregion
27702
+ //#region ../blocks/src/system/blocks/events/shared/eventSelection.ts
27703
+ /** Invalid saved selections fail closed rather than widening discovery. */
27704
+ function resolveEventSelection(mode, value) {
27705
+ if (mode !== "selected") return { kind: "matching" };
27706
+ const candidates = Array.isArray(value) ? value : typeof value === "string" ? value.split(",").filter(Boolean) : [];
27707
+ const ids = [];
27708
+ for (const candidate of candidates) {
27709
+ if (typeof candidate !== "string") return {
27710
+ kind: "selected",
27711
+ seriesIds: []
27712
+ };
27713
+ const parsed = parseEventSeriesId(candidate.trim());
27714
+ if (!parsed.ok) return {
27715
+ kind: "selected",
27716
+ seriesIds: []
27717
+ };
27718
+ ids.push(parsed.value);
27719
+ }
27720
+ return {
27721
+ kind: "selected",
27722
+ seriesIds: [...new Set(ids)].sort()
27723
+ };
27724
+ }
27725
+ /** Undefined means discovery; an empty string is an explicitly empty selection. */
27726
+ function eventSeriesScopeCsv(value) {
27727
+ if (value == null) return void 0;
27728
+ return typeof value === "string" ? value : value.join(",");
27729
+ }
27730
+ //#endregion
27669
27731
  //#region ../blocks/src/system/runtime/nodes/events/domain/capacity.ts
27670
27732
  /**
27671
27733
  * Compute remaining spots for an event from `availableSpots` with a fallback
@@ -30285,12 +30347,12 @@ const EventCompactRow = ({ event, buttonVariant = "primary", buttonText }) => {
30285
30347
  }), cta.hidden ? /* @__PURE__ */ jsx("span", {
30286
30348
  className: "event-compact-row-status",
30287
30349
  children: cta.label
30288
- }) : /* @__PURE__ */ jsxs("a", {
30350
+ }) : /* @__PURE__ */ jsx("a", {
30289
30351
  href: cta.href,
30290
30352
  target: cta.external ? "_blank" : void 0,
30291
30353
  rel: cta.external ? "noopener noreferrer" : void 0,
30292
30354
  className: `${buttonClass} event-compact-row-cta`,
30293
- children: [/* @__PURE__ */ jsx("span", { children: cta.label }), /* @__PURE__ */ jsx(ArrowRightIcon, { "aria-hidden": "true" })]
30355
+ children: /* @__PURE__ */ jsx("span", { children: cta.label })
30294
30356
  })]
30295
30357
  })]
30296
30358
  })]
@@ -30582,6 +30644,7 @@ const eventCollectionFilterSourceSchemaShape = {
30582
30644
  eventSurface: eventSurfaceScopeSchema$1.nullable().optional(),
30583
30645
  filterEventPresets: z$1.union([z$1.string(), z$1.array(z$1.string())]).nullable().optional(),
30584
30646
  scheduleScope: eventScheduleScopeSchema$1.nullable().optional(),
30647
+ seriesIds: z$1.union([z$1.string(), z$1.array(z$1.string())]).nullable().optional(),
30585
30648
  filterCategoryIds: z$1.union([z$1.string(), z$1.array(z$1.string())]).nullable().optional(),
30586
30649
  filterStaffMemberId: z$1.string().nullable().optional(),
30587
30650
  filterVenueId: z$1.string().nullable().optional()
@@ -30628,6 +30691,7 @@ const eventCollectionDisplaySchemaShape = {
30628
30691
  eventSurface: eventSurfaceScopeSchema$1,
30629
30692
  filterEventPresets: z$1.string().nullable(),
30630
30693
  scheduleScope: eventScheduleScopeSchema$1,
30694
+ seriesIds: z$1.string().nullable().optional(),
30631
30695
  filterCategoryIds: z$1.string().nullable(),
30632
30696
  filterStaffMemberId: z$1.string().nullable(),
30633
30697
  filterVenueId: z$1.string().nullable(),
@@ -30675,11 +30739,15 @@ function buildEventCollectionDisplay(source) {
30675
30739
  };
30676
30740
  }
30677
30741
  function buildEventCollectionFilterDisplay(source) {
30678
- return {
30679
- showFilters: source.showFilters ?? true,
30680
- showCategoryFilter: source.showCategoryFilter ?? "auto",
30681
- showVenueFilter: source.showVenueFilter ?? false,
30682
- showStaffFilter: source.showStaffFilter ?? true,
30742
+ const selected = source.seriesIds != null;
30743
+ const matchingFilters = selected ? {
30744
+ eventSurface: "all",
30745
+ filterEventPresets: null,
30746
+ scheduleScope: "any",
30747
+ filterCategoryIds: null,
30748
+ filterStaffMemberId: null,
30749
+ filterVenueId: null
30750
+ } : {
30683
30751
  eventSurface: normalizeEventSurfaceScope(source.eventSurface),
30684
30752
  filterEventPresets: normalizeEventSurfacePresetsCsv(source.filterEventPresets),
30685
30753
  scheduleScope: normalizeEventScheduleScope(source.scheduleScope),
@@ -30687,6 +30755,14 @@ function buildEventCollectionFilterDisplay(source) {
30687
30755
  filterStaffMemberId: normalizeEventStaffMemberId(source.filterStaffMemberId),
30688
30756
  filterVenueId: normalizeEventVenueId(source.filterVenueId)
30689
30757
  };
30758
+ return {
30759
+ seriesIds: eventSeriesScopeCsv(source.seriesIds),
30760
+ showFilters: selected ? false : source.showFilters ?? true,
30761
+ showCategoryFilter: source.showCategoryFilter ?? "auto",
30762
+ showVenueFilter: source.showVenueFilter ?? false,
30763
+ showStaffFilter: source.showStaffFilter ?? true,
30764
+ ...matchingFilters
30765
+ };
30690
30766
  }
30691
30767
  function buildEventCollectionPresentationDisplay(source) {
30692
30768
  return {
@@ -30701,14 +30777,15 @@ function buildEventCollectionPresentationDisplay(source) {
30701
30777
  }
30702
30778
  function buildEventCollectionHydration(source, now = /* @__PURE__ */ new Date()) {
30703
30779
  const timeZone = source.calendarWindow?.scope.timeZone ?? toBookingTimeZone(source.bookingTimeZone);
30780
+ const selected = source.seriesIds != null;
30704
30781
  return {
30705
30782
  calendarWindow: source.calendarWindow ?? void 0,
30706
30783
  siteId: source.siteId,
30707
30784
  stage: source.stage,
30708
30785
  prefetchedEvents: source.events != null,
30709
- eventSurface: normalizeEventSurfaceScope(source.eventSurface),
30710
- filterEventPresets: normalizeEventSurfacePresetsCsv(source.filterEventPresets),
30711
- scheduleScope: normalizeEventScheduleScope(source.scheduleScope),
30786
+ eventSurface: selected ? "all" : normalizeEventSurfaceScope(source.eventSurface),
30787
+ filterEventPresets: selected ? null : normalizeEventSurfacePresetsCsv(source.filterEventPresets),
30788
+ scheduleScope: selected ? "any" : normalizeEventScheduleScope(source.scheduleScope),
30712
30789
  calendarContext: {
30713
30790
  timeZone,
30714
30791
  initialToday: source.calendarWindow?.initialToday ?? getLocalScheduleDate(now, timeZone)
@@ -30794,6 +30871,7 @@ const eventListingHydrationSchema = z$1.object({
30794
30871
  eventSurface: eventSurfaceScopeSchema,
30795
30872
  filterEventPresets: z$1.string().nullable(),
30796
30873
  scheduleScope: eventScheduleScopeSchema,
30874
+ seriesIds: z$1.string().nullable().optional(),
30797
30875
  filterCategoryIds: z$1.string().nullable().optional(),
30798
30876
  filterStaffMemberId: z$1.string().nullable().optional(),
30799
30877
  filterVenueId: z$1.string().nullable().optional(),
@@ -30854,6 +30932,7 @@ const eventListingBlockRuntime = defineProgressiveBlockRuntime({
30854
30932
  eventSurface: normalizeEventSurfaceScope(source.eventSurface),
30855
30933
  filterEventPresets: normalizeEventSurfacePresetsCsv(source.filterEventPresets),
30856
30934
  scheduleScope: normalizeEventScheduleScope(source.scheduleScope),
30935
+ seriesIds: eventSeriesScopeCsv(source.seriesIds),
30857
30936
  filterCategoryIds: normalizeEventCategoryIdsCsv(source.filterCategoryIds),
30858
30937
  filterStaffMemberId: normalizeEventStaffMemberId(source.filterStaffMemberId),
30859
30938
  filterVenueId: normalizeEventVenueId(source.filterVenueId),
@@ -42715,6 +42794,26 @@ const headerRuntimeTransforms = [{
42715
42794
  run: resolveHeaderChromeRuntimeContract
42716
42795
  }];
42717
42796
  const defaultTransforms = createTransformRegistry([
42797
+ {
42798
+ id: "events.calendarSelectionParam",
42799
+ kind: "formatter",
42800
+ summary: "Resolve selected events instead of discovery filters",
42801
+ schema: z$1.object({ key: z$1.enum([
42802
+ "seriesIds",
42803
+ "eventSurface",
42804
+ "filterEventPresets",
42805
+ "scheduleScope",
42806
+ "filterCategoryIds",
42807
+ "filterStaffMemberId",
42808
+ "filterVenueId"
42809
+ ]) }),
42810
+ run(value, { key }) {
42811
+ const content = asPartialObject(value) ?? {};
42812
+ const selection = resolveEventSelection(content.eventSelection, content.selectedEventSeriesIds);
42813
+ if (selection.kind === "selected") return key === "seriesIds" ? selection.seriesIds : void 0;
42814
+ return key === "seriesIds" ? void 0 : content[key];
42815
+ }
42816
+ },
42718
42817
  {
42719
42818
  id: "events.calendarReadEnabled",
42720
42819
  kind: "formatter",
@@ -43892,17 +43991,16 @@ const ButtonNode = ({ value, children, href, variantId = "primary", size = "md",
43892
43991
  if (process.env.NODE_ENV === "development") console.warn("[ButtonNode] Missing href for link-required button");
43893
43992
  return null;
43894
43993
  }
43895
- const extraClassName = affordanceIcon ? [className, AFFORDANCE_SUPPRESS_CLASS].filter(Boolean).join(" ") : className;
43896
43994
  const resolvedVariantId = parseThemeButtonVariantId(variantId);
43897
43995
  if (variantId && !resolvedVariantId) {
43898
43996
  console.error("[ButtonNode] Invalid button variant", { variantId });
43899
43997
  return null;
43900
43998
  }
43901
- const combinedClassName = resolvedVariantId ? themeButtonClassName({
43999
+ const combinedClassName = resolvedVariantId ? (affordanceIcon ? themeButtonClassNameWithTrailingIcon : themeButtonClassName)({
43902
44000
  variant: resolvedVariantId,
43903
44001
  size,
43904
- extraClassName
43905
- }) : extraClassName;
44002
+ extraClassName: className
44003
+ }) : className;
43906
44004
  if (resolvedHref) return /* @__PURE__ */ jsxs("a", {
43907
44005
  href: resolvedHref,
43908
44006
  target,
@@ -45089,6 +45187,7 @@ const publicPricingSchema = z$1.object({
45089
45187
  });
45090
45188
  const publicAppointmentServiceSchema = z$1.object({
45091
45189
  id: z$1.string().min(1),
45190
+ slug: z$1.string().min(1).optional(),
45092
45191
  title: z$1.string(),
45093
45192
  description: z$1.string().nullable().optional(),
45094
45193
  durationMinutes: z$1.number().int().positive(),
@@ -45165,7 +45264,7 @@ function formatAmountOrFree(amount, currency) {
45165
45264
  currency
45166
45265
  }, { decimals: "auto" });
45167
45266
  }
45168
- function buildRows(services, pathname) {
45267
+ function buildRows(services, pathname, servicePathPrefix) {
45169
45268
  return services.map((service) => ({
45170
45269
  id: service.id,
45171
45270
  title: service.title,
@@ -45176,7 +45275,8 @@ function buildRows(services, pathname) {
45176
45275
  href: resolveDedicatedBookingHref(pathname, {
45177
45276
  kind: "appointment_service",
45178
45277
  serviceId: service.id
45179
- })
45278
+ }),
45279
+ detailsHref: servicePathPrefix && service.slug ? `${servicePathPrefix.replace(/\/$/, "")}/${encodeURIComponent(service.slug)}` : null
45180
45280
  }));
45181
45281
  }
45182
45282
  function buildAppointmentServicesView(input) {
@@ -45195,13 +45295,14 @@ function buildAppointmentServicesView(input) {
45195
45295
  };
45196
45296
  return {
45197
45297
  kind: "items",
45198
- rows: buildRows(parsed.services, input.pathname)
45298
+ rows: buildRows(parsed.services, input.pathname, input.servicePathPrefix ?? null)
45199
45299
  };
45200
45300
  }
45201
- function AppointmentServicesNode({ sectionHeading, services, pathname, className }) {
45301
+ function AppointmentServicesNode({ sectionHeading, services, pathname, servicePathPrefix, className }) {
45202
45302
  const view = buildAppointmentServicesView({
45203
45303
  services,
45204
- pathname: typeof pathname === "string" ? pathname : void 0
45304
+ pathname: typeof pathname === "string" ? pathname : void 0,
45305
+ servicePathPrefix: typeof servicePathPrefix === "string" ? servicePathPrefix : null
45205
45306
  });
45206
45307
  const rootClassName = `appointment-services ${className ?? ""}`.trim();
45207
45308
  const RowTitle = sectionHeading ? "h3" : "h2";
@@ -45232,7 +45333,10 @@ function AppointmentServicesNode({ sectionHeading, services, pathname, className
45232
45333
  children: [
45233
45334
  /* @__PURE__ */ jsx(RowTitle, {
45234
45335
  className: "appointment-services-row-title rb-text-lg rb-font-medium rb-leading-tight",
45235
- children: row.title
45336
+ children: row.detailsHref ? /* @__PURE__ */ jsx("a", {
45337
+ href: row.detailsHref,
45338
+ children: row.title
45339
+ }) : row.title
45236
45340
  }),
45237
45341
  row.description ? /* @__PURE__ */ jsx("p", {
45238
45342
  className: "appointment-services-row-description rb-text-sm rb-leading-6 status-muted",
@@ -46762,13 +46866,10 @@ function OfferingsPreviewContent(props) {
46762
46866
  }),
46763
46867
  groupCta ? /* @__PURE__ */ jsx("footer", {
46764
46868
  className: "offerings-preview-card-footer rb-mt-auto rb-flex",
46765
- children: /* @__PURE__ */ jsxs("a", {
46869
+ children: /* @__PURE__ */ jsx("a", {
46766
46870
  className: groupLinkClass,
46767
46871
  href: groupCta.href,
46768
- children: [/* @__PURE__ */ jsx("span", { children: groupCta.label }), /* @__PURE__ */ jsx(ArrowRightIcon, {
46769
- "aria-hidden": "true",
46770
- className: "offerings-preview-link-icon rb-h-4 rb-w-4"
46771
- })]
46872
+ children: /* @__PURE__ */ jsx("span", { children: groupCta.label })
46772
46873
  })
46773
46874
  }) : null
46774
46875
  ]
@@ -48130,22 +48231,121 @@ const formBlockDefinition = {
48130
48231
  runtime: formBlockRuntime
48131
48232
  };
48132
48233
  //#endregion
48234
+ //#region ../blocks/src/system/blocks/events/eventSelectionFields.ts
48235
+ const eventSelectionFields = [{
48236
+ id: "eventSelection",
48237
+ type: "select",
48238
+ label: "Events to show",
48239
+ required: false,
48240
+ multiple: false,
48241
+ defaultValue: "matching",
48242
+ options: [{
48243
+ value: "matching",
48244
+ label: "All matching events"
48245
+ }, {
48246
+ value: "selected",
48247
+ label: "Selected events"
48248
+ }],
48249
+ ui: { intent: "behavior" }
48250
+ }, createSiteOptionSelectField({
48251
+ id: "selectedEventSeriesIds",
48252
+ label: "Selected events",
48253
+ description: "Show upcoming dates for these events. Other event filters do not apply.",
48254
+ required: false,
48255
+ multiple: true,
48256
+ defaultValue: [],
48257
+ optionSource: "eventSeries",
48258
+ ui: {
48259
+ intent: "behavior",
48260
+ searchThreshold: 1,
48261
+ visibleWhen: {
48262
+ field: "eventSelection",
48263
+ equals: "selected"
48264
+ }
48265
+ }
48266
+ })];
48267
+ function withEventSelectionVisibility(field) {
48268
+ if (![
48269
+ "eventSurface",
48270
+ "filterEventPresets",
48271
+ "scheduleScope",
48272
+ "filterCategoryIds",
48273
+ "filterStaffMemberId",
48274
+ "filterVenueId",
48275
+ "showFilters",
48276
+ "showCategoryFilter",
48277
+ "showVenueFilter",
48278
+ "showStaffFilter"
48279
+ ].includes(field.id)) return field;
48280
+ const visibleWhen = field.ui?.visibleWhen;
48281
+ return {
48282
+ ...field,
48283
+ ui: {
48284
+ ...field.ui,
48285
+ visibleWhen: { allOf: [{
48286
+ field: "eventSelection",
48287
+ notEquals: "selected"
48288
+ }, ...visibleWhen ? [visibleWhen] : []] }
48289
+ }
48290
+ };
48291
+ }
48292
+ //#endregion
48133
48293
  //#region ../blocks/src/system/blocks/events/eventCalendarDataLoaders.ts
48134
48294
  const scopeParams = {
48135
48295
  siteId: { $bind: { from: "$root.siteId" } },
48296
+ seriesIds: { $bind: {
48297
+ from: "content",
48298
+ transforms: [{
48299
+ id: "events.calendarSelectionParam",
48300
+ options: { key: "seriesIds" }
48301
+ }]
48302
+ } },
48136
48303
  stage: { $bind: {
48137
48304
  from: "$root.previewStage",
48138
48305
  fallback: "published"
48139
48306
  } },
48140
- eventSurface: { $bind: { from: "content.eventSurface" } },
48307
+ eventSurface: { $bind: {
48308
+ from: "content",
48309
+ transforms: [{
48310
+ id: "events.calendarSelectionParam",
48311
+ options: { key: "eventSurface" }
48312
+ }, { id: "value.csv" }]
48313
+ } },
48141
48314
  eventPresets: { $bind: {
48142
- from: "content.filterEventPresets",
48143
- transforms: [{ id: "value.csv" }]
48315
+ from: "content",
48316
+ transforms: [{
48317
+ id: "events.calendarSelectionParam",
48318
+ options: { key: "filterEventPresets" }
48319
+ }, { id: "value.csv" }]
48320
+ } },
48321
+ scheduleScope: { $bind: {
48322
+ from: "content",
48323
+ transforms: [{
48324
+ id: "events.calendarSelectionParam",
48325
+ options: { key: "scheduleScope" }
48326
+ }, { id: "value.csv" }]
48144
48327
  } },
48145
- scheduleScope: { $bind: { from: "content.scheduleScope" } },
48146
- categoryIds: { $bind: { from: "content.filterCategoryIds" } },
48147
- staffMemberId: { $bind: { from: "content.filterStaffMemberId" } },
48148
- venueId: { $bind: { from: "content.filterVenueId" } }
48328
+ categoryIds: { $bind: {
48329
+ from: "content",
48330
+ transforms: [{
48331
+ id: "events.calendarSelectionParam",
48332
+ options: { key: "filterCategoryIds" }
48333
+ }, { id: "value.csv" }]
48334
+ } },
48335
+ staffMemberId: { $bind: {
48336
+ from: "content",
48337
+ transforms: [{
48338
+ id: "events.calendarSelectionParam",
48339
+ options: { key: "filterStaffMemberId" }
48340
+ }, { id: "value.csv" }]
48341
+ } },
48342
+ venueId: { $bind: {
48343
+ from: "content",
48344
+ transforms: [{
48345
+ id: "events.calendarSelectionParam",
48346
+ options: { key: "filterVenueId" }
48347
+ }, { id: "value.csv" }]
48348
+ } }
48149
48349
  };
48150
48350
  /** Combined renders two jobs; calendar-only variants never pay for the list seed. */
48151
48351
  const eventCalendarDataLoaders = {
@@ -48275,6 +48475,13 @@ const eventCalendarLayout = [styledSection({
48275
48475
  from: "content.defaultCalendarView",
48276
48476
  fallback: "month"
48277
48477
  } },
48478
+ seriesIds: { $bind: {
48479
+ from: "content",
48480
+ transforms: [{
48481
+ id: "events.calendarSelectionParam",
48482
+ options: { key: "seriesIds" }
48483
+ }]
48484
+ } },
48278
48485
  showFilters: { $bind: {
48279
48486
  from: "content.showFilters",
48280
48487
  fallback: true
@@ -48296,17 +48503,47 @@ const eventCalendarLayout = [styledSection({
48296
48503
  fallback: true
48297
48504
  } },
48298
48505
  eventSurface: { $bind: {
48299
- from: "content.eventSurface",
48300
- fallback: "all"
48506
+ from: "content",
48507
+ transforms: [{
48508
+ id: "events.calendarSelectionParam",
48509
+ options: { key: "eventSurface" }
48510
+ }]
48511
+ } },
48512
+ filterEventPresets: { $bind: {
48513
+ from: "content",
48514
+ transforms: [{
48515
+ id: "events.calendarSelectionParam",
48516
+ options: { key: "filterEventPresets" }
48517
+ }]
48301
48518
  } },
48302
- filterEventPresets: { $bind: { from: "content.filterEventPresets" } },
48303
48519
  scheduleScope: { $bind: {
48304
- from: "content.scheduleScope",
48305
- fallback: "any"
48520
+ from: "content",
48521
+ transforms: [{
48522
+ id: "events.calendarSelectionParam",
48523
+ options: { key: "scheduleScope" }
48524
+ }]
48525
+ } },
48526
+ filterCategoryIds: { $bind: {
48527
+ from: "content",
48528
+ transforms: [{
48529
+ id: "events.calendarSelectionParam",
48530
+ options: { key: "filterCategoryIds" }
48531
+ }]
48532
+ } },
48533
+ filterStaffMemberId: { $bind: {
48534
+ from: "content",
48535
+ transforms: [{
48536
+ id: "events.calendarSelectionParam",
48537
+ options: { key: "filterStaffMemberId" }
48538
+ }]
48539
+ } },
48540
+ filterVenueId: { $bind: {
48541
+ from: "content",
48542
+ transforms: [{
48543
+ id: "events.calendarSelectionParam",
48544
+ options: { key: "filterVenueId" }
48545
+ }]
48306
48546
  } },
48307
- filterCategoryIds: { $bind: { from: "content.filterCategoryIds" } },
48308
- filterStaffMemberId: { $bind: { from: "content.filterStaffMemberId" } },
48309
- filterVenueId: { $bind: { from: "content.filterVenueId" } },
48310
48547
  cardRole: { $bind: {
48311
48548
  from: "content._cardStyles.role",
48312
48549
  fallback: "default"
@@ -48810,6 +49047,7 @@ const eventCalendarAdditionalFields = [
48810
49047
  }
48811
49048
  }
48812
49049
  },
49050
+ ...eventSelectionFields,
48813
49051
  {
48814
49052
  id: "eventSurface",
48815
49053
  type: "select",
@@ -49019,7 +49257,7 @@ const eventCalendarBlockDefinition = {
49019
49257
  titleSource: "heading",
49020
49258
  description: "Display events with calendar, list, or combined views with filtering",
49021
49259
  skipSectionStyles: true,
49022
- additionalFields: eventCalendarAdditionalFields,
49260
+ additionalFields: eventCalendarAdditionalFields.map(withEventSelectionVisibility),
49023
49261
  styleTokens: {
49024
49262
  background: "surface",
49025
49263
  typography: "body",
@@ -54051,9 +54289,56 @@ function generateNavLinkCSS(options) {
54051
54289
  if (baseRules.length > 0) cssChunks.unshift(`\n${selector} {\n ${baseRules.join("\n ")}\n}\n`);
54052
54290
  if (hoverRules.length > 0) cssChunks.push(`\n${hoverSelector} {\n ${hoverRules.join("\n ")}\n}\n`);
54053
54291
  if (activeRules.length > 0) cssChunks.push(`\n${activeSelector} {\n ${activeRules.join("\n ")}\n}\n`);
54292
+ cssChunks.push(navLinkFocusVisibleCss(selector, style, theme, tokens));
54054
54293
  cssChunks.push(generateInteractiveChildInheritanceCSS(selector));
54055
54294
  return cssChunks.join("");
54056
54295
  }
54296
+ /**
54297
+ * Keyboard focus indicator for nav links, in the header, the footer and header
54298
+ * dropdown menus — the three surfaces `generateNavLinkCSS` serves.
54299
+ *
54300
+ * Emitted unconditionally rather than as an effect, because focus visibility is
54301
+ * a floor rather than a style choice. Only the interaction-palette pill ever
54302
+ * wrote an `effects.focus` group, so every other nav — every `quiet` palette,
54303
+ * every footer, every dropdown — previously fell back to whatever outline the
54304
+ * browser drew.
54305
+ *
54306
+ * The outline takes the link's own resolved colour, so on a header that adapts
54307
+ * to the section it floats over it moves with the adaptation instead of
54308
+ * asserting a brand colour against an unknown backdrop.
54309
+ *
54310
+ * Where the style asks for `soft-glow`, the same halo goes on the outline. That
54311
+ * treatment exists because the theme has already conceded the resolved colour
54312
+ * alone is not reliable over an unpredictable backdrop — a hero photograph with
54313
+ * mixed luminance. Without it the text would stay legible by its halo while the
54314
+ * focus ring, which is the part with a contrast requirement of its own, would
54315
+ * not.
54316
+ *
54317
+ * A style that also paints a focus pill keeps it: this adds an outline around
54318
+ * that pill rather than replacing it.
54319
+ */
54320
+ function navLinkFocusVisibleCss(selector, style, theme, tokens) {
54321
+ const color = tokens.getColor(style.colorToken);
54322
+ const halo = buildTextContrastShadow({
54323
+ theme,
54324
+ colorToken: style.colorToken,
54325
+ treatment: style.contrastTreatment
54326
+ });
54327
+ return `
54328
+ ${selector}:focus-visible {
54329
+ outline: 2px solid ${color};
54330
+ outline-offset: ${focusOutlineOffset(selector)};${halo ? `\n box-shadow: ${halo};` : ""}
54331
+ }
54332
+ `;
54333
+ }
54334
+ /**
54335
+ * Dropdown items are full-width inside a panel with no horizontal padding, so
54336
+ * an outset outline would paint over and past the panel's own border. Keeping
54337
+ * it flush is the only way it reads as belonging to the item.
54338
+ */
54339
+ function focusOutlineOffset(selector) {
54340
+ return selector.includes("nav-dropdown-link") ? "-2px" : "3px";
54341
+ }
54057
54342
  function buildTextContrastShadow(input) {
54058
54343
  if (input.treatment !== "soft-glow") return null;
54059
54344
  return isLikelyLightColorToken(input.theme, input.colorToken) ? "0 1px 3px rgb(0 0 0 / 0.55), 0 0 18px rgb(0 0 0 / 0.38)" : "0 1px 3px rgb(255 255 255 / 0.72), 0 0 18px rgb(255 255 255 / 0.5)";
@@ -57186,7 +57471,7 @@ function pageBlockPosition(index, blockCount) {
57186
57471
  //#endregion
57187
57472
  //#region ../blocks/src/pageRendererContracts.ts
57188
57473
  function buildPageRendererRootRuntime(dataContext) {
57189
- const { siteId = null, pageId = null, pathname = null, bookingTimeZone, previewStage = "published", apiBaseUrl = null, portalToken = null, bookingOfferingPresets = [], mailingList = { tag: "not_configured" }, eventRegistrationOverlayEnabled = false, loaderFailures = {} } = dataContext ?? {};
57474
+ const { siteId = null, pageId = null, pathname = null, bookingTimeZone, previewStage = "published", apiBaseUrl = null, portalToken = null, bookingOfferingPresets = [], appointmentServicePathPrefix = null, mailingList = { tag: "not_configured" }, eventRegistrationOverlayEnabled = false, loaderFailures = {} } = dataContext ?? {};
57190
57475
  return {
57191
57476
  siteId,
57192
57477
  pageId,
@@ -57196,6 +57481,7 @@ function buildPageRendererRootRuntime(dataContext) {
57196
57481
  apiBaseUrl,
57197
57482
  portalToken,
57198
57483
  bookingOfferingPresets,
57484
+ appointmentServicePathPrefix,
57199
57485
  mailingList,
57200
57486
  eventRegistrationOverlayEnabled,
57201
57487
  loaderFailures
@@ -61874,7 +62160,8 @@ const appointmentServicesBlockDefinition = {
61874
62160
  el("appointment-services", {
61875
62161
  sectionHeading: { $bind: { from: "content.heading" } },
61876
62162
  services: { $bind: { from: "data.services" } },
61877
- pathname: { $bind: { from: "$root.pathname" } }
62163
+ pathname: { $bind: { from: "$root.pathname" } },
62164
+ servicePathPrefix: { $bind: { from: "$root.appointmentServicePathPrefix" } }
61878
62165
  })
61879
62166
  ], { gap: "lg" })
61880
62167
  })]
@@ -69312,10 +69599,19 @@ const containerResponsiveThemeCss = `/*
69312
69599
  padding-top: 2.5rem;
69313
69600
  padding-bottom: 2.5rem;
69314
69601
  }
69602
+ /* Clearance for a surface that is not an authored block page.
69603
+ An authored page gets this through its opening block's container (see the
69604
+ overlay-clearance rule in styles.css). A reserved surface or a system
69605
+ destination page has no such block, so it consumes the same variable here.
69606
+ Marked with one class rather than per-surface selectors, because the last
69607
+ two additions to this family were both missed and shipped overlapping. */
69315
69608
  :where(.theme-scope)
69316
69609
  [data-site-document-layout-mode="header-overlay"]
69317
- [data-rb-reserved-surface].rb-reserved-surface-main {
69318
- padding-top: calc(var(--rb-reserved-surface-header-offset, 5.5rem) + 2.5rem);
69610
+ .rb-overlay-clearance-surface {
69611
+ padding-top: calc(
69612
+ var(--site-overlay-header-clearance, 5.5rem) +
69613
+ var(--site-overlay-opening-content-extra-pad, clamp(1rem, 2vw, 1.75rem))
69614
+ );
69319
69615
  }
69320
69616
  .rb-preview-editor-offset {
69321
69617
  padding-bottom: calc(
@@ -79672,6 +79968,23 @@ const containerResponsiveThemeCss = `/*
79672
79968
  gap: 0.5rem;
79673
79969
  }
79674
79970
 
79971
+ /* Error panel and field notes. The form block scopes these to its own
79972
+ data-block, so the newsletter form (which also renders in the footer)
79973
+ needs its own copy of the treatment. */
79974
+ :where(.theme-scope) .newsletter-form .fb-error:not([data-field-validation-message]) {
79975
+ background-color: var(--fb-error-bg);
79976
+ color: var(--fb-error-text);
79977
+ border: 1px solid var(--fb-error-border);
79978
+ border-radius: var(--rb-block-radius);
79979
+ padding: 1rem;
79980
+ font-size: 0.875rem;
79981
+ }
79982
+
79983
+ :where(.theme-scope) .newsletter-form [data-field-validation-message] {
79984
+ font-size: 0.875rem;
79985
+ color: var(--fb-error-text);
79986
+ }
79987
+
79675
79988
  /* Required indicator */
79676
79989
  :where(.theme-scope) .newsletter-required {
79677
79990
  color: rgb(var(--tb-primary));
@@ -82143,12 +82456,12 @@ function normalizeContent(block) {
82143
82456
  }
82144
82457
  /**
82145
82458
  * Normalize params for API calls.
82146
- * Converts all values to strings.
82459
+ * Converts supplied values to strings, preserving absent versus explicitly empty params.
82147
82460
  */
82148
82461
  function normalizeParams(input) {
82149
82462
  if (!input || typeof input !== "object") return {};
82150
82463
  const output = {};
82151
- for (const [key, value] of Object.entries(input)) output[key] = coerceToString(value);
82464
+ for (const [key, value] of Object.entries(input)) if (value !== void 0 && value !== null) output[key] = coerceToString(value);
82152
82465
  return output;
82153
82466
  }
82154
82467
  function isNonArrayObject(value) {
@@ -82212,6 +82525,14 @@ function coercePayload(payload) {
82212
82525
  * - Frontend: provide internal API client
82213
82526
  * - SDK: provide SDK client with endpoint mapping
82214
82527
  */
82528
+ function projectDataLoaders(loaders, shouldLoad, blockId, blockKind) {
82529
+ if (!shouldLoad) return [...loaders];
82530
+ return loaders.filter(({ key }) => shouldLoad({
82531
+ blockId,
82532
+ blockKind,
82533
+ loaderKey: key
82534
+ }));
82535
+ }
82215
82536
  function shouldSkipResolvedLoader(input) {
82216
82537
  if (input.loader.requiredParams?.some((param) => !input.params[param]?.trim())) return true;
82217
82538
  return Boolean(input.isValidEndpoint && !input.isValidEndpoint(input.endpoint));
@@ -82240,7 +82561,7 @@ async function prefetchBlockData$1(page, context, options) {
82240
82561
  return (await prefetchBlockDataWithFailures(page, context, options)).resolvedData;
82241
82562
  }
82242
82563
  async function prefetchBlockDataWithFailures(page, context, options) {
82243
- const { apiClient, isValidEndpoint, onError, getCustomBlockLoaders, getBlockDefinition: getBlockDefinition$1 = getBlockDefinition, resolveParamsBindings: resolveParamsBindings$1 = resolveParamsBindings } = options;
82564
+ const { apiClient, isValidEndpoint, onError, getCustomBlockLoaders, getBlockDefinition: getBlockDefinition$1 = getBlockDefinition, resolveParamsBindings: resolveParamsBindings$1 = resolveParamsBindings, shouldLoad } = options;
82244
82565
  const results = {};
82245
82566
  const loaderFailures = {};
82246
82567
  const tasks = [];
@@ -82257,6 +82578,7 @@ async function prefetchBlockDataWithFailures(page, context, options) {
82257
82578
  loader
82258
82579
  })) : [];
82259
82580
  } else loaders = [];
82581
+ loaders = projectDataLoaders(loaders, shouldLoad, blockId, block.kind);
82260
82582
  if (loaders.length === 0) continue;
82261
82583
  const root = {
82262
82584
  ...context.root ?? {},
@@ -82357,8 +82679,8 @@ function toStringParams(value) {
82357
82679
  for (const [k, v] of Object.entries(value)) if (typeof v === "string") out[k] = v;
82358
82680
  return out;
82359
82681
  }
82360
- function stripEmptyStringValues(params) {
82361
- for (const [key, value] of Object.entries(params)) if (value === "") delete params[key];
82682
+ function stripEmptyStringValues(params, endpoint) {
82683
+ for (const [key, value] of Object.entries(params)) if (value === "" && !(key === "seriesIds" && (endpoint === "listPublicEvents" || endpoint === "listPublicEventCalendarWindow"))) delete params[key];
82362
82684
  }
82363
82685
  function ensureSiteId(params, context) {
82364
82686
  if (!params.siteId && typeof context.siteId === "string" && context.siteId) params.siteId = context.siteId;
@@ -82371,7 +82693,7 @@ function ensureSiteId(params, context) {
82371
82693
  */
82372
82694
  function normalizeLoaderParams(endpoint, params, context) {
82373
82695
  const out = toStringParams(params);
82374
- stripEmptyStringValues(out);
82696
+ stripEmptyStringValues(out, endpoint);
82375
82697
  if (endpoint === "getPublicFormById") {
82376
82698
  ensureSiteId(out, context);
82377
82699
  if (!out.formId && out.formSlug) {
@@ -87533,6 +87855,15 @@ function isEntryResponse(response) {
87533
87855
  function isPageSurfaceResponse(response) {
87534
87856
  return response.type === "pageSurface";
87535
87857
  }
87858
+ z$1.object({
87859
+ palette: paletteColorsSchema,
87860
+ paletteMode: paletteModeSchema,
87861
+ typography: z$1.object({
87862
+ headingFamily: z$1.string().trim().min(1),
87863
+ bodyFamily: z$1.string().trim().min(1)
87864
+ }).strict(),
87865
+ corners
87866
+ }).strict();
87536
87867
  //#endregion
87537
87868
  //#region src/rendering/blocks-theme-runtime.ts
87538
87869
  function parseBlocksTheme(theme) {
@@ -88909,7 +89240,7 @@ var CircuitOpenError = class extends Error {
88909
89240
  * 1. This constant
88910
89241
  * 2. The "version" field in package.json
88911
89242
  */
88912
- const SDK_VERSION = "0.140.0";
89243
+ const SDK_VERSION = "0.141.0";
88913
89244
  //#endregion
88914
89245
  //#region src/next/content-load-failure.ts
88915
89246
  const SdkContentLoadError = RiverbankContentLoadError;