riverbankcms 0.8.0 → 0.10.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.
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
- import { $ as generateBaseInteractiveCSS, $n as createContentEntryRef, $t as NAV_LINK_LETTER_SPACING_MAP, A as getGradientPreset, An as featuresFromHex, At as resolveTokenOrCssColorValue, B as generateCssVars, Bn as normalizeCardRole, Bt as featureCardCompositionTreatmentValues, C as retargetCompiledBoundaryRuntimeForContentAdjacency, Cn as resolveSurfaceForeground, Ct as MQ_SM_DOWN, D as compileTransitionRuntime, Dn as defaultThemeTokens, Dt as isCssColorLiteral, E as getCuratedSiteStyle, En as buildThemeTokens, Et as headerVariantValues, F as parseBackgroundAppearanceColorToken, Fn as surfaceForegroundStyle, Ft as defineBlockDesignCapability, G as resolvedButtonColourDeclarations, Gn as footerModeSchema, Gt as testimonialsCompositionTreatmentValues, H as PUBLIC_BUTTON_ROLES, Hn as mediaSchema, Ht as introCompositionTreatmentValues, I as defineBlockDesignMetadata, In as surfaceForegroundValue, It as defineFrameCapability, J as contextualButtonSurfaceStyles, Jn as unsafeAsOpaqueButtonColourToken, Jt as getComponentBorderWidthPx, K as resolvedButtonFocusDeclarations, Kn as VARIANT_ROLES, Kt as tileTreatmentValues, L as require_jsx_runtime, Ln as generateShadowValue$1, Lt as defineNoBlockDesignCapability, M as boundaryRuntimeMetricsForTransition, Mn as oklchToHexGamut, N as backgroundAppearanceColorTokenNames, Nn as DEFAULT_SURFACE_TEXT_COLOR, Nt as asDesignBlockId, O as gradientToCss, On as ORDINARY_TEXT_MIN_CONTRAST_RATIO, Ot as resolveOnColorForThemeToken, P as backgroundAppearanceQuickColorTokenNames, Pn as surfaceForegroundDeclarations, Pt as assertNever$4, Q as generateEffectsCSS, Qn as createCommandRef, Qt as NAV_LINK_BORDER_RADIUS_MAP, R as require_react, Rn as cardRoleSchema, Rt as eventListTreatmentValues, Sn as textColorStyle, St as MQ_MD_DOWN, T as readHeaderNavFontSizePreference, Tn as onColorTokenName, Tt as MQ_TABLET_ONLY, U as generateButtonCss, Un as mediaTypeDiscriminants, Ut as makeBoundaryId, Vn as mediaIdentifierSchema, Vt as headingDecorationColorTokenValues, W as RESOLVED_BUTTON_DISABLED_DECLARATIONS, Wn as persistableMediaSchema, Wt as offeringsPreviewCompositionTreatmentValues, X as resolveContextualButtonRole, Xn as createBlockRef, Xt as parseBlockCustomCssRules, Y as deriveButtonSurfaceContext, Yn as parseBlockColorToken, Yt as getComponentShadowVar, Z as generateDefaultButtonSystem, Zn as createBlocksRef, Zt as parseCustomCssRules, _ as entryIdentifierForCommand, _n as backgroundColorStyle, _t as BREAKPOINT_LG, a as classifySdkEventBookingOffer, an as INPUT_SPACING_MAP, ar as createPageRef, at as compileButtonColourStates, b as pagePathForCommand, bn as mergeStyles, bt as BREAKPOINT_XL, c as stableStringify, cn as ACCORDION_SPACING_MAP, cr as refSlug, ct as expandPalette, d as mapEventCommandContent, dn as ICON_CONFIG, dt as boxBackgroundOverlaySchema, en as NAV_LINK_PADDING_MAP, er as createEventCategoryRef, et as generateInteractiveChildInheritanceCSS, f as evaluateSiteCommandBatchExposure, fn as ICON_SIZE_PX, ft as boxBackgroundSchema, g as blockOrderIdentifiersForCommand, gn as TokenResolver, gt as renderHeaderPaintTargetRules, h as blockIdentifierForCommand, hn as generateCardCss, ht as getHeaderPaintTargets, in as INPUT_FONT_SIZE_MAP, ir as createNavigationRef, it as parseThemeForPersistence, j as parseGradientPresetId, jn as hexToRgb, jt as pageDesignEditorBackgroundOverrideOwner, k as GRADIENT_PRESET_IDS, kn as contrastRatio, kt as resolveThemeColorReferenceValue, l as createDryRunReport, ln as ACCORDION_TRIGGER_FONT_SCALE, lr as slugPart, lt as getTextColorForBackground, m as getSiteCommandMetadata, mn as getDefaultCardVariants, mt as generateMobileOverlayBackdropFilterFix, nn as NAV_LINK_TEXT_SIZE_MAP, nr as createFooterRef, nt as themeButtonClassName, o as venueManagementFields, on as LABEL_FONT_SIZE_MAP, or as createSiteCommandSiteRef, ot as formatButtonColourContractError, p as evaluateSiteCommandExposure, pn as generateCardCoreCss, pt as generateHeaderScrollTreatmentStyles, q as contextualButtonSurfaceResetStyles, qn as buttonVariantIdSchema, qt as visibleHeadingDecorationFamilyValues, rn as FONT_WEIGHT_MAP, rr as createFormRef, rt as themeButtonClassNameWithTrailingIcon, s as sortRecord, sn as ACCORDION_OPEN_ACCENT_THICKNESS, sr as createVenueRef, st as generateShadowValue, t as classifySdkEventTiming, tn as NAV_LINK_PADDING_X_MAP, tr as createEventSeriesRef, tt as parseThemeButtonVariantId, u as parseAndPlanCommandBatchForTypes, un as ACCORDION_TRIGGER_LETTER_SPACING, ur as __toESM, ut as themeSchema, v as pageIdentifierForBlockCommand, vn as borderColorStyle, vt as BREAKPOINT_MD, w as mergeHeaderNavTypographyPreference, wn as isOnColorBackgroundCandidateToken, wt as MQ_SM_UP, x as hasConfiguredBookingVertical, xn as rgbColorValue, xt as MQ_LG_UP, y as pageIdentifierForCommand, yn as cssVarValue, yt as BREAKPOINT_SM, z as pickShadeTowardBackground, zn as cardVariantRoleValues, zt as eyebrowTreatmentValues } from "../sdk-event-upsert-Bf6wAl4s.mjs";
3
- import { $ as formatEventPricing, A as parseFooterCompositionV1, B as formatBookingTime, C as parseMailingListContentVersionId, D as DEFAULT_MAILING_LIST_SUCCESS_MESSAGE, E as planMailingListChoicePresentation, Et as unsafeAsMediaAssetId, F as normalizeLocationAddressText, G as getLocalScheduleTime, H as formatLocalScheduleTime, Ht as ok, I as toLocationCoordinates, It as unsafeAsStaffMemberId, J as toScheduledBookingDateRange, L as buildBookingUtcDateWindow, N as assertAllowedPublicUrl, O as parseMailingListProviderScope, Q as formatBookingPriceDisplay, R as formatBookingDate, S as parseMailingListBlockId, T as parseMailingListRuntimeContext, U as getBookingLocalDateKey, V as formatLocalScheduleDate, Vt as err, W as getLocalScheduleDate, Y as toScheduledBookingDateTime, Z as parseEventPageSurfaceSubject, _ as createSecret, at as resolvePricingOptionsPriceDisplay, bt as unsafeAsDemoCapability, c as DEFAULT_EVENT_TYPE_PRESETS, ct as formatCurrencyAmount, d as SURFACE_EVENT_PRESET_VALUES, dt as parseEventSeriesId, et as isPublicEventPricingOptionDisplayable, f as WHOLE_SERIES_EVENT_PRESET_VALUES, ft as parseMediaAssetId, g as resolveWholeSeriesBookingPhase, gt as unsafeAsAppointmentResourceId, h as orderedLiveRunSessions, ht as parseUserId, i as isEventSeriesVerticalPresetDefinition, it as resolveExactOrFreePriceDisplay, j as parseMailingListPlacementTargeting, kt as unsafeAsPositiveByteCount, l as EVENT_PRESET_VALUES, lt as assertNever, m as CANCELLED_SESSION_STATUS, mt as parseSiteId, n as areConfiguredBookingVerticalConfigsEqual, nt as publicEventPricingDisplay, p as publicReadFreshnessSeconds, pt as parsePageId, q as toBookingTimeZone, rt as publicEventPricingType, s as resolveSiteVerticalBookingConfig, t as NAVIGATION_LOCATIONS, tt as publicEventPricingCurrency, ut as parseApiKeyId, v as exposeSecret, w as parseMailingListSignedSourceToken, x as buildMailingListSignupBlockSourceRef, y as parseManagementKey, z as formatBookingDateParts } from "../src-B8fOSKJ6.mjs";
4
- import { $ as sdkUpsertEventResponseSchema, A as resolveMediaTransformForAspect, B as asRecord$1, C as walkAndCollectImageAttrs, D as normalizeWidthCandidates, E as rotateNormalizedPoint, F as buildMediaIdentifierFromFilename, G as parseSafeDownloadFilename, H as FILE_SIZE_LIMITS, I as parseMediaIdentifier, J as createHttpClient, K as ManagementApiError, L as deriveVideoSlotPolicy, M as getDirectImageUrlForSiteScopedPath, N as getImageUrl, O as isExplicitRectCrop, P as isSiteScopedDirectImageStoragePath, Q as sdkListEventsResponseSchema, R as resolveVideoSelectionIntentForMediaField, S as buildRenderableMediaAssetIndex, T as looksLikeUuid$1, U as classifyKnownMimeType, V as parseRelativeStoragePath, W as managementMediaLibraryUploadLimitForMimeType, X as sdkConfigureBookingVerticalResponseSchema, Y as is404Error, Z as sdkGetEventResponseSchema, _ as buildSettingsUpdateInput, _t as sdkConfiguredBookingVerticalConfigSchema, a as prepareLocalMediaForPush, at as externalLinkSchema$1, b as isMediaValue, c as writeBinaryFileAtomic, ct as internalRouteOnlyLinkSchema, d as normalizeMediaValueToIdentifierOnly, dt as linkSchema, et as sdkSettingsUpdateSchema, f as walkLocalContentMedia, ft as pageLinkSchema$1, g as SETTINGS_FILE_FIELDS, gt as sdkReorderResponseSchema, h as extractMediaIdentifiers, ht as sdkListEventOccurrencesResponseSchema, i as applyLocalMediaPush, it as entryLinkSchema$1, j as getDirectImageUrlForRelativePath, k as parseAspectRatioValue, l as sha256, lt as isInternalResolvedLinkValue, m as downloadMedia, mt as sdkEventOccurrenceResponseSchema, nt as RESOLVED_INTERNAL_LINK_ENTITY_TYPES, o as admitBinaryWriteDestination, ot as internalLinkSchema, p as buildStorageUrl, pt as sdkDeleteEventOccurrenceResponseSchema, q as buildRequestInfo, r as syncLocalMediaForPull, rt as customLinkSchema$1, s as readStableBinaryFile, st as internalResolvedLinkSchema, t as revalidateLocalMediaPushPlan, tt as linkPayloadSchema, u as normalizeMediaIdentifierInput, ut as isResolvedInternalLinkEntityType, v as hasOwnSettingsField, w as deleteEnvSpecificKeys, x as attachRenderableMediaAssetFields, y as writeMediaManifest, z as getMimeType } from "../local-sync-EcUwLrRx.mjs";
5
- import { n as CliSdkPeerError, r as CLI_VERSION, t as loadConfigFile } from "../load-config-De0cFlPg.mjs";
6
- import { a as RichTextDocSchema, c as isRecord$17, i as findUnfilledSentinels, n as buildEntryScaffold, o as isRichTextDoc, r as validateEntryInstance, s as isObjectRecord, t as eventUpsertInputSchema } from "../eventUpsertInputSchema-BE3nSNsn.mjs";
7
- import { a as prepareScaffoldExecution, c as LOCAL_PACKAGE_VENDOR_DIR, d as loadGeneratedPackageRanges, i as preflightScaffoldTargets, n as createScaffoldCompletion, s as deriveScaffoldLocalManifest, t as deriveScaffoldPlan } from "../plan-DtQEnwCM.mjs";
2
+ import { $ as resolveContextualButtonRole, $n as footerModeSchema, $t as getComponentBorderWidthPx, A as boundaryLayout, An as surfaceToneFromForegroundToken, At as headerVariantValues, B as require_jsx_runtime, Bn as oklchToHexGamut, Bt as defineBlockDesignCapability, C as mergeHeaderNavTypographyPreference, Cn as borderColorStyle, Ct as BREAKPOINT_SM, D as GRADIENT_PRESET_IDS, Dn as textColorStyle, Dt as MQ_SM_DOWN, E as gradientToCss, En as rgbColorValue, Et as MQ_MD_DOWN, F as transitionCatalogueEntries, Fn as defaultThemeTokens, Ft as pageDesignEditorBackgroundOverrideOwner, G as PUBLIC_BUTTON_ROLES, Gn as generateShadowValue$1, Gt as featureCardCompositionTreatmentValues, H as pickShadeTowardBackground, Hn as surfaceForegroundDeclarations, Ht as defineNoBlockDesignCapability, I as backgroundAppearanceColorTokenNames, In as ORDINARY_TEXT_MIN_CONTRAST_RATIO, It as stripStaleTransitionStyleGroup, J as resolvedButtonColourDeclarations, Jn as normalizeCardRole, Jt as makeBoundaryId, K as generateButtonCss, Kn as cardRoleSchema, Kt as headingDecorationColorTokenValues, L as backgroundAppearanceQuickColorTokenNames, Ln as contrastRatio, M as sectionFactsForContent, Mn as isOnColorBackgroundCandidateToken, Mt as resolveOnColorForThemeToken, N as boundaryRuntimeMetricsForDecorativeTransition, Nn as onColorTokenName, Nt as resolveThemeColorReferenceValue, O as getGradientPreset, On as textColorValue, Ot as MQ_SM_UP, P as anglePolygonCss, Pn as buildThemeTokens, Pt as resolveTokenOrCssColorValue, Q as deriveButtonSurfaceContext, Qn as persistableMediaSchema, Qt as visibleHeadingDecorationFamilyValues, R as parseBackgroundAppearanceColorToken, Rn as featuresFromHex, Rt as asDesignBlockId, Sn as backgroundColorStyle, St as BREAKPOINT_MD, T as getCuratedSiteStyle, Tn as mergeStyles, Tt as MQ_LG_UP, U as generateCssVars, Un as surfaceForegroundStyle, Ut as eventListTreatmentValues, V as require_react, Vn as DEFAULT_SURFACE_TEXT_COLOR, Vt as defineFrameCapability, Wn as surfaceForegroundValue, Wt as eyebrowTreatmentValues, X as contextualButtonSurfaceResetStyles, Xn as mediaSchema, Xt as testimonialsCompositionTreatmentValues, Y as resolvedButtonFocusDeclarations, Yn as mediaIdentifierSchema, Yt as offeringsPreviewCompositionTreatmentValues, Z as contextualButtonSurfaceStyles, Zn as mediaTypeDiscriminants, Zt as tileTreatmentValues, _ as entryIdentifierForCommand, _n as ICON_SIZE_PX, _r as slugPart, _t as generateHeaderScrollTreatmentStyles, a as classifySdkEventBookingOffer, an as NAV_LINK_PADDING_MAP, ar as createBlocksRef, at as themeButtonExtraClassesWithTrailingIcon, b as pagePathForCommand, bn as generateCardCss, bt as renderHeaderPaintTargetRules, c as stableStringify, cn as FONT_WEIGHT_MAP, cr as createEventCategoryRef, ct as parseThemeForPersistence, d as mapEventCommandContent, dn as LABEL_FONT_SIZE_MAP, dr as createFormRef, dt as generateShadowValue, en as getComponentShadowVar, er as VARIANT_ROLES, et as generateDefaultButtonSystem, f as evaluateSiteCommandBatchExposure, fn as ACCORDION_OPEN_ACCENT_THICKNESS, fr as createNavigationRef, ft as expandPalette, g as blockOrderIdentifiersForCommand, gn as ICON_CONFIG, gr as refSlug, gt as boxBackgroundSchema, h as blockIdentifierForCommand, hn as ACCORDION_TRIGGER_LETTER_SPACING, hr as createVenueRef, ht as boxBackgroundOverlaySchema, in as NAV_LINK_LETTER_SPACING_MAP, ir as createBlockRef, it as parseThemeButtonVariantId, j as composeBoundary, jn as resolveSurfaceForeground, jt as isCssColorLiteral, k as parseGradientPresetId, kn as selectLogoVariant, kt as MQ_TABLET_ONLY, l as createDryRunReport, ln as INPUT_FONT_SIZE_MAP, lr as createEventSeriesRef, lt as compileButtonColourStates, m as getSiteCommandMetadata, mn as ACCORDION_TRIGGER_FONT_SCALE, mr as createSiteCommandSiteRef, mt as themeSchema, nn as parseCustomCssRules, nr as unsafeAsOpaqueButtonColourToken, nt as generateBaseInteractiveCSS, o as venueManagementFields, on as NAV_LINK_PADDING_X_MAP, or as createCommandRef, ot as themeButtonSizeClassName, p as evaluateSiteCommandExposure, pn as ACCORDION_SPACING_MAP, pr as createPageRef, pt as getTextColorForBackground, q as RESOLVED_BUTTON_DISABLED_DECLARATIONS, qn as cardVariantRoleValues, qt as introCompositionTreatmentValues, rn as NAV_LINK_BORDER_RADIUS_MAP, rr as parseBlockColorToken, rt as generateInteractiveChildInheritanceCSS, s as sortRecord, sn as NAV_LINK_TEXT_SIZE_MAP, sr as createContentEntryRef, st as themeButtonVariantClassNames, t as classifySdkEventTiming, tn as parseBlockCustomCssRules, tr as buttonVariantIdSchema, tt as generateEffectsCSS, u as parseAndPlanCommandBatchForTypes, un as INPUT_SPACING_MAP, ur as createFooterRef, ut as formatButtonColourContractError, v as pageIdentifierForBlockCommand, vn as generateCardCoreCss, vr as __toESM, vt as generateMobileOverlayBackdropFilterFix, w as readHeaderNavFontSizePreference, wn as cssVarValue, wt as BREAKPOINT_XL, x as hasConfiguredBookingVertical, xn as TokenResolver, xt as BREAKPOINT_LG, y as pageIdentifierForCommand, yn as getDefaultCardVariants, yt as getHeaderPaintTargets, z as defineBlockDesignMetadata, zn as hexToRgb, zt as assertNever$4 } from "../sdk-event-upsert-DhdlT2ko.mjs";
3
+ import { $ as formatBookingPriceDisplay, A as parseFooterCompositionV1, At as unsafeAsPositiveByteCount, B as formatBookingDateParts, C as parseMailingListContentVersionId, D as DEFAULT_MAILING_LIST_SUCCESS_MESSAGE, Dt as unsafeAsMediaAssetId, E as planMailingListChoicePresentation, F as normalizeLocationAddressText, G as getLocalScheduleDate, H as formatLocalScheduleDate, Ht as err, I as toLocationCoordinates, J as toBookingTimeZone, K as getLocalScheduleTime, L as selectCategoryView, Lt as unsafeAsStaffMemberId, N as assertAllowedPublicUrl, O as parseMailingListProviderScope, Q as parseEventPageSurfaceSubject, R as buildBookingUtcDateWindow, S as parseMailingListBlockId, T as parseMailingListRuntimeContext, U as formatLocalScheduleTime, Ut as ok, V as formatBookingTime, W as getBookingLocalDateKey, X as toScheduledBookingDateTime, Y as toScheduledBookingDateRange, _ as createSecret, _t as unsafeAsAppointmentResourceId, at as resolveExactOrFreePriceDisplay, c as DEFAULT_EVENT_TYPE_PRESETS, d as SURFACE_EVENT_PRESET_VALUES, dt as parseApiKeyId, et as formatEventPricing, f as WHOLE_SERIES_EVENT_PRESET_VALUES, ft as parseEventSeriesId, g as resolveWholeSeriesBookingPhase, gt as parseUserId, h as orderedLiveRunSessions, ht as parseSiteId, it as publicEventPricingType, j as parseMailingListPlacementTargeting, l as EVENT_PRESET_VALUES, lt as formatCurrencyAmount, m as CANCELLED_SESSION_STATUS, mt as parsePageId, n as NAVIGATION_LOCATIONS, nt as publicEventPricingCurrency, ot as resolvePricingOptionsPriceDisplay, p as publicReadFreshnessSeconds, pt as parseMediaAssetId, r as areConfiguredBookingVerticalConfigsEqual, rt as publicEventPricingDisplay, s as resolveSiteVerticalBookingConfig, t as resolveEventCatalogue, tt as isPublicEventPricingOptionDisplayable, ut as assertNever, v as exposeSecret, w as parseMailingListSignedSourceToken, x as buildMailingListSignupBlockSourceRef, xt as unsafeAsDemoCapability, y as parseManagementKey, z as formatBookingDate } from "../src-DIAVNRwo.mjs";
4
+ import { $ as sdkUpsertEventResponseSchema, A as resolveMediaTransformForAspect, B as asRecord$1, C as walkAndCollectImageAttrs, D as normalizeWidthCandidates, E as rotateNormalizedPoint, F as buildMediaIdentifierFromFilename, G as parseSafeDownloadFilename, H as FILE_SIZE_LIMITS, I as parseMediaIdentifier, J as createHttpClient, K as ManagementApiError, L as deriveVideoSlotPolicy, M as getDirectImageUrlForSiteScopedPath, N as getImageUrl, O as isExplicitRectCrop, P as isSiteScopedDirectImageStoragePath, Q as sdkListEventsResponseSchema, R as resolveVideoSelectionIntentForMediaField, S as buildRenderableMediaAssetIndex, T as looksLikeUuid$1, U as classifyKnownMimeType, V as parseRelativeStoragePath, W as managementMediaLibraryUploadLimitForMimeType, X as sdkConfigureBookingVerticalResponseSchema, Y as is404Error, Z as sdkGetEventResponseSchema, _ as buildSettingsUpdateInput, _t as sdkConfiguredBookingVerticalConfigSchema, a as prepareLocalMediaForPush, at as externalLinkSchema$1, b as isMediaValue, c as writeBinaryFileAtomic, ct as internalRouteOnlyLinkSchema, d as normalizeMediaValueToIdentifierOnly, dt as linkSchema, et as sdkSettingsUpdateSchema, f as walkLocalContentMedia, ft as pageLinkSchema$1, g as SETTINGS_FILE_FIELDS, gt as sdkReorderResponseSchema, h as extractMediaIdentifiers, ht as sdkListEventOccurrencesResponseSchema, i as applyLocalMediaPush, it as entryLinkSchema$1, j as getDirectImageUrlForRelativePath, k as parseAspectRatioValue, l as sha256, lt as isInternalResolvedLinkValue, m as downloadMedia, mt as sdkEventOccurrenceResponseSchema, nt as RESOLVED_INTERNAL_LINK_ENTITY_TYPES, o as admitBinaryWriteDestination, ot as internalLinkSchema, p as buildStorageUrl, pt as sdkDeleteEventOccurrenceResponseSchema, q as buildRequestInfo, r as syncLocalMediaForPull, rt as customLinkSchema$1, s as readStableBinaryFile, st as internalResolvedLinkSchema, t as revalidateLocalMediaPushPlan, tt as linkPayloadSchema, u as normalizeMediaIdentifierInput, ut as isResolvedInternalLinkEntityType, v as hasOwnSettingsField, w as deleteEnvSpecificKeys, x as attachRenderableMediaAssetFields, y as writeMediaManifest, z as getMimeType } from "../local-sync-3ZG1khGb.mjs";
5
+ import { n as CliSdkPeerError, r as CLI_VERSION, t as loadConfigFile } from "../load-config-Bzc6Qo24.mjs";
6
+ import { a as RichTextDocSchema, c as isRecord$17, i as findUnfilledSentinels, n as buildEntryScaffold, o as isRichTextDoc, r as validateEntryInstance, s as isObjectRecord, t as eventUpsertInputSchema } from "../eventUpsertInputSchema-yErCHdr6.mjs";
7
+ import { a as prepareScaffoldExecution, c as LOCAL_PACKAGE_VENDOR_DIR, d as loadGeneratedPackageRanges, i as preflightScaffoldTargets, n as createScaffoldCompletion, s as deriveScaffoldLocalManifest, t as deriveScaffoldPlan } from "../plan-C1Frmu6F.mjs";
8
8
  import { config } from "dotenv";
9
9
  import { Command, CommanderError } from "commander";
10
10
  import { AsyncLocalStorage } from "node:async_hooks";
@@ -176,16 +176,16 @@ var BlockPatchStaleContentError = class extends ManagementApiError {
176
176
  function isBlockPatchStaleContentError(error$1) {
177
177
  return error$1 instanceof BlockPatchStaleContentError;
178
178
  }
179
- function isRecord$36(value) {
179
+ function isRecord$37(value) {
180
180
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
181
181
  }
182
182
  function extractStaleContentCurrentHash(error$1) {
183
183
  if (error$1.statusCode !== 409) return null;
184
- if (!isRecord$36(error$1.details)) return null;
184
+ if (!isRecord$37(error$1.details)) return null;
185
185
  const fieldErrors = error$1.details.fieldErrors;
186
186
  if (!Array.isArray(fieldErrors)) return null;
187
187
  for (const fieldError of fieldErrors) {
188
- if (isRecord$36(fieldError) && fieldError.field === SDK_PATCH_STALE_CONTENT_FIELD && fieldError.code === SDK_PATCH_STALE_CONTENT_CODE && typeof fieldError.message === "string") {
188
+ if (isRecord$37(fieldError) && fieldError.field === SDK_PATCH_STALE_CONTENT_FIELD && fieldError.code === SDK_PATCH_STALE_CONTENT_CODE && typeof fieldError.message === "string") {
189
189
  return fieldError.message;
190
190
  }
191
191
  }
@@ -2524,6 +2524,77 @@ function parsePublicProductCategorySelector(value) {
2524
2524
  return undefined;
2525
2525
  }
2526
2526
 
2527
+ //#endregion
2528
+ //#region ../api/src/defineEndpointDefinitions.ts
2529
+ /**
2530
+ * Validates extracted endpoint descriptors while preserving each literal path,
2531
+ * method, and parameter contract for the typed URL builders.
2532
+ */
2533
+ function defineEndpointDefinitions(definitions$1) {
2534
+ return definitions$1;
2535
+ }
2536
+
2537
+ //#endregion
2538
+ //#region ../api/src/publicNewsletterEndpointDefinitions.ts
2539
+ const PUBLIC_NEWSLETTER_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
2540
+ subscribeNewsletter: {
2541
+ path: "/public/sites/{siteId}/newsletter/subscribe",
2542
+ method: "POST",
2543
+ tags: ["public-newsletter-{siteId}"],
2544
+ auth: "public",
2545
+ responseKind: "json"
2546
+ },
2547
+ confirmNewsletter: {
2548
+ path: "/public/sites/{siteId}/newsletter/confirm/{token}",
2549
+ method: "GET",
2550
+ tags: ["public-newsletter-{siteId}"],
2551
+ auth: "public",
2552
+ responseKind: "text"
2553
+ },
2554
+ unsubscribeNewsletter: {
2555
+ path: "/public/sites/{siteId}/newsletter/unsubscribe/{token}",
2556
+ method: "GET",
2557
+ tags: ["public-newsletter-{siteId}"],
2558
+ auth: "public",
2559
+ responseKind: "text"
2560
+ },
2561
+ unsubscribeNewsletterPost: {
2562
+ path: "/public/sites/{siteId}/newsletter/unsubscribe/{token}",
2563
+ method: "POST",
2564
+ tags: ["public-newsletter-{siteId}"],
2565
+ auth: "public",
2566
+ responseKind: "text"
2567
+ },
2568
+ confirmNewsletterPost: {
2569
+ path: "/public/sites/{siteId}/newsletter/confirm/{token}",
2570
+ method: "POST",
2571
+ tags: ["public-newsletter-{siteId}"],
2572
+ auth: "public",
2573
+ responseKind: "text"
2574
+ },
2575
+ getNewsletterPreferences: {
2576
+ path: "/public/sites/{siteId}/newsletter/preferences/{token}",
2577
+ method: "GET",
2578
+ tags: ["public-newsletter-{siteId}"],
2579
+ auth: "public",
2580
+ responseKind: "text"
2581
+ },
2582
+ saveNewsletterPreferences: {
2583
+ path: "/public/sites/{siteId}/newsletter/preferences/{token}",
2584
+ method: "POST",
2585
+ tags: ["public-newsletter-{siteId}"],
2586
+ auth: "public",
2587
+ responseKind: "text"
2588
+ },
2589
+ getNewsletterArchive: {
2590
+ path: "/public/sites/{siteId}/newsletter/archive/{token}",
2591
+ method: "GET",
2592
+ tags: ["public-newsletter-{siteId}"],
2593
+ auth: "public",
2594
+ responseKind: "text"
2595
+ }
2596
+ });
2597
+
2527
2598
  //#endregion
2528
2599
  //#region ../api/src/apiEndpointTypes.ts
2529
2600
  function allowedDemoMutationPolicy() {
@@ -2783,18 +2854,89 @@ const SDK_ENTRY_READ_ENDPOINTS = {
2783
2854
  };
2784
2855
 
2785
2856
  //#endregion
2786
- //#region ../api/src/defineEndpointDefinitions.ts
2787
- /**
2788
- * Validates extracted endpoint descriptors while preserving each literal path,
2789
- * method, and parameter contract for the typed URL builders.
2790
- */
2791
- function defineEndpointDefinitions(definitions$1) {
2792
- return definitions$1;
2793
- }
2857
+ //#region ../api/src/appointmentServiceCategoryEndpoints.ts
2858
+ const APPOINTMENT_SERVICE_CATEGORY_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
2859
+ listGroupedAppointmentServices: {
2860
+ path: "/sites/{siteId}/bookings/services/grouped",
2861
+ method: "GET",
2862
+ auth: "user",
2863
+ responseKind: "json",
2864
+ errors: ["server:internal_error"]
2865
+ },
2866
+ reorderAppointmentServices: {
2867
+ path: "/sites/{siteId}/bookings/services/order",
2868
+ method: "PUT",
2869
+ auth: "user",
2870
+ responseKind: "json",
2871
+ errors: [
2872
+ "validation:invalid_input",
2873
+ "auth:forbidden",
2874
+ "resource:not_found",
2875
+ "resource:conflict",
2876
+ "server:internal_error"
2877
+ ]
2878
+ },
2879
+ listAppointmentServiceCategories: {
2880
+ path: "/sites/{siteId}/bookings/service-categories",
2881
+ method: "GET",
2882
+ auth: "user",
2883
+ responseKind: "json",
2884
+ errors: ["server:internal_error"]
2885
+ },
2886
+ createAppointmentServiceCategory: {
2887
+ path: "/sites/{siteId}/bookings/service-categories",
2888
+ method: "POST",
2889
+ auth: "user",
2890
+ responseKind: "json",
2891
+ errors: [
2892
+ "validation:invalid_input",
2893
+ "auth:forbidden",
2894
+ "resource:conflict",
2895
+ "server:internal_error"
2896
+ ]
2897
+ },
2898
+ updateAppointmentServiceCategory: {
2899
+ path: "/sites/{siteId}/bookings/service-categories/{categoryId}",
2900
+ method: "PUT",
2901
+ auth: "user",
2902
+ responseKind: "json",
2903
+ errors: [
2904
+ "validation:invalid_input",
2905
+ "auth:forbidden",
2906
+ "resource:not_found",
2907
+ "resource:conflict",
2908
+ "server:internal_error"
2909
+ ]
2910
+ },
2911
+ deleteAppointmentServiceCategory: {
2912
+ path: "/sites/{siteId}/bookings/service-categories/{categoryId}",
2913
+ method: "DELETE",
2914
+ auth: "user",
2915
+ responseKind: "json",
2916
+ errors: [
2917
+ "auth:forbidden",
2918
+ "resource:not_found",
2919
+ "server:internal_error"
2920
+ ]
2921
+ },
2922
+ reorderAppointmentServiceCategories: {
2923
+ path: "/sites/{siteId}/bookings/service-categories/order",
2924
+ method: "PUT",
2925
+ auth: "user",
2926
+ responseKind: "json",
2927
+ errors: [
2928
+ "validation:invalid_input",
2929
+ "auth:forbidden",
2930
+ "resource:conflict",
2931
+ "server:internal_error"
2932
+ ]
2933
+ }
2934
+ });
2794
2935
 
2795
2936
  //#endregion
2796
2937
  //#region ../api/src/appointmentEndpointDefinitions.ts
2797
2938
  const APPOINTMENT_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
2939
+ ...APPOINTMENT_SERVICE_CATEGORY_ENDPOINT_DEFINITIONS,
2798
2940
  listAppointmentResources: {
2799
2941
  path: "/sites/{siteId}/bookings/resources",
2800
2942
  method: "GET",
@@ -3945,45 +4087,23 @@ const NEWSLETTER_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
3945
4087
  auth: "user",
3946
4088
  responseKind: "json",
3947
4089
  demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
3948
- },
3949
- listNewsletterSendJobs: {
3950
- path: "/sites/{siteId}/newsletter/jobs",
3951
- method: "GET",
3952
- tags: [TAG_TEMPLATES.site, TAG_TEMPLATES.siteNewsletter],
3953
- auth: "user",
3954
- responseKind: "json"
3955
- },
3956
- retryNewsletterSendJob: {
3957
- path: "/sites/{siteId}/newsletter/jobs/{jobId}/retry",
3958
- method: "POST",
3959
- errors: [
3960
- "validation:invalid_input",
3961
- "resource:not_found",
3962
- "auth:forbidden",
3963
- "server:internal_error"
3964
- ],
3965
- tags: [TAG_TEMPLATES.site, TAG_TEMPLATES.siteNewsletter],
3966
- auth: "user",
3967
- responseKind: "json"
3968
- },
3969
- cancelNewsletterSendJob: {
3970
- path: "/sites/{siteId}/newsletter/jobs/{jobId}/cancel",
3971
- method: "POST",
3972
- errors: [
3973
- "validation:invalid_input",
3974
- "resource:not_found",
3975
- "auth:forbidden",
3976
- "server:internal_error"
3977
- ],
3978
- tags: [TAG_TEMPLATES.site, TAG_TEMPLATES.siteNewsletter],
3979
- auth: "user",
3980
- responseKind: "json"
3981
4090
  }
3982
4091
  });
