@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
@@ -2461,6 +2461,7 @@ function isDisplayMediaKind$2(kind) {
2461
2461
  }
2462
2462
  const siteOptionSources = [
2463
2463
  "eventCategories",
2464
+ "eventSeries",
2464
2465
  "venues",
2465
2466
  "staffMembers"
2466
2467
  ];
@@ -7186,14 +7187,12 @@ function generateVariantCSS(variant, themeId, cardClasses, tokens, theme) {
7186
7187
  const shadowValue = generateShadowValue$1(shadow);
7187
7188
  rules.push(`box-shadow: ${shadowValue}`);
7188
7189
  }
7189
- rules.push(`display: flex`);
7190
- rules.push(`flex-direction: column`);
7191
- rules.push(`position: relative`);
7192
- rules.push(`overflow: visible`);
7190
+ const structureSelector = cardClasses.map((cardClass) => `:where([data-theme-scope="${themeId}"]) :where(.${cardClass})`).join(",\n");
7193
7191
  const mediaRadius = MEDIA_CORNER_MAP[corners];
7194
7192
  const mediaRules = [`border-top-left-radius: ${mediaRadius}`, `border-top-right-radius: ${mediaRadius}`];
7195
7193
  const contentRules = [`padding: ${resolveContentPadding(variant)}`];