3983
4092
 
3984
4093
  //#endregion
3985
4094
  //#region ../api/src/publicEventEndpointDefinitions.ts
3986
4095
  const PUBLIC_EVENT_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
4096
+ checkPublicEventRegistrationNextStep: {
4097
+ path: "/public/sites/{siteId}/events/registration-next-step",
4098
+ method: "POST",
4099
+ auth: "public",
4100
+ responseKind: "json",
4101
+ errors: [
4102
+ "validation:invalid_input",
4103
+ "auth:forbidden",
4104
+ "server:internal_error"
4105
+ ]
4106
+ },
3987
4107
  listPublicEventCalendarWindow: {
3988
4108
  path: "/public/sites/{siteId}/events/calendar-window",
3989
4109
  method: "GET",
@@ -4746,6 +4866,7 @@ const BILLING_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
4746
4866
  //#endregion
4747
4867
  //#region ../api/src/endpoints.ts
4748
4868
  const ENDPOINT_DEFINITIONS = {
4869
+ ...PUBLIC_NEWSLETTER_ENDPOINT_DEFINITIONS,
4749
4870
  ...ACCOUNT_ENDPOINT_DEFINITIONS,
4750
4871
  ...PUBLIC_ONBOARDING_ATTEMPT_ENDPOINT_DEFINITIONS,
4751
4872
  ...PUBLIC_EVENT_ENDPOINT_DEFINITIONS,
@@ -7880,41 +8001,6 @@ const ENDPOINT_DEFINITIONS = {
7880
8001
  "server:internal_error"
7881
8002
  ]
7882
8003
  },
7883
- subscribeNewsletter: {
7884
- path: "/public/sites/{siteId}/newsletter/subscribe",
7885
- method: "POST",
7886
- tags: ["public-newsletter-{siteId}"],
7887
- auth: "public",
7888
- responseKind: "json"
7889
- },
7890
- confirmNewsletter: {
7891
- path: "/public/sites/{siteId}/newsletter/confirm/{token}",
7892
- method: "GET",
7893
- tags: ["public-newsletter-{siteId}"],
7894
- auth: "public",
7895
- responseKind: "text"
7896
- },
7897
- unsubscribeNewsletter: {
7898
- path: "/public/sites/{siteId}/newsletter/unsubscribe/{token}",
7899
- method: "GET",
7900
- tags: ["public-newsletter-{siteId}"],
7901
- auth: "public",
7902
- responseKind: "text"
7903
- },
7904
- unsubscribeNewsletterPost: {
7905
- path: "/public/sites/{siteId}/newsletter/unsubscribe/{token}",
7906
- method: "POST",
7907
- tags: ["public-newsletter-{siteId}"],
7908
- auth: "public",
7909
- responseKind: "text"
7910
- },
7911
- getNewsletterArchive: {
7912
- path: "/public/sites/{siteId}/newsletter/archive/{token}",
7913
- method: "GET",
7914
- tags: ["public-newsletter-{siteId}"],
7915
- auth: "public",
7916
- responseKind: "text"
7917
- },
7918
8004
  listSiteContentTypes: {
7919
8005
  path: "/sites/{siteId}/content-types",
7920
8006
  method: "GET",
@@ -10413,6 +10499,12 @@ function matchSurfaceSiteRootHost(host) {
10413
10499
  }
10414
10500
  return matchSurfaceHost(host, SURFACE_SITE_ROOT_HOSTS);
10415
10501
  }
10502
+ function resolveSurfaceSiteHostContext(value) {
10503
+ if (value === null || value === undefined || typeof value === "string" && value.length === 0) return null;
10504
+ const normalizedHost = normalizeHostLike(value instanceof URL ? value.toString() : value);
10505
+ if (normalizedHost === null) return null;
10506
+ return matchSurfaceSiteRootHost(normalizedHost);
10507
+ }
10416
10508
  function resolveSurfaceHostContext(value) {
10417
10509
  if (value === null || value === undefined || typeof value === "string" && value.length === 0) return null;
10418
10510
  const normalizedHost = normalizeHostLike(value instanceof URL ? value.toString() : value);
@@ -10489,7 +10581,7 @@ function extractSurfaceAwareSiteSlug(value) {
10489
10581
  return null;
10490
10582
  }
10491
10583
  const hostname$1 = parsed.hostname.toLowerCase();
10492
- const context = matchSurfaceSiteRootHost(hostname$1);
10584
+ const context = resolveSurfaceSiteHostContext(hostname$1);
10493
10585
  if (context === null) return null;
10494
10586
  if (hostname$1 === context.surfaceRootHost) return null;
10495
10587
  if (!hostname$1.endsWith(`.${context.surfaceRootHost}`)) return null;
@@ -10654,20 +10746,20 @@ function isApiError(result) {
10654
10746
  function isApiSuccess(result) {
10655
10747
  return result.success === true;
10656
10748
  }
10657
- function isRecord$35(value) {
10749
+ function isRecord$36(value) {
10658
10750
  return typeof value === "object" && value !== null && !Array.isArray(value);
10659
10751
  }
10660
10752
  function isFieldError(value) {
10661
- return isRecord$35(value) && typeof value.field === "string" && typeof value.code === "string" && typeof value.message === "string";
10753
+ return isRecord$36(value) && typeof value.field === "string" && typeof value.code === "string" && typeof value.message === "string";
10662
10754
  }
10663
10755
  function fieldErrorsFromUnknown(value) {
10664
10756
  if (!Array.isArray(value)) return null;
10665
10757
  return value.every(isFieldError) ? value : null;
10666
10758
  }
10667
10759
  function extractEnvelopeErrorObject(body) {
10668
- if (!isRecord$35(body)) return null;
10760
+ if (!isRecord$36(body)) return null;
10669
10761
  const error$1 = body.error;
10670
- if (!isRecord$35(error$1)) return null;
10762
+ if (!isRecord$36(error$1)) return null;
10671
10763
  if ("success" in body && body.success !== false) {
10672
10764
  return null;
10673
10765
  }
@@ -11277,7 +11369,7 @@ const DEFAULT_CONFIG_PATH = "./riverbank.config.ts";
11277
11369
  function formatPushConfigActionFailure() {
11278
11370
  return "push-config failed";
11279
11371
  }
11280
- function isRecord$34(value) {
11372
+ function isRecord$35(value) {
11281
11373
  return typeof value === "object" && value !== null;
11282
11374
  }
11283
11375
  function parseErrorDetails(value) {
@@ -11285,10 +11377,10 @@ function parseErrorDetails(value) {
11285
11377
  if (typeof value === "string") {
11286
11378
  return { message: value };
11287
11379
  }
11288
- if (!isRecord$34(value)) return {};
11380
+ if (!isRecord$35(value)) return {};
11289
11381
  const message = typeof value.message === "string" ? value.message : undefined;
11290
11382
  const fieldErrorsRaw = value.fieldErrors;
11291
- const fieldErrors = Array.isArray(fieldErrorsRaw) ? fieldErrorsRaw.filter(isRecord$34).map((d) => ({
11383
+ const fieldErrors = Array.isArray(fieldErrorsRaw) ? fieldErrorsRaw.filter(isRecord$35).map((d) => ({
11292
11384
  field: typeof d.field === "string" ? d.field : "",
11293
11385
  message: typeof d.message === "string" ? d.message : ""
11294
11386
  })).filter((d) => d.field.length > 0 && d.message.length > 0) : undefined;
@@ -11303,7 +11395,7 @@ function formatFieldErrors(fieldErrors) {
11303
11395
  }
11304
11396
  function getDashboardErrorMessage(responseJson, fallback) {
11305
11397
  if (!responseJson) return fallback;
11306
- if (isRecord$34(responseJson) && "error" in responseJson) {
11398
+ if (isRecord$35(responseJson) && "error" in responseJson) {
11307
11399
  const parsed = parseErrorDetails(responseJson.error);
11308
11400
  const msg = parsed.message ?? fallback;
11309
11401
  return msg + formatFieldErrors(parsed.fieldErrors);
@@ -13570,7 +13662,7 @@ function resolveDashboardBookingsNavPolicy(modules, ctx) {
13570
13662
  appointments: role === "owner" ? { kind: "owner_setup" } : { kind: "hidden" }
13571
13663
  };
13572
13664
  }
13573
- function buildDashboardBookingsNavPlan(modules, ctx, verticalConfig) {
13665
+ function buildDashboardBookingsNavPlan(modules, ctx, catalogue) {
13574
13666
  const policy = resolveDashboardBookingsNavPolicy(modules, ctx);
13575
13667
  if (policy.kind === "staff_scoped") {
13576
13668
  return buildStaffScopedBookingsNavPlan(policy);
@@ -13591,7 +13683,7 @@ function buildDashboardBookingsNavPlan(modules, ctx, verticalConfig) {
13591
13683
  groups.push({
13592
13684
  label: "Events",
13593
13685
  items: modules.events ? [
13594
- ...buildEventNavItems(verticalConfig),
13686
+ ...buildEventNavItems(catalogue),
13595
13687
  {
13596
13688
  label: "Venues",
13597
13689
  destination: { kind: "venues" },
@@ -13848,59 +13940,49 @@ const bookingProductsItem = {
13848
13940
  "unlimited"
13849
13941
  ]
13850
13942
  };
13851
- function buildEventNavItems(verticalConfig) {
13852
- const resolved = resolveSiteVerticalBookingConfig(verticalConfig);
13853
- if (resolved.kind !== "configured") {
13854
- return [{
13855
- label: "Events",
13943
+ function buildEventNavItems(catalogue) {
13944
+ const entries = catalogue.source === "generic" ? catalogue.entries.filter(({ preset }) => preset === "course") : catalogue.entries;
13945
+ return [
13946
+ {
13947
+ label: catalogue.source === "generic" ? "Events" : "All events",
13856
13948
  destination: { kind: "events_all" },
13857
13949
  keywords: [
13858
- "classes",
13859
- "workshops",
13950
+ "events",
13951
+ "all events",
13860
13952
  "sessions",
13861
13953
  "recurring",
13862
13954
  "shows",
13863
- "retreats"
13955
+ ...catalogue.entries.flatMap(({ label, pluralLabel }) => [label, pluralLabel])
13864
13956
  ]
13865
- }, {
13866
- label: "Courses",
13867
- destination: { kind: "courses" },
13957
+ },
13958
+ ...entries.map(buildEventSeriesPresetNavItem),
13959
+ ...catalogue.source === "business_profile" ? [{
13960
+ label: "Other events",
13961
+ destination: { kind: "events_other" },
13868
13962
  keywords: [
13869
- "multi-session",
13870
- "paid upfront",
13871
- "enrollment",
13872
- "series",
13873
- "terms",
13874
- "programmes"
13963
+ "other",
13964
+ "one-off",
13965
+ "fundraiser",
13966
+ "open day",
13967
+ "jumble sale",
13968
+ "party",
13969
+ "uncategorised"
13875
13970
  ]
13876
- }];
13877
- }
13878
- const eventSeriesItems = resolved.selectedPresets.filter(isEventSeriesVerticalPresetDefinition).map(buildEventSeriesPresetNavItem);
13879
- return [{
13880
- label: "All events",
13881
- destination: { kind: "events_all" },
13882
- keywords: [
13883
- "events",
13884
- "all events",
13885
- ...resolved.selectedPresets.flatMap((preset) => [
13886
- preset.label,
13887
- preset.pluralLabel,
13888
- preset.canonicalBehaviour
13889
- ])
13890
- ]
13891
- }, ...eventSeriesItems];
13971
+ }] : []
13972
+ ];
13892
13973
  }
13893
- function buildEventSeriesPresetNavItem(preset) {
13974
+ function buildEventSeriesPresetNavItem(entry) {
13894
13975
  return {
13895
- label: preset.pluralLabel,
13976
+ label: entry.pluralLabel,
13896
13977
  destination: {
13897
13978
  kind: "events_preset",
13898
- preset: preset.canonicalBehaviour
13979
+ preset: entry.preset
13899
13980
  },
13900
13981
  keywords: [
13901
- preset.label,
13902
- preset.pluralLabel,
13903
- preset.canonicalBehaviour
13982
+ entry.label,
13983
+ entry.pluralLabel,
13984
+ entry.preset,
13985
+ ...entry.preset === "term" ? ["course", "courses"] : []
13904
13986
  ]
13905
13987
  };
13906
13988
  }
@@ -14617,7 +14699,8 @@ const siteOptionSources = [
14617
14699
  "eventCategories",
14618
14700
  "eventSeries",
14619
14701
  "venues",
14620
- "staffMembers"
14702
+ "staffMembers",
14703
+ "appointmentServiceCategories"
14621
14704
  ];
14622
14705
  const mediaDeliverySchema = z.object({
14623
14706
  sizes: z.string().optional(),
@@ -16626,9 +16709,7 @@ function navRow(opts) {
16626
16709
  rel: { $bind: { from: `${childItemName}.rel` } },
16627
16710
  "data-active": { $bind: { from: `${childItemName}.active` } }
16628
16711
  }, [text({ as: "span" }, bind(`${childItemName}.label`))], repeat(`${itemName}.children`, childItemName));
16629
- const dropdown = el("div", { className: "nav-dropdown rb-relative" }, [button({
16630
- type: "button",
16631
- variantId: "",
16712
+ const dropdown = el("div", { className: "nav-dropdown rb-relative" }, [el("headerControl", {
16632
16713
  className: prependClassName("nav-dropdown-trigger", linkClassName),
16633
16714
  "aria-haspopup": "menu",
16634
16715
  "aria-expanded": "false",
@@ -16696,9 +16777,7 @@ function navColumn(opts) {
16696
16777
  const dropdown = el("div", {
16697
16778
  className: "nav-mobile-dropdown",
16698
16779
  "data-nav-mobile-dropdown": "true"
16699
- }, [button({
16700
- type: "button",
16701
- variantId: "",
16780
+ }, [el("headerControl", {
16702
16781
  className: triggerClassName,
16703
16782
  "aria-expanded": "false",
16704
16783
  "aria-controls": childrenId,
@@ -20507,7 +20586,7 @@ const teamMemberFragment = defineFragment({
20507
20586
  //#region ../blocks/src/system/data/linkedContentEntries.ts
20508
20587
  const LINKED_CONTENT_ENTRY_META_KEY = "__rbLinkedContentEntry";
20509
20588
  function coerceLinkedContentEntriesPayload(payload) {
20510
- if (!isRecord$33(payload)) return payload;
20589
+ if (!isRecord$34(payload)) return payload;
20511
20590
  const response = payload;
20512
20591
  if (!Array.isArray(response.entries)) return payload;
20513
20592
  const contentType = parsePublicContentTypeMeta(response.contentType);
@@ -20515,16 +20594,16 @@ function coerceLinkedContentEntriesPayload(payload) {
20515
20594
  return response.entries.map((entry) => enrichLinkedContentEntry(entry, contentType));
20516
20595
  }
20517
20596
  function getLinkedContentEntryMeta(value) {
20518
- if (!isRecord$33(value)) return null;
20597
+ if (!isRecord$34(value)) return null;
20519
20598
  const candidate = value[LINKED_CONTENT_ENTRY_META_KEY];
20520
20599
  return isLinkedContentEntryMeta(candidate) ? candidate : null;
20521
20600
  }
20522
20601
  function buildLinkedContentEditTarget(input) {
20523
20602
  const { entry, sourceBlockId, sourceBlockKind, itemIndex } = input;
20524
- if (!isRecord$33(entry)) return null;
20603
+ if (!isRecord$34(entry)) return null;
20525
20604
  const meta = getLinkedContentEntryMeta(entry);
20526
20605
  if (!meta || meta.support.kind !== "supported") return null;
20527
- const content = isRecord$33(entry.content) ? entry.content : {};
20606
+ const content = isRecord$34(entry.content) ? entry.content : {};
20528
20607
  return {
20529
20608
  kind: "linked-content-entry",
20530
20609
  entryId: meta.entryId,
@@ -20598,12 +20677,12 @@ function resolveLinkedEntryInlineFieldEligibility(input) {
20598
20677
  };
20599
20678
  }
20600
20679
  function enrichLinkedContentEntry(entry, contentType) {
20601
- if (!isRecord$33(entry)) return entry;
20680
+ if (!isRecord$34(entry)) return entry;
20602
20681
  const entryId = typeof entry.id === "string" ? entry.id : null;
20603
20682
  if (!entryId) return entry;
20604
20683
  const title = typeof entry.title === "string" && entry.title.trim().length > 0 ? entry.title : entryId;
20605
20684
  const optimisticHash = typeof entry.optimisticHash === "string" && entry.optimisticHash.length > 0 ? entry.optimisticHash : null;
20606
- const content = isRecord$33(entry.content) ? entry.content : {};
20685
+ const content = isRecord$34(entry.content) ? entry.content : {};
20607
20686
  const meta = {
20608
20687
  kind: "linked-content-entry",
20609
20688
  entryId,
@@ -20712,7 +20791,7 @@ function capitalize(value) {
20712
20791
  return value.charAt(0).toUpperCase() + value.slice(1).toLowerCase();
20713
20792
  }
20714
20793
  function parsePublicContentTypeMeta(value) {
20715
- if (!isRecord$33(value)) return null;
20794
+ if (!isRecord$34(value)) return null;
20716
20795
  if (typeof value.key !== "string" || value.key.trim().length === 0) return null;
20717
20796
  return {
20718
20797
  key: value.key,
@@ -20722,7 +20801,7 @@ function parsePublicContentTypeMeta(value) {
20722
20801
  };
20723
20802
  }
20724
20803
  function parsePublicContentTypeLinkedEntryEditing(value) {
20725
- if (!isRecord$33(value) || typeof value.kind !== "string") return null;
20804
+ if (!isRecord$34(value) || typeof value.kind !== "string") return null;
20726
20805
  switch (value.kind) {
20727
20806
  case "generic": return { kind: "generic" };
20728
20807
  case "unsupported-domain-backed": return {
@@ -20733,7 +20812,7 @@ function parsePublicContentTypeLinkedEntryEditing(value) {
20733
20812
  }
20734
20813
  }
20735
20814
  function parsePublicContentTypeFieldMeta(value) {
20736
- if (!isRecord$33(value)) return [];
20815
+ if (!isRecord$34(value)) return [];
20737
20816
  if (typeof value.id !== "string" || typeof value.type !== "string") return [];
20738
20817
  return [{
20739
20818
  id: value.id,
@@ -20748,14 +20827,14 @@ function parseStringArray(value) {
20748
20827
  return value.filter((item) => typeof item === "string");
20749
20828
  }
20750
20829
  function isLinkedContentEntryMeta(value) {
20751
- if (!isRecord$33(value)) return false;
20830
+ if (!isRecord$34(value)) return false;
20752
20831
  if (value.kind !== "linked-content-entry") return false;
20753
20832
  if (typeof value.entryId !== "string") return false;
20754
20833
  if (typeof value.contentTypeKey !== "string") return false;
20755
20834
  if (typeof value.contentTypeLabel !== "string") return false;
20756
20835
  if (typeof value.title !== "string") return false;
20757
20836
  if (!(value.optimisticHash === null || typeof value.optimisticHash === "string")) return false;
20758
- if (!isRecord$33(value.contentType)) return false;
20837
+ if (!isRecord$34(value.contentType)) return false;
20759
20838
  if (!isLinkedEntryFieldSourceArray(value.fieldSources)) return false;
20760
20839
  return isLinkedContentEditSupport(value.support);
20761
20840
  }
@@ -20763,7 +20842,7 @@ function isLinkedEntryFieldSourceArray(value) {
20763
20842
  return Array.isArray(value) && value.every(isLinkedEntryFieldSource);
20764
20843
  }
20765
20844
  function isLinkedEntryFieldSource(value) {
20766
- if (!isRecord$33(value)) return false;
20845
+ if (!isRecord$34(value)) return false;
20767
20846
  if (typeof value.displayPath !== "string") return false;
20768
20847
  switch (value.kind) {
20769
20848
  case "content-field": return typeof value.fieldPath === "string" && (value.fieldType === "text" || value.fieldType === "richText");
@@ -20784,7 +20863,7 @@ function isLinkedEntryInlineFieldReadOnlyReason(value) {
20784
20863
  }
20785
20864
  }
20786
20865
  function isLinkedContentEditSupport(value) {
20787
- if (!isRecord$33(value) || typeof value.kind !== "string") return false;
20866
+ if (!isRecord$34(value) || typeof value.kind !== "string") return false;
20788
20867
  switch (value.kind) {
20789
20868
  case "supported": return true;
20790
20869
  case "unsupported-domain-backed":
@@ -20793,7 +20872,7 @@ function isLinkedContentEditSupport(value) {
20793
20872
  default: return false;
20794
20873
  }
20795
20874
  }
20796
- function isRecord$33(value) {
20875
+ function isRecord$34(value) {
20797
20876
  return typeof value === "object" && value !== null && !Array.isArray(value);
20798
20877
  }
20799
20878
  function describeLinkedContentEditSupport(support) {
@@ -21732,6 +21811,58 @@ const layoutTransforms = [
21732
21811
  footerLogoTextVisibleTransform
21733
21812
  ];
21734
21813
 
21814
+ //#endregion
21815
+ //#region ../blocks/src/system/transforms/registry/chromeLogo.ts
21816
+ const chromeLogoSurfaceValues = [
21817
+ "header-root",
21818
+ "header-mobile-panel",
21819
+ "footer-root"
21820
+ ];
21821
+ const chromeLogoSchema = z.object({ surface: z.enum(chromeLogoSurfaceValues) });
21822
+ /** The brand foreground shares the logo's surface; navigation may own a separate capsule. */
21823
+ function chromeSurfaceTextToken(surface, theme, palette) {
21824
+ switch (surface) {
21825
+ case "header-root": {
21826
+ const header = theme.header;
21827
+ const foreground = resolveHeaderRootForeground(header, palette, resolveHeaderVisualStyles(header).isTransparent);
21828
+ return foreground.kind === "known" ? foreground.roles.text : resolveHeaderLeafTextColor(header);
21829
+ }
21830
+ case "header-mobile-panel": return theme.header?.dropdownStyle?.textColor ?? "text";
21831
+ case "footer-root": {
21832
+ const foreground = resolveFooterRootForeground(theme.footer, palette);
21833
+ return foreground.kind === "known" ? foreground.roles.text : undefined;
21834
+ }
21835
+ }
21836
+ }
21837
+ function readChromeTheme(viewModel) {
21838
+ const root = asPartialObject(viewModel?.["$root"]);
21839
+ return asPartialObject(root?.theme) ?? {};
21840
+ }
21841
+ function resolveChromeSurfaceTone(surface, context) {
21842
+ return surfaceToneFromForegroundToken(context.theme.palette, chromeSurfaceTextToken(surface, readChromeTheme(context.viewModel), context.theme.palette));
21843
+ }
21844
+ /**
21845
+ * Picks the site logo for the surface it is drawn on. Bound from block
21846
+ * `content`: `logoVariants` when the renderer supplies both logos, otherwise
21847
+ * the single `logo` older callers pass.
21848
+ */
21849
+ const chromeLogoTransform = {
21850
+ id: "layout.chromeLogo",
21851
+ kind: "formatter",
21852
+ summary: "Select the light- or dark-background site logo for a header or footer surface",
21853
+ schema: chromeLogoSchema,
21854
+ run: (value, options, context) => {
21855
+ const content = asPartialObject(value);
21856
+ const variants = asPartialObject(content?.logoVariants);
21857
+ if (!variants) return content?.logo ?? null;
21858
+ return selectLogoVariant(resolveChromeSurfaceTone(options.surface, context), {
21859
+ forLightBackgrounds: variants.forLightBackgrounds ?? null,
21860
+ forDarkBackgrounds: variants.forDarkBackgrounds ?? null
21861
+ });
21862
+ }
21863
+ };
21864
+ const chromeLogoTransforms = [chromeLogoTransform];
21865
+
21735
21866
  //#endregion
21736
21867
  //#region ../blocks/src/system/transforms/registry/ui.ts
21737
21868
  const joinClasses$2 = (parts) => parts.filter((part) => typeof part === "string" && part.trim().length > 0).join(" ").replace(/\s+/g, " ").trim();
@@ -24514,6 +24645,33 @@ function normalizeEventCalendarDisplayMode(input) {
24514
24645
  if (isEventCalendarDisplayMode(input.variant)) return input.variant;
24515
24646
  return isEventCalendarDisplayMode(input.displayMode) ? input.displayMode : undefined;
24516
24647
  }
24648
+ /** One closed authority for the projections required by each rendered mode. */
24649
+ function resolveEventCalendarReadPlan(input) {
24650
+ const mode = normalizeEventCalendarDisplayMode(input) ?? "combined";
24651
+ switch (mode) {
24652
+ case "combined": return {
24653
+ mode,
24654
+ jobs: "both",
24655
+ readProfile: "listing-card"
24656
+ };
24657
+ case "list": return {
24658
+ mode,
24659
+ jobs: "list",
24660
+ readProfile: "listing-card"
24661
+ };
24662
+ case "calendar": return {
24663
+ mode,
24664
+ jobs: "calendar",
24665
+ readProfile: "listing-card"
24666
+ };
24667
+ case "timetable":
24668
+ case "week-board": return {
24669
+ mode,
24670
+ jobs: "calendar",
24671
+ readProfile: "timetable"
24672
+ };
24673
+ }
24674
+ }
24517
24675
  function isEventCalendarDefaultView(value) {
24518
24676
  return typeof value === "string" && eventCalendarDefaultViewValues.includes(value);
24519
24677
  }
@@ -25649,8 +25807,7 @@ function normalizeEventStaffMemberId(value) {
25649
25807
  //#endregion
25650
25808
  //#region ../blocks/src/system/blocks/events/shared/calendarWindow.ts
25651
25809
  function resolveCalendarReadProfile(content) {
25652
- const mode = normalizeEventCalendarDisplayMode(content);
25653
- return mode === "timetable" || mode === "week-board" ? "timetable" : "listing-card";
25810
+ return resolveEventCalendarReadPlan(content).readProfile;
25654
25811
  }
25655
25812
  /** Runtime picker sentinels and bound loader IDs must describe the same query. */
25656
25813
  function normalizeCalendarFilterId(value) {
@@ -25879,8 +26036,8 @@ const eventCalendarReadEnabled = {
25879
26036
  schema: readJobSchema,
25880
26037
  run(value, options) {
25881
26038
  const content = asPartialObject(value) ?? {};
25882
- const mode = normalizeEventCalendarDisplayMode(content) ?? "combined";
25883
- return options.job === "calendar" ? mode !== "list" : mode === "list" || mode === "combined";
26039
+ const plan = resolveEventCalendarReadPlan(content);
26040
+ return plan.jobs === "both" || plan.jobs === options.job;
25884
26041
  }
25885
26042
  };
25886
26043
 
@@ -25892,6 +26049,7 @@ const builtinTransformDefinitions = [
25892
26049
  eventCalendarReadProfile,
25893
26050
  ...formattingTransforms,
25894
26051
  ...layoutTransforms,
26052
+ ...chromeLogoTransforms,
25895
26053
  ...uiTransforms,
25896
26054
  ...mediaTransforms,
25897
26055
  ...backgroundTransforms,
@@ -26062,12 +26220,12 @@ function Grid({ as: Comp = "div", cols, userColumns, gap = "md", className, styl
26062
26220
 
26063
26221
  //#endregion
26064
26222
  //#region ../blocks/src/system/runtime/nodes/layout.tsx
26065
- const SectionNode = ({ blockId: _blockId, blockKind: _blockKind, blockContent: _blockContent, fragmentRegistry: _fragmentRegistry, previewAuthoring: _previewAuthoring, pathBase: _pathBase, ...props$1 }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Section_default, { ...props$1 });
26066
- const StackNode = ({ blockId: _blockId, blockKind: _blockKind, blockContent: _blockContent, fragmentRegistry: _fragmentRegistry, previewAuthoring: _previewAuthoring, pathBase: _pathBase, ...props$1 }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Stack, { ...props$1 });
26067
- const InlineNode = ({ blockId: _blockId, blockKind: _blockKind, blockContent: _blockContent, fragmentRegistry: _fragmentRegistry, previewAuthoring: _previewAuthoring, pathBase: _pathBase, ...props$1 }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Inline, { ...props$1 });
26068
- const GridNode = ({ blockId: _blockId, blockKind: _blockKind, blockContent: _blockContent, fragmentRegistry: _fragmentRegistry, previewAuthoring: _previewAuthoring, pathBase: _pathBase, ...props$1 }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Grid, { ...props$1 });
26069
- const DivNode = ({ blockId: _blockId, blockKind: _blockKind, blockContent: _blockContent, fragmentRegistry: _fragmentRegistry, previewAuthoring: _previewAuthoring, pathBase: _pathBase, ...props$1 }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { ...props$1 });
26070
- const FigureNode = ({ blockId: _blockId, blockKind: _blockKind, blockContent: _blockContent, fragmentRegistry: _fragmentRegistry, previewAuthoring: _previewAuthoring, pathBase: _pathBase, ...props$1 }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("figure", { ...props$1 });
26223
+ const SectionNode = (props$1) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Section_default, { ...props$1 });
26224
+ const StackNode = (props$1) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Stack, { ...props$1 });
26225
+ const InlineNode = (props$1) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Inline, { ...props$1 });
26226
+ const GridNode = (props$1) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Grid, { ...props$1 });
26227
+ const DivNode = (props$1) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { ...props$1 });
26228
+ const FigureNode = (props$1) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("figure", { ...props$1 });
26071
26229
 
26072
26230
  //#endregion
26073
26231
  //#region ../path-utils/dist/redirectPaths.js
@@ -26248,11 +26406,11 @@ function assertSafePathSegments(segments) {
26248
26406
  }
26249
26407
  }
26250
26408
  }
26251
- function isRecord$32(value) {
26409
+ function isRecord$33(value) {
26252
26410
  return typeof value === "object" && value !== null && !Array.isArray(value);
26253
26411
  }
26254
26412
  function isPathContainer(value) {
26255
- return Array.isArray(value) || isRecord$32(value);
26413
+ return Array.isArray(value) || isRecord$33(value);
26256
26414
  }
26257
26415
  function createPathContainer(nextIsIndex) {
26258
26416
  return nextIsIndex ? [] : {};
@@ -26557,6 +26715,139 @@ function Text$1({ as: Comp = "span", children, className = "", path: path$3, max
26557
26715
  });
26558
26716
  }
26559
26717
 
26718
+ //#endregion
26719
+ //#region ../logger/src/noop.ts
26720
+ const noop = () => {};
26721
+ const logger = {
26722
+ debug: noop,
26723
+ info: noop,
26724
+ warn: noop,
26725
+ error: noop,
26726
+ withFields: (_) => logger
26727
+ };
26728
+
26729
+ //#endregion
26730
+ //#region ../blocks/src/system/runtime/nodes/richText-coerce.ts
26731
+ function parseRichTextDoc(value) {
26732
+ const parsed = RichTextDocSchema.safeParse(value);
26733
+ if (parsed.success) {
26734
+ return {
26735
+ kind: "valid",
26736
+ doc: parsed.data
26737
+ };
26738
+ }
26739
+ return {
26740
+ kind: "invalid",
26741
+ issues: parsed.error.issues.map((issue$1) => ({
26742
+ path: issue$1.path.map((segment) => String(segment)),
26743
+ message: issue$1.message
26744
+ }))
26745
+ };
26746
+ }
26747
+ function coerceRichTextDoc(value, source) {
26748
+ const parsed = parseRichTextDoc(value);
26749
+ if (parsed.kind === "valid") return parsed.doc;
26750
+ if (value !== null && value !== undefined) {
26751
+ logger.warn("blocks:rich-text:invalid-document", {
26752
+ source,
26753
+ issues: parsed.issues.slice(0, 3)
26754
+ });
26755
+ }
26756
+ return null;
26757
+ }
26758
+
26759
+ //#endregion
26760
+ //#region ../blocks/src/system/runtime/nodes/renderInlineText.tsx
26761
+ function renderInlineText(value) {
26762
+ return value.map((run, index) => renderRun(run, index));
26763
+ }
26764
+ function renderRun(run, key) {
26765
+ return (run.marks ?? []).reduceRight((child, mark, index) => renderMark(mark, `${String(key)}-${index}`, child), run.text);
26766
+ }
26767
+ function renderMark(mark, key, child) {
26768
+ switch (mark.kind) {
26769
+ case "strong": return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: child }, key);
26770
+ case "emphasis": return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("em", { children: child }, key);
26771
+ case "accent": return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
26772
+ className: `rb-inline-text-accent rb-inline-text-accent-${mark.tone}`,
26773
+ children: child
26774
+ }, key);
26775
+ case "highlight": return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
26776
+ className: `rb-inline-text-highlight rb-inline-text-highlight-${mark.tone}`,
26777
+ children: child
26778
+ }, key);
26779
+ }
26780
+ }
26781
+
26782
+ //#endregion
26783
+ //#region ../blocks/src/system/runtime/nodes/spinner.tsx
26784
+ function resolveColorStyle(color) {
26785
+ switch (color) {
26786
+ case undefined: return undefined;
26787
+ case "inherit": return { color: "inherit" };
26788
+ case "foreground": return { color: "rgb(var(--tb-foreground))" };
26789
+ case "text": return { color: "rgb(var(--tb-text))" };
26790
+ case "primary":
26791
+ default: return undefined;
26792
+ }
26793
+ }
26794
+ function SpinnerNode({ className, size = "md", color, strokeWidth = 3, srLabel, style, ...rest }) {
26795
+ const hasExplicitAriaLabel = typeof rest["aria-label"] === "string" && rest["aria-label"].trim().length > 0;
26796
+ const accessibilityProps = srLabel ? {
26797
+ role: "status",
26798
+ "aria-live": "polite"
26799
+ } : hasExplicitAriaLabel ? {} : { "aria-hidden": true };
26800
+ const trackStroke = color === "inherit" ? "currentColor" : "var(--rb-spinner-track-color)";
26801
+ const trackOpacity = color === "inherit" ? .25 : 1;
26802
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
26803
+ ...accessibilityProps,
26804
+ className: clsx_default("rb-spinner", size ? `rb-spinner--${size}` : null, color === "inherit" ? "rb-spinner--inherit" : null, className),
26805
+ style: {
26806
+ ...resolveColorStyle(color),
26807
+ ...style ?? {}
26808
+ },
26809
+ ...rest,
26810
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", {
26811
+ viewBox: "0 0 24 24",
26812
+ fill: "none",
26813
+ "aria-hidden": "true",
26814
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", {
26815
+ cx: "12",
26816
+ cy: "12",
26817
+ r: "10",
26818
+ stroke: trackStroke,
26819
+ strokeWidth,
26820
+ opacity: trackOpacity
26821
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", {
26822
+ d: "M12 2a10 10 0 0 1 10 10",
26823
+ stroke: "currentColor",
26824
+ strokeWidth,
26825
+ strokeLinecap: "round"
26826
+ })]
26827
+ }), srLabel ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
26828
+ className: "rb-sr-only",
26829
+ children: srLabel
26830
+ }) : null]
26831
+ });
26832
+ }
26833
+
26834
+ //#endregion
26835
+ //#region ../blocks/src/system/runtime/nodes/buttonAffordance.ts
26836
+ function normalize$3(value) {
26837
+ const trimmed = typeof value === "string" ? value.trim() : "";
26838
+ return trimmed.length > 0 ? trimmed : null;
26839
+ }
26840
+ /**
26841
+ * Resolve the node-authored trailing affordance, or `null` when no icon exists.
26842
+ */
26843
+ function resolveButtonAffordance(input) {
26844
+ const nodeIcon = normalize$3(input.trailingIcon);
26845
+ if (nodeIcon) {
26846
+ return { iconId: nodeIcon };
26847
+ }
26848
+ return null;
26849
+ }
26850
+
26560
26851
  //#endregion
26561
26852
  //#region ../blocks/src/system/icons/svg.tsx
26562
26853
  function createIcon(displayName, children) {
@@ -27700,89 +27991,146 @@ function getIconComponent(name) {
27700
27991
  }
27701
27992
 
27702
27993
  //#endregion
27703
- //#region ../blocks/src/system/runtime/nodes/buttonAffordance.ts
27704
- function normalize$3(value) {
27705
- const trimmed = typeof value === "string" ? value.trim() : "";
27706
- return trimmed.length > 0 ? trimmed : null;
27994
+ //#region ../blocks/src/system/runtime/shared/components/ThemedButton.tsx
27995
+ function themedButtonClasses(variant, size, extraClassName) {
27996
+ return [
27997
+ ...themeButtonVariantClassNames(variant),
27998
+ themeButtonSizeClassName(size),
27999
+ extraClassName
28000
+ ].filter(Boolean).join(" ");
27707
28001
  }
27708
- /**
27709
- * Resolve the node-authored trailing affordance, or `null` when no icon exists.
27710
- */
27711
- function resolveButtonAffordance(input) {
27712
- const nodeIcon = normalize$3(input.trailingIcon);
27713
- if (nodeIcon) {
27714
- return { iconId: nodeIcon };
27715
- }
27716
- return null;
28002
+ function ThemedButtonLabel(props$1) {
28003
+ const content = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
28004
+ props$1.pending ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SpinnerNode, {
28005
+ size: props$1.pending.spinnerSize ?? "sm",
28006
+ color: "inherit",
28007
+ className: props$1.pending.spinnerClassName ?? "rb-mr-2",
28008
+ srLabel: props$1.pending.srLabel
28009
+ }) : null,
28010
+ props$1.labelClassName ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
28011
+ className: props$1.labelClassName,
28012
+ children: props$1.pending?.label ?? props$1.label
28013
+ }) : props$1.pending?.label ?? props$1.label,
28014
+ props$1.screenReaderSuffix ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
28015
+ className: "rb-sr-only",
28016
+ children: props$1.screenReaderSuffix
28017
+ }) : null
28018
+ ] });
28019
+ return props$1.pending?.contentClassName ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
28020
+ className: props$1.pending.contentClassName,
28021
+ children: content
28022
+ }) : content;
27717
28023
  }
27718
-
27719
- //#endregion
27720
- //#region ../logger/src/noop.ts
27721
- const noop = () => {};
27722
- const logger = {
27723
- debug: noop,
27724
- info: noop,
27725
- warn: noop,
27726
- error: noop,
27727
- withFields: (_) => logger
27728
- };
27729
-
27730
- //#endregion
27731
- //#region ../blocks/src/system/runtime/nodes/richText-coerce.ts
27732
- function parseRichTextDoc(value) {
27733
- const parsed = RichTextDocSchema.safeParse(value);
27734
- if (parsed.success) {
27735
- return {
27736
- kind: "valid",
27737
- doc: parsed.data
27738
- };
27739
- }
27740
- return {
27741
- kind: "invalid",
27742
- issues: parsed.error.issues.map((issue$1) => ({
27743
- path: issue$1.path.map((segment) => String(segment)),
27744
- message: issue$1.message
27745
- }))
27746
- };
28024
+ function ThemedButton({ variant, size, extraClassName, screenReaderSuffix, labelClassName, pending, label, ...buttonProps }) {
28025
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
28026
+ ...buttonProps,
28027
+ className: themedButtonClasses(variant, size, extraClassName),
28028
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ThemedButtonLabel, {
28029
+ label,
28030
+ pending,
28031
+ screenReaderSuffix,
28032
+ labelClassName
28033
+ })
28034
+ });
27747
28035
  }
27748
- function coerceRichTextDoc(value, source) {
27749
- const parsed = parseRichTextDoc(value);
27750
- if (parsed.kind === "valid") return parsed.doc;
27751
- if (value !== null && value !== undefined) {
27752
- logger.warn("blocks:rich-text:invalid-document", {
27753
- source,
27754
- issues: parsed.issues.slice(0, 3)
27755
- });
27756
- }
27757
- return null;
28036
+ function ThemedButtonLink({ variant, size, extraClassName, screenReaderSuffix, labelClassName, label, ...anchorProps }) {
28037
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", {
28038
+ ...anchorProps,
28039
+ className: themedButtonClasses(variant, size, extraClassName),
28040
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ThemedButtonLabel, {
28041
+ label,
28042
+ screenReaderSuffix,
28043
+ labelClassName
28044
+ })
28045
+ });
27758
28046
  }
27759
-
27760
- //#endregion
27761
- //#region ../blocks/src/system/runtime/nodes/renderInlineText.tsx
27762
- function renderInlineText(value) {
27763
- return value.map((run, index) => renderRun(run, index));
28047
+ /** Noninteractive button-style preview with no caller-owned markup. */
28048
+ function ThemedButtonSpecimen({ variant, size, label, extraClassName, forceHover = false }) {
28049
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
28050
+ "data-force-hover": forceHover ? "true" : undefined,
28051
+ className: themedButtonClasses(variant, size, extraClassName),
28052
+ children: label
28053
+ });
28054
+ }
28055
+ /** Fixed icon-only actions control; callers cannot supply icon children. */
28056
+ function ThemedActionsButton({ variant, size, extraClassName, ...buttonProps }) {
28057
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
28058
+ ...buttonProps,
28059
+ "aria-label": "Actions",
28060
+ className: themedButtonClasses(variant, size, extraClassName),
28061
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", {
28062
+ width: "16",
28063
+ height: "16",
28064
+ viewBox: "0 0 16 16",
28065
+ fill: "currentColor",
28066
+ "aria-hidden": "true",
28067
+ children: [
28068
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", {
28069
+ cx: "8",
28070
+ cy: "3",
28071
+ r: "1.5"
28072
+ }),
28073
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", {
28074
+ cx: "8",
28075
+ cy: "8",
28076
+ r: "1.5"
28077
+ }),
28078
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", {
28079
+ cx: "8",
28080
+ cy: "13",
28081
+ r: "1.5"
28082
+ })
28083
+ ]
28084
+ })
28085
+ });
27764
28086
  }
27765
- function renderRun(run, key) {
27766
- return (run.marks ?? []).reduceRight((child, mark, index) => renderMark(mark, `${String(key)}-${index}`, child), run.text);
28087
+ /** Fixed semantic download affordance; callers cannot supply arbitrary icon children. */
28088
+ function ThemedDownloadLink({ variant, size, extraClassName, label, screenReaderSuffix, labelClassName, ...anchorProps }) {
28089
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("a", {
28090
+ ...anchorProps,
28091
+ className: themedButtonClasses(variant, size, extraClassName),
28092
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(DownloadIcon, {
28093
+ "aria-hidden": "true",
28094
+ size: 24
28095
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ThemedButtonLabel, {
28096
+ label,
28097
+ screenReaderSuffix,
28098
+ labelClassName
28099
+ })]
28100
+ });
27767
28101
  }
27768
- function renderMark(mark, key, child) {
27769
- switch (mark.kind) {
27770
- case "strong": return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: child }, key);
27771
- case "emphasis": return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("em", { children: child }, key);
27772
- case "accent": return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
27773
- className: `rb-inline-text-accent rb-inline-text-accent-${mark.tone}`,
27774
- children: child
27775
- }, key);
27776
- case "highlight": return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
27777
- className: `rb-inline-text-highlight rb-inline-text-highlight-${mark.tone}`,
27778
- children: child
27779
- }, key);
27780
- }
28102
+ /** Boundary for authored button nodes and their registry-backed trailing icon. */
28103
+ function ThemedAuthoredButton({ label, href, variant, size, extraClassName, disabled, type = "button", target, rel, ariaLabel, dataTestId, trailingIcon, onClick }) {
28104
+ const affordance = resolveButtonAffordance({ trailingIcon });
28105
+ const Icon = affordance ? getIconComponent(affordance.iconId) : null;
28106
+ const className = variant ? themedButtonClasses(variant, size, Icon ? [extraClassName, themeButtonExtraClassesWithTrailingIcon()].filter(Boolean).join(" ") : extraClassName) : extraClassName ?? undefined;
28107
+ const content = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [label, Icon ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, {
28108
+ "aria-hidden": true,
28109
+ className: "rb-ml-2 rb-h-4 rb-w-4 rb-inline-block"
28110
+ }) : null] });
28111
+ return href ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", {
28112
+ href,
28113
+ target,
28114
+ rel,
28115
+ "aria-label": ariaLabel,
28116
+ "data-testid": dataTestId,
28117
+ className,
28118
+ onClick,
28119
+ children: content
28120
+ }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
28121
+ type,
28122
+ disabled,
28123
+ "aria-label": ariaLabel,
28124
+ "data-testid": dataTestId,
28125
+ className,
28126
+ onClick,
28127
+ children: content
28128
+ });
27781
28129
  }
27782
28130
 
27783
28131
  //#endregion
27784
28132
  //#region ../blocks/src/system/runtime/nodes/basic.tsx
27785
- const TextNode = ({ value, children, blockId: _blockId, blockKind: _blockKind, blockContent, fragmentRegistry: _fragmentRegistry, pathBase: _pathBase, inlineTextFallbackPath, ...rest }) => {
28133
+ const TextNode = ({ value, children, blockContent, inlineTextFallbackPath, ...rest }) => {
27786
28134
  const inlineText = parseInlineTextFromUnknown(value);
27787
28135
  if (inlineText.ok && !isInlineTextEmpty(inlineText.value)) {
27788
28136
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text$1, {
@@ -27805,37 +28153,23 @@ function readStringPath(source, path$3) {
27805
28153
  const value = getAtPath(source, path$3);
27806
28154
  return typeof value === "string" ? value : null;
27807
28155
  }
27808
- const RichTextNode = ({ value, blockId: _blockId, blockKind: _blockKind, blockContent: _blockContent, fragmentRegistry: _fragmentRegistry, pathBase: _pathBase, ...rest }) => {
27809
- const source = `block-runtime:${_blockKind ?? "unknown"}:${rest.path ?? "richText"}`;
28156
+ const RichTextNode = ({ value, blockKind, ...rest }) => {
28157
+ const source = `block-runtime:${blockKind ?? "unknown"}:${rest.path ?? "richText"}`;
27810
28158
  const doc = coerceRichTextDoc(value, source);
27811
28159
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RichText$1, {
27812
28160
  doc: doc ?? undefined,
27813
28161
  ...rest
27814
28162
  });
27815
28163
  };
27816
- /**
27817
- * Render the resolved trailing affordance icon using the button's foreground.
27818
- */
27819
- function renderTrailingAffordanceIcon(affordance) {
27820
- if (!affordance) return null;
27821
- const Icon = getIconComponent(affordance.iconId);
27822
- if (!Icon) return null;
27823
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, {
27824
- "aria-hidden": true,
27825
- className: "rb-ml-2 rb-h-4 rb-w-4 rb-inline-block"
27826
- });
27827
- }
27828
28164
  function isMissingRequiredLink(linkRequired, resolvedHref) {
27829
28165
  return linkRequired && resolvedHref.length === 0;
27830
28166
  }
27831
- const ButtonNode = ({ value, children, href, variantId = "primary", size = "md", disabled, type = "button", target, rel, linkRequired = false, trailingIcon, blockId: _blockId, blockKind: _blockKind, blockContent: _blockContent, fragmentRegistry: _fragmentRegistry, pathBase: _pathBase, className, ...rest }) => {
28167
+ const ButtonNode = ({ value, children, href, variantId = "primary", size = "md", disabled, type = "button", target, rel, linkRequired = false, trailingIcon, onClick, className, ...rest }) => {
27832
28168
  const content = value ?? children;
27833
28169
  if (!content) {
27834
28170
  console.warn("[ButtonNode] No content to render - value and children are both empty");
27835
28171
  return null;
27836
28172
  }
27837
- const affordance = resolveButtonAffordance({ trailingIcon });
27838
- const affordanceIcon = renderTrailingAffordanceIcon(affordance);
27839
28173
  const resolvedHref = typeof href === "string" ? href.trim() : "";
27840
28174
  if (isMissingRequiredLink(linkRequired, resolvedHref)) {
27841
28175
  if (process.env.NODE_ENV === "development") {
@@ -27848,31 +28182,23 @@ const ButtonNode = ({ value, children, href, variantId = "primary", size = "md",
27848
28182
  console.error("[ButtonNode] Invalid button variant", { variantId });
27849
28183
  return null;
27850
28184
  }
27851
- const buildClassName = affordanceIcon ? themeButtonClassNameWithTrailingIcon : themeButtonClassName;
27852
- const combinedClassName = resolvedVariantId ? buildClassName({
27853
- variant: resolvedVariantId,
28185
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ThemedAuthoredButton, {
28186
+ label: content,
28187
+ href: resolvedHref || undefined,
28188
+ target,
28189
+ rel,
28190
+ variant: resolvedVariantId ?? null,
27854
28191
  size,
27855
- extraClassName: className
27856
- }) : className;
27857
- if (resolvedHref) {
27858
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("a", {
27859
- href: resolvedHref,
27860
- target,
27861
- rel,
27862
- className: combinedClassName,
27863
- ...rest,
27864
- children: [content, affordanceIcon]
27865
- });
27866
- }
27867
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", {
27868
- type,
27869
28192
  disabled,
27870
- className: combinedClassName,
27871
- ...rest,
27872
- children: [content, affordanceIcon]
28193
+ type,
28194
+ trailingIcon,
28195
+ onClick,
28196
+ extraClassName: className,
28197
+ ariaLabel: rest["aria-label"],
28198
+ dataTestId: rest["data-testid"]
27873
28199
  });
27874
28200
  };
27875
- const LinkNode = ({ href, children, className, target, rel, linkRequired = false, blockId: _blockId, blockKind: _blockKind, blockContent: _blockContent, fragmentRegistry: _fragmentRegistry, pathBase: _pathBase, ...rest }) => {
28201
+ const LinkNode = ({ href, children, className, target, rel, linkRequired = false, ...rest }) => {
27876
28202
  if (!children) return null;
27877
28203
  const resolvedHref = typeof href === "string" ? href.trim() : "";
27878
28204
  if (resolvedHref.length === 0) {
@@ -27944,7 +28270,7 @@ function parseApprovedIconExampleSetId(value) {
27944
28270
  //#endregion
27945
28271
  //#region ../blocks/src/system/icons/value.ts
27946
28272
  const NO_BLOCK_ICON_VALUE = { kind: "none" };
27947
- function isRecord$31(value) {
28273
+ function isRecord$32(value) {
27948
28274
  return typeof value === "object" && value !== null && !Array.isArray(value);
27949
28275
  }
27950
28276
  function parseBlockIconValue(value) {
@@ -27954,7 +28280,7 @@ function parseBlockIconValue(value) {
27954
28280
  iconId: value
27955
28281
  };
27956
28282
  }
27957
- if (!isRecord$31(value)) {
28283
+ if (!isRecord$32(value)) {
27958
28284
  return NO_BLOCK_ICON_VALUE;
27959
28285
  }
27960
28286
  switch (value.kind) {
@@ -28047,7 +28373,7 @@ function buildGeneratedBlockIconRenderAssetLookupFromUnknown(value) {
28047
28373
  }
28048
28374
  const inputs = [];
28049
28375
  for (const [index, item] of value.entries()) {
28050
- if (!isRecord$31(item)) {
28376
+ if (!isRecord$32(item)) {
28051
28377
  return {
28052
28378
  kind: "invalid_asset_entry",
28053
28379
  index,
@@ -28115,7 +28441,7 @@ function resolveBlockIconRenderValue(value, generatedAssets = new Map()) {
28115
28441
  }
28116
28442
  }
28117
28443
  function getGeneratedBlockIconStyleState(value, currentStyleGuideVersionId) {
28118
- if (isRecord$31(value) && value.kind === "generated" && parseBlockIconValue(value).kind !== "generated") {
28444
+ if (isRecord$32(value) && value.kind === "generated" && parseBlockIconValue(value).kind !== "generated") {
28119
28445
  return { kind: "invalid_generated" };
28120
28446
  }
28121
28447
  const parsed = parseBlockIconValue(value);
@@ -28201,11 +28527,11 @@ function resolveFeatureCardGeneratedIconSizePx(value) {
28201
28527
  const parsed = parseFeatureCardGeneratedIconSizePx(value);
28202
28528
  return parsed.ok ? parsed.value : unsafeAsFeatureCardGeneratedIconSizePx(FEATURE_CARD_GENERATED_ICON_SIZE_PX.default);
28203
28529
  }
28204
- function isRecord$30(value) {
28530
+ function isRecord$31(value) {
28205
28531
  return typeof value === "object" && value !== null && !Array.isArray(value);
28206
28532
  }
28207
28533
  function toPlainTextFromTipTap(value) {
28208
- if (!isRecord$30(value)) return "";
28534
+ if (!isRecord$31(value)) return "";
28209
28535
  if (typeof value.text === "string") return value.text;
28210
28536
  const content = value.content;
28211
28537
  if (!Array.isArray(content)) return "";
@@ -28262,7 +28588,7 @@ function suggestSemanticIconForFeatureCard(card) {
28262
28588
 
28263
28589
  //#endregion
28264
28590
  //#region ../blocks/src/system/icons/generatedAssets.ts
28265
- function isRecord$29(value) {
28591
+ function isRecord$30(value) {
28266
28592
  return typeof value === "object" && value !== null && !Array.isArray(value);
28267
28593
  }
28268
28594
  function generatedIconAssetRefKey(ref) {
@@ -28272,11 +28598,11 @@ function collectGeneratedIconAssetRefs(page) {
28272
28598
  const blocks = [];
28273
28599
  for (const block of page.blocks) {
28274
28600
  if (block.kind !== "block.feature-cards" || typeof block.id !== "string") continue;
28275
- const content = isRecord$29(block.draftContent) ? block.draftContent : isRecord$29(block.content) ? block.content : null;
28601
+ const content = isRecord$30(block.draftContent) ? block.draftContent : isRecord$30(block.content) ? block.content : null;
28276
28602
  const cards = Array.isArray(content?.cards) ? content.cards : [];
28277
28603
  const refs = new Map();
28278
28604
  for (const card of cards) {
28279
- if (!isRecord$29(card)) continue;
28605
+ if (!isRecord$30(card)) continue;
28280
28606
  const icon$1 = parseBlockIconValue(card.icon);
28281
28607
  if (icon$1.kind !== "generated") continue;
28282
28608
  const ref = {
@@ -28496,18 +28822,13 @@ function FileDownloadNode({ value, title, description, buttonLabel, buttonVarian
28496
28822
  })
28497
28823
  ]
28498
28824
  })]
28499
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("a", {
28825
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ThemedDownloadLink, {
28500
28826
  href,
28501
28827
  download: filename,
28502
- className: themeButtonClassName({
28503
- variant,
28504
- size: "md",
28505
- extraClassName: "rb-inline-flex rb-shrink-0 rb-items-center rb-justify-center rb-gap-2"
28506
- }),
28507
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(DownloadIcon, {
28508
- "aria-hidden": "true",
28509
- size: 24
28510
- }), label]
28828
+ variant,
28829
+ size: "md",
28830
+ extraClassName: "rb-inline-flex rb-shrink-0 rb-items-center rb-justify-center rb-gap-2",
28831
+ label
28511
28832
  })]
28512
28833
  })
28513
28834
  })
@@ -29171,54 +29492,19 @@ const HeaderSectionNode = ({ blockId, children, className, runtime, "data-previe
29171
29492
  var header_section_server_default = markEditableSurfaceForwarding(HeaderSectionNode);
29172
29493
 
29173
29494
  //#endregion
29174
- //#region ../blocks/src/system/runtime/nodes/spinner.tsx
29175
- function resolveColorStyle(color) {
29176
- switch (color) {
29177
- case undefined: return undefined;
29178
- case "inherit": return { color: "inherit" };
29179
- case "foreground": return { color: "rgb(var(--tb-foreground))" };
29180
- case "text": return { color: "rgb(var(--tb-text))" };
29181
- case "primary":
29182
- default: return undefined;
29183
- }
29184
- }
29185
- function SpinnerNode({ className, size = "md", color, strokeWidth = 3, srLabel, style, ...rest }) {
29186
- const hasExplicitAriaLabel = typeof rest["aria-label"] === "string" && rest["aria-label"].trim().length > 0;
29187
- const accessibilityProps = srLabel ? {
29188
- role: "status",
29189
- "aria-live": "polite"
29190
- } : hasExplicitAriaLabel ? {} : { "aria-hidden": true };
29191
- const trackStroke = color === "inherit" ? "currentColor" : "var(--rb-spinner-track-color)";
29192
- const trackOpacity = color === "inherit" ? .25 : 1;
29193
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
29194
- ...accessibilityProps,
29195
- className: clsx_default("rb-spinner", size ? `rb-spinner--${size}` : null, color === "inherit" ? "rb-spinner--inherit" : null, className),
29196
- style: {
29197
- ...resolveColorStyle(color),
29198
- ...style ?? {}
29199
- },
29200
- ...rest,
29201
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", {
29202
- viewBox: "0 0 24 24",
29203
- fill: "none",
29204
- "aria-hidden": "true",
29205
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", {
29206
- cx: "12",
29207
- cy: "12",
29208
- r: "10",
29209
- stroke: trackStroke,
29210
- strokeWidth,
29211
- opacity: trackOpacity
29212
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", {
29213
- d: "M12 2a10 10 0 0 1 10 10",
29214
- stroke: "currentColor",
29215
- strokeWidth,
29216
- strokeLinecap: "round"
29217
- })]
29218
- }), srLabel ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
29219
- className: "rb-sr-only",
29220
- children: srLabel
29221
- }) : null]
29495
+ //#region ../blocks/src/system/runtime/nodes/header-control.tsx
29496
+ /** System navigation controls retain their runtime hooks independently of authored CTAs. */
29497
+ function HeaderControlNode({ className, children, "aria-label": label, "aria-expanded": expanded, "aria-controls": controls, "aria-haspopup": hasPopup, "data-nav-mobile-toggle": mobileToggle, "data-nav-mobile-trigger": mobileTrigger }) {
29498
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
29499
+ type: "button",
29500
+ className,
29501
+ "aria-label": label,
29502
+ "aria-expanded": expanded,
29503
+ "aria-controls": controls,
29504
+ "aria-haspopup": hasPopup,
29505
+ "data-nav-mobile-toggle": mobileToggle,
29506
+ "data-nav-mobile-trigger": mobileTrigger,
29507
+ children
29222
29508
  });
29223
29509
  }
29224
29510
 
@@ -29419,18 +29705,43 @@ const publicAppointmentServiceSchema = z.object({
29419
29705
  pricing: publicPricingSchema.optional(),
29420
29706
  priceAmount: z.number().nullable(),
29421
29707
  priceCurrency: z.string().nullable(),
29422
- location: publicLocationSchema
29708
+ location: publicLocationSchema,
29709
+ categoryId: z.string().nullable().optional().transform((value) => value ?? null)
29710
+ });
29711
+ const publicServiceCategorySchema = z.object({
29712
+ id: z.string().min(1),
29713
+ name: z.string(),
29714
+ description: z.string().nullable().optional().transform((value) => value ?? null)
29423
29715
  });
29424
- const publicAppointmentServicesSchema = z.array(publicAppointmentServiceSchema);
29716
+ /**
29717
+ * The loader hands over the catalogue `{ services, categories }` (issue 1403).
29718
+ * A bare services array is still accepted and read as a site with no
29719
+ * categories, so callers from before categories keep the flat list.
29720
+ */
29721
+ const publicAppointmentServicesSchema = z.union([z.array(publicAppointmentServiceSchema).transform((services) => ({
29722
+ services,
29723
+ categories: []
29724
+ })), z.object({
29725
+ services: z.array(publicAppointmentServiceSchema),
29726
+ categories: z.array(publicServiceCategorySchema)
29727
+ })]);
29425
29728
  const EMPTY_MESSAGE = "No appointments are available right now.";
29426
29729
  const ERROR_MESSAGE = "Appointments are temporarily unavailable. Please try again shortly.";
29730
+ const OTHER_GROUP_KEY = "other";
29731
+ const OTHER_GROUP_HEADING = "Other";
29427
29732
  function parseServices(value) {
29428
29733
  const result = publicAppointmentServicesSchema.safeParse(value);
29429
29734
  return result.success ? {
29430
29735
  kind: "valid",
29431
- services: result.data
29736
+ services: result.data.services,
29737
+ categories: result.data.categories
29432
29738
  } : { kind: "invalid" };
29433
29739
  }
29740
+ function readCategoryFilter(value) {
29741
+ if (typeof value !== "string") return null;
29742
+ const trimmed = value.trim();
29743
+ return trimmed.length > 0 ? trimmed : null;
29744
+ }
29434
29745
  function formatAppointmentDuration(durationMinutes) {
29435
29746
  return `${durationMinutes} min`;
29436
29747
  }
@@ -29504,8 +29815,44 @@ function buildRows(services, pathname, servicePathPrefix) {
29504
29815
  detailsHref: servicePathPrefix && service.slug ? `${servicePathPrefix.replace(/\/$/, "")}/${encodeURIComponent(service.slug)}` : null
29505
29816
  }));
29506
29817
  }
29818
+ const EMPTY_VIEW = {
29819
+ kind: "empty",
29820
+ message: EMPTY_MESSAGE
29821
+ };
29822
+ function categoryGroup(category, services, toRows) {
29823
+ return {
29824
+ key: category.id,
29825
+ heading: category.name,
29826
+ intro: category.description,
29827
+ rows: toRows(services)
29828
+ };
29829
+ }
29830
+ function viewFromLayout(layout, toRows) {
29831
+ switch (layout.kind) {
29832
+ case "uncategorized-site": return layout.services.length === 0 ? EMPTY_VIEW : {
29833
+ kind: "items",
29834
+ rows: toRows(layout.services)
29835
+ };
29836
+ case "categorized-site": {
29837
+ const groups = layout.groups.map((group) => categoryGroup(group.category, group.services, toRows));
29838
+ const other = layout.other.length === 0 ? [] : [{
29839
+ key: OTHER_GROUP_KEY,
29840
+ heading: OTHER_GROUP_HEADING,
29841
+ intro: null,
29842
+ rows: toRows(layout.other)
29843
+ }];
29844
+ const allGroups = [...groups, ...other];
29845
+ return allGroups.length === 0 ? EMPTY_VIEW : {
29846
+ kind: "groups",
29847
+ groups: allGroups
29848
+ };
29849
+ }
29850
+ default: return assertNever(layout);
29851
+ }
29852
+ }
29507
29853
  function buildAppointmentServicesView(input) {
29508
- if (!input.pathname) {
29854
+ const pathname = input.pathname;
29855
+ if (!pathname) {
29509
29856
  return {
29510
29857
  kind: "error",
29511
29858
  message: ERROR_MESSAGE
@@ -29518,27 +29865,101 @@ function buildAppointmentServicesView(input) {
29518
29865
  message: ERROR_MESSAGE
29519
29866
  };
29520
29867
  }
29521
- if (parsed.services.length === 0) {
29522
- return {
29523
- kind: "empty",
29524
- message: EMPTY_MESSAGE
29868
+ const toRows = (services) => buildRows(services, pathname, input.servicePathPrefix ?? null);
29869
+ const view = selectCategoryView(parsed.categories, parsed.services, readCategoryFilter(input.categoryId));
29870
+ switch (view.kind) {
29871
+ case "single": return view.group.services.length === 0 ? EMPTY_VIEW : {
29872
+ kind: "groups",
29873
+ groups: [categoryGroup(view.group.category, view.group.services, toRows)]
29525
29874
  };
29875
+ case "all":
29876
+ case "fallback-all": return viewFromLayout(view.layout, toRows);
29877
+ default: return assertNever(view);
29526
29878
  }
29527
- return {
29528
- kind: "items",
29529
- rows: buildRows(parsed.services, input.pathname, input.servicePathPrefix ?? null)
29530
- };
29531
29879
  }
29532
- function AppointmentServicesNode({ sectionHeading, services, pathname, servicePathPrefix, className }) {
29880
+ function AppointmentServiceRows({ rows, RowTitle }) {
29881
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
29882
+ className: "appointment-services-rows rb-flex rb-flex-col",
29883
+ children: rows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("article", {
29884
+ className: "appointment-services-row rb-border-b rb-border-border rb-py-4",
29885
+ children: [
29886
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
29887
+ className: "appointment-services-row-main rb-min-w-0",
29888
+ children: [
29889
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RowTitle, {
29890
+ className: "appointment-services-row-title rb-text-lg rb-font-medium rb-leading-tight",
29891
+ children: row.detailsHref ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", {
29892
+ href: row.detailsHref,
29893
+ children: row.title
29894
+ }) : row.title
29895
+ }),
29896
+ row.description ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
29897
+ className: "appointment-services-row-description rb-text-sm rb-leading-6 status-muted",
29898
+ children: row.description
29899
+ }) : null,
29900
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", {
29901
+ className: "appointment-services-row-meta rb-caption status-muted",
29902
+ children: [row.durationLabel, row.locationLabel ? ` · ${row.locationLabel}` : ""]
29903
+ })
29904
+ ]
29905
+ }),
29906
+ row.priceLabel ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
29907
+ className: "appointment-services-row-price rb-text-lg",
29908
+ children: row.priceLabel
29909
+ }) : null,
29910
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ThemedButtonLink, {
29911
+ variant: "secondary",
29912
+ size: "sm",
29913
+ extraClassName: "appointment-services-row-action",
29914
+ href: row.href,
29915
+ label: "Check times",
29916
+ screenReaderSuffix: ` for ${row.title}`
29917
+ })
29918
+ ]
29919
+ }, row.id))
29920
+ });
29921
+ }
29922
+ function AppointmentServiceGroups({ groups, hasSectionHeading, idPrefix }) {
29923
+ const GroupHeading = hasSectionHeading ? "h3" : "h2";
29924
+ const RowTitle = hasSectionHeading ? "h4" : "h3";
29925
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
29926
+ className: "appointment-services-groups rb-flex rb-flex-col rb-gap-10",
29927
+ children: groups.map((group) => {
29928
+ const headingId = `${idPrefix}-group-${group.key}`;
29929
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", {
29930
+ className: "appointment-services-group rb-flex rb-flex-col rb-gap-2",
29931
+ "aria-labelledby": headingId,
29932
+ "data-appointment-services-group": group.key,
29933
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
29934
+ className: "appointment-services-group-heading",
29935
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(GroupHeading, {
29936
+ id: headingId,
29937
+ className: "appointment-services-group-title rb-text-sm rb-font-semibold rb-uppercase rb-tracking-wide",
29938
+ children: group.heading
29939
+ }), group.intro ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
29940
+ className: "appointment-services-group-intro rb-text-sm rb-leading-6 rb-max-w-prose status-muted",
29941
+ children: group.intro
29942
+ }) : null]
29943
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AppointmentServiceRows, {
29944
+ rows: group.rows,
29945
+ RowTitle
29946
+ })]
29947
+ }, group.key);
29948
+ })
29949
+ });
29950
+ }
29951
+ function AppointmentServicesNode({ sectionHeading, categoryId, services, pathname, servicePathPrefix, blockId, className }) {
29533
29952
  const view = buildAppointmentServicesView({
29534
29953
  services,
29954
+ categoryId,
29535
29955
  pathname: typeof pathname === "string" ? pathname : undefined,
29536
29956
  servicePathPrefix: typeof servicePathPrefix === "string" ? servicePathPrefix : null
29537
29957
  });
29538
29958
  const rootClassName = `appointment-services ${className ?? ""}`.trim();
29539
- const RowTitle = sectionHeading ? "h3" : "h2";
29540
- if (view.kind === "error" || view.kind === "empty") {
29541
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
29959
+ const hasSectionHeading = Boolean(sectionHeading);
29960
+ switch (view.kind) {
29961
+ case "error":
29962
+ case "empty": return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
29542
29963
  className: rootClassName,
29543
29964
  "data-appointment-services-state": view.kind,
29544
29965
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
@@ -29547,56 +29968,25 @@ function AppointmentServicesNode({ sectionHeading, services, pathname, servicePa
29547
29968
  children: view.message
29548
29969
  })
29549
29970
  });
29971
+ case "items": return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
29972
+ className: `${rootClassName} rb-flex rb-flex-col`,
29973
+ "data-appointment-services-state": "populated",
29974
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AppointmentServiceRows, {
29975
+ rows: view.rows,
29976
+ RowTitle: hasSectionHeading ? "h3" : "h2"
29977
+ })
29978
+ });
29979
+ case "groups": return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
29980
+ className: `${rootClassName} rb-flex rb-flex-col`,
29981
+ "data-appointment-services-state": "populated",
29982
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AppointmentServiceGroups, {
29983
+ groups: view.groups,
29984
+ hasSectionHeading,
29985
+ idPrefix: `appointment-services-${blockId ?? "block"}`
29986
+ })
29987
+ });
29988
+ default: return assertNever(view);
29550
29989
  }
29551
- const actionClassName = themeButtonClassName({
29552
- variant: "secondary",
29553
- size: "sm",
29554
- extraClassName: "appointment-services-row-action"
29555
- });
29556
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
29557
- className: `${rootClassName} rb-flex rb-flex-col`,
29558
- "data-appointment-services-state": "populated",
29559
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
29560
- className: "appointment-services-rows rb-flex rb-flex-col",
29561
- children: view.rows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("article", {
29562
- className: "appointment-services-row rb-border-b rb-border-border rb-py-4",
29563
- children: [
29564
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
29565
- className: "appointment-services-row-main rb-min-w-0",
29566
- children: [
29567
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RowTitle, {
29568
- className: "appointment-services-row-title rb-text-lg rb-font-medium rb-leading-tight",
29569
- children: row.detailsHref ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", {
29570
- href: row.detailsHref,
29571
- children: row.title
29572
- }) : row.title
29573
- }),
29574
- row.description ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
29575
- className: "appointment-services-row-description rb-text-sm rb-leading-6 status-muted",
29576
- children: row.description
29577
- }) : null,
29578
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", {
29579
- className: "appointment-services-row-meta rb-caption status-muted",
29580
- children: [row.durationLabel, row.locationLabel ? ` · ${row.locationLabel}` : ""]
29581
- })
29582
- ]
29583
- }),
29584
- row.priceLabel ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
29585
- className: "appointment-services-row-price rb-text-lg",
29586
- children: row.priceLabel
29587
- }) : null,
29588
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("a", {
29589
- className: actionClassName,
29590
- href: row.href,
29591
- children: ["Check times", /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
29592
- className: "rb-sr-only",
29593
- children: [" for ", row.title]
29594
- })]
29595
- })
29596
- ]
29597
- }, row.id))
29598
- })
29599
- });
29600
29990
  }