7196
7194
  return [
7195
+ `${structureSelector} {\n display: flex;\n flex-direction: column;\n position: relative;\n overflow: visible;\n}`,
7197
7196
  `${containerSelector} {\n ${rules.join(";\n ")};\n}`,
7198
7197
  ...cardDecorationPseudoRules(containerSelectors, variant.decorations, resolveColor),
7199
7198
  `${fallbackBackgroundSelector} {\n background: transparent;\n}`,
@@ -13224,7 +13223,7 @@ const BUTTON_CONTRAST_POLICY = {
13224
13223
  nonTextMinimumRatio: 3,
13225
13224
  gradientSamplesPerSegment: 20,
13226
13225
  alphaBackgrounds: "reject-without-known-surface",
13227
- disabled: "retain-full-colour-contract"
13226
+ disabled: "validated-colour-pair-with-muted-control-opacity"
13228
13227
  };
13229
13228
  function formatButtonColourContractError(error) {
13230
13229
  switch (error.tag) {
@@ -13812,6 +13811,25 @@ function parseThemeForPersistence(value) {
13812
13811
  };
13813
13812
  }
13814
13813
  //#endregion
13814
+ //#region ../theme-core/src/buttons/affordanceSuppression.ts
13815
+ /**
13816
+ * Internal: the opt-out the generated affordance rule is written against.
13817
+ *
13818
+ * A button style may declare a trailing `affordance`, which the theme renders as
13819
+ * a CSS `::after` on every button of that variant. An authored button that
13820
+ * renders its own trailing icon must not also receive the theme's, or it shows
13821
+ * two.
13822
+ *
13823
+ * Deliberately not exported from `./index`. This used to be public, and two
13824
+ * block components reached past the theme to draw arrows of their own — one of
13825
+ * them doubling up on the styles that declare an affordance, both of them
13826
+ * overriding the twelve styles that deliberately declare none. Whether a button
13827
+ * carries a trailing affordance is the style's decision; the only caller that
13828
+ * legitimately opts out is the authored-button renderer, which reaches it
13829
+ * through `themeButtonClassNameWithTrailingIcon`.
13830
+ */
13831
+ const AFFORDANCE_SUPPRESS_CLASS = "rb-affordance-off";
13832
+ //#endregion
13815
13833
  //#region ../theme-core/src/buttons/classNames.ts
13816
13834
  /**
13817
13835
  * Parse content/runtime variant identifiers into the closed theme-button class
@@ -13844,6 +13862,27 @@ function themeButtonClassName(spec) {
13844
13862
  spec.extraClassName
13845
13863
  ].filter(Boolean).join(" ");
13846
13864
  }
13865
+ /**
13866
+ * Button classes for an authored button that renders its own trailing icon.
13867
+ *
13868
+ * A separate function rather than a flag on `themeButtonClassName`, because
13869
+ * there is exactly one caller and it should stay visible in a diff. The name
13870
+ * states what the caller knows to be true of its own markup — that it renders a
13871
+ * trailing icon — rather than what the theme does about it. The consequence is
13872
+ * the theme's to decide and to change; a caller naming the consequence would be
13873
+ * asserting a policy it does not own, and would quietly become a lie the moment
13874
+ * that policy moved.
13875
+ *
13876
+ * Do not reach for this to remove an arrow you simply do not want. A trailing
13877
+ * affordance is declared by the button style, and a block overriding that is the
13878
+ * defect this replaced.
13879
+ */
13880
+ function themeButtonClassNameWithTrailingIcon(spec) {
13881
+ return themeButtonClassName({
13882
+ ...spec,
13883
+ extraClassName: [spec.extraClassName, AFFORDANCE_SUPPRESS_CLASS].filter(Boolean).join(" ")
13884
+ });
13885
+ }
13847
13886
  //#endregion
13848
13887
  //#region ../theme-core/src/interactive/generateBaseCSS.ts
13849
13888
  /**
@@ -15756,26 +15795,19 @@ function resolvedButtonFocusDeclarations(indicator, role) {
15756
15795
  ] : [["outline", value("outline", `3px solid ${indicator.colorCss}`)], ["outline-offset", value("outline-offset", "3px")]];
15757
15796
  }
15758
15797
  /**
15759
- * Disabled buttons retain their validated colour pair and add a non-layout
15760
- * visual affordance. `currentColor` keeps the cue inside the same contrast
15761
- * relationship, while retaining pointer events lets the not-allowed cursor
15762
- * remain observable.
15798
+ * Disabled buttons are deliberately muted as unavailable controls. Native
15799
+ * disabled controls are exempt from active-control contrast requirements;
15800
+ * opacity distinguishes the state without introducing a focus-like outline.
15801
+ * Retaining pointer events lets the not-allowed cursor remain observable.
15763
15802
  */
15764
15803
  const RESOLVED_BUTTON_DISABLED_DECLARATIONS = [
15765
15804
  ["cursor", "not-allowed"],
15766
15805
  ["transform", "none"],
15767
15806
  ["box-shadow", "none"],
15768
- ["outline", "2px dashed currentColor"],
15769
- ["outline-offset", "-4px"]
15807
+ ["opacity", "0.55"]
15770
15808
  ];
15771
15809
  //#endregion
15772
15810
  //#region ../theme-core/src/buttons/generateButtonCss.ts
15773
- /**
15774
- * Class the `button` runtime node adds when it renders its own trailing icon,
15775
- * so a node-level icon suppresses the theme's CSS `::after` affordance.
15776
- * Shared so generator and renderer can't drift.
15777
- */
15778
- const AFFORDANCE_SUPPRESS_CLASS = "rb-affordance-off";
15779
15811
  const BUTTON_SIZE_NAMES = buttonSizeNameSchema.options;
15780
15812
  /**
15781
15813
  * Letter spacing token → CSS value.
@@ -28071,6 +28103,7 @@ z$1.object({
28071
28103
  eventSurface: z$1.enum(eventSurfaceScopeValues).optional(),
28072
28104
  eventPresets: z$1.string().optional(),
28073
28105
  scheduleScope: z$1.enum(eventScheduleScopeValues).optional(),
28106
+ seriesIds: z$1.string().optional(),
28074
28107
  categoryIds: z$1.string().optional(),
28075
28108
  venueId: z$1.string().transform(normalizeCalendarFilterId).optional(),
28076
28109
  staffMemberId: z$1.string().transform(normalizeCalendarFilterId).optional()
@@ -28121,7 +28154,56 @@ const calendarWindowPageSchema = z$1.discriminatedUnion("kind", [z$1.object({
28121
28154
  kind: z$1.literal("partial"),
28122
28155
  nextCursor: calendarSourceCursorSchema
28123
28156
  })]);
28157
+ //#endregion
28158
+ //#region ../blocks/src/system/blocks/events/shared/eventSelection.ts
28159
+ /** Invalid saved selections fail closed rather than widening discovery. */
28160
+ function resolveEventSelection(mode, value) {
28161
+ if (mode !== "selected") return { kind: "matching" };
28162
+ const candidates = Array.isArray(value) ? value : typeof value === "string" ? value.split(",").filter(Boolean) : [];
28163
+ const ids = [];
28164
+ for (const candidate of candidates) {
28165
+ if (typeof candidate !== "string") return {
28166
+ kind: "selected",
28167
+ seriesIds: []
28168
+ };
28169
+ const parsed = parseEventSeriesId(candidate.trim());
28170
+ if (!parsed.ok) return {
28171
+ kind: "selected",
28172
+ seriesIds: []
28173
+ };
28174
+ ids.push(parsed.value);
28175
+ }
28176
+ return {
28177
+ kind: "selected",
28178
+ seriesIds: [...new Set(ids)].sort()
28179
+ };
28180
+ }
28181
+ /** Undefined means discovery; an empty string is an explicitly empty selection. */
28182
+ function eventSeriesScopeCsv(value) {
28183
+ if (value == null) return void 0;
28184
+ return typeof value === "string" ? value : value.join(",");
28185
+ }
28124
28186
  const defaultTransforms = createTransformRegistry([
28187
+ {
28188
+ id: "events.calendarSelectionParam",
28189
+ kind: "formatter",
28190
+ summary: "Resolve selected events instead of discovery filters",
28191
+ schema: z$1.object({ key: z$1.enum([
28192
+ "seriesIds",
28193
+ "eventSurface",
28194
+ "filterEventPresets",
28195
+ "scheduleScope",
28196
+ "filterCategoryIds",
28197
+ "filterStaffMemberId",
28198
+ "filterVenueId"
28199
+ ]) }),
28200
+ run(value, { key }) {
28201
+ const content = asPartialObject(value) ?? {};
28202
+ const selection = resolveEventSelection(content.eventSelection, content.selectedEventSeriesIds);
28203
+ if (selection.kind === "selected") return key === "seriesIds" ? selection.seriesIds : void 0;
28204
+ return key === "seriesIds" ? void 0 : content[key];
28205
+ }
28206
+ },
28125
28207
  {
28126
28208
  id: "events.calendarReadEnabled",
28127
28209
  kind: "formatter",
@@ -29875,17 +29957,16 @@ const ButtonNode = ({ value, children, href, variantId = "primary", size = "md",
29875
29957
  if (process.env.NODE_ENV === "development") console.warn("[ButtonNode] Missing href for link-required button");
29876
29958
  return null;
29877
29959
  }
29878
- const extraClassName = affordanceIcon ? [className, AFFORDANCE_SUPPRESS_CLASS].filter(Boolean).join(" ") : className;
29879
29960
  const resolvedVariantId = parseThemeButtonVariantId(variantId);
29880
29961
  if (variantId && !resolvedVariantId) {
29881
29962
  console.error("[ButtonNode] Invalid button variant", { variantId });
29882
29963
  return null;
29883
29964
  }
29884
- const combinedClassName = resolvedVariantId ? themeButtonClassName({
29965
+ const combinedClassName = resolvedVariantId ? (affordanceIcon ? themeButtonClassNameWithTrailingIcon : themeButtonClassName)({
29885
29966
  variant: resolvedVariantId,
29886
29967
  size,
29887
- extraClassName
29888
- }) : extraClassName;
29968
+ extraClassName: className
29969
+ }) : className;
29889
29970
  if (resolvedHref) return /* @__PURE__ */ jsxs("a", {
29890
29971
  href: resolvedHref,
29891
29972
  target,
@@ -31157,6 +31238,7 @@ const publicPricingSchema = z$1.object({
31157
31238
  });
31158
31239
  const publicAppointmentServiceSchema = z$1.object({
31159
31240
  id: z$1.string().min(1),
31241
+ slug: z$1.string().min(1).optional(),
31160
31242
  title: z$1.string(),
31161
31243
  description: z$1.string().nullable().optional(),
31162
31244
  durationMinutes: z$1.number().int().positive(),
@@ -31233,7 +31315,7 @@ function formatAmountOrFree(amount, currency) {
31233
31315
  currency
31234
31316
  }, { decimals: "auto" });
31235
31317
  }
31236
- function buildRows(services, pathname) {
31318
+ function buildRows(services, pathname, servicePathPrefix) {
31237
31319
  return services.map((service) => ({
31238
31320
  id: service.id,
31239
31321
  title: service.title,
@@ -31244,7 +31326,8 @@ function buildRows(services, pathname) {
31244
31326
  href: resolveDedicatedBookingHref(pathname, {
31245
31327
  kind: "appointment_service",
31246
31328
  serviceId: service.id
31247
- })
31329
+ }),
31330
+ detailsHref: servicePathPrefix && service.slug ? `${servicePathPrefix.replace(/\/$/, "")}/${encodeURIComponent(service.slug)}` : null
31248
31331
  }));
31249
31332
  }
31250
31333
  function buildAppointmentServicesView(input) {
@@ -31263,13 +31346,14 @@ function buildAppointmentServicesView(input) {
31263
31346
  };
31264
31347
  return {
31265
31348
  kind: "items",
31266
- rows: buildRows(parsed.services, input.pathname)
31349
+ rows: buildRows(parsed.services, input.pathname, input.servicePathPrefix ?? null)
31267
31350
  };
31268
31351
  }
31269
- function AppointmentServicesNode({ sectionHeading, services, pathname, className }) {
31352
+ function AppointmentServicesNode({ sectionHeading, services, pathname, servicePathPrefix, className }) {
31270
31353
  const view = buildAppointmentServicesView({
31271
31354
  services,
31272
- pathname: typeof pathname === "string" ? pathname : void 0
31355
+ pathname: typeof pathname === "string" ? pathname : void 0,
31356
+ servicePathPrefix: typeof servicePathPrefix === "string" ? servicePathPrefix : null
31273
31357
  });
31274
31358
  const rootClassName = `appointment-services ${className ?? ""}`.trim();
31275
31359
  const RowTitle = sectionHeading ? "h3" : "h2";
@@ -31300,7 +31384,10 @@ function AppointmentServicesNode({ sectionHeading, services, pathname, className
31300
31384
  children: [
31301
31385
  /* @__PURE__ */ jsx(RowTitle, {
31302
31386
  className: "appointment-services-row-title rb-text-lg rb-font-medium rb-leading-tight",
31303
- children: row.title
31387
+ children: row.detailsHref ? /* @__PURE__ */ jsx("a", {
31388
+ href: row.detailsHref,
31389
+ children: row.title
31390
+ }) : row.title
31304
31391
  }),
31305
31392
  row.description ? /* @__PURE__ */ jsx("p", {
31306
31393
  className: "appointment-services-row-description rb-text-sm rb-leading-6 status-muted",
@@ -33807,12 +33894,12 @@ const EventCompactRow = ({ event, buttonVariant = "primary", buttonText }) => {
33807
33894
  }), cta.hidden ? /* @__PURE__ */ jsx("span", {
33808
33895
  className: "event-compact-row-status",
33809
33896
  children: cta.label
33810
- }) : /* @__PURE__ */ jsxs("a", {
33897
+ }) : /* @__PURE__ */ jsx("a", {
33811
33898
  href: cta.href,
33812
33899
  target: cta.external ? "_blank" : void 0,
33813
33900
  rel: cta.external ? "noopener noreferrer" : void 0,
33814
33901
  className: `${buttonClass} event-compact-row-cta`,
33815
- children: [/* @__PURE__ */ jsx("span", { children: cta.label }), /* @__PURE__ */ jsx(ArrowRightIcon, { "aria-hidden": "true" })]
33902
+ children: /* @__PURE__ */ jsx("span", { children: cta.label })
33816
33903
  })]
33817
33904
  })]
33818
33905
  })]
@@ -34905,6 +34992,7 @@ const eventCollectionFilterSourceSchemaShape = {
34905
34992
  eventSurface: eventSurfaceScopeSchema$1.nullable().optional(),
34906
34993
  filterEventPresets: z$1.union([z$1.string(), z$1.array(z$1.string())]).nullable().optional(),
34907
34994
  scheduleScope: eventScheduleScopeSchema$1.nullable().optional(),
34995
+ seriesIds: z$1.union([z$1.string(), z$1.array(z$1.string())]).nullable().optional(),
34908
34996
  filterCategoryIds: z$1.union([z$1.string(), z$1.array(z$1.string())]).nullable().optional(),
34909
34997
  filterStaffMemberId: z$1.string().nullable().optional(),
34910
34998
  filterVenueId: z$1.string().nullable().optional()
@@ -34951,6 +35039,7 @@ const eventCollectionDisplaySchemaShape = {
34951
35039
  eventSurface: eventSurfaceScopeSchema$1,
34952
35040
  filterEventPresets: z$1.string().nullable(),
34953
35041
  scheduleScope: eventScheduleScopeSchema$1,
35042
+ seriesIds: z$1.string().nullable().optional(),
34954
35043
  filterCategoryIds: z$1.string().nullable(),
34955
35044
  filterStaffMemberId: z$1.string().nullable(),
34956
35045
  filterVenueId: z$1.string().nullable(),
@@ -34998,11 +35087,15 @@ function buildEventCollectionDisplay(source) {
34998
35087
  };
34999
35088
  }
35000
35089
  function buildEventCollectionFilterDisplay(source) {
35001
- return {
35002
- showFilters: source.showFilters ?? true,
35003
- showCategoryFilter: source.showCategoryFilter ?? "auto",
35004
- showVenueFilter: source.showVenueFilter ?? false,
35005
- showStaffFilter: source.showStaffFilter ?? true,
35090
+ const selected = source.seriesIds != null;
35091
+ const matchingFilters = selected ? {
35092
+ eventSurface: "all",
35093
+ filterEventPresets: null,
35094
+ scheduleScope: "any",
35095
+ filterCategoryIds: null,
35096
+ filterStaffMemberId: null,
35097
+ filterVenueId: null
35098
+ } : {
35006
35099
  eventSurface: normalizeEventSurfaceScope(source.eventSurface),
35007
35100
  filterEventPresets: normalizeEventSurfacePresetsCsv(source.filterEventPresets),
35008
35101
  scheduleScope: normalizeEventScheduleScope(source.scheduleScope),
@@ -35010,6 +35103,14 @@ function buildEventCollectionFilterDisplay(source) {
35010
35103
  filterStaffMemberId: normalizeEventStaffMemberId(source.filterStaffMemberId),
35011
35104
  filterVenueId: normalizeEventVenueId(source.filterVenueId)
35012
35105
  };
35106
+ return {
35107
+ seriesIds: eventSeriesScopeCsv(source.seriesIds),
35108
+ showFilters: selected ? false : source.showFilters ?? true,
35109
+ showCategoryFilter: source.showCategoryFilter ?? "auto",
35110
+ showVenueFilter: source.showVenueFilter ?? false,
35111
+ showStaffFilter: source.showStaffFilter ?? true,
35112
+ ...matchingFilters
35113
+ };
35013
35114
  }
35014
35115
  function buildEventCollectionPresentationDisplay(source) {
35015
35116
  return {
@@ -35024,14 +35125,15 @@ function buildEventCollectionPresentationDisplay(source) {
35024
35125
  }
35025
35126
  function buildEventCollectionHydration(source, now = /* @__PURE__ */ new Date()) {
35026
35127
  const timeZone = source.calendarWindow?.scope.timeZone ?? toBookingTimeZone(source.bookingTimeZone);
35128
+ const selected = source.seriesIds != null;
35027
35129
  return {
35028
35130
  calendarWindow: source.calendarWindow ?? void 0,
35029
35131
  siteId: source.siteId,
35030
35132
  stage: source.stage,
35031
35133
  prefetchedEvents: source.events != null,
35032
- eventSurface: normalizeEventSurfaceScope(source.eventSurface),
35033
- filterEventPresets: normalizeEventSurfacePresetsCsv(source.filterEventPresets),
35034
- scheduleScope: normalizeEventScheduleScope(source.scheduleScope),
35134
+ eventSurface: selected ? "all" : normalizeEventSurfaceScope(source.eventSurface),
35135
+ filterEventPresets: selected ? null : normalizeEventSurfacePresetsCsv(source.filterEventPresets),
35136
+ scheduleScope: selected ? "any" : normalizeEventScheduleScope(source.scheduleScope),
35035
35137
  calendarContext: {
35036
35138
  timeZone,
35037
35139
  initialToday: source.calendarWindow?.initialToday ?? getLocalScheduleDate(now, timeZone)
@@ -35601,13 +35703,10 @@ function OfferingsPreviewContent(props) {
35601
35703
  }),
35602
35704
  groupCta ? /* @__PURE__ */ jsx("footer", {
35603
35705
  className: "offerings-preview-card-footer rb-mt-auto rb-flex",
35604
- children: /* @__PURE__ */ jsxs("a", {
35706
+ children: /* @__PURE__ */ jsx("a", {
35605
35707
  className: groupLinkClass,
35606
35708
  href: groupCta.href,
35607
- children: [/* @__PURE__ */ jsx("span", { children: groupCta.label }), /* @__PURE__ */ jsx(ArrowRightIcon, {
35608
- "aria-hidden": "true",
35609
- className: "offerings-preview-link-icon rb-h-4 rb-w-4"
35610
- })]
35709
+ children: /* @__PURE__ */ jsx("span", { children: groupCta.label })
35611
35710
  })
35612
35711
  }) : null
35613
35712
  ]
@@ -38552,6 +38651,65 @@ const formBlockDefinition = {
38552
38651
  runtime: formBlockRuntime
38553
38652
  };
38554
38653
  //#endregion
38654
+ //#region ../blocks/src/system/blocks/events/eventSelectionFields.ts
38655
+ const eventSelectionFields = [{
38656
+ id: "eventSelection",
38657
+ type: "select",
38658
+ label: "Events to show",
38659
+ required: false,
38660
+ multiple: false,
38661
+ defaultValue: "matching",
38662
+ options: [{
38663
+ value: "matching",
38664
+ label: "All matching events"
38665
+ }, {
38666
+ value: "selected",
38667
+ label: "Selected events"
38668
+ }],
38669
+ ui: { intent: "behavior" }
38670
+ }, createSiteOptionSelectField({
38671
+ id: "selectedEventSeriesIds",
38672
+ label: "Selected events",
38673
+ description: "Show upcoming dates for these events. Other event filters do not apply.",
38674
+ required: false,
38675
+ multiple: true,
38676
+ defaultValue: [],
38677
+ optionSource: "eventSeries",
38678
+ ui: {
38679
+ intent: "behavior",
38680
+ searchThreshold: 1,
38681
+ visibleWhen: {
38682
+ field: "eventSelection",
38683
+ equals: "selected"
38684
+ }
38685
+ }
38686
+ })];
38687
+ function withEventSelectionVisibility(field) {
38688
+ if (![
38689
+ "eventSurface",
38690
+ "filterEventPresets",
38691
+ "scheduleScope",
38692
+ "filterCategoryIds",
38693
+ "filterStaffMemberId",
38694
+ "filterVenueId",
38695
+ "showFilters",
38696
+ "showCategoryFilter",
38697
+ "showVenueFilter",
38698
+ "showStaffFilter"
38699
+ ].includes(field.id)) return field;
38700
+ const visibleWhen = field.ui?.visibleWhen;
38701
+ return {
38702
+ ...field,
38703
+ ui: {
38704
+ ...field.ui,
38705
+ visibleWhen: { allOf: [{
38706
+ field: "eventSelection",
38707
+ notEquals: "selected"
38708
+ }, ...visibleWhen ? [visibleWhen] : []] }
38709
+ }
38710
+ };
38711
+ }
38712
+ //#endregion
38555
38713
  //#region ../blocks/src/system/runtime/nodes/events/EventCalendar.interactive.ts
38556
38714
  const eventCalendarSourceSchema = z$1.object({
38557
38715
  ...eventCollectionSourceSchemaShape,
@@ -38649,19 +38807,59 @@ function buildEventCalendarInteractiveIslandProps(props) {
38649
38807
  //#region ../blocks/src/system/blocks/events/eventCalendarDataLoaders.ts
38650
38808
  const scopeParams = {
38651
38809
  siteId: { $bind: { from: "$root.siteId" } },
38810
+ seriesIds: { $bind: {
38811
+ from: "content",
38812
+ transforms: [{
38813
+ id: "events.calendarSelectionParam",
38814
+ options: { key: "seriesIds" }
38815
+ }]
38816
+ } },
38652
38817
  stage: { $bind: {
38653
38818
  from: "$root.previewStage",
38654
38819
  fallback: "published"
38655
38820
  } },
38656
- eventSurface: { $bind: { from: "content.eventSurface" } },
38821
+ eventSurface: { $bind: {
38822
+ from: "content",
38823
+ transforms: [{
38824
+ id: "events.calendarSelectionParam",
38825
+ options: { key: "eventSurface" }
38826
+ }, { id: "value.csv" }]
38827
+ } },
38657
38828
  eventPresets: { $bind: {
38658
- from: "content.filterEventPresets",
38659
- transforms: [{ id: "value.csv" }]
38829
+ from: "content",
38830
+ transforms: [{
38831
+ id: "events.calendarSelectionParam",
38832
+ options: { key: "filterEventPresets" }
38833
+ }, { id: "value.csv" }]
38834
+ } },
38835
+ scheduleScope: { $bind: {
38836
+ from: "content",
38837
+ transforms: [{
38838
+ id: "events.calendarSelectionParam",
38839
+ options: { key: "scheduleScope" }
38840
+ }, { id: "value.csv" }]
38841
+ } },
38842
+ categoryIds: { $bind: {
38843
+ from: "content",
38844
+ transforms: [{
38845
+ id: "events.calendarSelectionParam",
38846
+ options: { key: "filterCategoryIds" }
38847
+ }, { id: "value.csv" }]
38848
+ } },
38849
+ staffMemberId: { $bind: {
38850
+ from: "content",
38851
+ transforms: [{
38852
+ id: "events.calendarSelectionParam",
38853
+ options: { key: "filterStaffMemberId" }
38854
+ }, { id: "value.csv" }]
38660
38855
  } },
38661
- scheduleScope: { $bind: { from: "content.scheduleScope" } },
38662
- categoryIds: { $bind: { from: "content.filterCategoryIds" } },
38663
- staffMemberId: { $bind: { from: "content.filterStaffMemberId" } },
38664
- venueId: { $bind: { from: "content.filterVenueId" } }
38856
+ venueId: { $bind: {
38857
+ from: "content",
38858
+ transforms: [{
38859
+ id: "events.calendarSelectionParam",
38860
+ options: { key: "filterVenueId" }
38861
+ }, { id: "value.csv" }]
38862
+ } }
38665
38863
  };
38666
38864
  /** Combined renders two jobs; calendar-only variants never pay for the list seed. */
38667
38865
  const eventCalendarDataLoaders = {
@@ -38791,6 +38989,13 @@ const eventCalendarLayout = [styledSection({
38791
38989
  from: "content.defaultCalendarView",
38792
38990
  fallback: "month"
38793
38991
  } },
38992
+ seriesIds: { $bind: {
38993
+ from: "content",
38994
+ transforms: [{
38995
+ id: "events.calendarSelectionParam",
38996
+ options: { key: "seriesIds" }
38997
+ }]
38998
+ } },
38794
38999
  showFilters: { $bind: {
38795
39000
  from: "content.showFilters",
38796
39001
  fallback: true
@@ -38812,17 +39017,47 @@ const eventCalendarLayout = [styledSection({
38812
39017
  fallback: true
38813
39018
  } },
38814
39019
  eventSurface: { $bind: {
38815
- from: "content.eventSurface",
38816
- fallback: "all"
39020
+ from: "content",
39021
+ transforms: [{
39022
+ id: "events.calendarSelectionParam",
39023
+ options: { key: "eventSurface" }
39024
+ }]
39025
+ } },
39026
+ filterEventPresets: { $bind: {
39027
+ from: "content",
39028
+ transforms: [{
39029
+ id: "events.calendarSelectionParam",
39030
+ options: { key: "filterEventPresets" }
39031
+ }]
38817
39032
  } },
38818
- filterEventPresets: { $bind: { from: "content.filterEventPresets" } },
38819
39033
  scheduleScope: { $bind: {
38820
- from: "content.scheduleScope",
38821
- fallback: "any"
39034
+ from: "content",
39035
+ transforms: [{
39036
+ id: "events.calendarSelectionParam",
39037
+ options: { key: "scheduleScope" }
39038
+ }]
39039
+ } },
39040
+ filterCategoryIds: { $bind: {
39041
+ from: "content",
39042
+ transforms: [{
39043
+ id: "events.calendarSelectionParam",
39044
+ options: { key: "filterCategoryIds" }
39045
+ }]
39046
+ } },
39047
+ filterStaffMemberId: { $bind: {
39048
+ from: "content",
39049
+ transforms: [{
39050
+ id: "events.calendarSelectionParam",
39051
+ options: { key: "filterStaffMemberId" }
39052
+ }]
39053
+ } },
39054
+ filterVenueId: { $bind: {
39055
+ from: "content",
39056
+ transforms: [{
39057
+ id: "events.calendarSelectionParam",
39058
+ options: { key: "filterVenueId" }
39059
+ }]
38822
39060
  } },
38823
- filterCategoryIds: { $bind: { from: "content.filterCategoryIds" } },
38824
- filterStaffMemberId: { $bind: { from: "content.filterStaffMemberId" } },
38825
- filterVenueId: { $bind: { from: "content.filterVenueId" } },
38826
39061
  cardRole: { $bind: {
38827
39062
  from: "content._cardStyles.role",
38828
39063
  fallback: "default"
@@ -39326,6 +39561,7 @@ const eventCalendarAdditionalFields = [
39326
39561
  }
39327
39562
  }
39328
39563
  },
39564
+ ...eventSelectionFields,
39329
39565
  {
39330
39566
  id: "eventSurface",
39331
39567
  type: "select",
@@ -39535,7 +39771,7 @@ const eventCalendarBlockDefinition = {
39535
39771
  titleSource: "heading",
39536
39772
  description: "Display events with calendar, list, or combined views with filtering",
39537
39773
  skipSectionStyles: true,
39538
- additionalFields: eventCalendarAdditionalFields,
39774
+ additionalFields: eventCalendarAdditionalFields.map(withEventSelectionVisibility),
39539
39775
  styleTokens: {
39540
39776
  background: "surface",
39541
39777
  typography: "body",
@@ -39644,6 +39880,7 @@ const eventListingHydrationSchema = z$1.object({
39644
39880
  eventSurface: eventSurfaceScopeSchema,
39645
39881
  filterEventPresets: z$1.string().nullable(),
39646
39882
  scheduleScope: eventScheduleScopeSchema,
39883
+ seriesIds: z$1.string().nullable().optional(),
39647
39884
  filterCategoryIds: z$1.string().nullable().optional(),
39648
39885
  filterStaffMemberId: z$1.string().nullable().optional(),
39649
39886
  filterVenueId: z$1.string().nullable().optional(),
@@ -39704,6 +39941,7 @@ const eventListingBlockRuntime = defineProgressiveBlockRuntime({
39704
39941
  eventSurface: normalizeEventSurfaceScope(source.eventSurface),
39705
39942
  filterEventPresets: normalizeEventSurfacePresetsCsv(source.filterEventPresets),
39706
39943
  scheduleScope: normalizeEventScheduleScope(source.scheduleScope),
39944
+ seriesIds: eventSeriesScopeCsv(source.seriesIds),
39707
39945
  filterCategoryIds: normalizeEventCategoryIdsCsv(source.filterCategoryIds),
39708
39946
  filterStaffMemberId: normalizeEventStaffMemberId(source.filterStaffMemberId),
39709
39947
  filterVenueId: normalizeEventVenueId(source.filterVenueId),
@@ -45061,9 +45299,56 @@ function generateNavLinkCSS(options) {
45061
45299
  if (baseRules.length > 0) cssChunks.unshift(`\n${selector} {\n ${baseRules.join("\n ")}\n}\n`);
45062
45300
  if (hoverRules.length > 0) cssChunks.push(`\n${hoverSelector} {\n ${hoverRules.join("\n ")}\n}\n`);
45063
45301
  if (activeRules.length > 0) cssChunks.push(`\n${activeSelector} {\n ${activeRules.join("\n ")}\n}\n`);
45302
+ cssChunks.push(navLinkFocusVisibleCss(selector, style, theme, tokens));
45064
45303
  cssChunks.push(generateInteractiveChildInheritanceCSS(selector));
45065
45304
  return cssChunks.join("");
45066
45305
  }
45306
+ /**
45307
+ * Keyboard focus indicator for nav links, in the header, the footer and header
45308
+ * dropdown menus — the three surfaces `generateNavLinkCSS` serves.
45309
+ *
45310
+ * Emitted unconditionally rather than as an effect, because focus visibility is
45311
+ * a floor rather than a style choice. Only the interaction-palette pill ever
45312
+ * wrote an `effects.focus` group, so every other nav — every `quiet` palette,
45313
+ * every footer, every dropdown — previously fell back to whatever outline the
45314
+ * browser drew.
45315
+ *
45316
+ * The outline takes the link's own resolved colour, so on a header that adapts
45317
+ * to the section it floats over it moves with the adaptation instead of
45318
+ * asserting a brand colour against an unknown backdrop.
45319
+ *
45320
+ * Where the style asks for `soft-glow`, the same halo goes on the outline. That
45321
+ * treatment exists because the theme has already conceded the resolved colour
45322
+ * alone is not reliable over an unpredictable backdrop — a hero photograph with
45323
+ * mixed luminance. Without it the text would stay legible by its halo while the
45324
+ * focus ring, which is the part with a contrast requirement of its own, would
45325
+ * not.
45326
+ *
45327
+ * A style that also paints a focus pill keeps it: this adds an outline around
45328
+ * that pill rather than replacing it.
45329
+ */
45330
+ function navLinkFocusVisibleCss(selector, style, theme, tokens) {
45331
+ const color = tokens.getColor(style.colorToken);
45332
+ const halo = buildTextContrastShadow({
45333
+ theme,
45334
+ colorToken: style.colorToken,
45335
+ treatment: style.contrastTreatment
45336
+ });
45337
+ return `
45338
+ ${selector}:focus-visible {
45339
+ outline: 2px solid ${color};
45340
+ outline-offset: ${focusOutlineOffset(selector)};${halo ? `\n box-shadow: ${halo};` : ""}
45341
+ }
45342
+ `;
45343
+ }
45344
+ /**
45345
+ * Dropdown items are full-width inside a panel with no horizontal padding, so
45346
+ * an outset outline would paint over and past the panel's own border. Keeping
45347
+ * it flush is the only way it reads as belonging to the item.
45348
+ */
45349
+ function focusOutlineOffset(selector) {
45350
+ return selector.includes("nav-dropdown-link") ? "-2px" : "3px";
45351
+ }
45067
45352
  function buildTextContrastShadow(input) {
45068
45353
  if (input.treatment !== "soft-glow") return null;
45069
45354
  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)";
@@ -48196,7 +48481,7 @@ function pageBlockPosition(index, blockCount) {
48196
48481
  //#endregion
48197
48482
  //#region ../blocks/src/pageRendererContracts.ts
48198
48483
  function buildPageRendererRootRuntime(dataContext) {
48199
- const { siteId = null, pageId = null, pathname = null, bookingTimeZone, previewStage = "published", apiBaseUrl = null, portalToken = null, bookingOfferingPresets = [], mailingList = { tag: "not_configured" }, eventRegistrationOverlayEnabled = false, loaderFailures = {} } = dataContext ?? {};
48484
+ 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 ?? {};
48200
48485
  return {
48201
48486
  siteId,
48202
48487
  pageId,
@@ -48206,6 +48491,7 @@ function buildPageRendererRootRuntime(dataContext) {
48206
48491
  apiBaseUrl,
48207
48492
  portalToken,
48208
48493
  bookingOfferingPresets,
48494
+ appointmentServicePathPrefix,
48209
48495
  mailingList,
48210
48496
  eventRegistrationOverlayEnabled,
48211
48497
  loaderFailures
@@ -52948,7 +53234,8 @@ const appointmentServicesBlockDefinition = {
52948
53234
  el("appointment-services", {
52949
53235
  sectionHeading: { $bind: { from: "content.heading" } },
52950
53236
  services: { $bind: { from: "data.services" } },
52951
- pathname: { $bind: { from: "$root.pathname" } }
53237
+ pathname: { $bind: { from: "$root.pathname" } },
53238
+ servicePathPrefix: { $bind: { from: "$root.appointmentServicePathPrefix" } }
52952
53239
  })
52953
53240
  ], { gap: "lg" })
52954
53241
  })]
@@ -59401,10 +59688,19 @@ const containerResponsiveThemeCss = `/*
59401
59688
  padding-top: 2.5rem;
59402
59689
  padding-bottom: 2.5rem;
59403
59690
  }
59691
+ /* Clearance for a surface that is not an authored block page.
59692
+ An authored page gets this through its opening block's container (see the
59693
+ overlay-clearance rule in styles.css). A reserved surface or a system
59694
+ destination page has no such block, so it consumes the same variable here.
59695
+ Marked with one class rather than per-surface selectors, because the last
59696
+ two additions to this family were both missed and shipped overlapping. */
59404
59697
  :where(.theme-scope)
59405
59698
  [data-site-document-layout-mode="header-overlay"]
59406
- [data-rb-reserved-surface].rb-reserved-surface-main {
59407
- padding-top: calc(var(--rb-reserved-surface-header-offset, 5.5rem) + 2.5rem);
59699
+ .rb-overlay-clearance-surface {
59700
+ padding-top: calc(
59701
+ var(--site-overlay-header-clearance, 5.5rem) +
59702
+ var(--site-overlay-opening-content-extra-pad, clamp(1rem, 2vw, 1.75rem))
59703
+ );
59408
59704
  }
59409
59705
  .rb-preview-editor-offset {
59410
59706
  padding-bottom: calc(
@@ -69761,6 +70057,23 @@ const containerResponsiveThemeCss = `/*
69761
70057
  gap: 0.5rem;
69762
70058
  }
69763
70059
 
70060
+ /* Error panel and field notes. The form block scopes these to its own
70061
+ data-block, so the newsletter form (which also renders in the footer)
70062
+ needs its own copy of the treatment. */
70063
+ :where(.theme-scope) .newsletter-form .fb-error:not([data-field-validation-message]) {
70064
+ background-color: var(--fb-error-bg);
70065
+ color: var(--fb-error-text);
70066
+ border: 1px solid var(--fb-error-border);
70067
+ border-radius: var(--rb-block-radius);
70068
+ padding: 1rem;
70069
+ font-size: 0.875rem;
70070
+ }
70071
+
70072
+ :where(.theme-scope) .newsletter-form [data-field-validation-message] {
70073
+ font-size: 0.875rem;
70074
+ color: var(--fb-error-text);
70075
+ }
70076
+
69764
70077
  /* Required indicator */
69765
70078
  :where(.theme-scope) .newsletter-required {
69766
70079
  color: rgb(var(--tb-primary));
@@ -72129,6 +72442,15 @@ z$1.object({
72129
72442
  }).optional(),
72130
72443
  overrides: z$1.record(z$1.string(), z$1.string()).optional()
72131
72444
  }).passthrough();
72445
+ z$1.object({
72446
+ palette: paletteColorsSchema,
72447
+ paletteMode: paletteModeSchema,
72448
+ typography: z$1.object({
72449
+ headingFamily: z$1.string().trim().min(1),
72450
+ bodyFamily: z$1.string().trim().min(1)
72451
+ }).strict(),
72452
+ corners
72453
+ }).strict();
72132
72454
  //#endregion
72133
72455
  //#region src/rendering/blocks-theme-runtime.ts
72134
72456
  function parseBlocksTheme(theme) {