29601
29991
  var appointment_services_default = AppointmentServicesNode;
29602
29992
 
@@ -31161,8 +31551,8 @@ function createLoadableValueState(tag, key, value) {
31161
31551
  };
31162
31552
  }
31163
31553
  function upsertRedirectRule(existing, next) {
31164
- if (existing.findIndex((rule$1) => rule$1.id === next.id) < 0) return [next, ...existing];
31165
- return existing.map((rule$1) => rule$1.id === next.id ? next : rule$1);
31554
+ if (existing.findIndex((rule$2) => rule$2.id === next.id) < 0) return [next, ...existing];
31555
+ return existing.map((rule$2) => rule$2.id === next.id ? next : rule$2);
31166
31556
  }
31167
31557
  function createInitialRedirectsClientState(initialState) {
31168
31558
  return {
@@ -31517,7 +31907,7 @@ function getWizardLocalStorage() {
31517
31907
  }
31518
31908
  }
31519
31909
  function parseEnvelope(raw, config$1) {
31520
- if (!isRecord$28(raw)) return {
31910
+ if (!isRecord$29(raw)) return {
31521
31911
  kind: "removed_invalid",
31522
31912
  reason: "invalid_envelope"
31523
31913
  };
@@ -31606,7 +31996,7 @@ function createWizardDraftStorage(config$1) {
31606
31996
  }
31607
31997
  };
31608
31998
  }
31609
- function isRecord$28(value) {
31999
+ function isRecord$29(value) {
31610
32000
  return typeof value === "object" && value !== null && !Array.isArray(value);
31611
32001
  }
31612
32002
  function deepEqualJsonValue(left, right) {
@@ -31616,8 +32006,8 @@ function deepEqualJsonValue(left, right) {
31616
32006
  if (left.length !== right.length) return false;
31617
32007
  return left.every((item, index) => deepEqualJsonValue(item, right[index]));
31618
32008
  }
31619
- if (isRecord$28(left) || isRecord$28(right)) {
31620
- if (!isRecord$28(left) || !isRecord$28(right)) return false;
32009
+ if (isRecord$29(left) || isRecord$29(right)) {
32010
+ if (!isRecord$29(left) || !isRecord$29(right)) return false;
31621
32011
  const leftKeys = Object.keys(left).sort();
31622
32012
  if (!deepEqualJsonValue(leftKeys, Object.keys(right).sort())) return false;
31623
32013
  return leftKeys.every((key) => deepEqualJsonValue(left[key], right[key]));
@@ -32079,12 +32469,12 @@ function resolveBookingSiteId(siteId, form$1) {
32079
32469
  return siteId || form$1?.siteId || "";
32080
32470
  }
32081
32471
  function normalizeBookingFormConfig(form$1) {
32082
- if (!isRecord$27(form$1)) return null;
32472
+ if (!isRecord$28(form$1)) return null;
32083
32473
  const id = readNonEmptyString(form$1.id);
32084
32474
  const name = readNonEmptyString(form$1.name);
32085
32475
  if (!id || !name) return null;
32086
- const schemaSource = isRecord$27(form$1.schema) ? form$1.schema : isRecord$27(form$1.schemaJson) ? form$1.schemaJson : null;
32087
- const settingsSource = isRecord$27(form$1.settings) ? form$1.settings : isRecord$27(form$1.settingsJson) ? form$1.settingsJson : null;
32476
+ const schemaSource = isRecord$28(form$1.schema) ? form$1.schema : isRecord$28(form$1.schemaJson) ? form$1.schemaJson : null;
32477
+ const settingsSource = isRecord$28(form$1.settings) ? form$1.settings : isRecord$28(form$1.settingsJson) ? form$1.settingsJson : null;
32088
32478
  return {
32089
32479
  id,
32090
32480
  name,
@@ -32108,10 +32498,10 @@ function normalizeBookingServices(services) {
32108
32498
  if (Array.isArray(services)) {
32109
32499
  return services.filter(isBookingFormService).map(normalizeService);
32110
32500
  }
32111
- if (isRecord$27(services) && "services" in services) {
32501
+ if (isRecord$28(services) && "services" in services) {
32112
32502
  return Array.isArray(services.services) ? services.services.filter(isBookingFormService).map(normalizeService) : [];
32113
32503
  }
32114
- return isRecord$27(services) ? Object.values(services).filter(isBookingFormService).map(normalizeService) : [];
32504
+ return isRecord$28(services) ? Object.values(services).filter(isBookingFormService).map(normalizeService) : [];
32115
32505
  }
32116
32506
  function normalizeBookingSchema(value) {
32117
32507
  if (!value) return undefined;
@@ -32123,7 +32513,7 @@ function normalizeBookingSchema(value) {
32123
32513
  };
32124
32514
  }
32125
32515
  function readBookingFormField(value) {
32126
- if (!isRecord$27(value)) return null;
32516
+ if (!isRecord$28(value)) return null;
32127
32517
  const id = readNonEmptyString(value.id);
32128
32518
  const label = readNonEmptyString(value.label);
32129
32519
  const type = readBookingFieldType(value.type);
@@ -32166,7 +32556,7 @@ function readBookingFieldOptions(value) {
32166
32556
  return options.length > 0 ? options : undefined;
32167
32557
  }
32168
32558
  function readBookingFieldOption(value) {
32169
- if (!isRecord$27(value)) return null;
32559
+ if (!isRecord$28(value)) return null;
32170
32560
  const optionValue = readNonEmptyString(value.value);
32171
32561
  const label = readNonEmptyString(value.label);
32172
32562
  return optionValue && label ? {
@@ -32186,7 +32576,7 @@ function normalizeBookingSettings(value) {
32186
32576
  };
32187
32577
  }
32188
32578
  function isBookingFormService(value) {
32189
- return isRecord$27(value) && typeof value.id === "string" && typeof value.siteId === "string" && typeof value.title === "string" && (value.consent === undefined || blockBookingConsentSchema.safeParse(value.consent).success);
32579
+ return isRecord$28(value) && typeof value.id === "string" && typeof value.siteId === "string" && typeof value.title === "string" && (value.consent === undefined || blockBookingConsentSchema.safeParse(value.consent).success);
32190
32580
  }
32191
32581
  function collectBookingCustomFields(data) {
32192
32582
  const customFields = {};
@@ -32242,7 +32632,7 @@ function readStringArray(value) {
32242
32632
  const strings = value.filter((item) => typeof item === "string");
32243
32633
  return strings.length > 0 ? strings : undefined;
32244
32634
  }
32245
- function isRecord$27(value) {
32635
+ function isRecord$28(value) {
32246
32636
  return typeof value === "object" && value !== null;
32247
32637
  }
32248
32638
  function getBookingServicePaymentSelectionMode(service) {
@@ -32471,6 +32861,41 @@ function getBookingSuccessMessage(successMessage) {
32471
32861
  return successMessage?.trim() || "Your appointment has been booked! Check your email for confirmation.";
32472
32862
  }
32473
32863
 
32864
+ //#endregion
32865
+ //#region ../blocks/src/system/runtime/nodes/booking-form.service-categories.ts
32866
+ function isRecord$27(value) {
32867
+ return typeof value === "object" && value !== null && !Array.isArray(value);
32868
+ }
32869
+ function readCategory(value) {
32870
+ if (!isRecord$27(value)) return [];
32871
+ const { id, name, description } = value;
32872
+ if (typeof id !== "string" || id.trim() === "" || typeof name !== "string") {
32873
+ return [];
32874
+ }
32875
+ return [{
32876
+ id,
32877
+ name,
32878
+ description: typeof description === "string" ? description : null
32879
+ }];
32880
+ }
32881
+ /**
32882
+ * The ordered service categories carried by a catalogue-shaped services
32883
+ * source (`{ services, categories }`). Every other shape has none, which
32884
+ * reads as a site without categories. Order is preserved: the database owns
32885
+ * it.
32886
+ */
32887
+ function normalizeBookingServiceCategories(services) {
32888
+ if (!isRecord$27(services) || !Array.isArray(services.categories)) return [];
32889
+ return services.categories.flatMap(readCategory);
32890
+ }
32891
+ /**
32892
+ * The ordered service categories a headless booking override was given in
32893
+ * its loader data (`data.services`).
32894
+ */
32895
+ function readOverrideServiceCategories(data) {
32896
+ return isRecord$27(data) ? normalizeBookingServiceCategories(data.services) : [];
32897
+ }
32898
+
32474
32899
  //#endregion
32475
32900
  //#region ../blocks/src/system/runtime/nodes/booking-runtime-sources.ts
32476
32901
  const APPOINTMENT_BOOKING_RUNTIME_FORM_ID = "booking-form";
@@ -32597,7 +33022,8 @@ function normalizeAppointmentBookingServices(input) {
32597
33022
  priceCurrency: service.priceCurrency,
32598
33023
  paymentTerms: service.paymentTerms,
32599
33024
  paymentTermsAvailability: service.paymentTermsAvailability,
32600
- consent: service.consent
33025
+ consent: service.consent,
33026
+ categoryId: service.categoryId ?? null
32601
33027
  }));
32602
33028
  }
32603
33029
  function buildAppointmentBookingSourceProps(input) {
@@ -32615,6 +33041,7 @@ function buildAppointmentBookingSourceProps(input) {
32615
33041
  siteId: input.siteId,
32616
33042
  services: input.services
32617
33043
  }),
33044
+ serviceCategories: [...input.serviceCategories ?? []],
32618
33045
  serviceId: input.serviceId,
32619
33046
  resourceId: input.resourceId,
32620
33047
  initialData: input.initialData,
@@ -32644,6 +33071,7 @@ function buildEventRegistrationSourceProps(input) {
32644
33071
  apiBaseUrl: input.apiBaseUrl,
32645
33072
  portalToken: input.portalToken,
32646
33073
  previewToken: input.previewToken,
33074
+ readAuthority: input.readAuthority,
32647
33075
  occurrenceContext: input.occurrenceContext,
32648
33076
  events: input.events ? [...input.events] : null,
32649
33077
  stage: input.stage,
@@ -32680,11 +33108,20 @@ const bookingServiceSchema = z.object({
32680
33108
  priceCurrency: z.string().nullable().optional(),
32681
33109
  paymentTerms: blockBookingPaymentTermsSchema.optional(),
32682
33110
  paymentTermsAvailability: blockBookingPaymentTermsAvailabilitySchema.optional(),
32683
- consent: blockBookingConsentSchema.optional()
33111
+ consent: blockBookingConsentSchema.optional(),
33112
+ categoryId: z.string().nullable().optional()
33113
+ });
33114
+ const bookingServiceCategorySchema = z.object({
33115
+ id: z.string(),
33116
+ name: z.string(),
33117
+ description: z.string().nullable()
32684
33118
  });
32685
33119
  const bookingServicesSourceSchema = z.union([
32686
33120
  z.array(bookingServiceSchema),
32687
- z.object({ services: z.array(bookingServiceSchema).optional() }),
33121
+ z.object({
33122
+ services: z.array(bookingServiceSchema).optional(),
33123
+ categories: z.array(bookingServiceCategorySchema).optional()
33124
+ }),
32688
33125
  z.record(z.string(), bookingServiceSchema)
32689
33126
  ]);
32690
33127
  const bookingConfigSchema = z.object({
@@ -32737,6 +33174,7 @@ const bookingHydrationSchema = z.object({
32737
33174
  rebookContext: z.object({ kind: z.literal("portal_rebook") }).nullable().optional(),
32738
33175
  form: bookingConfigSchema.nullable(),
32739
33176
  services: z.array(bookingServiceSchema),
33177
+ serviceCategories: z.array(bookingServiceCategorySchema).optional(),
32740
33178
  spamProtectionEnabled: z.boolean().optional()
32741
33179
  });
32742
33180
  const bookingRenderSchema = z.object({
@@ -32782,6 +33220,7 @@ const bookingFormBlockRuntime = defineClientOwnedBlockRuntime({
32782
33220
  rebookContext: source.rebookContext ?? null,
32783
33221
  form: form$1,
32784
33222
  services,
33223
+ serviceCategories: normalizeBookingServiceCategories(source.services),
32785
33224
  spamProtectionEnabled: source.spamProtectionEnabled
32786
33225
  }
32787
33226
  };
@@ -34557,16 +34996,14 @@ function LocationMapView({ addressText, location: location$1, zoom, heightPx, sh
34557
34996
  style: textColorStyle("mutedText"),
34558
34997
  children: addressText
34559
34998
  }) : null,
34560
- showDirections && directionsUrl ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", {
34999
+ showDirections && directionsUrl ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ThemedButtonLink, {
34561
35000
  href: directionsUrl,
34562
35001
  target: "_blank",
34563
35002
  rel: "noreferrer",
34564
- className: themeButtonClassName({
34565
- variant: "ghost",
34566
- size: "sm",
34567
- extraClassName: "rb-w-fit"
34568
- }),
34569
- children: directionsLabel
35003
+ variant: "ghost",
35004
+ size: "sm",
35005
+ extraClassName: "rb-w-fit",
35006
+ label: directionsLabel
34570
35007
  }) : null
34571
35008
  ]
34572
35009
  });
@@ -34724,10 +35161,6 @@ const EventCard = ({ event, cardRole = "default", buttonVariant = "primary", but
34724
35161
  const formattedTime = `${formatTime(event.startsAt, { timeZone })} - ${formatTime(event.endsAt, { timeZone })}`;
34725
35162
  const cta = resolveEventCta(event, buttonText);
34726
35163
  const cardClass = boxStyleClassNames({ role: cardRole }, { baseClass: "event-card" });
34727
- const buttonClass = themeButtonClassName({
34728
- variant: buttonVariant,
34729
- size: "md"
34730
- });
34731
35164
  const title = event.title;
34732
35165
  const summary = event.presentation?.summary ?? event.description;
34733
35166
  const image = event.presentation?.image ?? null;
@@ -34758,7 +35191,7 @@ const EventCard = ({ event, cardRole = "default", buttonVariant = "primary", but
34758
35191
  image
34759
35192
  }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EventCardContent, {
34760
35193
  allowMap,
34761
- buttonClass,
35194
+ buttonVariant,
34762
35195
  capacityText,
34763
35196
  categoryBadge,
34764
35197
  categoryId: category?.id,
@@ -34862,7 +35295,7 @@ function EventCardContent(props$1) {
34862
35295
  children: props$1.summary
34863
35296
  }),
34864
35297
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EventCardFooter, {
34865
- buttonClass: props$1.buttonClass,
35298
+ buttonVariant: props$1.buttonVariant,
34866
35299
  capacityText: props$1.capacityText,
34867
35300
  cta: props$1.cta,
34868
35301
  priceText: props$1.priceText
@@ -34900,12 +35333,14 @@ function EventCardFooter(props$1) {
34900
35333
  className: "event-card-status rb-caption status-muted rb-text-center",
34901
35334
  children: props$1.cta.label
34902
35335
  }),
34903
- !props$1.cta.hidden && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", {
35336
+ !props$1.cta.hidden && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ThemedButtonLink, {
34904
35337
  href: props$1.cta.href,
34905
35338
  target: props$1.cta.external ? "_blank" : undefined,
34906
35339
  rel: props$1.cta.external ? "noopener noreferrer" : undefined,
34907
- className: `${props$1.buttonClass} event-card-cta`,
34908
- children: props$1.cta.label
35340
+ variant: props$1.buttonVariant,
35341
+ size: "md",
35342
+ extraClassName: "event-card-cta",
35343
+ label: props$1.cta.label
34909
35344
  })
34910
35345
  ]
34911
35346
  });
@@ -34977,10 +35412,6 @@ const EventCompactRow = ({ event, buttonVariant = "primary", buttonText }) => {
34977
35412
  const price = formatEventPrice(event);
34978
35413
  const teacherLine = formatEventTeacherLine(event);
34979
35414
  const cta = resolveEventCta(event, buttonText);
34980
- const buttonClass = themeButtonClassName({
34981
- variant: buttonVariant,
34982
- size: "sm"
34983
- });
34984
35415
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("article", {
34985
35416
  className: "event-compact-row",
34986
35417
  children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("time", {
@@ -35044,12 +35475,15 @@ const EventCompactRow = ({ event, buttonVariant = "primary", buttonText }) => {
35044
35475
  }), cta.hidden ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
35045
35476
  className: "event-compact-row-status",
35046
35477
  children: cta.label
35047
- }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", {
35478
+ }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ThemedButtonLink, {
35048
35479
  href: cta.href,
35049
35480
  target: cta.external ? "_blank" : undefined,
35050
35481
  rel: cta.external ? "noopener noreferrer" : undefined,
35051
- className: `${buttonClass} event-compact-row-cta`,
35052
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: cta.label })
35482
+ variant: buttonVariant,
35483
+ size: "sm",
35484
+ extraClassName: "event-compact-row-cta",
35485
+ labelClassName: "event-compact-row-cta-label",
35486
+ label: cta.label
35053
35487
  })]
35054
35488
  })]
35055
35489
  })]
@@ -35093,10 +35527,6 @@ function EventQuickDateCard(props$1) {
35093
35527
  kind: "event_occurrence",
35094
35528
  occurrenceId: event.occurrenceId
35095
35529
  });
35096
- const buttonClass = themeButtonClassName({
35097
- variant: props$1.buttonVariant,
35098
- size: "sm"
35099
- });
35100
35530
  const quickDateLabel = `${event.title}, ${date.label}`;
35101
35531
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("article", {
35102
35532
  className: "event-quick-date rb-flex rb-min-w-12rem rb-shrink-0 rb-flex-col rb-gap-3 rb-rounded-lg rb-border rb-bg-surface rb-p-4",
@@ -35128,13 +35558,15 @@ function EventQuickDateCard(props$1) {
35128
35558
  children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
35129
35559
  className: "event-quick-date-price",
35130
35560
  children: formatEventPrice(event)
35131
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", {
35132
- className: `${buttonClass} event-quick-date-cta`,
35561
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ThemedButtonLink, {
35562
+ variant: props$1.buttonVariant,
35563
+ size: "sm",
35564
+ extraClassName: "event-quick-date-cta",
35133
35565
  href: ctaHref,
35134
35566
  target: cta.external ? "_blank" : undefined,
35135
35567
  rel: cta.external ? "noopener noreferrer" : undefined,
35136
35568
  "aria-label": `${cta.label} ${quickDateLabel}`,
35137
- children: cta.label
35569
+ label: cta.label
35138
35570
  })]
35139
35571
  })
35140
35572
  ]
@@ -35214,10 +35646,6 @@ const EventSpotlight = ({ events, layout = "grid", columns = "3", cardRole = "de
35214
35646
  }
35215
35647
  const containerClass = getContainerClass(layout, columns);
35216
35648
  const cardOrientation = getCardOrientation(layout);
35217
- const buttonClass = themeButtonClassName({
35218
- variant: buttonVariant,
35219
- size: "md"
35220
- });
35221
35649
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
35222
35650
  className: `event-spotlight-section ${className || ""}`,
35223
35651
  "data-block": "event-spotlight",
@@ -35235,16 +35663,45 @@ const EventSpotlight = ({ events, layout = "grid", columns = "3", cardRole = "de
35235
35663
  }, event.occurrenceId || event.id))
35236
35664
  }), ctaLabel && ctaUrl ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
35237
35665
  className: "rb-mt-8 rb-text-center",
35238
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", {
35666
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ThemedButtonLink, {
35239
35667
  href: ctaUrl,
35240
- className: buttonClass,
35241
- children: ctaLabel
35668
+ variant: buttonVariant,
35669
+ size: "md",
35670
+ label: ctaLabel
35242
35671
  })
35243
35672
  }) : null]
35244
35673
  });
35245
35674
  };
35246
35675
  var EventSpotlight_default = EventSpotlight;
35247
35676
 
35677
+ //#endregion
35678
+ //#region ../blocks/src/system/runtime/api/readAuthority.ts
35679
+ const browserReadAuthoritySchema = z.discriminatedUnion("kind", [z.object({ kind: z.literal("published") }).strict(), z.object({
35680
+ kind: z.literal("preview"),
35681
+ token: z.string().min(1)
35682
+ }).strict()]);
35683
+ /** Generic SDK/editor configuration is projected here; hosted callers supply the closed union. */
35684
+ function getBlockApiReadStage(config$1) {
35685
+ return config$1.readAuthority?.kind ?? (config$1.isPreview && config$1.auth.type !== "none" ? "preview" : "published");
35686
+ }
35687
+ function createHostedBlockApiConfig(input) {
35688
+ const { baseUrl, siteId, readAuthority, portalToken } = input;
35689
+ return {
35690
+ baseUrl,
35691
+ siteId,
35692
+ readAuthority,
35693
+ auth: readAuthority.kind === "preview" ? {
35694
+ type: "bearer",
35695
+ token: readAuthority.token
35696
+ } : { type: "none" },
35697
+ isPreview: readAuthority.kind === "preview",
35698
+ authOverrides: { portal: portalToken ? {
35699
+ type: "bearer",
35700
+ token: portalToken
35701
+ } : { type: "none" } }
35702
+ };
35703
+ }
35704
+
35248
35705
  //#endregion
35249
35706
  //#region ../blocks/src/system/runtime/nodes/shared/contract-schemas.ts
35250
35707
  const previewStageSchema = z.enum(["preview", "published"]);
@@ -36249,6 +36706,7 @@ const eventCollectionSourceSchemaShape = {
36249
36706
  events: z.array(publicEventSchema).nullable().optional(),
36250
36707
  siteId: z.string(),
36251
36708
  apiBaseUrl: z.string().optional(),
36709
+ readAuthority: browserReadAuthoritySchema.optional(),
36252
36710
  stage: previewStageSchema.optional(),
36253
36711
  listLayout: eventLayoutSchema.optional(),
36254
36712
  listColumns: columnOptionSchema.optional(),
@@ -36301,7 +36759,6 @@ const eventCollectionDisplaySchemaShape = {
36301
36759
  const eventCollectionHydrationSchema = z.object({
36302
36760
  siteId: z.string(),
36303
36761
  calendarWindow: calendarWindowPageSchema.optional(),
36304
- stage: previewStageSchema.optional(),
36305
36762
  prefetchedEvents: z.boolean(),
36306
36763
  eventSurface: eventSurfaceScopeSchema$1,
36307
36764
  filterEventPresets: z.string().nullable(),
@@ -36376,7 +36833,6 @@ function buildEventCollectionHydration(source, now = new Date()) {
36376
36833
  return {
36377
36834
  calendarWindow: source.calendarWindow ?? undefined,
36378
36835
  siteId: source.siteId,
36379
- stage: source.stage,
36380
36836
  prefetchedEvents: source.events != null,
36381
36837
  eventSurface: selected ? "all" : normalizeEventSurfaceScope(source.eventSurface),
36382
36838
  filterEventPresets: selected ? null : normalizeEventSurfacePresetsCsv(source.filterEventPresets),
@@ -36424,9 +36880,10 @@ const eventCombinedRenderSchema = z.object({
36424
36880
  const eventCombinedIslandMetaCodec = createZodCodec(z.object({
36425
36881
  siteId: z.string(),
36426
36882
  apiBaseUrl: z.string().optional(),
36883
+ readAuthority: browserReadAuthoritySchema.optional(),
36427
36884
  stage: previewStageSchema.optional()
36428
36885
  }));
36429
- const eventCombinedIslandMetaKeys = defineInteractiveIslandMetaKeys("siteId", "apiBaseUrl", "stage");
36886
+ const eventCombinedIslandMetaKeys = defineInteractiveIslandMetaKeys("siteId", "apiBaseUrl", "readAuthority", "stage");
36430
36887
  function buildEventCombinedDisplay(source) {
36431
36888
  return {
36432
36889
  ...buildEventCollectionDisplay(source),
@@ -36456,6 +36913,7 @@ const eventCombinedInteractiveIslandPropsCodec = createInteractiveIslandCodec({
36456
36913
  selectMeta: (value) => ({
36457
36914
  siteId: value.siteId,
36458
36915
  apiBaseUrl: value.apiBaseUrl,
36916
+ readAuthority: value.readAuthority,
36459
36917
  stage: value.stage
36460
36918
  })
36461
36919
  });
@@ -36466,6 +36924,7 @@ function buildEventCombinedInteractiveIslandProps(props$1) {
36466
36924
  meta: {
36467
36925
  siteId: props$1.siteId,
36468
36926
  apiBaseUrl: props$1.apiBaseUrl,
36927
+ readAuthority: props$1.readAuthority,
36469
36928
  stage: props$1.stage
36470
36929
  },
36471
36930
  source: props$1
@@ -36960,11 +37419,6 @@ function OfferingsCatalogue(props$1) {
36960
37419
  //#endregion
36961
37420
  //#region ../blocks/src/system/runtime/nodes/offerings-preview-content.tsx
36962
37421
  function OfferingsPreviewContent(props$1) {
36963
- const groupLinkClass = themeButtonClassName({
36964
- variant: props$1.buttonVariant,
36965
- size: "md",
36966
- extraClassName: "offerings-preview-card-link rb-inline-flex rb-items-center rb-gap-2"
36967
- });
36968
37422
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
36969
37423
  className: "offerings-preview rb-flex rb-flex-col rb-gap-6",
36970
37424
  "data-block": "offerings-preview",
@@ -37004,10 +37458,12 @@ function OfferingsPreviewContent(props$1) {
37004
37458
  }),
37005
37459
  groupCta ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("footer", {
37006
37460
  className: "offerings-preview-card-footer rb-mt-auto rb-flex",
37007
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", {
37008
- className: groupLinkClass,
37461
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ThemedButtonLink, {
37462
+ variant: props$1.buttonVariant,
37463
+ size: "md",
37464
+ extraClassName: "offerings-preview-card-link rb-inline-flex rb-items-center rb-gap-2",
37009
37465
  href: groupCta.href,
37010
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: groupCta.label })
37466
+ label: groupCta.label
37011
37467
  })
37012
37468
  }) : null
37013
37469
  ]
@@ -37343,10 +37799,6 @@ function WholeSeriesRunCompactRow({ group, path: path$3, now }) {
37343
37799
  const timeRange = `${formatTime(firstSession.startsAt, { timeZone })} - ${formatTime(firstSession.endsAt, { timeZone })}`;
37344
37800
  const price = formatEventPriceDisplay(group.representative.pricing);
37345
37801
  const statusLabel = resolveWholeSeriesBookingPhase(group.run, now).kind === "open" ? null : "Registration closed";
37346
- const ctaClass = themeButtonClassName({
37347
- variant: "primary",
37348
- size: "sm"
37349
- });
37350
37802
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("article", {
37351
37803
  className: "event-compact-row offerings-preview-whole-series-row",
37352
37804
  children: [
@@ -37405,10 +37857,13 @@ function WholeSeriesRunCompactRow({ group, path: path$3, now }) {
37405
37857
  }), statusLabel || !path$3 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
37406
37858
  className: "event-compact-row-status",
37407
37859
  children: statusLabel ?? "Details coming soon"
37408
- }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", {
37860
+ }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ThemedButtonLink, {
37409
37861
  href: path$3,
37410
- className: `${ctaClass} event-compact-row-cta`,
37411
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "Book now" })
37862
+ variant: "primary",
37863
+ size: "sm",
37864
+ extraClassName: "event-compact-row-cta",
37865
+ labelClassName: "event-compact-row-cta-label",
37866
+ label: "Book now"
37412
37867
  })]
37413
37868
  })
37414
37869
  ]
@@ -37425,10 +37880,6 @@ function WholeSeriesRunFeatureCard({ group, now, path: path$3, buttonVariant, bu
37425
37880
  const formattedDate = formatEventCompactDateRail(firstSession.startsAt, { timeZone }).label;
37426
37881
  const timeRange = `${formatTime(firstSession.startsAt, { timeZone })} - ${formatTime(firstSession.endsAt, { timeZone })}`;
37427
37882
  const price = formatEventPriceDisplay(group.representative.pricing);
37428
- const ctaClass = themeButtonClassName({
37429
- variant: buttonVariant,
37430
- size: "md"
37431
- });
37432
37883
  const statusLabel = resolveWholeSeriesBookingPhase(group.run, now).kind === "open" ? null : "Registration closed";
37433
37884
  const description = group.representative.description;
37434
37885
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("article", {
@@ -37461,10 +37912,12 @@ function WholeSeriesRunFeatureCard({ group, now, path: path$3, buttonVariant, bu
37461
37912
  }), statusLabel || !path$3 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
37462
37913
  className: "event-compact-row-status",
37463
37914
  children: statusLabel ?? "Details coming soon"
37464
- }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", {
37915
+ }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ThemedButtonLink, {
37465
37916
  href: path$3,
37466
- className: `${ctaClass} event-card-cta`,
37467
- children: buttonText || "Book now"
37917
+ variant: buttonVariant,
37918
+ size: "md",
37919
+ extraClassName: "event-card-cta",
37920
+ label: buttonText || "Book now"
37468
37921
  })]
37469
37922
  })
37470
37923
  ]
@@ -37627,15 +38080,13 @@ function WeeklySlotAvailabilityView({ availability, loading = false, error: erro
37627
38080
  "."
37628
38081
  ]
37629
38082
  }),
37630
- resolvedCtaUrl ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", {
37631
- className: themeButtonClassName({
37632
- variant: "ghost",
37633
- size: "sm",
37634
- extraClassName: "weekly-slot-availability__cta"
37635
- }),
38083
+ resolvedCtaUrl ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ThemedButtonLink, {
38084
+ variant: "ghost",
38085
+ size: "sm",
38086
+ extraClassName: "weekly-slot-availability__cta",
37636
38087
  href: buildSlotCtaUrl(resolvedCtaUrl, slot),
37637
38088
  "aria-label": buildSlotCtaLabel(resolvedCtaText, slot),
37638
- children: resolvedCtaText
38089
+ label: resolvedCtaText
37639
38090
  }) : null
37640
38091
  ]
37641
38092
  }, slot.id))
@@ -38590,6 +39041,7 @@ const shopSourceSchema = z.object({
38590
39041
  products: z.array(publicProductSchema).nullable().optional(),
38591
39042
  siteId: z.string().optional(),
38592
39043
  apiBaseUrl: z.string().optional(),
39044
+ readAuthority: browserReadAuthoritySchema.optional(),
38593
39045
  stage: previewStageSchema.optional()
38594
39046
  });
38595
39047
  const productVariantOptionDisplaySchema = z.object({
@@ -38757,13 +39209,15 @@ function resolveShowPricePerCredit(source) {
38757
39209
  const shopIslandMetaCodec = createZodCodec(z.object({
38758
39210
  siteId: z.string().optional(),
38759
39211
  apiBaseUrl: z.string().optional(),
39212
+ readAuthority: browserReadAuthoritySchema.optional(),
38760
39213
  stage: previewStageSchema.optional()
38761
39214
  }));
38762
- const shopIslandMetaKeys = defineInteractiveIslandMetaKeys("siteId", "apiBaseUrl", "stage");
39215
+ const shopIslandMetaKeys = defineInteractiveIslandMetaKeys("siteId", "apiBaseUrl", "readAuthority", "stage");
38763
39216
  function selectShopIslandMeta(value) {
38764
39217
  return {
38765
39218
  siteId: value.siteId,
38766
39219
  apiBaseUrl: value.apiBaseUrl,
39220
+ readAuthority: value.readAuthority,
38767
39221
  stage: value.stage
38768
39222
  };
38769
39223
  }
@@ -38934,6 +39388,7 @@ function buildShopInteractiveIslandProps(props$1) {
38934
39388
  meta: {
38935
39389
  siteId: props$1.siteId,
38936
39390
  apiBaseUrl: props$1.apiBaseUrl,
39391
+ readAuthority: props$1.readAuthority,
38937
39392
  stage: props$1.stage
38938
39393
  },
38939
39394
  source: {
@@ -38949,6 +39404,7 @@ function buildProductListInteractiveIslandProps(props$1) {
38949
39404
  meta: {
38950
39405
  siteId: props$1.siteId,
38951
39406
  apiBaseUrl: props$1.apiBaseUrl,
39407
+ readAuthority: props$1.readAuthority,
38952
39408
  stage: props$1.stage
38953
39409
  },
38954
39410
  source: {
@@ -38964,6 +39420,7 @@ function buildProductDetailInteractiveIslandProps(props$1) {
38964
39420
  meta: {
38965
39421
  siteId: props$1.siteId,
38966
39422
  apiBaseUrl: props$1.apiBaseUrl,
39423
+ readAuthority: props$1.readAuthority,
38967
39424
  stage: props$1.stage
38968
39425
  },
38969
39426
  source: {
@@ -38979,6 +39436,7 @@ function buildCartInteractiveIslandProps(props$1) {
38979
39436
  meta: {
38980
39437
  siteId: props$1.siteId,
38981
39438
  apiBaseUrl: props$1.apiBaseUrl,
39439
+ readAuthority: props$1.readAuthority,
38982
39440
  stage: props$1.stage
38983
39441
  },
38984
39442
  source: {
@@ -38994,6 +39452,7 @@ function buildCheckoutInteractiveIslandProps(props$1) {
38994
39452
  meta: {
38995
39453
  siteId: props$1.siteId,
38996
39454
  apiBaseUrl: props$1.apiBaseUrl,
39455
+ readAuthority: props$1.readAuthority,
38997
39456
  stage: props$1.stage
38998
39457
  },
38999
39458
  source: {
@@ -39096,6 +39555,7 @@ const cartManifest = createBlockManifest({
39096
39555
  baseClass: "",
39097
39556
  spacing: "spacious",
39098
39557
  children: sectionContainer([cart(withApiBindings({
39558
+ readAuthority: { $bind: { from: "$root.readAuthority" } },
39099
39559
  mode: "cart",
39100
39560
  heading: { $bind: {
39101
39561
  from: "content.heading",
@@ -39183,6 +39643,7 @@ const checkoutManifest = createBlockManifest({
39183
39643
  baseClass: "",
39184
39644
  spacing: "spacious",
39185
39645
  children: sectionContainer([checkout(withApiBindings({
39646
+ readAuthority: { $bind: { from: "$root.readAuthority" } },
39186
39647
  mode: "checkout",
39187
39648
  heading: { $bind: {
39188
39649
  from: "content.heading",
@@ -39514,6 +39975,18 @@ function getStepNumber(step, wizardSteps) {
39514
39975
 
39515
39976
  //#endregion
39516
39977
  //#region ../blocks/src/system/runtime/nodes/event-registration/registrationDerivations.ts
39978
+ /** Public requests share subject identity without copying the run's display sessions. */
39979
+ function toRegistrationRequestSubject(subject, attendanceMode) {
39980
+ return subject.kind === "occurrence" ? {
39981
+ kind: "occurrence",
39982
+ occurrenceId: subject.occurrenceId,
39983
+ attendanceMode: attendanceMode ?? undefined
39984
+ } : {
39985
+ kind: "wholeSeries",
39986
+ eventSeriesId: subject.eventSeriesId,
39987
+ attendanceMode: attendanceMode ?? undefined
39988
+ };
39989
+ }
39517
39990
  function eventMatchesOccurrenceId(event, occurrenceId) {
39518
39991
  return event.registrationSubject.kind === "occurrence" && (event.registrationSubject.occurrenceId === occurrenceId || event.selectionId === occurrenceId);
39519
39992
  }
@@ -39724,6 +40197,7 @@ const eventRegistrationSourceSchema = z.object({
39724
40197
  apiBaseUrl: z.string().optional(),
39725
40198
  portalToken: z.string().nullable().optional(),
39726
40199
  previewToken: z.string().nullable().optional(),
40200
+ readAuthority: browserReadAuthoritySchema.optional(),
39727
40201
  ...eventRegistrationHydrationSchemaShape,
39728
40202
  events: z.array(eventRegistrationPublicEventSchema).nullable().optional(),
39729
40203
  wholeSeriesRunEvents: z.array(eventRegistrationPublicEventSchema).nullable().optional(),
@@ -39761,9 +40235,10 @@ const eventRegistrationIslandMetaCodec = createZodCodec(z.object({
39761
40235
  apiBaseUrl: z.string().optional(),
39762
40236
  portalToken: z.string().nullable().optional(),
39763
40237
  previewToken: z.string().nullable().optional(),
40238
+ readAuthority: browserReadAuthoritySchema.optional(),
39764
40239
  stage: previewStageSchema.optional()
39765
40240
  }));
39766
- const eventRegistrationIslandMetaKeys = defineInteractiveIslandMetaKeys("siteId", "apiBaseUrl", "portalToken", "previewToken", "stage");
40241
+ const eventRegistrationIslandMetaKeys = defineInteractiveIslandMetaKeys("siteId", "apiBaseUrl", "portalToken", "previewToken", "readAuthority", "stage");
39767
40242
  function buildEventRegistrationDisplayFromScopedEvents(source, scopedSourceEvents) {
39768
40243
  const selectedRun = resolveSelectedWholeSeriesRun(scopedSourceEvents);
39769
40244
  if (selectedRun && (!selectedRun.run.enrollmentOpen || toWholeSeriesRegistrationEvent(selectedRun) === null)) {
@@ -39844,6 +40319,7 @@ function shellLabelForRegistrationStep(step, events) {
39844
40319
  case "redirecting":
39845
40320
  case "verifying-payment":
39846
40321
  case "verifying-timeout":
40322
+ case "payment-status":
39847
40323
  case "payment-failed": return "Details";
39848
40324
  }
39849
40325
  }
@@ -39918,6 +40394,7 @@ const eventRegistrationInteractiveIslandPropsCodec = createInteractiveIslandCode
39918
40394
  apiBaseUrl: value.apiBaseUrl,
39919
40395
  portalToken: value.portalToken,
39920
40396
  previewToken: value.previewToken,
40397
+ readAuthority: value.readAuthority,
39921
40398
  stage: value.stage
39922
40399
  })
39923
40400
  });
@@ -39930,6 +40407,7 @@ function buildEventRegistrationInteractiveIslandProps(props$1) {
39930
40407
  apiBaseUrl: props$1.apiBaseUrl,
39931
40408
  portalToken: props$1.portalToken,
39932
40409
  previewToken: props$1.previewToken,
40410
+ readAuthority: props$1.readAuthority,
39933
40411
  stage: props$1.stage
39934
40412
  },
39935
40413
  source: props$1
@@ -40079,6 +40557,7 @@ const eventRegistrationManifest = createBlockManifest({
40079
40557
  text({ as: "h2" }, bind("content.heading"), when("content.heading")),
40080
40558
  richText({ className: "rb-prose rb-max-w-none" }, bind("content.description"), when("content.description")),
40081
40559
  eventRegistration(withApiBindings({
40560
+ readAuthority: { $bind: { from: "$root.readAuthority" } },
40082
40561
  occurrenceContext: { $bind: { from: "$root.occurrenceContext" } },
40083
40562
  subject: { $bind: { from: "$root.subject" } },
40084
40563
  portalToken: { $bind: {
@@ -40540,9 +41019,10 @@ const eventCalendarRenderSchema = z.object({
40540
41019
  const eventCalendarIslandMetaCodec = createZodCodec(z.object({
40541
41020
  siteId: z.string(),
40542
41021
  apiBaseUrl: z.string().optional(),
41022
+ readAuthority: browserReadAuthoritySchema.optional(),
40543
41023
  stage: previewStageSchema.optional()
40544
41024
  }));
40545
- const eventCalendarIslandMetaKeys = defineInteractiveIslandMetaKeys("siteId", "apiBaseUrl", "stage");
41025
+ const eventCalendarIslandMetaKeys = defineInteractiveIslandMetaKeys("siteId", "apiBaseUrl", "readAuthority", "stage");
40546
41026
  /**
40547
41027
  * Collapse an optional/blank string to `undefined` so downstream week-board
40548
41028
  * copy (title, footer note) and the CTA href stay hidden unless a site opts in
@@ -40562,7 +41042,7 @@ function buildEventCalendarDisplay(source) {
40562
41042
  listColumns: source.listColumns ?? source.columns
40563
41043
  }),
40564
41044
  kind: "event-calendar",
40565
- displayMode: normalizeEventCalendarDisplayMode(source) ?? "combined",
41045
+ displayMode: resolveEventCalendarReadPlan(source).mode,
40566
41046
  className: source.className ?? null,
40567
41047
  events: (source.events ?? []).slice().sort((left, right) => new Date(left.startsAt).getTime() - new Date(right.startsAt).getTime()),
40568
41048
  boardTitle: normalizeOptionalText(source.boardTitle),
@@ -40583,7 +41063,6 @@ function buildEventCalendarListingRender(render, className = render.display.clas
40583
41063
  display: buildEventCalendarListingDisplay(display, hydration.prefetchedEvents, className),
40584
41064
  hydration: {
40585
41065
  siteId: hydration.siteId,
40586
- stage: hydration.stage,
40587
41066
  eventsPerPage: display.eventsPerPage,
40588
41067
  paginationAction: display.paginationAction,
40589
41068
  showFilters: display.showFilters,
@@ -40607,13 +41086,17 @@ const eventCalendarBlockRuntime = defineProgressiveBlockRuntime({
40607
41086
  source: createZodCodec(eventCalendarSourceSchema),
40608
41087
  render: createZodCodec(eventCalendarRenderSchema)
40609
41088
  },
40610
- buildRender: (source) => ({
40611
- display: buildEventCalendarDisplay(source.calendarWindow && (source.variant ?? source.displayMode ?? "combined") !== "combined" && (source.variant ?? source.displayMode) !== "list" ? {
41089
+ buildRender: (source) => {
41090
+ const plan = resolveEventCalendarReadPlan(source);
41091
+ const displaySource = source.calendarWindow && plan.jobs === "calendar" ? {
40612
41092
  ...source,
40613
41093
  events: source.calendarWindow.events
40614
- } : source),
40615
- hydration: buildEventCollectionHydration(source)
40616
- })
41094
+ } : source;
41095
+ return {
41096
+ display: buildEventCalendarDisplay(displaySource),
41097
+ hydration: buildEventCollectionHydration(source)
41098
+ };
41099
+ }
40617
41100
  });
40618
41101
  const eventCalendarInteractiveIslandPropsCodec = createInteractiveIslandCodec({
40619
41102
  runtime: eventCalendarBlockRuntime,
@@ -40623,6 +41106,7 @@ const eventCalendarInteractiveIslandPropsCodec = createInteractiveIslandCodec({
40623
41106
  selectMeta: (value) => ({
40624
41107
  siteId: value.siteId,
40625
41108
  apiBaseUrl: value.apiBaseUrl,
41109
+ readAuthority: value.readAuthority,
40626
41110
  stage: value.stage
40627
41111
  })
40628
41112
  });
@@ -40633,6 +41117,7 @@ function buildEventCalendarInteractiveIslandProps(props$1) {
40633
41117
  meta: {
40634
41118
  siteId: props$1.siteId,
40635
41119
  apiBaseUrl: props$1.apiBaseUrl,
41120
+ readAuthority: props$1.readAuthority,
40636
41121
  stage: props$1.stage
40637
41122
  },
40638
41123
  source: props$1
@@ -40788,6 +41273,7 @@ const eventCalendarLayout = [styledSection({
40788
41273
  rootType: "stack",
40789
41274
  rootProps: { gap: "lg" },
40790
41275
  children: [...eventSectionHeaderLayoutNodes({ splitClassName: "event-section-head event-section-head--split" }), el("event-calendar", withApiBindings({
41276
+ readAuthority: { $bind: { from: "$root.readAuthority" } },
40791
41277
  events: { $bind: { from: "data.events" } },
40792
41278
  calendarWindow: { $bind: { from: "data.calendarWindow" } },
40793
41279
  stage: { $bind: {
@@ -41671,6 +42157,7 @@ const eventListingSourceSchema = z.object({
41671
42157
  events: z.array(publicEventSchema).nullable().optional(),
41672
42158
  siteId: z.string(),
41673
42159
  apiBaseUrl: z.string().optional(),
42160
+ readAuthority: browserReadAuthoritySchema.optional(),
41674
42161
  stage: previewStageSchema.optional(),
41675
42162
  layout: eventLayoutSchema.optional(),
41676
42163
  columns: columnOptionSchema.optional(),
@@ -41711,7 +42198,6 @@ const eventListingDisplaySchema = z.object({
41711
42198
  });
41712
42199
  const eventListingHydrationSchema = z.object({
41713
42200
  siteId: z.string(),
41714
- stage: previewStageSchema.optional(),
41715
42201
  eventsPerPage: eventPageSizeSchema,
41716
42202
  paginationAction: eventListPaginationActionSchema,
41717
42203
  showFilters: z.boolean(),
@@ -41734,6 +42220,7 @@ const eventListingRenderSchema = z.object({
41734
42220
  const eventListingIslandMetaCodec = createZodCodec(z.object({
41735
42221
  siteId: z.string(),
41736
42222
  apiBaseUrl: z.string().optional(),
42223
+ readAuthority: browserReadAuthoritySchema.optional(),
41737
42224
  stage: previewStageSchema.optional()
41738
42225
  }));
41739
42226
  const eventListingBlockRuntime = defineProgressiveBlockRuntime({
@@ -41768,7 +42255,6 @@ const eventListingBlockRuntime = defineProgressiveBlockRuntime({
41768
42255
  },
41769
42256
  hydration: {
41770
42257
  siteId: source.siteId,
41771
- stage: source.stage,
41772
42258
  eventsPerPage: pageSize,
41773
42259
  paginationAction: resolveEventListPaginationAction({
41774
42260
  paginationMode: source.paginationMode,
@@ -41791,7 +42277,7 @@ const eventListingBlockRuntime = defineProgressiveBlockRuntime({
41791
42277
  };
41792
42278
  }
41793
42279
  });
41794
- const eventListingIslandMetaKeys = defineInteractiveIslandMetaKeys("siteId", "apiBaseUrl", "stage");
42280
+ const eventListingIslandMetaKeys = defineInteractiveIslandMetaKeys("siteId", "apiBaseUrl", "readAuthority", "stage");
41795
42281
  const eventListingInteractiveIslandPropsCodec = createInteractiveIslandCodec({
41796
42282
  runtime: eventListingBlockRuntime,
41797
42283
  mode: "event-listing",
@@ -41800,6 +42286,7 @@ const eventListingInteractiveIslandPropsCodec = createInteractiveIslandCodec({
41800
42286
  selectMeta: (value) => ({
41801
42287
  siteId: value.siteId,
41802
42288
  apiBaseUrl: value.apiBaseUrl,
42289
+ readAuthority: value.readAuthority,
41803
42290
  stage: value.stage
41804
42291
  })
41805
42292
  });
@@ -41810,6 +42297,7 @@ function buildEventListingInteractiveIslandProps(props$1) {
41810
42297
  meta: {
41811
42298
  siteId: props$1.siteId,
41812
42299
  apiBaseUrl: props$1.apiBaseUrl,
42300
+ readAuthority: props$1.readAuthority,
41813
42301
  stage: props$1.stage
41814
42302
  },
41815
42303
  source: props$1
@@ -42055,6 +42543,7 @@ const eventListingLayout = [styledSection({
42055
42543
  rootType: "stack",
42056
42544
  rootProps: { gap: "lg" },
42057
42545
  children: [...eventSectionHeaderLayoutNodes(), el("event-listing", withApiBindings({
42546
+ readAuthority: { $bind: { from: "$root.readAuthority" } },
42058
42547
  events: { $bind: { from: "data.events" } },
42059
42548
  stage: { $bind: {
42060
42549
  from: "$root.previewStage",
@@ -42777,6 +43266,7 @@ const productDetailManifest = createBlockManifest({
42777
43266
  baseClass: "",
42778
43267
  spacing: "spacious",
42779
43268
  children: sectionContainer([productDetail(withApiBindings({
43269
+ readAuthority: { $bind: { from: "$root.readAuthority" } },
42780
43270
  mode: "product-detail",
42781
43271
  heading: { $bind: {
42782
43272
  from: "content.heading",
@@ -42949,6 +43439,7 @@ const productListManifest = createBlockManifest({
42949
43439
  baseClass: "",
42950
43440
  spacing: "spacious",
42951
43441
  children: sectionContainer([productList(withApiBindings({
43442
+ readAuthority: { $bind: { from: "$root.readAuthority" } },
42952
43443
  mode: "product-list",
42953
43444
  heading: { $bind: {
42954
43445
  from: "content.heading",
@@ -43233,6 +43724,7 @@ const shopManifest = createBlockManifest({
43233
43724
  baseClass: "",
43234
43725
  spacing: "spacious",
43235
43726
  children: sectionContainer([shop(withApiBindings({
43727
+ readAuthority: { $bind: { from: "$root.readAuthority" } },
43236
43728
  mode: "passes-memberships",
43237
43729
  showPasses: { $bind: {
43238
43730
  from: "content.showPasses",
@@ -43643,15 +44135,13 @@ function CheckoutShellView(props$1) {
43643
44135
  //#endregion
43644
44136
  //#region ../blocks/src/system/runtime/nodes/shop-commerce.server.tsx
43645
44137
  function renderServerPendingAction(label, soldOut) {
43646
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
44138
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ThemedButton, {
43647
44139
  type: "button",
43648
- className: themeButtonClassName({
43649
- variant: "default",
43650
- size: "md"
43651
- }),
44140
+ variant: "default",
44141
+ size: "md",
44142
+ label: soldOut ? "Sold out" : label,
43652
44143
  disabled: true,
43653
- "aria-disabled": "true",
43654
- children: soldOut ? "Sold out" : label
44144
+ "aria-disabled": "true"
43655
44145
  }), !soldOut ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
43656
44146
  className: "rb-caption status-muted",
43657
44147
  children: "Cart actions become interactive after page load."
@@ -43668,13 +44158,11 @@ function ProductListServerContent(props$1) {
43668
44158
  selectedVariantId: card.selectedVariantId,
43669
44159
  disabled: true
43670
44160
  }),
43671
- actions: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [renderServerPendingAction(card.actionLabel, card.soldOut), card.path ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", {
44161
+ actions: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [renderServerPendingAction(card.actionLabel, card.soldOut), card.path ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ThemedButtonLink, {
43672
44162
  href: card.path,
43673
- className: themeButtonClassName({
43674
- variant: "secondary",
43675
- size: "sm"
43676
- }),
43677
- children: "View details"
44163
+ variant: "secondary",
44164
+ size: "sm",
44165
+ label: "View details"
43678
44166
  }) : null] })
43679
44167
  }, card.productId))
43680
44168
  });
@@ -43978,10 +44466,6 @@ function AgendaLinkCard({ event, showCapacity, showVenue, buttonVariant, buttonT
43978
44466
  const price = formatEventPrice(event);
43979
44467
  const capacity = showCapacity ? formatEventRemainingPlaces(event) : null;
43980
44468
  const cta = resolveEventCta(event, buttonText);
43981
- const buttonClass = themeButtonClassName({
43982
- variant: buttonVariant,
43983
- size: "sm"
43984
- });
43985
44469
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("article", {
43986
44470
  className: "event-agenda-card event-agenda-card--agenda",
43987
44471
  children: [
@@ -44033,12 +44517,14 @@ function AgendaLinkCard({ event, showCapacity, showVenue, buttonVariant, buttonT
44033
44517
  }), cta.hidden ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
44034
44518
  className: "event-agenda-card-status status-muted",
44035
44519
  children: cta.label
44036
- }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", {
44520
+ }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ThemedButtonLink, {
44037
44521
  href: cta.href,
44038
44522
  target: cta.external ? "_blank" : undefined,
44039
44523
  rel: cta.external ? "noopener noreferrer" : undefined,
44040
- className: `${buttonClass} event-agenda-card-cta`,
44041
- children: cta.label
44524
+ variant: buttonVariant,
44525
+ size: "sm",
44526
+ extraClassName: "event-agenda-card-cta",
44527
+ label: cta.label
44042
44528
  })]
44043
44529
  })
44044
44530
  ]
@@ -44244,7 +44730,7 @@ const WeekBoardCard = ({ event, showCapacity, calendarTimeZone }) => {
44244
44730
  ]
44245
44731
  });
44246
44732
  };
44247
- const WeekBoardNavigationControls = ({ navigation: navigation$1, todayClassName }) => {
44733
+ const WeekBoardNavigationControls = ({ navigation: navigation$1, buttonVariant }) => {
44248
44734
  const handlers = navigation$1.kind === "interactive" ? navigation$1 : {
44249
44735
  onPrevious: undefined,
44250
44736
  onNext: undefined,
@@ -44277,12 +44763,13 @@ const WeekBoardNavigationControls = ({ navigation: navigation$1, todayClassName
44277
44763
  onClick: handlers.onNext,
44278
44764
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CalendarNavigationChevron, { direction: "next" })
44279
44765
  }),
44280
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
44766
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ThemedButton, {
44281
44767
  type: "button",
44282
- className: todayClassName,
44768
+ variant: buttonVariant,
44769
+ size: "sm",
44770
+ label: "Today",
44283
44771
  disabled: navigation$1.isCurrentWeek,
44284
- onClick: handlers.onToday,
44285
- children: "Today"
44772
+ onClick: handlers.onToday
44286
44773
  })
44287
44774
  ]
44288
44775
  });
@@ -44298,18 +44785,19 @@ const WeekBoardLegend = () => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div",
44298
44785
  }), item.label]
44299
44786
  }, item.status))
44300
44787
  });
44301
- const WeekBoardLoadError = ({ navigation: navigation$1, buttonClassName }) => {
44788
+ const WeekBoardLoadError = ({ navigation: navigation$1, buttonVariant }) => {
44302
44789
  if (navigation$1.kind !== "interactive" || navigation$1.loadState.kind !== "error") {
44303
44790
  return null;
44304
44791
  }
44305
44792
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
44306
44793
  className: "event-week-board-error",
44307
44794
  role: "status",
44308
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { children: "Failed to load events" }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
44795
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { children: "Failed to load events" }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ThemedButton, {
44309
44796
  type: "button",
44310
- className: buttonClassName,
44311
- onClick: navigation$1.loadState.onRetry,
44312
- children: "Try again"
44797
+ variant: buttonVariant,
44798
+ size: "sm",
44799
+ label: "Try again",
44800
+ onClick: navigation$1.loadState.onRetry
44313
44801
  })]
44314
44802
  });
44315
44803
  };
@@ -44341,17 +44829,18 @@ const WeekBoardGrid = ({ days, eventsByDate, showCapacity, calendarTimeZone, tod
44341
44829
  }, dateKey);
44342
44830
  })
44343
44831
  });
44344
- const WeekBoardFooter = ({ note, ctaHref, ctaLabel, ctaClassName }) => {
44832
+ const WeekBoardFooter = ({ note, ctaHref, ctaLabel, buttonVariant }) => {
44345
44833
  if (note === null && ctaHref === null) return null;
44346
44834
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
44347
44835
  className: "event-week-board-foot",
44348
44836
  children: [note === null ? null : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
44349
44837
  className: "event-week-board-foot-note",
44350
44838
  children: note
44351
- }), ctaHref === null ? null : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", {
44352
- className: ctaClassName,
44839
+ }), ctaHref === null ? null : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ThemedButtonLink, {
44840
+ variant: buttonVariant,
44841
+ size: "sm",
44353
44842
  href: ctaHref,
44354
- children: ctaLabel
44843
+ label: ctaLabel
44355
44844
  })]
44356
44845
  });
44357
44846
  };
@@ -44366,14 +44855,6 @@ const WeekBoardFooter = ({ note, ctaHref, ctaLabel, ctaClassName }) => {
44366
44855
  const WeekBoardView = ({ days, events, navigation: navigation$1, showCapacity, emptyMessage = "No classes scheduled this week", title, footerNote, ctaLabel = "Reserve a place", ctaHref = null, buttonVariant = "outline", elevated = false, banded = false, calendarTimeZone, today }) => {
44367
44856
  const eventsByDate = groupEventsByDate(events, calendarTimeZone);
44368
44857
  const hasAnyEvents = days.some((date) => (eventsByDate.get(formatDateKey(date)) ?? []).length > 0);
44369
- const ctaClassName = themeButtonClassName({
44370
- variant: buttonVariant,
44371
- size: "sm"
44372
- });
44373
- const todayClassName = themeButtonClassName({
44374
- variant: buttonVariant,
44375
- size: "sm"
44376
- });
44377
44858
  const hasTitle = typeof title === "string" && title.length > 0;
44378
44859
  const hasFooterNote = typeof footerNote === "string" && footerNote.length > 0;
44379
44860
  const footerNoteText = hasAnyEvents ? hasFooterNote ? footerNote : null : emptyMessage;
@@ -44396,14 +44877,14 @@ const WeekBoardView = ({ days, events, navigation: navigation$1, showCapacity, e
44396
44877
  }) : null,
44397
44878
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(WeekBoardNavigationControls, {
44398
44879
  navigation: navigation$1,
44399
- todayClassName
44880
+ buttonVariant
44400
44881
  }),
44401
44882
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(WeekBoardLegend, {})
44402
44883
  ]
44403
44884
  }),
44404
44885
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(WeekBoardLoadError, {
44405
44886
  navigation: navigation$1,
44406
- buttonClassName: todayClassName
44887
+ buttonVariant
44407
44888
  }),
44408
44889
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(WeekBoardGrid, {
44409
44890
  days,
@@ -44416,7 +44897,7 @@ const WeekBoardView = ({ days, events, navigation: navigation$1, showCapacity, e
44416
44897
  note: footerNoteText,
44417
44898
  ctaHref: resolvedCtaHref,
44418
44899
  ctaLabel,
44419
- ctaClassName
44900
+ buttonVariant
44420
44901
  })
44421
44902
  ]
44422
44903
  })
@@ -44521,6 +45002,54 @@ function assertNeverDisplayMode(value) {
44521
45002
  function renderEventCard(event, display) {
44522
45003
  return renderEventListItem(event, display);
44523
45004
  }
45005
+ function CalendarSsrHeader(props$1) {
45006
+ const periodLabel = props$1.period === "week" ? "week" : "month";
45007
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
45008
+ className: "event-calendar-header",
45009
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
45010
+ className: "event-calendar-nav",
45011
+ children: [
45012
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
45013
+ type: "button",
45014
+ className: "event-calendar-nav-btn",
45015
+ "aria-label": `Previous ${periodLabel}`,
45016
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CalendarSsrChevron, { direction: "previous" })
45017
+ }),
45018
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", {
45019
+ className: "event-calendar-title",
45020
+ children: props$1.title
45021
+ }),
45022
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
45023
+ type: "button",
45024
+ className: "event-calendar-nav-btn",
45025
+ "aria-label": `Next ${periodLabel}`,
45026
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CalendarSsrChevron, { direction: "next" })
45027
+ })
45028
+ ]
45029
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ThemedButton, {
45030
+ type: "button",
45031
+ variant: props$1.buttonVariant,
45032
+ size: "sm",
45033
+ label: "Today"
45034
+ })]
45035
+ });
45036
+ }
45037
+ function CalendarSsrChevron(props$1) {
45038
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", {
45039
+ width: "20",
45040
+ height: "20",
45041
+ fill: "none",
45042
+ stroke: "currentColor",
45043
+ strokeWidth: 2,
45044
+ viewBox: "0 0 24 24",
45045
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", {
45046
+ strokeLinecap: "round",
45047
+ strokeLinejoin: "round",
45048
+ strokeWidth: 2,
45049
+ d: props$1.direction === "previous" ? "M15 19l-7-7 7-7" : "M9 5l7 7-7 7"
45050
+ })
45051
+ });
45052
+ }
44524
45053
  function renderCombinedSsr(display, prefetchedEvents) {
44525
45054
  const listDisplay = buildEventCalendarListingDisplay(display, prefetchedEvents, "event-combined-content");
44526
45055
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
@@ -44568,62 +45097,10 @@ function renderCalendarSsr(display, hydration) {
44568
45097
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
44569
45098
  className: clsx_default("event-calendar", display.className ?? undefined),
44570
45099
  "data-block": "event-calendar",
44571
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
44572
- className: "event-calendar-header",
44573
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
44574
- className: "event-calendar-nav",
44575
- children: [
44576
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
44577
- type: "button",
44578
- className: "event-calendar-nav-btn",
44579
- "aria-label": calendarView === "week" ? "Previous week" : "Previous month",
44580
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", {
44581
- width: "20",
44582
- height: "20",
44583
- fill: "none",
44584
- stroke: "currentColor",
44585
- strokeWidth: 2,
44586
- viewBox: "0 0 24 24",
44587
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", {
44588
- strokeLinecap: "round",
44589
- strokeLinejoin: "round",
44590
- strokeWidth: 2,
44591
- d: "M15 19l-7-7 7-7"
44592
- })
44593
- })
44594
- }),
44595
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", {
44596
- className: "event-calendar-title",
44597
- children: viewport.title
44598
- }),
44599
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
44600
- type: "button",
44601
- className: "event-calendar-nav-btn",
44602
- "aria-label": calendarView === "week" ? "Next week" : "Next month",
44603
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", {
44604
- width: "20",
44605
- height: "20",
44606
- fill: "none",
44607
- stroke: "currentColor",
44608
- strokeWidth: 2,
44609
- viewBox: "0 0 24 24",
44610
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", {
44611
- strokeLinecap: "round",
44612
- strokeLinejoin: "round",
44613
- strokeWidth: 2,
44614
- d: "M9 5l7 7-7 7"
44615
- })
44616
- })
44617
- })
44618
- ]
44619
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
44620
- type: "button",
44621
- className: themeButtonClassName({
44622
- variant: display.buttonVariant,
44623
- size: "sm"
44624
- }),
44625
- children: "Today"
44626
- })]
45100
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CalendarSsrHeader, {
45101
+ title: viewport.title,
45102
+ period: calendarView,
45103
+ buttonVariant: display.buttonVariant
44627
45104
  }), viewport.kind === "week" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(WeekAgendaView, {
44628
45105
  days: viewport.days,
44629
45106
  events: [...display.events],
@@ -44700,62 +45177,10 @@ function renderTimetableSsr(display, hydration) {
44700
45177
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
44701
45178
  className: clsx_default("event-calendar", "event-calendar--timetable", display.className ?? undefined),
44702
45179
  "data-block": "event-calendar",
44703
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
44704
- className: "event-calendar-header",
44705
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
44706
- className: "event-calendar-nav",
44707
- children: [
44708
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
44709
- type: "button",
44710
- className: "event-calendar-nav-btn",
44711
- "aria-label": "Previous week",
44712
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", {
44713
- width: "20",
44714
- height: "20",
44715
- fill: "none",
44716
- stroke: "currentColor",
44717
- strokeWidth: 2,
44718
- viewBox: "0 0 24 24",
44719
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", {
44720
- strokeLinecap: "round",
44721
- strokeLinejoin: "round",
44722
- strokeWidth: 2,
44723
- d: "M15 19l-7-7 7-7"
44724
- })
44725
- })
44726
- }),
44727
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", {
44728
- className: "event-calendar-title",
44729
- children: viewport.title
44730
- }),
44731
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
44732
- type: "button",
44733
- className: "event-calendar-nav-btn",
44734
- "aria-label": "Next week",
44735
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", {
44736
- width: "20",
44737
- height: "20",
44738
- fill: "none",
44739
- stroke: "currentColor",
44740
- strokeWidth: 2,
44741
- viewBox: "0 0 24 24",
44742
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", {
44743
- strokeLinecap: "round",
44744
- strokeLinejoin: "round",
44745
- strokeWidth: 2,
44746
- d: "M9 5l7 7-7 7"
44747
- })
44748
- })
44749
- })
44750
- ]
44751
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
44752
- type: "button",
44753
- className: themeButtonClassName({
44754
- variant: display.buttonVariant,
44755
- size: "sm"
44756
- }),
44757
- children: "Today"
44758
- })]
45180
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CalendarSsrHeader, {
45181
+ title: viewport.title,
45182
+ period: "week",
45183
+ buttonVariant: display.buttonVariant
44759
45184
  }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
44760
45185
  className: "event-timetable",
44761
45186
  children: [
@@ -45271,14 +45696,12 @@ const FormNodeSSR = ({ blockId, value, submitLabel, successMessage, className, o
45271
45696
  className: "fb-actions",
45272
45697
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
45273
45698
  className: "fb-actions-inner",
45274
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
45699
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ThemedButton, {
45275
45700
  type: "submit",
45276
- className: themeButtonClassName({
45277
- variant: "primary",
45278
- size: "md",
45279
- extraClassName: "rb-w-full rb-sm-w-auto"
45280
- }),
45281
- children: display.submitLabel
45701
+ variant: "primary",
45702
+ size: "md",
45703
+ extraClassName: "rb-w-full rb-sm-w-auto",
45704
+ label: display.submitLabel
45282
45705
  })
45283
45706
  })
45284
45707
  })
@@ -45376,13 +45799,11 @@ function NewsletterFormSSR(props$1) {
45376
45799
  }) : null,
45377
45800
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
45378
45801
  className: "newsletter-submit",
45379
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
45802
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ThemedButton, {
45380
45803
  type: "submit",
45381
- className: themeButtonClassName({
45382
- variant: display.buttonVariant,
45383
- size: "md"
45384
- }),
45385
- children: display.buttonLabel
45804
+ variant: display.buttonVariant,
45805
+ size: "md",
45806
+ label: display.buttonLabel
45386
45807
  })
45387
45808
  })
45388
45809
  ]
@@ -45470,28 +45891,24 @@ function ShopSSR({ blockId, siteId, apiBaseUrl, stage, children, checkoutEndpoin
45470
45891
  display: render.display,
45471
45892
  passCards: render.display.passes.map((pass) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PassCardView, {
45472
45893
  display: pass,
45473
- action: pass.action.kind === "unavailable" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PassPurchaseUnavailable, { label: pass.action.label }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
45894
+ action: pass.action.kind === "unavailable" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PassPurchaseUnavailable, { label: pass.action.label }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ThemedButton, {
45474
45895
  type: "button",
45475
- className: themeButtonClassName({
45476
- variant: render.hydration.buttonVariant,
45477
- size: "md"
45478
- }),
45896
+ variant: render.hydration.buttonVariant,
45897
+ size: "md",
45898
+ label: pass.action.label,
45479
45899
  disabled: true,
45480
- "aria-disabled": "true",
45481
- children: pass.action.label
45900
+ "aria-disabled": "true"
45482
45901
  })
45483
45902
  }, pass.id)),
45484
45903
  membershipCards: render.display.memberships.map((membership) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MembershipCardView, {
45485
45904
  display: membership,
45486
- action: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
45905
+ action: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ThemedButton, {
45487
45906
  type: "button",
45488
- className: themeButtonClassName({
45489
- variant: render.hydration.buttonVariant,
45490
- size: "md"
45491
- }),
45907
+ variant: render.hydration.buttonVariant,
45908
+ size: "md",
45909
+ label: membership.actionLabel,
45492
45910
  disabled: true,
45493
- "aria-disabled": "true",
45494
- children: membership.actionLabel
45911
+ "aria-disabled": "true"
45495
45912
  })
45496
45913
  }, membership.id))
45497
45914
  }),
@@ -45559,6 +45976,7 @@ const serverComponentRegistry = {
45559
45976
  svg: SvgNode,
45560
45977
  section: SectionNode,
45561
45978
  headerSection: header_section_server_default,
45979
+ headerControl: HeaderControlNode,
45562
45980
  stack: StackNode,
45563
45981
  inline: InlineNode,
45564
45982
  grid: GridNode,
@@ -46501,16 +46919,73 @@ function resolveChildren(nodes, context) {
46501
46919
  function isReactNode(value) {
46502
46920
  return value !== null && value !== undefined;
46503
46921
  }
46922
+ const RENDERER_METADATA_PROP_KEYS = new Set([
46923
+ "pathBase",
46924
+ "blockId",
46925
+ "blockKind",
46926
+ "blockContent",
46927
+ "fragmentRegistry",
46928
+ "previewAuthoring",
46929
+ "contentVersionId",
46930
+ "imageResolveContext"
46931
+ ]);
46932
+ function omitRendererMetadataProps(props$1) {
46933
+ const presentationProps = {};
46934
+ for (const [key, value] of Object.entries(props$1)) {
46935
+ if (!RENDERER_METADATA_PROP_KEYS.has(key)) presentationProps[key] = value;
46936
+ }
46937
+ return presentationProps;
46938
+ }
46939
+ const BLOCK_ID_METADATA_CONSUMERS = new Set([
46940
+ "accordion",
46941
+ "appointment-services",
46942
+ "booking-form",
46943
+ "carousel",
46944
+ "cart",
46945
+ "checkout",
46946
+ "event-calendar",
46947
+ "event-combined",
46948
+ "event-details",
46949
+ "event-listing",
46950
+ "event-registration",
46951
+ "form",
46952
+ "gifting",
46953
+ "headersection",
46954
+ "location-map",
46955
+ "newsletter-form",
46956
+ "product-detail",
46957
+ "product-list",
46958
+ "shop",
46959
+ "weekly-slot-availability"
46960
+ ]);
46961
+ const BLOCK_CONTENT_METADATA_CONSUMERS = new Set([
46962
+ "feature-card-icon",
46963
+ "headersection",
46964
+ "media",
46965
+ "text"
46966
+ ]);
46967
+ const BLOCK_KIND_METADATA_CONSUMERS = new Set([
46968
+ "headersection",
46969
+ "media",
46970
+ "richtext"
46971
+ ]);
46972
+ /**
46973
+ * Projects resolver context only to node kinds with an explicit metadata
46974
+ * contract. Presentation props and renderer metadata never share a universal
46975
+ * spread boundary, so adding metadata cannot leak it into DOM-backed nodes.
46976
+ */
46504
46977
  function resolveNodeMetadata(nodeType, context) {
46505
- return {
46506
- pathBase: context.pathBase,
46507
- blockId: context.blockId,
46508
- blockKind: context.blockKind,
46509
- blockContent: context.blockContent,
46510
- fragmentRegistry: context.fragmentRegistry,
46511
- previewAuthoring: context.previewAuthoring,
46512
- ...nodeType.toLowerCase() === "newsletter-form" ? { contentVersionId: context.contentVersionId } : {},
46513
- ...nodeType === "media" && context.imageResolveContext ? { imageResolveContext: context.imageResolveContext } : {}
46978
+ const normalizedType = nodeType.toLowerCase();
46979
+ return {
46980
+ ...BLOCK_ID_METADATA_CONSUMERS.has(normalizedType) ? { blockId: context.blockId } : {},
46981
+ ...BLOCK_KIND_METADATA_CONSUMERS.has(normalizedType) ? { blockKind: context.blockKind } : {},
46982
+ ...BLOCK_CONTENT_METADATA_CONSUMERS.has(normalizedType) ? { blockContent: context.blockContent } : {},
46983
+ ...normalizedType === "headersection" ? {
46984
+ pathBase: context.pathBase,
46985
+ fragmentRegistry: context.fragmentRegistry
46986
+ } : {},
46987
+ ...normalizedType === "newsletter-form" ? { contentVersionId: context.contentVersionId } : {},
46988
+ ...normalizedType === "media" && context.imageResolveContext ? { imageResolveContext: context.imageResolveContext } : {}
46514
46989
  };
46515
46990
  }
46516
46991
  /**
@@ -46553,7 +47028,7 @@ function resolveNode(node, context, indexFallback) {
46553
47028
  props$1 = omitHeadingDecorationProps(props$1);
46554
47029
  const children = resolveChildren(node.children, scopeContext);
46555
47030
  const elementProps = {
46556
- ...props$1,
47031
+ ...omitRendererMetadataProps(props$1),
46557
47032
  key: node.key ?? indexFallback,
46558
47033
  ...resolveNodeMetadata(node.type, context)
46559
47034
  };
@@ -47276,7 +47751,7 @@ function generateInputCss({ themeId, theme, inputSystem }) {
47276
47751
  baseInputRules.push("transition: border-color 0.2s ease, box-shadow 0.2s ease");
47277
47752
  const labelSelector = `${rootSelector} .form-label`;
47278
47753
  const labelRules = [];
47279
- labelRules.push(`color: ${rgbColorValue(inputSystem.label.textColorToken)}`);
47754
+ labelRules.push(`color: ${textColorValue(inputSystem.label.textColorToken)}`);
47280
47755
  labelRules.push(`font-weight: ${FONT_WEIGHT_MAP[inputSystem.label.fontWeight]}`);
47281
47756
  labelRules.push(`font-size: ${LABEL_FONT_SIZE_MAP[inputSystem.label.fontSize]}`);
47282
47757
  if (inputSystem.label.textTransform && inputSystem.label.textTransform !== "none") {
@@ -48556,6 +49031,125 @@ function generateFooterBottomTextLinkStyles(footer, themeId, tokens) {
48556
49031
  return cssChunks.join("\n");
48557
49032
  }
48558
49033
 
49034
+ //#endregion
49035
+ //#region ../theme-core/src/layout/boundaryCss.ts
49036
+ /**
49037
+ * Section-break CSS, generated from the transition catalogue (issue 1422).
49038
+ *
49039
+ * The renderer emits one element per shown join:
49040
+ *
49041
+ * <div data-block-boundary data-boundary-treatment="wave-edge-gentle"
49042
+ * data-boundary-placement="previous"
49043
+ * style="--boundary-shape-paint: …; --boundary-band-paint: …">
49044
+ *
49045
+ * Every selector matches an exact attribute value, so there is no reliance on
49046
+ * prefix ordering in the cascade and nothing reads colours out of a string.
49047
+ * The shape layer is `::after`; the band layer (paint → paint only) is
49048
+ * `::before`.
49049
+ */
49050
+ const waveMaskSvgPaths = {
49051
+ classic: "M0 72V46C130 55 260 24 420 30C590 36 690 62 860 42C1035 21 1160 47 1305 36C1365 31 1415 33 1440 38V72H0Z",
49052
+ balanced: "M0 72V42C120 24 240 24 360 42C480 60 600 60 720 42C840 24 960 24 1080 42C1200 60 1320 60 1440 42V72H0Z",
49053
+ gentle: "M0 72V43C180 32 300 32 480 43C660 54 780 54 960 43C1140 32 1260 32 1440 43V72H0Z",
49054
+ bold: "M0 72V44C90 14 270 14 360 44C450 74 630 74 720 44C810 14 990 14 1080 44C1170 74 1350 74 1440 44V72H0Z",
49055
+ drift: "M0 72V39C115 31 205 54 340 48C505 41 610 16 760 33C920 51 1015 64 1160 44C1280 27 1375 35 1440 50V72H0Z"
49056
+ };
49057
+ function waveMaskDataUrl(mask) {
49058
+ return svgDataUrl(`<svg viewBox='0 0 1440 72' xmlns='http://www.w3.org/2000/svg' preserveAspectRatio='none'><path d='${waveMaskSvgPaths[mask]}' fill='white'/></svg>`);
49059
+ }
49060
+ /**
49061
+ * How each placement anchors the layers against the zero-height boundary
49062
+ * element that sits exactly on the join.
49063
+ *
49064
+ * - `centred` straddles the join, band under shape.
49065
+ * - `previous` sits above the join, inside the previous section.
49066
+ * - `next` sits below the join, inside the next section, with the shape
49067
+ * flipped so it reads as the mirror of `previous`.
49068
+ */
49069
+ const placementRules = {
49070
+ centred: {
49071
+ shape: ["top: 0;", "transform: translateY(-50%);"],
49072
+ band: ["top: 0;", "transform: translateY(-50%);"]
49073
+ },
49074
+ previous: {
49075
+ shape: ["bottom: 0;"],
49076
+ band: null
49077
+ },
49078
+ next: {
49079
+ shape: ["top: 0;", "transform: scaleY(-1);"],
49080
+ band: null
49081
+ }
49082
+ };
49083
+ function generateBoundaryCss(selector) {
49084
+ const boundary = `${selector} [data-block-boundary]`;
49085
+ return [
49086
+ rule$1(boundary, [
49087
+ "position: relative;",
49088
+ "z-index: 3;",
49089
+ "height: 0;",
49090
+ "pointer-events: none;"
49091
+ ]),
49092
+ rule$1(`${selector} [data-block][data-site-style-boundary-before] > :where([data-slot='section'])`, ["padding-top: calc(var(--rb-section-pad-y, 0rem) + var(--site-style-boundary-before-reserve, 0rem));"]),
49093
+ rule$1(`${selector} [data-block][data-site-style-boundary-after] > :where([data-slot='section'])`, ["padding-bottom: calc(var(--rb-section-pad-y, 0rem) + var(--site-style-boundary-after-reserve, 0rem));"]),
49094
+ rule$1(`${boundary}::before,\n${boundary}::after`, [
49095
+ "content: '';",
49096
+ "position: absolute;",
49097
+ "left: 0;",
49098
+ "right: 0;",
49099
+ "height: var(--boundary-height);",
49100
+ "pointer-events: none;"
49101
+ ]),
49102
+ rule$1(`${boundary}::before`, ["z-index: 0;", "background: var(--boundary-band-paint, transparent);"]),
49103
+ rule$1(`${boundary}::after`, ["z-index: 1;"]),
49104
+ ...placementCss(boundary),
49105
+ ...transitionCatalogueEntries.flatMap((entry) => treatmentCss(boundary, entry))
49106
+ ].join("\n\n");
49107
+ }
49108
+ function placementCss(boundary) {
49109
+ return Object.keys(placementRules).flatMap((placement) => {
49110
+ const placed = `${boundary}[data-boundary-placement='${placement}']`;
49111
+ const rules = placementRules[placement];
49112
+ return [rule$1(`${placed}::after`, rules.shape), rules.band ? rule$1(`${placed}::before`, rules.band) : rule$1(`${placed}::before`, ["content: none;"])];
49113
+ });
49114
+ }
49115
+ function treatmentCss(boundary, entry) {
49116
+ const selected = `${boundary}[data-boundary-treatment='${entry.intent}']`;
49117
+ const metrics = boundaryRuntimeMetricsForDecorativeTransition(entry.intent);
49118
+ return [rule$1(selected, [`--boundary-height: ${metrics.heightCss};`]), rule$1(`${selected}::after`, shapeDeclarations(entry))];
49119
+ }
49120
+ function shapeDeclarations(entry) {
49121
+ switch (entry.shape.kind) {
49122
+ case "fade": return [
49123
+ "/* Fallback for browsers without color-mix(). */",
49124
+ "background: linear-gradient(to bottom, transparent 0%, var(--boundary-shape-paint) 100%);",
49125
+ "background: linear-gradient(to bottom, transparent 0%, color-mix(in srgb, var(--boundary-shape-paint) 16%, transparent) 34%, color-mix(in srgb, var(--boundary-shape-paint) 68%, transparent) 78%, var(--boundary-shape-paint) 100%);"
49126
+ ];
49127
+ case "wave": {
49128
+ const mask = waveMaskDataUrl(entry.shape.mask);
49129
+ return [
49130
+ "background: var(--boundary-shape-paint);",
49131
+ `mask-image: url("${mask}");`,
49132
+ "mask-repeat: no-repeat;",
49133
+ "mask-size: 100% 100%;",
49134
+ `-webkit-mask-image: url("${mask}");`,
49135
+ "-webkit-mask-repeat: no-repeat;",
49136
+ "-webkit-mask-size: 100% 100%;"
49137
+ ];
49138
+ }
49139
+ case "angle": return [
49140
+ "height: calc(var(--boundary-height) + 2px);",
49141
+ "background: var(--boundary-shape-paint);",
49142
+ `clip-path: ${anglePolygonCss(entry.shape.polygon)};`
49143
+ ];
49144
+ }
49145
+ }
49146
+ function rule$1(selector, declarations) {
49147
+ return `${selector} {\n ${declarations.join("\n ")}\n}`;
49148
+ }
49149
+ function svgDataUrl(svg) {
49150
+ return `data:image/svg+xml,${encodeURIComponent(svg)}`;
49151
+ }
49152
+
48559
49153
  //#endregion
48560
49154
  //#region ../theme-core/src/layout/generateLayoutCss.ts
48561
49155
  /**
@@ -48591,7 +49185,7 @@ function generateLayoutCss(options) {
48591
49185
  if (bodyTextTypographyCss) {
48592
49186
  cssChunks.push(bodyTextTypographyCss);
48593
49187
  }
48594
- cssChunks.push(generateSiteStyleTransitionCss(themeId));
49188
+ cssChunks.push(generateBoundaryCss(selector));
48595
49189
  return cssChunks.join("\n\n");
48596
49190
  }
48597
49191
  function toPaddingValue(preset) {
@@ -48603,197 +49197,6 @@ function toPaddingValue(preset) {
48603
49197
  };
48604
49198
  return map[preset];
48605
49199
  }
48606
- const classicWaveTransitionMask = svgDataUrl("<svg viewBox='0 0 1440 72' xmlns='http://www.w3.org/2000/svg' preserveAspectRatio='none'><path d='M0 72V46C130 55 260 24 420 30C590 36 690 62 860 42C1035 21 1160 47 1305 36C1365 31 1415 33 1440 38V72H0Z' fill='white'/></svg>");
48607
- const balancedWaveTransitionMask = svgDataUrl("<svg viewBox='0 0 1440 72' xmlns='http://www.w3.org/2000/svg' preserveAspectRatio='none'><path d='M0 72V42C120 24 240 24 360 42C480 60 600 60 720 42C840 24 960 24 1080 42C1200 60 1320 60 1440 42V72H0Z' fill='white'/></svg>");
48608
- const gentleWaveTransitionMask = svgDataUrl("<svg viewBox='0 0 1440 72' xmlns='http://www.w3.org/2000/svg' preserveAspectRatio='none'><path d='M0 72V43C180 32 300 32 480 43C660 54 780 54 960 43C1140 32 1260 32 1440 43V72H0Z' fill='white'/></svg>");
48609
- const boldWaveTransitionMask = svgDataUrl("<svg viewBox='0 0 1440 72' xmlns='http://www.w3.org/2000/svg' preserveAspectRatio='none'><path d='M0 72V44C90 14 270 14 360 44C450 74 630 74 720 44C810 14 990 14 1080 44C1170 74 1350 74 1440 44V72H0Z' fill='white'/></svg>");
48610
- const driftWaveTransitionMask = svgDataUrl("<svg viewBox='0 0 1440 72' xmlns='http://www.w3.org/2000/svg' preserveAspectRatio='none'><path d='M0 72V39C115 31 205 54 340 48C505 41 610 16 760 33C920 51 1015 64 1160 44C1280 27 1375 35 1440 50V72H0Z' fill='white'/></svg>");
48611
- function generateSiteStyleTransitionCss(themeId) {
48612
- const selector = `:where([data-theme-scope="${themeId}"])`;
48613
- const compactBoundaryHeight = requiredBoundaryHeightCss("wave-edge-gentle");
48614
- const mediumBoundaryHeight = requiredBoundaryHeightCss("wave-edge");
48615
- const largeBoundaryHeight = requiredBoundaryHeightCss("wave-edge-bold");
48616
- const spaciousBoundaryHeight = requiredBoundaryHeightCss("soft-fade-long");
48617
- const expansiveBoundaryHeight = requiredBoundaryHeightCss("soft-fade-expansive");
48618
- return `${selector} [data-style-group^='site-style-transition-'] {
48619
- position: relative;
48620
- z-index: 2;
48621
- --site-style-transition-from: transparent;
48622
- --site-style-transition-to: rgb(var(--tb-background));
48623
- }
48624
-
48625
- ${selector} [data-block-boundary][data-style-group^='site-style-transition-'] {
48626
- position: relative;
48627
- z-index: 3;
48628
- height: 0;
48629
- pointer-events: none;
48630
- --site-style-boundary-height: ${mediumBoundaryHeight};
48631
- }
48632
-
48633
- ${selector} [data-block][data-site-style-boundary-before] > :where([data-slot='section']) {
48634
- padding-top: calc(var(--rb-section-pad-y, 0rem) + var(--site-style-boundary-before-reserve, 0rem));
48635
- }
48636
-
48637
- ${selector} [data-block][data-site-style-boundary-after] > :where([data-slot='section']) {
48638
- padding-bottom: calc(var(--rb-section-pad-y, 0rem) + var(--site-style-boundary-after-reserve, 0rem));
48639
- }
48640
-
48641
- ${selector} [data-block-boundary][data-style-group^='site-style-transition-wave-edge-']::before,
48642
- ${selector} [data-block-boundary][data-style-group^='site-style-transition-angle-edge-']::before,
48643
- ${selector} [data-block-boundary][data-style-group^='site-style-transition-soft-fade']::before {
48644
- content: '';
48645
- position: absolute;
48646
- left: 0;
48647
- right: 0;
48648
- top: 0;
48649
- transform: translateY(-50%);
48650
- z-index: 0;
48651
- height: var(--site-style-boundary-height);
48652
- background: var(--site-style-transition-from);
48653
- pointer-events: none;
48654
- }
48655
-
48656
- ${selector} [data-block-boundary][data-style-group^='site-style-transition-wave-edge-']::after,
48657
- ${selector} [data-block-boundary][data-style-group^='site-style-transition-angle-edge-']::after,
48658
- ${selector} [data-block-boundary][data-style-group^='site-style-transition-soft-fade']::after {
48659
- content: '';
48660
- position: absolute;
48661
- left: 0;
48662
- right: 0;
48663
- top: 0;
48664
- transform: translateY(-50%);
48665
- z-index: 1;
48666
- height: var(--site-style-boundary-height);
48667
- pointer-events: none;
48668
- }
48669
-
48670
- ${selector} [data-style-group*='-from-base-'] {
48671
- --site-style-transition-from: rgb(var(--tb-background));
48672
- }
48673
-
48674
- ${selector} [data-style-group*='-from-muted-band-'] {
48675
- --site-style-transition-from: rgb(var(--tb-muted));
48676
- }
48677
-
48678
- ${selector} [data-style-group*='-from-accent-band-'] {
48679
- --site-style-transition-from: rgb(var(--tb-accent));
48680
- }
48681
-
48682
- ${selector} [data-style-group*='-from-brand-depth-band-'] {
48683
- --site-style-transition-from: rgb(var(--tb-primary-800));
48684
- }
48685
-
48686
- ${selector} [data-style-group$='-to-base'],
48687
- ${selector} [data-style-group$='-to-hero-image'] {
48688
- --site-style-transition-to: rgb(var(--tb-background));
48689
- }
48690
-
48691
- ${selector} [data-style-group$='-to-muted-band'] {
48692
- --site-style-transition-to: rgb(var(--tb-muted));
48693
- }
48694
-
48695
- ${selector} [data-style-group$='-to-accent-band'] {
48696
- --site-style-transition-to: rgb(var(--tb-accent));
48697
- }
48698
-
48699
- ${selector} [data-style-group$='-to-brand-depth-band'] {
48700
- --site-style-transition-to: rgb(var(--tb-primary-800));
48701
- }
48702
-
48703
- ${selector} [data-block-boundary][data-style-group^='site-style-transition-soft-fade']::after {
48704
- /* Fallback for browsers without color-mix(). */
48705
- background: linear-gradient(
48706
- to bottom,
48707
- transparent 0%,
48708
- var(--site-style-transition-to) 100%
48709
- );
48710
- background: linear-gradient(
48711
- to bottom,
48712
- transparent 0%,
48713
- color-mix(in srgb, var(--site-style-transition-to) 16%, transparent) 34%,
48714
- color-mix(in srgb, var(--site-style-transition-to) 68%, transparent) 78%,
48715
- var(--site-style-transition-to) 100%
48716
- );
48717
- }
48718
-
48719
- ${selector} [data-block-boundary][data-style-group^='site-style-transition-soft-fade-long-'] {
48720
- --site-style-boundary-height: ${spaciousBoundaryHeight};
48721
- }
48722
-
48723
- ${selector} [data-block-boundary][data-style-group^='site-style-transition-soft-fade-expansive-'] {
48724
- --site-style-boundary-height: ${expansiveBoundaryHeight};
48725
- }
48726
-
48727
- ${selector} [data-block-boundary][data-style-group^='site-style-transition-angle-edge-']::after {
48728
- height: calc(var(--site-style-boundary-height) + 2px);
48729
- background: var(--site-style-transition-to);
48730
- clip-path: polygon(0 42%, 100% 8%, 100% 100%, 0 100%);
48731
- }
48732
-
48733
- ${selector} [data-block-boundary][data-style-group^='site-style-transition-angle-edge-subtle-'] {
48734
- --site-style-boundary-height: ${compactBoundaryHeight};
48735
- }
48736
-
48737
- ${selector} [data-block-boundary][data-style-group^='site-style-transition-angle-edge-subtle-']::after {
48738
- clip-path: polygon(0 34%, 100% 18%, 100% 100%, 0 100%);
48739
- }
48740
-
48741
- ${selector} [data-block-boundary][data-style-group^='site-style-transition-angle-edge-steep-'] {
48742
- --site-style-boundary-height: ${largeBoundaryHeight};
48743
- }
48744
-
48745
- ${selector} [data-block-boundary][data-style-group^='site-style-transition-angle-edge-steep-']::after {
48746
- clip-path: polygon(0 54%, 100% 0%, 100% 100%, 0 100%);
48747
- }
48748
-
48749
- ${selector} [data-block-boundary][data-style-group^='site-style-transition-wave-edge-']::after {
48750
- background: var(--site-style-transition-to);
48751
- mask-image: url("${classicWaveTransitionMask}");
48752
- mask-repeat: no-repeat;
48753
- mask-size: 100% 100%;
48754
- -webkit-mask-image: url("${classicWaveTransitionMask}");
48755
- -webkit-mask-repeat: no-repeat;
48756
- -webkit-mask-size: 100% 100%;
48757
- }
48758
-
48759
- ${selector} [data-block-boundary][data-style-group^='site-style-transition-wave-edge-balanced-']::after {
48760
- mask-image: url("${balancedWaveTransitionMask}");
48761
- -webkit-mask-image: url("${balancedWaveTransitionMask}");
48762
- }
48763
-
48764
- ${selector} [data-block-boundary][data-style-group^='site-style-transition-wave-edge-gentle-'] {
48765
- --site-style-boundary-height: ${compactBoundaryHeight};
48766
- }
48767
-
48768
- ${selector} [data-block-boundary][data-style-group^='site-style-transition-wave-edge-gentle-']::after {
48769
- mask-image: url("${gentleWaveTransitionMask}");
48770
- -webkit-mask-image: url("${gentleWaveTransitionMask}");
48771
- }
48772
-
48773
- ${selector} [data-block-boundary][data-style-group^='site-style-transition-wave-edge-bold-'] {
48774
- --site-style-boundary-height: ${largeBoundaryHeight};
48775
- }
48776
-
48777
- ${selector} [data-block-boundary][data-style-group^='site-style-transition-wave-edge-bold-']::after {
48778
- mask-image: url("${boldWaveTransitionMask}");
48779
- -webkit-mask-image: url("${boldWaveTransitionMask}");
48780
- }
48781
-
48782
- ${selector} [data-block-boundary][data-style-group^='site-style-transition-wave-edge-drift-']::after {
48783
- mask-image: url("${driftWaveTransitionMask}");
48784
- -webkit-mask-image: url("${driftWaveTransitionMask}");
48785
- }`;
48786
- }
48787
- function requiredBoundaryHeightCss(transition) {
48788
- const metrics = boundaryRuntimeMetricsForTransition(transition);
48789
- if (!metrics) {
48790
- throw new Error(`Missing boundary runtime metrics for ${transition}`);
48791
- }
48792
- return metrics.heightCss;
48793
- }
48794
- function svgDataUrl(svg) {
48795
- return `data:image/svg+xml,${encodeURIComponent(svg)}`;
48796
- }
48797
49200
  function generateHeroTypographyCss(themeId, theme) {
48798
49201
  const typography = theme.hero?.typography;
48799
49202
  if (!typography) return "";
@@ -48820,36 +49223,29 @@ function generateHeroTypographyCss(themeId, theme) {
48820
49223
  if (microSubheadlineRules.length > 0) {
48821
49224
  chunks.push(`${microSubheadlineSelector} {\n ${microSubheadlineRules.join("\n ")}\n}`);
48822
49225
  }
48823
- if (typography.responsive?.tablet) {
48824
- const tabletHeadlineRules = buildTypographyRules("headline", typography.responsive.tablet.headlineSize, typography.responsive.tablet.headlineLineHeight);
48825
- const tabletSubheadlineRules = buildTypographyRules("subheadline", typography.responsive.tablet.subheadlineSize, typography.responsive.tablet.subheadlineLineHeight);
48826
- const tabletChunks = [];
48827
- if (tabletHeadlineRules.length > 0) {
48828
- tabletChunks.push(`${headlineSelector} {\n ${tabletHeadlineRules.join("\n ")}\n }`);
48829
- }
48830
- if (tabletSubheadlineRules.length > 0) {
48831
- tabletChunks.push(`${subheadlineSelector} {\n ${tabletSubheadlineRules.join("\n ")}\n }`);
48832
- }
48833
- if (tabletChunks.length > 0) {
48834
- chunks.push(`@media ${MQ_TABLET_ONLY} {\n ${tabletChunks.join("\n\n ")}\n}`);
48835
- }
48836
- }
48837
- if (typography.responsive?.mobile) {
48838
- const mobileHeadlineRules = buildTypographyRules("headline", typography.responsive.mobile.headlineSize, typography.responsive.mobile.headlineLineHeight);
48839
- const mobileSubheadlineRules = buildTypographyRules("subheadline", typography.responsive.mobile.subheadlineSize, typography.responsive.mobile.subheadlineLineHeight);
48840
- const mobileChunks = [];
48841
- if (mobileHeadlineRules.length > 0) {
48842
- mobileChunks.push(`${headlineSelector} {\n ${mobileHeadlineRules.join("\n ")}\n }`);
48843
- }
48844
- if (mobileSubheadlineRules.length > 0) {
48845
- mobileChunks.push(`${subheadlineSelector} {\n ${mobileSubheadlineRules.join("\n ")}\n }`);
48846
- }
48847
- if (mobileChunks.length > 0) {
48848
- chunks.push(`@media ${MQ_SM_DOWN} {\n ${mobileChunks.join("\n\n ")}\n}`);
48849
- }
49226
+ const selectors = {
49227
+ headline: headlineSelector,
49228
+ subheadline: subheadlineSelector
49229
+ };
49230
+ const responsiveChunks = [responsiveHeroTypographyCss(MQ_TABLET_ONLY, selectors, typography.responsive?.tablet), responsiveHeroTypographyCss(MQ_SM_DOWN, selectors, typography.responsive?.mobile)];
49231
+ for (const chunk of responsiveChunks) {
49232
+ if (chunk) chunks.push(chunk);
48850
49233
  }
48851
49234
  return chunks.join("\n\n");
48852
49235
  }
49236
+ function responsiveHeroTypographyCss(media$1, selectors, overrides) {
49237
+ if (!overrides) return null;
49238
+ const headlineRules = buildTypographyRules("headline", overrides.headlineSize, overrides.headlineLineHeight);
49239
+ const subheadlineRules = buildTypographyRules("subheadline", overrides.subheadlineSize, overrides.subheadlineLineHeight);
49240
+ const mediaChunks = [];
49241
+ if (headlineRules.length > 0) {
49242
+ mediaChunks.push(`${selectors.headline} {\n ${headlineRules.join("\n ")}\n }`);
49243
+ }
49244
+ if (subheadlineRules.length > 0) {
49245
+ mediaChunks.push(`${selectors.subheadline} {\n ${subheadlineRules.join("\n ")}\n }`);
49246
+ }
49247
+ return mediaChunks.length > 0 ? `@media ${media$1} {\n ${mediaChunks.join("\n\n ")}\n}` : null;
49248
+ }
48853
49249
  function buildTypographyRules(role, size, lineHeight) {
48854
49250
  const rules = [];
48855
49251
  if (size) {
@@ -50066,7 +50462,7 @@ function escapeStyleContent(css) {
50066
50462
  function compileCustomCssRules(rules, themeId) {
50067
50463
  if (!rules || rules.length === 0) return "";
50068
50464
  const scopePrefix = `:where([data-theme-scope="${themeId}"])`;
50069
- return rules.map((rule$1) => compileRule(rule$1.selector, rule$1.declarations, scopePrefix)).filter(Boolean).join("\n\n");
50465
+ return rules.map((rule$2) => compileRule(rule$2.selector, rule$2.declarations, scopePrefix)).filter(Boolean).join("\n\n");
50070
50466
  }
50071
50467
  /**
50072
50468
  * Compile an array of block-specific CSS rules to a scoped CSS string.
@@ -50079,15 +50475,15 @@ function compileCustomCssRules(rules, themeId) {
50079
50475
  function compileBlockCustomCssRules(rules, themeId) {
50080
50476
  if (!rules || rules.length === 0) return "";
50081
50477
  const rulesByBlock = new Map();
50082
- for (const rule$1 of rules) {
50083
- const existing = rulesByBlock.get(rule$1.blockKind) || [];
50084
- existing.push(rule$1);
50085
- rulesByBlock.set(rule$1.blockKind, existing);
50478
+ for (const rule$2 of rules) {
50479
+ const existing = rulesByBlock.get(rule$2.blockKind) || [];
50480
+ existing.push(rule$2);
50481
+ rulesByBlock.set(rule$2.blockKind, existing);
50086
50482
  }
50087
50483
  const cssChunks = [];
50088
50484
  for (const [blockKind, blockRules] of rulesByBlock) {
50089
50485
  const scopePrefix = `:where([data-theme-scope="${themeId}"]) :where([data-block="${blockKind}"])`;
50090
- const blockCss = blockRules.map((rule$1) => compileRule(rule$1.selector, rule$1.declarations, scopePrefix)).filter(Boolean).join("\n");
50486
+ const blockCss = blockRules.map((rule$2) => compileRule(rule$2.selector, rule$2.declarations, scopePrefix)).filter(Boolean).join("\n");
50091
50487
  if (blockCss) {
50092
50488
  cssChunks.push(`/* Block: ${blockKind} */\n${blockCss}`);
50093
50489
  }
@@ -50339,7 +50735,7 @@ function compileFontFace(atRule) {
50339
50735
  * }
50340
50736
  */
50341
50737
  function compileMedia(atRule, scopePrefix, options) {
50342
- const rules = atRule.rules.map((rule$1) => compileNestedRule(rule$1.selector, rule$1.declarations, scopePrefix)).filter(Boolean).join("\n");
50738
+ const rules = atRule.rules.map((rule$2) => compileNestedRule(rule$2.selector, rule$2.declarations, scopePrefix)).filter(Boolean).join("\n");
50343
50739
  if (!rules) return "";
50344
50740
  const containerQuery = options.responsiveMode === "container" ? convertMediaQueryToContainerQuery(atRule.query) : null;
50345
50741
  if (containerQuery) {
@@ -50357,7 +50753,7 @@ function compileMedia(atRule, scopePrefix, options) {
50357
50753
  * }
50358
50754
  */
50359
50755
  function compileSupports(atRule, scopePrefix) {
50360
- const rules = atRule.rules.map((rule$1) => compileNestedRule(rule$1.selector, rule$1.declarations, scopePrefix)).filter(Boolean).join("\n");
50756
+ const rules = atRule.rules.map((rule$2) => compileNestedRule(rule$2.selector, rule$2.declarations, scopePrefix)).filter(Boolean).join("\n");
50361
50757
  if (!rules) return "";
50362
50758
  return `@supports ${atRule.condition} {\n${indent(rules, 2)}\n}`;
50363
50759
  }
@@ -50394,15 +50790,6 @@ function indent(str, spaces) {
50394
50790
  //#endregion
50395
50791
  //#region ../theme-core/src/customCss/patch.ts
50396
50792
  /**
50397
- * Generate a unique ID for a new CSS rule.
50398
- * Uses timestamp + random suffix for uniqueness.
50399
- */
50400
- function generateCssRuleId() {
50401
- const timestamp = Date.now().toString(36);
50402
- const random = Math.random().toString(36).slice(2, 6);
50403
- return `css-${timestamp}-${random}`;
50404
- }
50405
- /**
50406
50793
  * Apply a single patch operation to a rules array.
50407
50794
  *
50408
50795
  * @param rules - Current rules array
@@ -50452,20 +50839,20 @@ function diffCssRules(before, after) {
50452
50839
  });
50453
50840
  }
50454
50841
  }
50455
- for (const [id, rule$1] of afterMap) {
50842
+ for (const [id, rule$2] of afterMap) {
50456
50843
  const beforeRule = beforeMap.get(id);
50457
50844
  if (!beforeRule) {
50458
50845
  patches.push({
50459
50846
  op: "add",
50460
- rule: rule$1
50847
+ rule: rule$2
50461
50848
  });
50462
- } else if (!rulesEqual(beforeRule, rule$1)) {
50849
+ } else if (!rulesEqual(beforeRule, rule$2)) {
50463
50850
  const changes = {};
50464
- if (beforeRule.selector !== rule$1.selector) {
50465
- changes.selector = rule$1.selector;
50851
+ if (beforeRule.selector !== rule$2.selector) {
50852
+ changes.selector = rule$2.selector;
50466
50853
  }
50467
- if (!declarationsEqual(beforeRule.declarations, rule$1.declarations)) {
50468
- changes.declarations = rule$1.declarations;
50854
+ if (!declarationsEqual(beforeRule.declarations, rule$2.declarations)) {
50855
+ changes.declarations = rule$2.declarations;
50469
50856
  }
50470
50857
  if (Object.keys(changes).length > 0) {
50471
50858
  patches.push({
@@ -51098,71 +51485,173 @@ function requireThemeResources(resources, blockKind) {
51098
51485
  }
51099
51486
 
51100
51487
  //#endregion
51101
- //#region ../blocks/src/pageRendererBoundaries.tsx
51102
- const boundaryKey = (previousBlockId, nextBlockId) => `${previousBlockId}\u0000${nextBlockId}`;
51103
- function isSiteStyleTransitionStyleGroup(value) {
51104
- return value?.startsWith("site-style-transition-") === true;
51488
+ //#region ../blocks/src/pageRenderJoins.ts
51489
+ /**
51490
+ * Re-points joins across omitted blocks. Pure over joins.
51491
+ *
51492
+ * Joins are keyed by adjacent block-id pairs, so dropping B from [A, B, C]
51493
+ * removes the A→C join as well as B's own, because no A→C join was ever
51494
+ * resolved. For each surviving pair the original join is kept when the pair
51495
+ * was already adjacent. Across a gap, the treatment comes from the join
51496
+ * entering the omitted run (A→first omitted), falling back to the one leaving
51497
+ * it (last omitted→C). Nothing visual is carried: the survivors are composed
51498
+ * from their own content afterwards.
51499
+ *
51500
+ * `survivors` are compared by identity against `originalBlocks`.
51501
+ */
51502
+ function retargetJoinsAcrossOmissions(input) {
51503
+ const { joins, originalBlocks, survivingBlocks } = input;
51504
+ if (joins.length === 0) return joins;
51505
+ if (originalBlocks.every((block) => survivingBlocks.has(block))) return joins;
51506
+ const byPair = joinsByPair(joins);
51507
+ const retargeted = [];
51508
+ let previousSurvivor = null;
51509
+ let run = [];
51510
+ for (const block of originalBlocks) {
51511
+ if (!survivingBlocks.has(block)) {
51512
+ run.push(block);
51513
+ continue;
51514
+ }
51515
+ if (previousSurvivor?.id && block.id) {
51516
+ const join$1 = run.length === 0 ? byPair.get(pairKey(previousSurvivor.id, block.id)) : joinAcrossRun(byPair, previousSurvivor.id, block.id, run);
51517
+ if (join$1) retargeted.push(join$1);
51518
+ }
51519
+ previousSurvivor = block;
51520
+ run = [];
51521
+ }
51522
+ return retargeted;
51105
51523
  }
51106
- function boundaryMapForAdjacentBlockIds(boundaries) {
51107
- return new Map(boundaries.map((boundary) => [boundaryKey(boundary.previousBlockId, boundary.nextBlockId), boundary]));
51524
+ function joinAcrossRun(byPair, previousBlockId, nextBlockId, run) {
51525
+ const firstOmittedId = run[0]?.id;
51526
+ const lastOmittedId = run[run.length - 1]?.id;
51527
+ const entering = firstOmittedId ? byPair.get(pairKey(previousBlockId, firstOmittedId)) : undefined;
51528
+ const exiting = lastOmittedId ? byPair.get(pairKey(lastOmittedId, nextBlockId)) : undefined;
51529
+ const donor = entering ?? exiting;
51530
+ return donor ? {
51531
+ previousBlockId,
51532
+ nextBlockId,
51533
+ treatment: donor.treatment
51534
+ } : undefined;
51108
51535
  }
51109
- function boundaryBetweenBlocks(previousBlock, nextBlock, boundaries) {
51110
- const previousBlockId = previousBlock?.id ?? null;
51111
- const nextBlockId = nextBlock?.id ?? null;
51112
- if (!previousBlockId || !nextBlockId) return null;
51113
- return boundaries.get(boundaryKey(previousBlockId, nextBlockId)) ?? null;
51536
+ /**
51537
+ * The single composition site. For every adjacent pair of survivors with ids,
51538
+ * finds its join and composes it from both survivors' final content: what
51539
+ * each paints with and the frame each draws.
51540
+ */
51541
+ function composePageJoins(input) {
51542
+ const byPair = joinsByPair(input.joins);
51543
+ return input.survivors.flatMap((previous, index) => {
51544
+ const next = input.survivors[index + 1];
51545
+ if (!next || !previous.id || !next.id) return [];
51546
+ const join$1 = byPair.get(pairKey(previous.id, next.id));
51547
+ return [{
51548
+ previousBlockId: previous.id,
51549
+ nextBlockId: next.id,
51550
+ join: join$1 ? composeJoin(join$1, previous, next) : null
51551
+ }];
51552
+ });
51553
+ }
51554
+ function composeJoin(join$1, previous, next) {
51555
+ return {
51556
+ boundaryId: pairKey(join$1.previousBlockId, join$1.nextBlockId),
51557
+ previousBlockId: join$1.previousBlockId,
51558
+ nextBlockId: join$1.nextBlockId,
51559
+ treatment: join$1.treatment,
51560
+ outcome: composeBoundary(sectionFactsForContent(previous.content), sectionFactsForContent(next.content))
51561
+ };
51562
+ }
51563
+ /** Placement, reserves and paint for a join that draws; null otherwise. */
51564
+ function renderedJoinLayout(join$1) {
51565
+ if (!join$1 || join$1.outcome.kind !== "shown") return null;
51566
+ return boundaryLayout(join$1.treatment, join$1.outcome.composition);
51567
+ }
51568
+ /** Joins with a missing id on either side cannot sit between two blocks. */
51569
+ function joinsByPair(joins) {
51570
+ return new Map(joins.flatMap((join$1) => join$1.previousBlockId && join$1.nextBlockId ? [[pairKey(join$1.previousBlockId, join$1.nextBlockId), join$1]] : []));
51571
+ }
51572
+ /** Slot lookup key for an adjacent pair, in the one boundary-id scheme. */
51573
+ function joinSlotKey(previousBlockId, nextBlockId) {
51574
+ return pairKey(previousBlockId, nextBlockId);
51575
+ }
51576
+ function pairKey(previousBlockId, nextBlockId) {
51577
+ return makeBoundaryId(asDesignBlockId(previousBlockId), asDesignBlockId(nextBlockId));
51578
+ }
51579
+
51580
+ //#endregion
51581
+ //#region ../blocks/src/pageRendererBoundaries.tsx
51582
+ function joinSlotsByPair(slots) {
51583
+ return new Map(slots.map((slot) => [joinSlotKey(slot.previousBlockId, slot.nextBlockId), slot]));
51114
51584
  }
51115
- function renderBoundaryAfterBlock(input) {
51116
- const previousBlockId = input.block.id;
51117
- const nextBlockId = input.nextBlock?.id ?? null;
51585
+ function joinSlotBetween(previousBlockId, nextBlockId, slots) {
51118
51586
  if (!previousBlockId || !nextBlockId) return null;
51119
- const boundary = input.boundaryByAdjacentBlockIds.get(boundaryKey(previousBlockId, nextBlockId));
51120
- if (!boundary) return null;
51121
- const rendered = /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
51587
+ return slots.get(joinSlotKey(previousBlockId, nextBlockId)) ?? null;
51588
+ }
51589
+ /**
51590
+ * The markup at one join: the painted boundary element when the join draws,
51591
+ * then whatever `renderJoin` adds. Null when there is nothing to render.
51592
+ */
51593
+ function renderJoinSlot(input) {
51594
+ const { slot } = input;
51595
+ if (!slot) return null;
51596
+ const layout = renderedJoinLayout(slot.join);
51597
+ const painted = slot.join && layout ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
51122
51598
  "aria-hidden": "true",
51123
51599
  "data-block-boundary": "",
51124
- "data-boundary-id": boundary.boundaryId,
51125
- "data-boundary-previous-block-id": boundary.previousBlockId,
51126
- "data-boundary-next-block-id": boundary.nextBlockId,
51127
- "data-style-group": boundary.styleGroup,
51128
- style: boundaryCssVarsStyle(boundary)
51129
- }, `${input.blockKey}:boundary`);
51130
- return input.wrapBoundary ? input.wrapBoundary(boundary, rendered) : rendered;
51600
+ "data-boundary-id": slot.join.boundaryId,
51601
+ "data-boundary-previous-block-id": slot.previousBlockId,
51602
+ "data-boundary-next-block-id": slot.nextBlockId,
51603
+ "data-boundary-treatment": slot.join.treatment,
51604
+ "data-boundary-placement": layout.placement,
51605
+ style: boundaryPaintStyle(layout.paint)
51606
+ }, `${input.blockKey}:boundary`) : null;
51607
+ const extra = input.renderJoin?.({
51608
+ previousBlockId: slot.previousBlockId,
51609
+ nextBlockId: slot.nextBlockId,
51610
+ join: slot.join
51611
+ });
51612
+ if (!painted && (extra === null || extra === undefined)) return null;
51613
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react.Fragment, { children: [painted, extra] }, `${input.blockKey}:join`);
51131
51614
  }
51132
- function boundaryCssVarsStyle(boundary) {
51133
- return {
51134
- "--site-style-transition-from": boundary.cssVars.from,
51135
- "--site-style-transition-to": boundary.cssVars.to
51136
- };
51615
+ /**
51616
+ * The one render-edge place a theme token becomes CSS.
51617
+ */
51618
+ function themeTokenCss(token) {
51619
+ return `rgb(var(--tb-${token}))`;
51137
51620
  }
51138
- function boundaryReserveCssVarsStyle(input) {
51139
- const before = input.before?.metrics.reserveCss ?? null;
51140
- const after = input.after?.metrics.reserveCss ?? null;
51141
- if (!before && !after) return undefined;
51621
+ function boundaryPaintStyle(paint) {
51142
51622
  return {
51143
- ...before ? { "--site-style-boundary-before-reserve": before } : {},
51144
- ...after ? { "--site-style-boundary-after-reserve": after } : {}
51623
+ "--boundary-shape-paint": themeTokenCss(paint.shape),
51624
+ ...paint.band ? { "--boundary-band-paint": themeTokenCss(paint.band) } : {}
51145
51625
  };
51146
51626
  }
51147
- function transitionCssVarsStyle(content) {
51148
- const transitionStyles = isObjectRecord(content._transitionStyles) ? content._transitionStyles : null;
51149
- const cssVars = isObjectRecord(transitionStyles?.cssVars) ? transitionStyles.cssVars : null;
51150
- const from = typeof cssVars?.from === "string" ? cssVars.from : null;
51151
- const to = typeof cssVars?.to === "string" ? cssVars.to : null;
51152
- if (!from && !to) return undefined;
51153
- return {
51154
- ...from ? { "--site-style-transition-from": from } : {},
51155
- ...to ? { "--site-style-transition-to": to } : {}
51627
+ /**
51628
+ * Reserve attributes and variables for a block wrapper, from the joins on
51629
+ * either side. A join's `before` reserve sits inside its previous section, so
51630
+ * it pads the bottom of the block above the join; its `after` reserve pads the
51631
+ * top of the block below. Joins that do not draw reserve nothing.
51632
+ */
51633
+ function blockBoundaryReserves(input) {
51634
+ const top = reserveOnSide(input.before, "after");
51635
+ const bottom = reserveOnSide(input.after, "before");
51636
+ const style = {
51637
+ ...top ? { "--site-style-boundary-before-reserve": top.length } : {},
51638
+ ...bottom ? { "--site-style-boundary-after-reserve": bottom.length } : {}
51156
51639
  };
51157
- }
51158
- function mergeStyleObjects(left, right) {
51159
- if (!left) return right;
51160
- if (!right) return left;
51161
51640
  return {
51162
- ...left,
51163
- ...right
51641
+ topPlacement: top?.placement,
51642
+ bottomPlacement: bottom?.placement,
51643
+ style: top || bottom ? style : undefined
51164
51644
  };
51165
51645
  }
51646
+ /** The reserve one join needs on one side of itself, if it draws at all. */
51647
+ function reserveOnSide(slot, side) {
51648
+ const layout = renderedJoinLayout(slot?.join ?? null);
51649
+ const length = layout?.reserves[side] ?? null;
51650
+ return layout && length ? {
51651
+ length,
51652
+ placement: layout.placement
51653
+ } : null;
51654
+ }
51166
51655
  function pageBlockPosition(index, blockCount) {
51167
51656
  if (blockCount <= 1) return "only";
51168
51657
  if (index === 0) return "first";
@@ -51173,7 +51662,7 @@ function pageBlockPosition(index, blockCount) {
51173
51662
  //#endregion
51174
51663
  //#region ../blocks/src/pageRendererContracts.ts
51175
51664
  function buildPageRendererRootRuntime(dataContext) {
51176
- 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 ?? {};
51665
+ const { siteId = null, pageId = null, pathname = null, bookingTimeZone, previewStage = "published", apiBaseUrl = null, portalToken = null, readAuthority, bookingOfferingPresets = [], appointmentServicePathPrefix = null, mailingList = { tag: "not_configured" }, eventRegistrationOverlayEnabled = false, loaderFailures = {} } = dataContext ?? {};
51177
51666
  return {
51178
51667
  siteId,
51179
51668
  pageId,
@@ -51182,6 +51671,7 @@ function buildPageRendererRootRuntime(dataContext) {
51182
51671
  previewStage,
51183
51672
  apiBaseUrl,
51184
51673
  portalToken,
51674
+ readAuthority,
51185
51675
  bookingOfferingPresets,
51186
51676
  appointmentServicePathPrefix,
51187
51677
  mailingList,
@@ -54322,6 +54812,7 @@ const transformDefinitions = {
54322
54812
  "layout.headerRuntimeContract": headerRuntimeContractTransform,
54323
54813
  "layout.headerLogoClass": headerLogoClassTransform,
54324
54814
  "layout.headerLogoMediaClass": headerLogoMediaClassTransform,
54815
+ "layout.chromeLogo": chromeLogoTransform,
54325
54816
  "layout.headerLogoTextVisible": headerLogoTextVisibleTransform,
54326
54817
  "layout.footerRootClass": footerRootClassTransform,
54327
54818
  "layout.headerRootStyle": headerRootStyleTransform,
@@ -54401,46 +54892,42 @@ const whenTransformed = (from, transformId, equals = true) => (node) => ({
54401
54892
  equals
54402
54893
  }
54403
54894
  });
54404
- const logoRow = link$1({
54895
+ /** Draw whichever site logo suits the surface this row sits on. */
54896
+ const bindChromeLogo = (surface) => bind("content", { transforms: [{
54897
+ id: "layout.chromeLogo",
54898
+ options: { surface }
54899
+ }] });
54900
+ /**
54901
+ * The brand link. The logo is chosen per surface because the open mobile menu
54902
+ * paints its own background, which may be the opposite tone to the header.
54903
+ */
54904
+ const createLogoRow = (surface) => link$1({
54405
54905
  href: "/",
54406
54906
  className: bindProp("$root.theme.header.logo", {
54407
54907
  transforms: pipe(tx("layout.headerLogoClass")),
54408
54908
  fallback: "header-logo rb-flex rb-min-w-0 rb-items-center rb-gap-3 rb-no-underline rb-transition-opacity rb-hover-opacity-80"
54409
54909
  })
54410
- }, [
54411
- media({ className: bindProp("$root.theme.header.logo", {
54412
- transforms: pipe(tx("layout.headerLogoMediaClass", { base: "rb-header-logo-sm rb-w-auto rb-transition-all rb-duration-300" })),
54413
- fallback: "rb-header-logo-sm rb-w-auto rb-transition-all rb-duration-300"
54414
- }) }, when("content.logo"), bind("content.logo")),
54415
- stack({ className: "rb-contents" }, [media({ className: bindProp("$root.theme.header.logo", {
54416
- transforms: pipe(tx("layout.headerLogoMediaClass", { base: "rb-header-logo-sm rb-w-auto rb-transition-all rb-duration-300" })),
54417
- fallback: "rb-header-logo-sm rb-w-auto rb-transition-all rb-duration-300"
54418
- }) }, when("site.logo"), bind("site.logo"))], when("content.logo", { not: true })),
54419
- text({
54420
- as: "strong",
54421
- className: "header-logo-text rb-truncate"
54422
- }, whenTransformed("$root.theme.header.logo", "layout.headerLogoTextVisible"), bind("site.title", { fallback: "Your Site" }))
54423
- ]);
54910
+ }, [media({ className: bindProp("$root.theme.header.logo", {
54911
+ transforms: pipe(tx("layout.headerLogoMediaClass", { base: "rb-header-logo-sm rb-w-auto rb-transition-all rb-duration-300" })),
54912
+ fallback: "rb-header-logo-sm rb-w-auto rb-transition-all rb-duration-300"
54913
+ }) }, when("content.logo"), bindChromeLogo(surface)), text({
54914
+ as: "strong",
54915
+ className: "header-logo-text rb-truncate"
54916
+ }, whenTransformed("$root.theme.header.logo", "layout.headerLogoTextVisible"), bind("site.title", { fallback: "Your Site" }))]);
54917
+ const logoRow = createLogoRow("header-root");
54424
54918
  const centeredLogoRow = link$1({
54425
54919
  href: "/",
54426
54920
  className: bindProp("$root.theme.header.logo", {
54427
54921
  transforms: pipe(tx("layout.headerLogoClass", { base: "header-logo rb-flex rb-items-center rb-justify-center rb-gap-3 rb-text-center rb-no-underline rb-transition-opacity rb-hover-opacity-80" })),
54428
54922
  fallback: "header-logo rb-flex rb-items-center rb-justify-center rb-gap-3 rb-text-center rb-no-underline rb-transition-opacity rb-hover-opacity-80"
54429
54923
  })
54430
- }, [
54431
- media({ className: bindProp("$root.theme.header.logo", {
54432
- transforms: pipe(tx("layout.headerLogoMediaClass", { base: "rb-header-logo-lg rb-w-auto rb-transition-all rb-duration-300" })),
54433
- fallback: "rb-header-logo-lg rb-w-auto rb-transition-all rb-duration-300"
54434
- }) }, when("content.logo"), bind("content.logo")),
54435
- stack({ className: "rb-contents" }, [media({ className: bindProp("$root.theme.header.logo", {
54436
- transforms: pipe(tx("layout.headerLogoMediaClass", { base: "rb-header-logo-lg rb-w-auto rb-transition-all rb-duration-300" })),
54437
- fallback: "rb-header-logo-lg rb-w-auto rb-transition-all rb-duration-300"
54438
- }) }, when("site.logo"), bind("site.logo"))], when("content.logo", { not: true })),
54439
- text({
54440
- as: "strong",
54441
- className: "header-logo-text"
54442
- }, whenTransformed("$root.theme.header.logo", "layout.headerLogoTextVisible"), bind("site.title", { fallback: "Your Site" }))
54443
- ]);
54924
+ }, [media({ className: bindProp("$root.theme.header.logo", {
54925
+ transforms: pipe(tx("layout.headerLogoMediaClass", { base: "rb-header-logo-lg rb-w-auto rb-transition-all rb-duration-300" })),
54926
+ fallback: "rb-header-logo-lg rb-w-auto rb-transition-all rb-duration-300"
54927
+ }) }, when("content.logo"), bindChromeLogo("header-root")), text({
54928
+ as: "strong",
54929
+ className: "header-logo-text"
54930
+ }, whenTransformed("$root.theme.header.logo", "layout.headerLogoTextVisible"), bind("site.title", { fallback: "Your Site" }))]);
54444
54931
  const createNavRow = (className, align = "end") => navRow({
54445
54932
  className: `${className} header-nav-row`,
54446
54933
  align,
@@ -54480,10 +54967,8 @@ const mobileToggleIcon = stack({
54480
54967
  }
54481
54968
  ]);
54482
54969
  const mobileToggleButton = {
54483
- type: "button",
54970
+ type: "headerControl",
54484
54971
  props: {
54485
- type: "button",
54486
- variantId: "",
54487
54972
  className: `nav-mobile-toggle ${mobileOnlyDisplay("inline-flex")} rb-h-10 rb-w-10 rb-items-center rb-justify-center rb-rounded-md transition-theme-standard`,
54488
54973
  "aria-label": "Open menu",
54489
54974
  "aria-expanded": "false",
@@ -54493,10 +54978,8 @@ const mobileToggleButton = {
54493
54978
  children: [mobileToggleIcon]
54494
54979
  };
54495
54980
  const mobileOverlayToggleButton = {
54496
- type: "button",
54981
+ type: "headerControl",
54497
54982
  props: {
54498
- type: "button",
54499
- variantId: "",
54500
54983
  className: "nav-mobile-toggle rb-inline-flex rb-h-10 rb-w-10 rb-items-center rb-justify-center rb-rounded-md transition-theme-standard",
54501
54984
  "aria-label": "Open menu",
54502
54985
  "aria-expanded": "false",
@@ -54520,7 +55003,7 @@ const mobileOverlayHeader = inline({
54520
55003
  align: "center",
54521
55004
  justify: "between",
54522
55005
  style: borderColorStyle("border")
54523
- }, [logoRow, mobileOverlayToggleButton]);
55006
+ }, [createLogoRow("header-mobile-panel"), mobileOverlayToggleButton]);
54524
55007
  const mobileOverlayBody = stack({
54525
55008
  className: "rb-flex-1 rb-px-6 rb-py-6",
54526
55009
  gap: "md",
@@ -54712,7 +55195,10 @@ const brandLogo = link$1({
54712
55195
  options: { base: "rb-h-10 rb-w-auto" }
54713
55196
  }],
54714
55197
  fallback: "rb-h-10 rb-w-auto"
54715
- } } }, when("module.showLogo", { equals: true }), when("content.logo"), bind("content.logo")), text({
55198
+ } } }, when("module.showLogo", { equals: true }), when("content.logo"), bind("content", { transforms: [{
55199
+ id: "layout.chromeLogo",
55200
+ options: { surface: "footer-root" }
55201
+ }] })), text({
54716
55202
  as: "strong",
54717
55203
  className: "footer-logo-text rb-nav-text"
54718
55204
  }, when("module.showTitle", { equals: true }), bind("site.title", { fallback: "Your Site" }))], when("module.kind", { equals: "brand" }));
@@ -56511,6 +56997,15 @@ const appointmentServicesManifest = createBlockManifest({
56511
56997
  required: false,
56512
56998
  ui: { intent: "content" }
56513
56999
  },
57000
+ createSiteOptionSelectField({
57001
+ id: "categoryId",
57002
+ label: "Category",
57003
+ description: "Show one category (with its heading and intro), or leave it on All categories to show everything grouped.",
57004
+ required: false,
57005
+ multiple: false,
57006
+ optionSource: "appointmentServiceCategories",
57007
+ ui: { intent: "content" }
57008
+ }),
56514
57009
  sectionStylesField({
56515
57010
  id: "_sectionStyles",
56516
57011
  label: "Section styles",
@@ -56545,6 +57040,7 @@ const appointmentServicesManifest = createBlockManifest({
56545
57040
  richText({ className: "rb-prose rb-max-w-none" }, bind("content.description"), when("content.description")),
56546
57041
  el("appointment-services", {
56547
57042
  sectionHeading: { $bind: { from: "content.heading" } },
57043
+ categoryId: { $bind: { from: "content.categoryId" } },
56548
57044
  services: { $bind: { from: "data.services" } },
56549
57045
  pathname: { $bind: { from: "$root.pathname" } },
56550
57046
  servicePathPrefix: { $bind: { from: "$root.appointmentServicePathPrefix" } }
@@ -62158,11 +62654,10 @@ function buildPageRenderPlan(input) {
62158
62654
  return {
62159
62655
  entries,
62160
62656
  omitted,
62161
- runtimeBoundaries: retargetBoundariesAcrossOmissions({
62162
- boundaries: input.runtimeBoundaries,
62657
+ runtimeJoins: retargetJoinsAcrossOmissions({
62658
+ joins: input.runtimeJoins ?? [],
62163
62659
  originalBlocks: input.page.blocks,
62164
- survivingBlocks: new Set(entries.map((entry) => entry.block)),
62165
- previewStage: input.previewStage
62660
+ survivingBlocks: new Set(entries.map((entry) => entry.block))
62166
62661
  })
62167
62662
  };
62168
62663
  }
@@ -62271,88 +62766,15 @@ function getBlockOverride(blockKind, overrides) {
62271
62766
  * For draft/preview: draftContent takes priority over content.
62272
62767
  * For published: content is the source of truth.
62273
62768
  */
62769
+ /**
62770
+ * The content a block renders with. Every render path (public, preview,
62771
+ * templates, SDK) chooses content here, so this is also where a stale
62772
+ * `site-style-transition-*` styleGroup is dropped; authored values survive.
62773
+ */
62274
62774
  function getRenderableContent(block, previewStage = "published") {
62275
62775
  const source = previewStage === "preview" && block.draftContent ? block.draftContent : block.content ?? {};
62276
- return isObjectRecord(source) ? source : {};
62277
- }
62278
- /**
62279
- * Re-points section boundaries across omitted blocks.
62280
- *
62281
- * Boundaries are keyed by adjacent block-id *pairs*, so dropping B from
62282
- * [A, B, C] does not merely remove B's boundaries — it removes the boundary
62283
- * between the survivors, because no `A→C` key was ever compiled.
62284
- *
62285
- * Per decision D2 the treatment for a merged gap comes from the boundary
62286
- * entering the omitted run (`A→firstOmitted`), falling back to the one leaving
62287
- * it (`lastOmitted→C`). The destination surface is a separate question: only
62288
- * the exiting boundary knows what C looks like, so the merged boundary ends on
62289
- * that endpoint rather than on the omitted block's. In the exiting-only
62290
- * fallback the origin remains an approximation: `from` is the omitted block's
62291
- * surface, because no compiled boundary carries A's. The hosted path no longer
62292
- * needs this at all (site-renderer admits blocks before compiling boundaries);
62293
- * it remains the safety net for an SDK whose compiled boundaries predate an
62294
- * omission.
62295
- */
62296
- function retargetBoundariesAcrossOmissions(input) {
62297
- const { boundaries, originalBlocks, survivingBlocks, previewStage } = input;
62298
- if (boundaries === undefined) return undefined;
62299
- if (boundaries.length === 0) return boundaries;
62300
- const anyOmitted = originalBlocks.some((block) => !survivingBlocks.has(block));
62301
- if (!anyOmitted) return boundaries;
62302
- const byPair = new Map(boundaries.map((boundary) => [pairKey(boundary.previousBlockId, boundary.nextBlockId), boundary]));
62303
- const retargeted = [];
62304
- let previousSurvivor = null;
62305
- let run = [];
62306
- for (const block of originalBlocks) {
62307
- if (!survivingBlocks.has(block)) {
62308
- run.push(block);
62309
- continue;
62310
- }
62311
- if (previousSurvivor?.id && block.id) {
62312
- const boundary = run.length === 0 ? byPair.get(pairKey(previousSurvivor.id, block.id)) : mergedBoundary({
62313
- byPair,
62314
- previousBlock: previousSurvivor,
62315
- previousBlockId: previousSurvivor.id,
62316
- nextBlock: block,
62317
- nextBlockId: block.id,
62318
- run,
62319
- previewStage
62320
- });
62321
- if (boundary) retargeted.push(boundary);
62322
- }
62323
- previousSurvivor = block;
62324
- run = [];
62325
- }
62326
- return retargeted;
62776
+ return isObjectRecord(source) ? stripStaleTransitionStyleGroup(source) : {};
62327
62777
  }
62328
- function mergedBoundary(input) {
62329
- const { byPair, previousBlock, previousBlockId, nextBlock, nextBlockId, run, previewStage } = input;
62330
- const firstOmittedId = run[0]?.id;
62331
- const lastOmittedId = run[run.length - 1]?.id;
62332
- const entering = firstOmittedId ? byPair.get(pairKey(previousBlockId, firstOmittedId)) : undefined;
62333
- const exiting = lastOmittedId ? byPair.get(pairKey(lastOmittedId, nextBlockId)) : undefined;
62334
- const donor = entering ?? exiting;
62335
- if (!donor) return undefined;
62336
- const transition = compileTransitionRuntime({
62337
- treatment: donor.treatment,
62338
- from: donor.from,
62339
- to: exiting?.to ?? donor.to
62340
- });
62341
- const rekeyed = {
62342
- ...donor,
62343
- boundaryId: makeBoundaryId(asDesignBlockId(previousBlockId), asDesignBlockId(nextBlockId)),
62344
- previousBlockId,
62345
- nextBlockId,
62346
- from: transition.from,
62347
- to: transition.to,
62348
- cssVars: transition.cssVars
62349
- };
62350
- return retargetCompiledBoundaryRuntimeForContentAdjacency(rekeyed, {
62351
- currentContent: getRenderableContent(previousBlock, previewStage),
62352
- nextContent: getRenderableContent(nextBlock, previewStage)
62353
- });
62354
- }
62355
- const pairKey = boundaryKey;
62356
62778
 
62357
62779
  //#endregion
62358
62780
  //#region ../blocks/src/system/manifest/hydrateLinks.ts
@@ -62550,25 +62972,47 @@ function preparePageRender(input) {
62550
62972
  prepared
62551
62973
  });
62552
62974
  }
62553
- if (constructionFailures.length === 0 || input.audience === "authoring") {
62554
- return {
62555
- entries,
62556
- constructionFailures,
62557
- runtimeBoundaries: input.plan.runtimeBoundaries
62558
- };
62559
- }
62560
- const survivors = entries.filter((candidate) => candidate.prepared.kind !== "render-threw");
62975
+ const survivors = input.audience === "authoring" ? entries : entries.filter((candidate) => candidate.prepared.kind !== "render-threw");
62561
62976
  return {
62562
62977
  entries: survivors,
62563
62978
  constructionFailures,
62564
- runtimeBoundaries: retargetBoundariesAcrossOmissions({
62565
- boundaries: input.plan.runtimeBoundaries,
62566
- originalBlocks: input.plan.entries.map((planned) => planned.block),
62567
- survivingBlocks: new Set(survivors.map((survivor) => survivor.entry.block)),
62568
- previewStage: input.previewStage
62569
- })
62979
+ joins: composeSurvivorJoins(input.plan, survivors, input.themeResources)
62570
62980
  };
62571
62981
  }
62982
+ /**
62983
+ * The only place joins are composed. Plan-time omissions were already
62984
+ * re-pointed by the plan; construction failures are re-pointed here by the
62985
+ * same primitive, so `[A, B, C]` losing B still gets an A→C join. Each
62986
+ * survivor is then classified from its final content.
62987
+ */
62988
+ function composeSurvivorJoins(plan, survivors, themeResources) {
62989
+ const joins = retargetJoinsAcrossOmissions({
62990
+ joins: plan.runtimeJoins,
62991
+ originalBlocks: plan.entries.map((planned) => planned.block),
62992
+ survivingBlocks: new Set(survivors.map((survivor) => survivor.entry.block))
62993
+ });
62994
+ return composePageJoins({
62995
+ joins,
62996
+ survivors: survivors.map(({ entry }) => ({
62997
+ id: entry.block.id,
62998
+ kind: entry.block.kind,
62999
+ content: boundaryClassificationContent(entry, themeResources)
63000
+ }))
63001
+ });
63002
+ }
63003
+ /**
63004
+ * The content a join is classified from must be the content that paints the
63005
+ * section. The default block renderer layers the theme's per-block style
63006
+ * defaults (`theme.blockOverrides[kind].styles`, background included) under
63007
+ * the block's own `_sectionStyles`, so classify that same projection. An
63008
+ * override component renders its own markup from the unmerged content.
63009
+ */
63010
+ function boundaryClassificationContent(entry, themeResources) {
63011
+ if (entry.kind !== "renderable" || entry.override) {
63012
+ return entry.renderableContent;
63013
+ }
63014
+ return mergeContentWithBlockStyleOverrides(entry.renderableContent, themeResources.kind === "available" ? themeResources.config : undefined, entry.block.kind);
63015
+ }
62572
63016
  function prepareEntry(entry, input) {
62573
63017
  if (entry.kind !== "renderable") return { kind: "plan-decided" };
62574
63018
  const draftContent = previewableEditorContent(entry);
@@ -62641,6 +63085,7 @@ function blockSessionProps(dataContext) {
62641
63085
  supabaseUrl: dataContext?.supabaseUrl,
62642
63086
  portalToken: dataContext?.portalToken ?? null,
62643
63087
  previewToken: dataContext?.previewToken ?? null,
63088
+ readAuthority: dataContext?.readAuthority,
62644
63089
  stage: dataContext?.previewStage
62645
63090
  };
62646
63091
  }
@@ -62781,7 +63226,7 @@ function EditorPageRenderer(props$1) {
62781
63226
  });
62782
63227
  }
62783
63228
  function PageRendererCore(props$1) {
62784
- const { page, audience, runtimeBoundaries, dataContext, routeMap, registry, sdkConfig, customBlocks, blockOverrides } = props$1;
63229
+ const { page, audience, runtimeJoins, dataContext, routeMap, registry, sdkConfig, customBlocks, blockOverrides } = props$1;
62785
63230
  const imageResolveContext = import_react.useMemo(() => resolvePageRendererImageResolveContext(dataContext), [
62786
63231
  dataContext?.imageResolveContext,
62787
63232
  dataContext?.mediaAssets,
@@ -62797,7 +63242,7 @@ function PageRendererCore(props$1) {
62797
63242
  blocks: []
62798
63243
  },
62799
63244
  audience,
62800
- runtimeBoundaries,
63245
+ runtimeJoins,
62801
63246
  previewStage,
62802
63247
  sdkConfig,
62803
63248
  customBlocks,
@@ -62805,7 +63250,7 @@ function PageRendererCore(props$1) {
62805
63250
  }), [
62806
63251
  page,
62807
63252
  audience,
62808
- runtimeBoundaries,
63253
+ runtimeJoins,
62809
63254
  previewStage,
62810
63255
  sdkConfig,
62811
63256
  customBlocks,
@@ -62822,19 +63267,16 @@ function PageRendererCore(props$1) {
62822
63267
  dataContext,
62823
63268
  routeMap,
62824
63269
  themeResources,
62825
- imageResolveContext,
62826
- previewStage
63270
+ imageResolveContext
62827
63271
  }), [
62828
63272
  plan,
62829
63273
  audience,
62830
63274
  dataContext,
62831
63275
  routeMap,
62832
63276
  themeResources,
62833
- imageResolveContext,
62834
- previewStage
63277
+ imageResolveContext
62835
63278
  ]);
62836
- const boundaryByAdjacentBlockIds = import_react.useMemo(() => boundaryMapForAdjacentBlockIds(preparation.runtimeBoundaries ?? []), [preparation.runtimeBoundaries]);
62837
- const usesRuntimeBoundaries = preparation.runtimeBoundaries !== undefined;
63279
+ const joinSlots = import_react.useMemo(() => joinSlotsByPair(preparation.joins), [preparation.joins]);
62838
63280
  reportAndReplayOmissions({
62839
63281
  plan,
62840
63282
  preparation,
@@ -62854,10 +63296,9 @@ function PageRendererCore(props$1) {
62854
63296
  themeResources,
62855
63297
  imageResolveContext,
62856
63298
  resolvedRegistry,
62857
- boundaryByAdjacentBlockIds,
62858
- usesRuntimeBoundaries,
63299
+ joinSlots,
62859
63300
  wrapBlock: props$1.wrapBlock,
62860
- wrapBoundary: props$1.wrapBoundary
63301
+ renderJoin: props$1.renderJoin
62861
63302
  })) });
62862
63303
  }
62863
63304
  /**
@@ -62952,27 +63393,25 @@ function requireEntryBlockOverride(entry, themeResources) {
62952
63393
  }
62953
63394
  /**
62954
63395
  * Renders one planned block: its wrapper, style-group data attributes,
62955
- * boundary reserve space and any boundary or transition sibling that follows.
63396
+ * boundary reserve space and the join markup that follows it.
62956
63397
  *
62957
63398
  * Extracted from PageRendererCore so the component stays about wiring the plan
62958
63399
  * rather than also owning per-block markup.
62959
63400
  */
62960
63401
  function renderPlanEntry(input) {
62961
- const { index, entries, props: props$1, themeResources, imageResolveContext, resolvedRegistry, boundaryByAdjacentBlockIds, usesRuntimeBoundaries, wrapBlock, wrapBoundary } = input;
63402
+ const { index, entries, props: props$1, themeResources, imageResolveContext, resolvedRegistry, joinSlots, wrapBlock, renderJoin } = input;
62962
63403
  const entry = input.entry.entry;
62963
63404
  const block = entry.block;
62964
63405
  const blockPosition = pageBlockPosition(index, entries.length);
62965
63406
  const blockKey = blockKeyFor(block, index);
62966
63407
  const previousBlock = entries[index - 1]?.entry.block ?? null;
62967
63408
  const nextBlock = entries[index + 1]?.entry.block ?? null;
62968
- const boundaryBefore = boundaryBetweenBlocks(previousBlock, block, boundaryByAdjacentBlockIds);
62969
- const boundaryAfter = boundaryBetweenBlocks(block, nextBlock, boundaryByAdjacentBlockIds);
62970
- const boundaryElement = renderBoundaryAfterBlock({
62971
- block,
62972
- nextBlock,
63409
+ const joinBefore = joinSlotBetween(previousBlock?.id, block.id, joinSlots);
63410
+ const joinAfter = joinSlotBetween(block.id, nextBlock?.id, joinSlots);
63411
+ const boundaryElement = renderJoinSlot({
63412
+ slot: joinAfter,
62973
63413
  blockKey,
62974
- boundaryByAdjacentBlockIds,
62975
- wrapBoundary
63414
+ renderJoin
62976
63415
  });
62977
63416
  const cleanKind = block.kind.replace(/^block\./, "");
62978
63417
  const managesOwnWrapper = entry.kind === "renderable" && entry.managesOwnWrapper;
@@ -62995,12 +63434,10 @@ function renderPlanEntry(input) {
62995
63434
  const styleGroup = typeof renderableContent.styleGroup === "string" ? renderableContent.styleGroup : undefined;
62996
63435
  const blockLook = typeof renderableContent.blockLook === "string" ? renderableContent.blockLook : undefined;
62997
63436
  const blockComposition = readBlockComposition(renderableContent.blockComposition);
62998
- const transitionStyle = transitionCssVarsStyle(renderableContent);
62999
- const boundaryReserveStyle = boundaryReserveCssVarsStyle({
63000
- before: boundaryBefore,
63001
- after: boundaryAfter
63437
+ const reserves = blockBoundaryReserves({
63438
+ before: joinBefore,
63439
+ after: joinAfter
63002
63440
  });
63003
- const blockStyle = mergeStyleObjects(transitionStyle, boundaryReserveStyle);
63004
63441
  const blockElement = /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
63005
63442
  className: wrapperClassName,
63006
63443
  "data-block": cleanKind,
@@ -63012,25 +63449,16 @@ function renderPlanEntry(input) {
63012
63449
  "data-block-composition": blockComposition?.treatment,
63013
63450
  "data-block-composition-kind": blockComposition?.kind,
63014
63451
  "data-page-block-position": blockPosition,
63015
- "data-site-style-boundary-before": boundaryBefore?.metrics.size,
63016
- "data-site-style-boundary-after": boundaryAfter?.metrics.size,
63452
+ "data-site-style-boundary-before": reserves.topPlacement,
63453
+ "data-site-style-boundary-after": reserves.bottomPlacement,
63017
63454
  "data-style-group": styleGroup,
63018
- style: blockStyle,
63455
+ style: reserves.style,
63019
63456
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MemoBlockSection, { ...blockSectionProps })
63020
63457
  }, blockKey);
63021
63458
  if (boundaryElement) {
63022
63459
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react.Fragment, { children: [blockElement, boundaryElement] }, blockKey);
63023
63460
  }
63024
- if (usesRuntimeBoundaries || !isSiteStyleTransitionStyleGroup(styleGroup)) {
63025
- return blockElement;
63026
- }
63027
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react.Fragment, { children: [blockElement, /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
63028
- "aria-hidden": "true",
63029
- "data-block-transition": "",
63030
- "data-block-transition-for": block.id ?? blockKey,
63031
- "data-style-group": styleGroup,
63032
- style: transitionStyle
63033
- })] }, blockKey);
63461
+ return blockElement;
63034
63462
  }
63035
63463
  function resolvePageRendererImageResolveContext(dataContext) {
63036
63464
  const input = dataContext?.imageResolveContext;
@@ -65770,6 +66198,12 @@ function generateRecommendedThemes(input, opts) {
65770
66198
 
65771
66199
  //#endregion
65772
66200
  //#region ../theme-core/src/inputs/core.ts
66201
+ /**
66202
+ * Core Input CSS Generator
66203
+ *
66204
+ * Pure functions for generating form input CSS without requiring the full Theme type.
66205
+ * Used by both the full CMS theme system and the SDK theme bridge.
66206
+ */
65773
66207
  const CORNER_RADIUS_MAP$1 = {
65774
66208
  square: "0",
65775
66209
  soft: "0.25rem",
@@ -65804,7 +66238,7 @@ function generateInputCoreCss(scopeId, settings) {
65804
66238
  const borderRadius = CORNER_RADIUS_MAP$1[settings.corners];
65805
66239
  const cssBlocks = [];
65806
66240
  cssBlocks.push(`${root} .form-label {
65807
- color: rgb(var(--tb-${settings.labelToken}));
66241
+ color: ${textColorValue(settings.labelToken)};
65808
66242
  font-weight: 600;
65809
66243
  font-size: 0.875rem;
65810
66244
  display: block;
@@ -68063,6 +68497,12 @@ const containerResponsiveThemeCss = `/*
68063
68497
  :where(.theme-scope) .rb-prose p {
68064
68498
  margin: var(--rt-space-y) 0;
68065
68499
  }
68500
+ :where(.theme-scope) .rb-prose li > p:first-child {
68501
+ margin-top: 0;
68502
+ }
68503
+ :where(.theme-scope) .rb-prose li > p:last-child {
68504
+ margin-bottom: 0;
68505
+ }
68066
68506
  :where(.theme-scope) .rb-prose img {
68067
68507
  display: block;
68068
68508
  max-width: 100%;
@@ -80986,6 +81426,17 @@ function coerceToString(value) {
80986
81426
  return "";
80987
81427
  }
80988
81428
  /**
81429
+ * The appointment-services catalogue (issue 1403) pairs the services with the
81430
+ * site's ordered categories. Both are needed to group them, so that response
81431
+ * is passed through whole; any other `{ services }` wrapper is unwrapped.
81432
+ */
81433
+ function coerceServicesPayload(record) {
81434
+ return Array.isArray(record.services) && Array.isArray(record.categories) ? {
81435
+ services: record.services,
81436
+ categories: record.categories
81437
+ } : record.services;
81438
+ }
81439
+ /**
80989
81440
  * Extract data from API response.
80990
81441
  * Unwraps common response wrappers: { data }, { form }, { entries }, { services }, { teamMembers }
80991
81442
  *
@@ -81000,7 +81451,7 @@ function coercePayload(payload) {
81000
81451
  if ("data" in record && typeof record.data !== "function") return record.data;
81001
81452
  if ("form" in record && typeof record.form !== "function") return record.form;
81002
81453
  if ("entries" in record && typeof record.entries !== "function") return record.entries;
81003
- if ("services" in record && typeof record.services !== "function") return record.services;
81454
+ if ("services" in record && typeof record.services !== "function") return coerceServicesPayload(record);
81004
81455
  if ("teamMembers" in record && typeof record.teamMembers !== "function") return record.teamMembers;
81005
81456
  }
81006
81457
  return payload;
@@ -95790,6 +96241,7 @@ function emptyPulledContent(overrides) {
95790
96241
  homepageId: null,
95791
96242
  seoDefaults: null,
95792
96243
  logoIdentifier: null,
96244
+ logoDarkBackgroundIdentifier: null,
95793
96245
  faviconIdentifier: null
95794
96246
  },
95795
96247
  forms: [],
@@ -101567,7 +102019,7 @@ async function loadConfig(configPath, output) {
101567
102019
  return { errorMessage: "No config path provided." };
101568
102020
  }
101569
102021
  try {
101570
- const { loadConfigFile: loadConfigFile$1 } = await import("../load-config-Ca13nCpT.mjs");
102022
+ const { loadConfigFile: loadConfigFile$1 } = await import("../load-config-BToL9PfS.mjs");
101571
102023
  const rawConfig = await loadConfigFile$1(configPath);
101572
102024
  const parsed = riverbankSiteConfigSchema.safeParse(rawConfig);
101573
102025
  if (!parsed.success) {
@@ -112976,6 +113428,7 @@ const allowedPathPrefixes = [
112976
113428
  "/sites/{siteId}/bookings/closures",
112977
113429
  "/sites/{siteId}/bookings/resources",
112978
113430
  "/sites/{siteId}/bookings/services",
113431
+ "/sites/{siteId}/bookings/service-categories",
112979
113432
  "/sites/{siteId}/bookings/appointment-setup",
112980
113433
  "/sites/{siteId}/bookings/appointments",
112981
113434
  "/sites/{siteId}/bookings/appointment-reservations",
@@ -113109,13 +113562,13 @@ function classifyDemoDashboardMutationDescriptor(descriptor) {
113109
113562
  publicMessage: descriptor.demoMutation.publicMessage
113110
113563
  };
113111
113564
  }
113112
- for (const rule$1 of demoMutationClassificationRules) {
113113
- if (!matchesClassificationRule(descriptor, rule$1)) continue;
113565
+ for (const rule$2 of demoMutationClassificationRules) {
113566
+ if (!matchesClassificationRule(descriptor, rule$2)) continue;
113114
113567
  return {
113115
113568
  kind: "classified",
113116
113569
  capability,
113117
- classification: rule$1.classification,
113118
- publicMessage: rule$1.publicMessage
113570
+ classification: rule$2.classification,
113571
+ publicMessage: rule$2.publicMessage
113119
113572
  };
113120
113573
  }
113121
113574
  return {
@@ -113124,12 +113577,12 @@ function classifyDemoDashboardMutationDescriptor(descriptor) {
113124
113577
  publicMessage: "This demo action needs a safety classification before it can run."
113125
113578
  };
113126
113579
  }
113127
- function matchesClassificationRule(descriptor, rule$1) {
113128
- switch (rule$1.kind) {
113129
- case "path_starts_with": return rule$1.prefixes.some((prefix) => descriptor.path.startsWith(prefix));
113130
- case "path_fragments": return pathContainsAnySegmentSequence(descriptor.path, rule$1.fragments);
113131
- case "path_prefixes": return rule$1.prefixes.some((prefix) => descriptor.path.startsWith(prefix));
113132
- default: return assertNever(rule$1);
113580
+ function matchesClassificationRule(descriptor, rule$2) {
113581
+ switch (rule$2.kind) {
113582
+ case "path_starts_with": return rule$2.prefixes.some((prefix) => descriptor.path.startsWith(prefix));
113583
+ case "path_fragments": return pathContainsAnySegmentSequence(descriptor.path, rule$2.fragments);
113584
+ case "path_prefixes": return rule$2.prefixes.some((prefix) => descriptor.path.startsWith(prefix));
113585
+ default: return assertNever(rule$2);
113133
113586
  }
113134
113587
  }
113135
113588
  function isDashboardSiteMutation(descriptor) {
@@ -113887,25 +114340,10 @@ function deriveLaunchDomainRequirement(siteId, domainState) {
113887
114340
  } : evidenceFromDerivedState(state)
113888
114341
  });
113889
114342
  }
113890
- function deriveLaunchReadiness(input) {
113891
- const siteId = input.siteId ?? null;
113892
- const overrides = input.overrides ?? [];
113893
- const appointmentOverrideDefinition = LAUNCH_REQUIREMENT_OVERRIDE_DEFINITIONS.configure_appointments;
114343
+ function generatedSiteReviewRequirements(input) {
114344
+ if (input.publicExperience === "hosted_booking") return [];
113894
114345
  const isGeneratedSiteReviewed = input.reviewGeneratedSite.kind === "reviewed";
113895
- const requirements = [];
113896
- const confirmEmailState = input.email.kind === "confirmed" ? "complete" : "pending";
113897
- requirements.push(requirement({
113898
- id: "confirm_email",
113899
- packId: "core",
113900
- priority: "required",
113901
- state: confirmEmailState,
113902
- owner: "either",
113903
- title: "Confirm your email",
113904
- description: confirmEmailState === "complete" ? "Email confirmed. Your dashboard and launch path are unlocked." : "Confirm your email before the site can go live.",
113905
- action: informationalAction("Confirm your email"),
113906
- evidence: evidenceFromDerivedState(confirmEmailState)
113907
- }));
113908
- requirements.push(requirement({
114346
+ return [requirement({
113909
114347
  id: "review_generated_site",
113910
114348
  packId: "core",
113911
114349
  priority: "required",
@@ -113927,7 +114365,26 @@ function deriveLaunchReadiness(input) {
113927
114365
  kind: "deferred",
113928
114366
  reason: "pending_acknowledgement"
113929
114367
  }
114368
+ })];
114369
+ }
114370
+ function deriveLaunchReadiness(input) {
114371
+ const siteId = input.siteId ?? null;
114372
+ const overrides = input.overrides ?? [];
114373
+ const appointmentOverrideDefinition = LAUNCH_REQUIREMENT_OVERRIDE_DEFINITIONS.configure_appointments;
114374
+ const requirements = [];
114375
+ const confirmEmailState = input.email.kind === "confirmed" ? "complete" : "pending";
114376
+ requirements.push(requirement({
114377
+ id: "confirm_email",
114378
+ packId: "core",
114379
+ priority: "required",
114380
+ state: confirmEmailState,
114381
+ owner: "either",
114382
+ title: "Confirm your email",
114383
+ description: confirmEmailState === "complete" ? "Email confirmed. Your dashboard and launch path are unlocked." : "Confirm your email before the site can go live.",
114384
+ action: informationalAction("Confirm your email"),
114385
+ evidence: evidenceFromDerivedState(confirmEmailState)
113930
114386
  }));
114387
+ requirements.push(...generatedSiteReviewRequirements(input));
113931
114388
  if (input.appointments.kind !== "disabled") {
113932
114389
  const appointmentsOverride = input.appointments.kind === "pending_setup" ? findLaunchOverride(overrides, appointmentOverrideDefinition.requirementId) : null;
113933
114390
  requirements.push(requirement({
@@ -114386,7 +114843,8 @@ const appointmentSetupServiceDraftSchema = z.object({
114386
114843
  venue: appointmentSetupVenueChoiceSchema,
114387
114844
  timezone: z.string().trim().min(1).nullable(),
114388
114845
  payment: appointmentSetupPaymentDraftSchema,
114389
- assignment: appointmentSetupServiceAssignmentDraftSchema
114846
+ assignment: appointmentSetupServiceAssignmentDraftSchema,
114847
+ categoryId: z.string().uuid().nullable().optional()
114390
114848
  }).superRefine((service, ctx) => {
114391
114849
  if (service.payment.kind !== "free" && (service.priceAmount === null || service.priceAmount <= 0)) {
114392
114850
  ctx.addIssue({
@@ -116027,6 +116485,13 @@ function applyBookingSettingsSectionUpdate(settings, update) {
116027
116485
  function applyBookingSettingsSectionUpdates(settings, updates) {
116028
116486
  return updates.reduce(applyBookingSettingsSectionUpdate, settings);
116029
116487
  }
116488
+ /** Normalize optional wire defaults once before projecting operational Event policy. */
116489
+ function resolveBookingSettingsEventCatalogue(settings) {
116490
+ return resolveEventCatalogue({
116491
+ verticalConfig: settings.verticalConfig,
116492
+ eventTypePresets: settings.eventTypePresets ?? DEFAULT_EVENT_TYPE_PRESETS
116493
+ });
116494
+ }
116030
116495
 
116031
116496
  //#endregion
116032
116497
  //#region ../api/src/bookingPaymentTermSchemas.ts
@@ -116652,16 +117117,12 @@ async function deleteRedirectRule(apiClient, { siteId, ruleId, options }) {
116652
117117
 
116653
117118
  //#endregion
116654
117119
  //#region ../api/src/billing.ts
116655
- async function changePlan(apiClient, { attemptId, planId, interval, prorationBehavior, options }) {
117120
+ async function changePlan(apiClient, request) {
117121
+ const { options, ...body } = request;
116656
117122
  try {
116657
117123
  return unwrapResponse(await apiClient({
116658
117124
  endpoint: "changePlan",
116659
- body: {
116660
- attemptId,
116661
- planId,
116662
- interval,
116663
- prorationBehavior
116664
- },
117125
+ body,
116665
117126
  options
116666
117127
  }));
116667
117128
  } catch (error$1) {
@@ -118422,9 +118883,9 @@ function isNegationForEnvRule(line) {
118422
118883
  function normalizePattern(pattern) {
118423
118884
  return pattern.replace(/^\.\//u, "").replace(/\/$/u, "");
118424
118885
  }
118425
- function appendGitignoreRule(content, rule$1) {
118426
- if (content.length === 0) return `${rule$1}\n`;
118427
- return `${content.endsWith("\n") ? content : `${content}\n`}${rule$1}\n`;
118886
+ function appendGitignoreRule(content, rule$2) {
118887
+ if (content.length === 0) return `${rule$2}\n`;
118888
+ return `${content.endsWith("\n") ? content : `${content}\n`}${rule$2}\n`;
118428
118889
  }
118429
118890
  /**
118430
118891
  * Plan the one exact environment rule needed by local onboarding. Existing