riverbankcms 0.23.0 → 0.25.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 createFormRef, $n as managementMediaLibraryUploadLimitForMimeType, $r as parseThemeColorToken, An as mediaPosterSchema, Ar as surfaceDecorationColors, At as BREAKPOINT_MD, Bn as parseMediaIdentifier, Br as resolveOnColorForThemeToken, Bt as themeButtonExtraClassesWithTrailingIcon, C as sortRecord, Cn as isExplicitRectCrop, Cr as makeBoundaryId, Ct as deriveSiteStyleBlockPolicy, D as mapEventCommandContent, Dn as getDirectImageUrlForSiteScopedPath, Dr as toNonEmptyReadonlyArray, Dt as getHeaderPaintTargets, En as getDirectImageUrlForRelativePath, Er as tileTreatmentValues, Et as generateMobileOverlayBackdropFilterFix, F as pageIdentifierForBlockCommand, Fn as resolveManagedMediaReference, Fr as mergeStyles, Ft as getComponentBorderWidthPx, G as ianaTimezoneSchema, Gr as surfaceToneFromForegroundToken, Gt as footerForegroundCandidates, H as bookingPaymentTermsSchema, Hr as resolveTokenOrCssColorValue, Ht as themeButtonVariantClassNames, I as pageIdentifierForCommand, In as mediaTypeDiscriminants, Ir as rgbColorValue, It as getComponentShadowVar, J as createCommandRef, Jr as surfaceForegroundInputFromResolved, Jt as arrangementLookHooks, K as createBlockRef, Kn as getMimeType, Kr as defaultThemeTokens, Kt as buildTextContrastShadow, L as pagePathForCommand, Ln as mediaIdentifierSchema, Lr as textColorStyle, Lt as ICON_CONFIG, M as blockIdentifierForCommand, Mn as persistableMediaSchema, Mr as TokenResolver, Mt as BREAKPOINT_XL, N as blockOrderIdentifiersForCommand, Nn as runtimeMediaSchema, Nr as backgroundColorStyle, Nt as MQ_MD_DOWN, On as getImageUrl, Or as visibleHeadingDecorationFamilyValues, Ot as renderHeaderPaintTargetRules, P as entryIdentifierForCommand, Pn as buildRenderableMediaAssetIndex, Pr as borderColorStyle, Pt as headerVariantValues, Q as createFooterRef, Qn as classifyKnownMimeType, Qr as getTextColorForBackground, R as hasConfiguredBookingVertical, Rn as buildMediaIdentifierFromFilename, Rr as opaqueSurfaceDeclarations, Rt as generateDefaultButtonSystem, S as venueManagementFields, Sn as normalizeWidthCandidates, Sr as introCompositionTreatmentValues, St as parseGradientPresetId, Tn as resolveMediaTransformForAspect, Tr as testimonialsCompositionTreatmentValues, Tt as generateHeaderScrollTreatmentStyles, U as require_jsx_runtime, Un as deriveVideoSlotPolicy, Ur as PUBLIC_BUTTON_ROLES, Ut as parseThemeForPersistence, V as bookingPaymentCollectionOptionSchema, Vr as resolveThemeColorReferenceValue, Vt as themeButtonSizeClassName, W as require_react, Wn as resolveVideoSelectionIntentForMediaField, Wr as selectLogoVariant, X as createEventCategoryRef, Xn as FILE_SIZE_LIMITS, Xr as surfaceForegroundValue, Xt as resolveItemSurface, Y as createContentEntryRef, Yn as parseRelativeStoragePath, Yr as surfaceForegroundStyle, Yt as arrangementSlotNames, Z as createEventSeriesRef, Zr as expandPalette, Zt as resolveLookSlotSurfaces, _n as summarizePortableMediaReferences, _r as defineNoBlockDesignCapability, _t as resolvePublishedLook, an as deriveSectionGround, ar as defineBlockDesignMetadata, b as isEventVisibility, bn as looksLikeUuid, br as featureCardCompositionTreatmentValues, bt as gradientToCss, c as customLinkSchema$1, cn as resolveSectionBackground, cr as cardListKnobBlocks, ct as headerLeafTextColor, d as internalLinkSchema, dn as boxBackgroundOverlaySchema, dr as asLayoutVariantKey, dt as mergeHeaderNavTypographyPreference, ei as parseBlockColorToken, er as parseSafeDownloadFilename, et as createNavigationRef, f as internalResolvedLinkSchema, fn as boxBackgroundSchema, ft as readHeaderNavFontSizePreference, g as linkSchema, gn as collectPortableMediaReferencesFromContent, gr as defineFrameCapability, gt as resolveModeArrangement, h as isResolvedInternalLinkEntityType, hn as stripStaleTransitionStyleGroup, hr as defineBlockDesignCapability, ht as resolveEffectiveArrangement, in as sectionFactsForContent, ir as normalizeCardRole, it as refSlug, j as eventManagementTiming, jn as mediaSchema, jr as resolveSurfaceForeground, jt as BREAKPOINT_SM, kn as isSiteScopedDirectImageStoragePath, kr as resolveSurface, kt as BREAKPOINT_LG, l as entryLinkSchema$1, ln as resolveSectionPhotoPlacement, lt as transparentHeaderForegroundInput, mn as siteChromeBackgroundOverrideOwner, mr as assertNever$11, mt as readStoredMode, ni as __toESM, nn as boundaryLayout, nr as cardRoleSchema, o as classifySdkEventBookingOffer, on as heroPhotoPaintsGround, or as resolveEffectiveKnobs, ot as effectiveHeaderNavLinkStyle, p as internalRouteOnlyLinkSchema, pn as runtimeBoxBackgroundSchema, pr as asSiteStyleId, pt as arrangementManifestFromVariants, q as createBlocksRef, qn as asRecord, qr as surfaceForegroundDeclarations, qt as generateNavLinkCSS, rn as composeBoundary, rr as cardVariantRoleValues, rt as createVenueRef, s as RESOLVED_INTERNAL_LINK_ENTITY_TYPES, sn as parseCanonicalRuntimeBackground, sr as cardListFamilyBlocks, st as headerForegroundCandidates, t as classifySdkEventTiming, ti as __commonJSMin, tn as headerRootPaint, tr as renderCssDeclarations, tt as createPageRef, u as externalLinkSchema$1, un as sectionForegroundBackground, ur as asDesignBlockId, ut as readOpeningForegroundProjection, v as pageLinkSchema$1, vn as walkAndCollectImageAttrs, vr as eventListTreatmentValues, vt as requireCuratedSiteStyle, w as stableStringify, wn as parseAspectRatioValue, wr as offeringsPreviewCompositionTreatmentValues, wt as themeSchema, xn as rotateNormalizedPoint, xr as headingDecorationColorTokenValues, xt as getGradientPreset, yn as deleteEnvSpecificKeys, yr as eyebrowTreatmentValues, yt as compiledRuntimeStyleFieldNames, z as eventCommandScheduleSchema, zn as parseCanonicalMediaIdentifier, zr as isCssColorLiteral, zt as parseThemeButtonVariantId } from "../sdk-event-upsert-BnBxyTR6.mjs";
3
- import { $ as inferSiteDateLocale, $t as parseCurrencyCode, A as assessMailingListTargeting, An as unsafeAsPositiveByteCount, At as resolveFlexibleBalanceInitialPaymentCents, Bt as resolveExactOrFreePriceDisplay, C as parseManagementKey, Ct as clampConfiguredAmount, D as parseMailingListContentVersionId, Dn as unsafeAsOccurrenceId, Dt as omitZeroAmountFutureRows, E as parseMailingListBlockId, En as unsafeAsMediaAssetId, Et as getBookingInstalmentProtectedDepositAmountCents, F as parseMailingListPlacementTargeting, Ft as isPublicEventPricingOptionDisplayable, Gt as isNonNegativeWholeCents$1, H as assertAllowedPublicUrl, Ht as fromArray, I as DEFAULT_MAILING_LIST_TARGETING, It as publicEventPricingCurrency, J as formatDateRange, Jt as toCents, K as selectCategoryView, Kt as parseNonNegativeCents, L as planMailingListChoicePresentation, Lt as publicEventPricingDisplay, M as parseMailingListProviderScope, Mn as unsafeAsPricingOptionId, Mt as parseEventPageSurfaceSubject, N as parseFooterCompositionV1, Nt as formatBookingPriceDisplay, O as parseMailingListSignedSourceToken, Ot as splitAmountWithRemainderInFirst, Pt as formatEventPricing, Q as formatTimeRange, Qt as formatCurrencyAmount, R as isCanonicalRichTextDoc, Rt as publicEventPricingOptions, S as exposeSecret, Sn as unsafeAsEventInstanceId, St as addIntervalPreservingMonthAnchor, T as slugify, Tt as getBookingInstalmentPlanIntervalCount, U as normalizeLocationAddressText, Un as err, V as parseWeeklyOpeningHours, Vt as resolvePricingOptionsPriceDisplay, W as toLocationCoordinates, Wn as ok, Wt as mapReadonlyNonEmptyArray, X as formatDateTimeRange, Xt as unsafeAsNonNegativeCents, Y as formatDateTime, Yt as toNonNegativeCents, Z as formatTime$1, Zt as unsafeAsPositiveCents, _ as nextLiveRunSessionStartMs, _n as unsafeAsCheckoutLineId, an as parseDatedOfferingCapacityHoldId, at as getBookingLocalDateKey, b as resolveWholeSeriesRunLifecycle, bt as isSettleableFlexibleBalanceContractStatus, cn as parseMembershipId, d as EVENT_PRESET_VALUES, dn as parseSiteId, dt as parseUtcIsoDateTimeString, en as assertNever, et as resolveBookingDisplayContext, fn as parseSiteTermsVersionId, ft as resolveBookingBusinessTimeZone, g as CANCELLED_SESSION_STATUS, gt as toUtcIsoDateTimeString, ht as toScheduledBookingDateTime, i as NAVIGATION_LOCATIONS, in as parseDatedOfferingCapacityHoldAuditRef, it as formatLocalScheduleTime, j as DEFAULT_MAILING_LIST_SUCCESS_MESSAGE, jt as deriveTotalTicketQuantity, k as parseMailingListRuntimeContext, kn as unsafeAsPassId, kt as resolveFlexibleBalanceDueAt, l as resolveSiteVerticalBookingConfig, lt as parseBookingLocalDate, m as WHOLE_SERIES_EVENT_PRESET_VALUES, mt as toBookingTimeZone, nn as parseApiKeyId, nt as compareLocalScheduleDates, on as parseEventSeriesId, ot as getLocalScheduleDate, p as SURFACE_EVENT_PRESET_VALUES, pn as parseUserId, pt as resolveBookingTimeZoneId, q as formatDate, qt as parsePositiveCents, r as EVENT_PRESET_VOCABULARY, rn as parseCustomerId, rt as formatLocalScheduleDate, st as getLocalScheduleTime, tn as formatDurationUnitLabel, tt as buildBookingUtcDateWindow, un as parseRetiredCourseId, ut as parseLocalScheduleTime, v as orderedLiveRunSessions, vt as validateBookingPaymentOptionKinds, wt as getBookingInstalmentDepositRefundability, x as createSecret, xt as isSettleableOrderInstalmentPlanStatus, y as resolveWholeSeriesBookingPhase, yn as unsafeAsDemoCapability, yt as isLiveOrderInstalmentPlanStatus, z as formatOpeningHoursRows, zt as publicEventPricingType } from "../src-BPh_OivC.mjs";
4
- import { $ as normalizeMediaValueToIdentifierOnly, $t as bindRequestTimeout, A as formatDiffDetail, An as transportSuggestion, At as navigationIdentity, B as buildFieldChanges, Bn as sdkEventScheduleSchema, Bt as preparePushConfigTarget, C as reportFromOutcomes, Cn as parseEnvironmentSelection, Ct as fileExists, D as normalizeRemoteHomepageReference, Dn as withRiverbankEnv, Dt as writeJsonFileAtomic, E as createEmptySyncResult, En as requireEnvironmentWriteAuthorization, Et as writeJsonFile, F as calculatePullDiff, Fn as isLocalConfigured, Ft as navigationCommandItemToManagementInput, G as syncLocalMediaForPull, Gt as APPOINTMENT_SERVICE_VISIBILITY_VALUES, H as formatFieldPath, Hn as linkPayloadSchema, Ht as extractApiErrorMessage, I as buildJsonDiff, In as isRemoteConfigured, It as normalizeNavigationConfigItemForCommand, J as admitBinaryWriteDestination, Jt as ApiEnvelopeError, K as applyLocalMediaPush, Kt as ApiRequestError, L as hasPageOperations, Ln as loadSdkEnvironment, Lt as applyPushConfigPlan, M as hasPendingChanges, Mt as convertPulledFooterToLocal, N as findChangedFieldsWithValues, Nn as getEnvPrefix, Nt as convertPulledNavigationToLocal, O as calculateDiff, On as ErrorCodes, Ot as isMediaValue, P as formatHumanDiff, Pn as getEnvironmentDebugInfo, Pt as convertPulledPagesToLocal, Q as normalizeMediaIdentifierInput, Qt as mapEnvironmentExecutionOutcomesJson, R as pageMetadataForUpsert, Rn as createManagementClient, Rt as createPushConfigCommand, S as planCliCommandBatchForBindings, Sn as executeEnvironmentPlan, St as ensureDir, T as executeResidualSettingsSyncPlan, Tn as planEnvironmentWriteAuthorization, Tt as readJsonFile, U as revalidateLocalMediaPushPlan, Un as portablePageDesignSchema, Ut as normalizeApiError, V as formatFieldChange, Vn as sdkSettingsUpdateSchema, Vt as revalidatePushConfigPlan, Wn as sdkConfiguredBookingVerticalConfigSchema, Wt as isRecord$2, X as writeBinaryFileAtomic, Xt as deriveCmsApiUrlFromDashboardUrl, Y as readStableBinaryFile, Yt as unwrapResponse, Z as sha256, Zt as API_ENDPOINTS, _ as commandExecutionToReport, _n as runWithInvocation, _t as metadataFilePath, a as executeEntryCommandPlanAsReport, an as createOutputForCommand, at as readEntries, b as executeCompiledCliCommandPlanAsReport, bn as withErrorHandling, bt as writeMetadataFile, c as titleFromEntryData, cn as getOutputContext, ct as readEventsMeta, d as unsafeAsCliEntryIdentifier, dn as managementClientConfigFor, dt as readNavigationMeta, en as confirmAction, et as walkLocalContentMedia, f as unsafeAsCliFormSlug, fn as mapEntryForOutput, ft as readPagesMeta, g as commandCompileFailureToReport, gn as resolveCommandPath, gt as ensureMetadataDir, h as mutationCounterForEffect, hn as parsePaginationOptions, ht as writeMediaManifest, i as entrySiteCommandTypes, in as createListCommand, it as findLegacyEntryFiles, j as formatDiffSummary, jn as CliExit, jt as navigationIdentityMap, k as calculateFooterDiff, kn as formatError, kt as duplicateNavigationIdentityMessage, l as unsafeAsCliBlockIdentifier, ln as getOutputOnlyContext, lt as readFooterMeta, m as commandReportToSyncResult, mn as parseJsonData, mt as readVenuesMeta, n as entryCommandCompileErrorToReport, nn as createCommandContext, nt as downloadMedia, o as executeEntryCommandPlanAsSyncResult, on as currentInvocationEnvelope, ot as readAllMeta, p as unsafeAsCliPageIdentifier, pn as parseJsonArray, pt as readSettingsMeta, q as prepareLocalMediaForPush, qt as createBearerAPIClient, r as entryCommandReportToSyncResult, rn as createGetCommand, rt as extractMediaIdentifiers, s as syncResultForEntryCommandCompileError, sn as formatDateShort, st as readEventCategoriesMeta, t as compileEntryPushCommands, tn as createClientForEnv, tt as buildStorageUrl, u as unsafeAsCliContentTypeKey, un as handleCommandError, ut as readFormsMeta, v as commandReportHasFailures, vn as withCommandContext, vt as metadataTargetFromEnvironment, w as mergeManySyncResults, wn as planEnvironmentExecution, wt as listFiles, x as formatManagementError, xn as withOutputOnlyErrorHandling, xt as writeMetadataRecordMap, y as executeCliCommandPlan, yn as withConfirmation, yt as readMetadataFile, zn as ManagementApiError, zt as loadPushConfigTarget } from "../entryCommands-BdN5YrqI.mjs";
5
- import { r as CLI_VERSION, t as loadConfigFile } from "../load-config-D5DDfmv1.mjs";
6
- import { a as RichTextDocSchema, c as isRecord$18, i as findUnfilledSentinels, n as buildEntryScaffold, o as isRichTextDoc, r as validateEntryInstance, s as isObjectRecord, t as eventUpsertInputSchema } from "../eventUpsertInputSchema-kp-U13TZ.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-6m8gsGI8.mjs";
2
+ import { $ as createFormRef, $n as deriveVideoSlotPolicy, $r as resolveTokenOrCssColorValue, An as deleteEnvSpecificKeys, Ar as makeBoundaryId, At as generateHeaderScrollTreatmentStyles, Bn as isSiteScopedDirectImageStoragePath, Br as surfaceDecorationColors, Bt as getComponentBorderWidthPx, C as sortRecord, Cn as boxBackgroundSchema, Cr as defineFrameCapability, Ct as deriveSiteStyleBlockPolicy, D as mapEventCommandContent, Dn as collectPortableMediaReferencesFromContent, Dr as featureCardCompositionTreatmentValues, Dt as getGradientPreset, En as stripStaleTransitionStyleGroup, Er as eyebrowTreatmentValues, Et as gradientToCss, F as pageIdentifierForBlockCommand, Fn as parseAspectRatioValue, Fr as visibleHeadingDecorationFamilyValues, Ft as BREAKPOINT_MD, G as ianaTimezoneSchema, Gn as resolveManagedMediaReference, Gr as mergeStyles, Gt as themeButtonExtraClassesWithTrailingIcon, H as bookingPaymentTermsSchema, Hn as persistableMediaSchema, Hr as TokenResolver, Ht as ICON_CONFIG, I as pageIdentifierForCommand, In as resolveMediaTransformForAspect, Ir as parseResolvedSurface, It as BREAKPOINT_SM, J as createCommandRef, Jn as buildMediaIdentifierFromFilename, Jr as mapDrawingStyle, Jt as parseThemeForPersistence, K as createBlockRef, Kn as mediaTypeDiscriminants, Kr as rgbColorValue, Kt as themeButtonSizeClassName, L as pagePathForCommand, Ln as getDirectImageUrlForRelativePath, Lr as parseSurfaceTree, Lt as BREAKPOINT_XL, M as blockIdentifierForCommand, Mn as rotateNormalizedPoint, Mr as testimonialsCompositionTreatmentValues, Mt as getHeaderPaintTargets, N as blockOrderIdentifiersForCommand, Nn as normalizeWidthCandidates, Nr as tileTreatmentValues, Nt as renderHeaderPaintTargetRules, On as summarizePortableMediaReferences, Or as headingDecorationColorTokenValues, Ot as parseGradientPresetId, P as entryIdentifierForCommand, Pn as isExplicitRectCrop, Pr as toNonEmptyReadonlyArray, Pt as BREAKPOINT_LG, Q as createFooterRef, Qr as resolveThemeColorReferenceValue, Qt as normalizeCardRole, R as hasConfiguredBookingVertical, Rn as getDirectImageUrlForSiteScopedPath, Rr as resolveSurface, Rt as MQ_MD_DOWN, S as venueManagementFields, Sn as boxBackgroundOverlaySchema, Sr as defineBlockDesignCapability, St as resolvePublishedLook, Tn as siteChromeBackgroundOverrideOwner, Tr as eventListTreatmentValues, Tt as compiledRuntimeStyleFieldNames, U as require_jsx_runtime, Un as runtimeMediaSchema, Ur as backgroundColorStyle, Ut as generateDefaultButtonSystem, V as bookingPaymentCollectionOptionSchema, Vn as mediaSchema, Vr as resolveSurfaceForeground, Vt as getComponentShadowVar, W as require_react, Wn as buildRenderableMediaAssetIndex, Wr as borderColorStyle, Wt as parseThemeButtonVariantId, X as createEventCategoryRef, Xn as parseMediaIdentifier, Xr as isCssColorLiteral, Xt as cardRoleSchema, Y as createContentEntryRef, Yn as parseCanonicalMediaIdentifier, Yr as opaqueSurfaceDeclarations, Yt as renderCssDeclarations, Z as createEventSeriesRef, Zr as resolveOnColorForThemeToken, Zt as cardVariantRoleValues, _n as heroPhotoPaintsGround, _r as asDesignBlockId, _t as resolveLookSlotSurfaces, ai as surfaceForegroundInputFromResolved, ar as parseRelativeStoragePath, b as isEventVisibility, bn as resolveSectionPhotoPlacement, br as asSiteStyleId, bt as resolveEffectiveArrangement, c as customLinkSchema$1, ci as expandPalette, cn as generateNavLinkCSS, cr as classifyKnownMimeType, ct as headerLeafTextColor, d as internalLinkSchema, di as parseBlockColorToken, dr as defineBlockDesignMetadata, ei as PUBLIC_BUTTON_ROLES, er as resolveVideoSelectionIntentForMediaField, et as createNavigationRef, f as internalResolvedLinkSchema, fi as __commonJSMin, fn as headerRootPaint, fr as resolveEffectiveKnobs, ft as mergeHeaderNavTypographyPreference, g as linkSchema, gn as deriveSectionGround, gt as resolveItemSurface, h as isResolvedInternalLinkEntityType, hn as sectionFactsForContent, hr as arrangementModes, ht as arrangementSlotNames, ii as surfaceForegroundDeclarations, it as refSlug, j as eventManagementTiming, jn as looksLikeUuid, jr as offeringsPreviewCompositionTreatmentValues, jt as generateMobileOverlayBackdropFilterFix, kn as walkAndCollectImageAttrs, kr as introCompositionTreatmentValues, kt as themeSchema, l as entryLinkSchema$1, li as getTextColorForBackground, lr as managementMediaLibraryUploadLimitForMimeType, lt as transparentHeaderForegroundInput, mn as composeBoundary, mr as cardListKnobBlocks, mt as arrangementLookHooks, ni as surfaceToneFromForegroundToken, nr as getMimeType, o as classifySdkEventBookingOffer, oi as surfaceForegroundStyle, on as footerForegroundCandidates, or as FILE_SIZE_LIMITS, ot as effectiveHeaderNavLinkStyle, p as internalRouteOnlyLinkSchema, pi as __toESM, pn as boundaryLayout, pr as cardListFamilyBlocks, pt as readHeaderNavFontSizePreference, q as createBlocksRef, qn as mediaIdentifierSchema, qr as textColorStyle, qt as themeButtonVariantClassNames, ri as defaultThemeTokens, rr as asRecord, rt as createVenueRef, s as RESOLVED_INTERNAL_LINK_ENTITY_TYPES, si as surfaceForegroundValue, sn as buildTextContrastShadow, st as headerForegroundCandidates, t as classifySdkEventTiming, ti as selectLogoVariant, tt as createPageRef, u as externalLinkSchema$1, ui as parseThemeColorToken, ur as parseSafeDownloadFilename, ut as readOpeningForegroundProjection, v as pageLinkSchema$1, vn as parseCanonicalRuntimeBackground, vr as asLayoutVariantKey, vt as arrangementManifestFromVariants, w as stableStringify, wn as runtimeBoxBackgroundSchema, wr as defineNoBlockDesignCapability, wt as requireCuratedSiteStyle, xn as sectionForegroundBackground, xr as assertNever$10, xt as resolveModeArrangement, yn as resolveSectionBackground, yt as readStoredMode, z as eventCommandScheduleSchema, zn as getImageUrl, zr as serializeSurfaceTree, zt as headerVariantValues } from "../sdk-event-upsert-4t4e1z-h.mjs";
3
+ import { $ as mapDrawingSchema, $n as ok, $t as isNonNegativeWholeCents$1, A as assessMailingListTargeting, At as addIntervalPreservingMonthAnchor, Bt as parseEventPageSurfaceSubject, C as exposeSecret, Ct as toScheduledBookingDateTime, D as parseMailingListContentVersionId, Dt as isLiveOrderInstalmentPlanStatus, E as parseMailingListBlockId, En as unsafeAsCheckoutLineId, Et as validateBookingPaymentOptionKinds, F as parseMailingListPlacementTargeting, Fn as unsafeAsMediaAssetId, Ft as omitZeroAmountFutureRows, G as locationMapLinks, Gt as publicEventPricingDisplay, H as assertAllowedPublicUrl, Ht as formatEventPricing, I as DEFAULT_MAILING_LIST_TARGETING, In as unsafeAsOccurrenceId, It as splitAmountWithRemainderInFirst, J as parseLocationValue, Jt as resolveExactOrFreePriceDisplay, K as locationValueSchema, Kt as publicEventPricingOptions, L as planMailingListChoicePresentation, Lt as resolveFlexibleBalanceDueAt, M as parseMailingListProviderScope, Mt as getBookingInstalmentDepositRefundability, N as parseFooterCompositionV1, Nt as getBookingInstalmentPlanIntervalCount, O as parseMailingListSignedSourceToken, On as unsafeAsDemoCapability, Ot as isSettleableFlexibleBalanceContractStatus, Pt as getBookingInstalmentProtectedDepositAmountCents, Qn as err, Qt as mapReadonlyNonEmptyArray, R as isCanonicalRichTextDoc, Rn as unsafeAsPassId, Rt as resolveFlexibleBalanceInitialPaymentCents, S as createSecret, Sn as parseUserId, St as toBookingTimeZone, T as slugify, U as decideLocationSave, Ut as isPublicEventPricingOptionDisplayable, V as parseWeeklyOpeningHours, Vn as unsafeAsPricingOptionId, Vt as formatBookingPriceDisplay, Wt as publicEventPricingCurrency, X as publicLocationSchema$1, Xt as fromArray, Y as projectPublicLocation, Yt as resolvePricingOptionsPriceDisplay, Z as toLocationCoordinates, _ as CANCELLED_SESSION_STATUS, _n as parseMembershipId, _t as parseBookingLocalDate, a as NAVIGATION_LOCATIONS, an as unsafeAsPositiveCents, at as formatTime$1, b as resolveWholeSeriesBookingPhase, bn as parseSiteId, bt as resolveBookingBusinessTimeZone, cn as assertNever, ct as resolveBookingDisplayContext, dn as parseCustomerId, dt as formatLocalScheduleDate, en as parseNonNegativeCents, et as selectCategoryView, f as EVENT_PRESET_VALUES, fn as parseDatedOfferingCapacityHoldAuditRef, ft as formatLocalScheduleTime, h as WHOLE_SERIES_EVENT_PRESET_VALUES, hn as parseEventSeriesId, ht as getLocalScheduleTime, i as EVENT_PRESET_VOCABULARY, in as unsafeAsNonNegativeCents, it as formatDateTimeRange, j as DEFAULT_MAILING_LIST_SUCCESS_MESSAGE, jn as unsafeAsEventInstanceId, jt as clampConfiguredAmount, k as parseMailingListRuntimeContext, kt as isSettleableOrderInstalmentPlanStatus, ln as formatDurationUnitLabel, lt as buildBookingUtcDateWindow, m as SURFACE_EVENT_PRESET_VALUES, mt as getLocalScheduleDate, nn as toCents, nt as formatDateRange, on as formatCurrencyAmount, ot as formatTimeRange, pn as parseDatedOfferingCapacityHoldId, pt as getBookingLocalDateKey, q as normalizeLocationAddressText, qt as publicEventPricingType, rn as toNonNegativeCents, rt as formatDateTime, sn as parseCurrencyCode, st as inferSiteDateLocale, tn as parsePositiveCents, tt as formatDate, u as resolveSiteVerticalBookingConfig, un as parseApiKeyId, ut as compareLocalScheduleDates, v as nextLiveRunSessionStartMs, vt as parseLocalScheduleTime, w as parseManagementKey, wt as toUtcIsoDateTimeString, x as resolveWholeSeriesRunLifecycle, xn as parseSiteTermsVersionId, xt as resolveBookingTimeZoneId, y as orderedLiveRunSessions, yn as parseRetiredCourseId, yt as parseUtcIsoDateTimeString, z as formatOpeningHoursRows, zn as unsafeAsPositiveByteCount, zt as deriveTotalTicketQuantity } from "../src-LhtqTjH7.mjs";
4
+ import { $ as normalizeMediaValueToIdentifierOnly, $t as createCommandContext, A as formatDiffDetail, An as getEnvPrefix, At as navigationIdentity, B as buildFieldChanges, Bn as portablePageDesignSchema, Bt as preparePushConfigTarget, C as reportFromOutcomes, Cn as requireEnvironmentWriteAuthorization, Ct as fileExists, D as normalizeRemoteHomepageReference, Dn as transportSuggestion, Dt as writeJsonFileAtomic, E as createEmptySyncResult, En as formatError, Et as writeJsonFile, F as calculatePullDiff, Fn as createManagementClient, Ft as navigationCommandItemToManagementInput, G as syncLocalMediaForPull, Gt as APPOINTMENT_SERVICE_VISIBILITY_VALUES, H as formatFieldPath, Hn as API_ENDPOINTS, Ht as extractApiErrorMessage, I as buildJsonDiff, In as ManagementApiError, It as normalizeNavigationConfigItemForCommand, J as admitBinaryWriteDestination, Jt as deriveCmsApiUrlFromDashboardUrl, K as applyLocalMediaPush, Kt as ApiRequestError, L as hasPageOperations, Ln as sdkEventScheduleSchema, Lt as applyPushConfigPlan, M as hasPendingChanges, Mn as isLocalConfigured, Mt as convertPulledFooterToLocal, N as findChangedFieldsWithValues, Nn as isRemoteConfigured, Nt as convertPulledNavigationToLocal, O as calculateDiff, On as CliExit, Ot as isMediaValue, P as formatHumanDiff, Pn as loadSdkEnvironment, Pt as convertPulledPagesToLocal, Q as normalizeMediaIdentifierInput, Qt as createClientForEnv, R as pageMetadataForUpsert, Rn as sdkSettingsUpdateSchema, Rt as createPushConfigCommand, S as planCliCommandBatchForBindings, Sn as planEnvironmentWriteAuthorization, St as ensureDir, T as executeResidualSettingsSyncPlan, Tn as ErrorCodes, Tt as readJsonFile, U as revalidateLocalMediaPushPlan, Un as ApiEnvelopeError, Ut as normalizeApiError, V as formatFieldChange, Vn as sdkConfiguredBookingVerticalConfigSchema, Vt as revalidatePushConfigPlan, Wn as unwrapResponse, Wt as isRecord$2, X as writeBinaryFileAtomic, Xt as bindRequestTimeout, Y as readStableBinaryFile, Yt as mapEnvironmentExecutionOutcomesJson, Z as sha256, Zt as confirmAction, _ as commandExecutionToReport, _n as withErrorHandling, _t as metadataFilePath, a as executeEntryCommandPlanAsReport, an as getOutputContext, at as readEntries, b as executeCompiledCliCommandPlanAsReport, bn as parseEnvironmentSelection, bt as writeMetadataFile, c as titleFromEntryData, cn as managementClientConfigFor, ct as readEventsMeta, d as unsafeAsCliEntryIdentifier, dn as parseJsonData, dt as readNavigationMeta, en as createGetCommand, et as walkLocalContentMedia, f as unsafeAsCliFormSlug, fn as parsePaginationOptions, ft as readPagesMeta, g as commandCompileFailureToReport, gn as withConfirmation, gt as ensureMetadataDir, h as mutationCounterForEffect, hn as withCommandContext, ht as writeMediaManifest, i as entrySiteCommandTypes, in as formatDateShort, it as findLegacyEntryFiles, j as formatDiffSummary, jn as getEnvironmentDebugInfo, jt as navigationIdentityMap, k as calculateFooterDiff, kt as duplicateNavigationIdentityMessage, l as unsafeAsCliBlockIdentifier, ln as mapEntryForOutput, lt as readFooterMeta, m as commandReportToSyncResult, mn as runWithInvocation, mt as readVenuesMeta, n as entryCommandCompileErrorToReport, nn as createOutputForCommand, nt as downloadMedia, o as executeEntryCommandPlanAsSyncResult, on as getOutputOnlyContext, ot as readAllMeta, p as unsafeAsCliPageIdentifier, pn as resolveCommandPath, pt as readSettingsMeta, q as prepareLocalMediaForPush, qt as createBearerAPIClient, r as entryCommandReportToSyncResult, rn as currentInvocationEnvelope, rt as extractMediaIdentifiers, s as syncResultForEntryCommandCompileError, sn as handleCommandError, st as readEventCategoriesMeta, t as compileEntryPushCommands, tn as createListCommand, tt as buildStorageUrl, u as unsafeAsCliContentTypeKey, un as parseJsonArray, ut as readFormsMeta, v as commandReportHasFailures, vn as withOutputOnlyErrorHandling, vt as metadataTargetFromEnvironment, w as mergeManySyncResults, wn as withRiverbankEnv, wt as listFiles, x as formatManagementError, xn as planEnvironmentExecution, xt as writeMetadataRecordMap, y as executeCliCommandPlan, yn as executeEnvironmentPlan, yt as readMetadataFile, zn as linkPayloadSchema, zt as loadPushConfigTarget } from "../entryCommands-nATGxgma.mjs";
5
+ import { r as CLI_VERSION, t as loadConfigFile } from "../load-config-DwiS-Ibn.mjs";
6
+ import { a as RichTextDocSchema, c as isRecord$18, i as findUnfilledSentinels, n as buildEntryScaffold, o as isRichTextDoc, r as validateEntryInstance, s as isObjectRecord, t as eventUpsertInputSchema } from "../eventUpsertInputSchema-XRzH6yFb.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-ChNV88KF.mjs";
8
8
  import { config } from "dotenv";
9
9
  import { Command, CommanderError } from "commander";
10
10
  import * as fs$2 from "fs/promises";
@@ -386,8 +386,10 @@ async function writeVenues(contentDir, pulledVenues, options) {
386
386
  description: venue.description,
387
387
  timezone: venue.timezone,
388
388
  capacity: venue.capacity,
389
- address: venue.address,
390
- location: venue.location,
389
+ ...venue.locationValue !== undefined ? { locationValue: venue.locationValue } : {
390
+ address: venue.address,
391
+ location: venue.location
392
+ },
391
393
  mapEmbed: venue.mapEmbed
392
394
  });
393
395
  filePaths.push(filePath);
@@ -2132,18 +2134,7 @@ function calculateFooterPullDiff(args) {
2132
2134
  }
2133
2135
  return { type: "unchanged" };
2134
2136
  }
2135
- function mapRemoteVenueToLocalComparable(v$1) {
2136
- return {
2137
- slug: v$1.slug,
2138
- title: v$1.title,
2139
- description: v$1.description,
2140
- timezone: v$1.timezone,
2141
- capacity: v$1.capacity,
2142
- address: v$1.address,
2143
- location: v$1.location,
2144
- mapEmbed: v$1.mapEmbed
2145
- };
2146
- }
2137
+ const mapRemoteVenueToLocalComparable = mapLocalVenueToComparable;
2147
2138
  function mapLocalVenueToComparable(v$1) {
2148
2139
  return {
2149
2140
  slug: v$1.slug,
@@ -2151,8 +2142,10 @@ function mapLocalVenueToComparable(v$1) {
2151
2142
  description: v$1.description,
2152
2143
  timezone: v$1.timezone,
2153
2144
  capacity: v$1.capacity,
2154
- address: v$1.address,
2155
- location: v$1.location,
2145
+ ...v$1.locationValue !== undefined ? { locationValue: v$1.locationValue } : {
2146
+ address: v$1.address,
2147
+ location: v$1.location
2148
+ },
2156
2149
  mapEmbed: v$1.mapEmbed
2157
2150
  };
2158
2151
  }
@@ -4773,6 +4766,7 @@ function venueCommand(venue) {
4773
4766
  type: "upsertVenue",
4774
4767
  ref: createVenueRef([venue.slug]),
4775
4768
  input: {
4769
+ ...venue.locationValue !== undefined ? { locationValue: venue.locationValue } : {},
4776
4770
  slug: venue.slug,
4777
4771
  title: venue.title,
4778
4772
  description: venue.description ?? undefined,
@@ -4947,7 +4941,7 @@ function compileDatedOfferingPushCommands(input) {
4947
4941
  }
4948
4942
  /** One Event graph contains all its run commands, so write it only once. */
4949
4943
  function uniqueDatedOfferingCommands(plan) {
4950
- return plan.reportedCommands.filter((reported, index, commands) => reported.plannedCommand.command.type !== "upsertEventSeries" || commands.findIndex((candidate) => candidate.plannedCommand.command.type === "upsertEventSeries" && candidate.reportSubject.identifier === reported.reportSubject.identifier) === index);
4944
+ return plan.reportedCommands.filter((reported, index, commands$1) => reported.plannedCommand.command.type !== "upsertEventSeries" || commands$1.findIndex((candidate) => candidate.plannedCommand.command.type === "upsertEventSeries" && candidate.reportSubject.identifier === reported.reportSubject.identifier) === index);
4951
4945
  }
4952
4946
  async function executeDatedOfferingCommand(input, reported) {
4953
4947
  const command = reported.plannedCommand.command;
@@ -5134,8 +5128,8 @@ function eventGraphCommands(compiledPlan, eventIdentifier) {
5134
5128
  return candidate.reportSubject.identifier === eventIdentifier && command.type === "upsertEventSeries" ? [command] : [];
5135
5129
  });
5136
5130
  }
5137
- function eventGraphUpsertInput(attendeeNotification, commands) {
5138
- const [firstCommand, ...remainingCommands] = commands;
5131
+ function eventGraphUpsertInput(attendeeNotification, commands$1) {
5132
+ const [firstCommand, ...remainingCommands] = commands$1;
5139
5133
  if (!firstCommand) throw new Error("Validated Event graph has no run commands");
5140
5134
  const first = eventSeriesUpsertInput(firstCommand);
5141
5135
  const additionalRuns = remainingCommands.map((command) => eventSeriesUpsertInput(command).runs[0]);
@@ -5641,8 +5635,8 @@ function findCompiledBookingSettingsPlan(compiled) {
5641
5635
  return undefined;
5642
5636
  }
5643
5637
  function requireSingleBookingCommand(compiled) {
5644
- const commands = compiled.plan.commands;
5645
- return commands.length === 1 && commands[0] !== undefined ? ok(commands[0].command) : err(new Error(`Booking settings command compilation produced ${commands.length} commands; expected exactly one.`));
5638
+ const commands$1 = compiled.plan.commands;
5639
+ return commands$1.length === 1 && commands$1[0] !== undefined ? ok(commands$1[0].command) : err(new Error(`Booking settings command compilation produced ${commands$1.length} commands; expected exactly one.`));
5646
5640
  }
5647
5641
  function operationInputForMode(input, command) {
5648
5642
  const { plan: _plan, ...operation } = input;
@@ -7082,7 +7076,7 @@ const uiSchema = z.object({
7082
7076
  "behavior",
7083
7077
  "style"
7084
7078
  ]).optional(),
7085
- valueContract: z.enum(["boxBackground"]).optional()
7079
+ valueContract: z.enum(["boxBackground", "location"]).optional()
7086
7080
  }).partial().superRefine((ui, ctx) => {
7087
7081
  if (ui.layoutGridColumns !== undefined && ui.layoutGridColumnsFields !== undefined) {
7088
7082
  ctx.addIssue({
@@ -7607,11 +7601,14 @@ const manifestSchema = z.object({
7607
7601
  }).optional()
7608
7602
  }).optional(),
7609
7603
  promotedFields: z.array(z.string().min(1)).optional(),
7604
+ arrangementOwnedFieldIds: z.array(z.string().min(1)).readonly().optional(),
7610
7605
  variantMeaning: z.discriminatedUnion("kind", [z.object({
7611
7606
  kind: z.literal("arrangement"),
7612
7607
  lookOnlyKeys: z.array(z.string().min(1)).readonly().optional()
7613
7608
  }), z.object({
7614
7609
  kind: z.literal("mode"),
7610
+ modes: z.array(z.enum(arrangementModes)).min(1).readonly(),
7611
+ defaultMode: z.enum(arrangementModes),
7615
7612
  arrangementField: z.string().min(1),
7616
7613
  keys: z.array(z.string().min(1)).min(1).readonly(),
7617
7614
  defaultKey: z.string().min(1),
@@ -7696,7 +7693,9 @@ function canonicalizeObjectForWrite(plans, value) {
7696
7693
  function canonicalizeFieldValue(plan, value) {
7697
7694
  switch (plan.kind) {
7698
7695
  case "media": return canonicalizeMedia(value);
7699
- case "group": return plan.childSelection.kind === "discriminatedTabs" ? canonicalizeDiscriminatedGroup(plan, value) : canonicalizeObjectForWrite(plan.childSelection.fields, value);
7696
+ case "group":
7697
+ if (plan.valueContract === "location") return value;
7698
+ return plan.childSelection.kind === "discriminatedTabs" ? canonicalizeDiscriminatedGroup(plan, value) : canonicalizeObjectForWrite(plan.childSelection.fields, value);
7700
7699
  case "repeater": return canonicalizeRepeater(plan, value);
7701
7700
  case "string":
7702
7701
  case "number":
@@ -9352,7 +9351,7 @@ const ALLOWED_URL_PROTOCOLS = ["http:", "https:"];
9352
9351
  const DATE_PATTERN = /^(?<year>[1-9]\d{3})-(?<month>\d{2})-(?<day>\d{2})$/;
9353
9352
  const TIME_PATTERN = /^(?<hours>[01]\d|2[0-3]):(?<minutes>[0-5]\d)$/;
9354
9353
  const DATETIME_PATTERN = /^(?<date>[1-9]\d{3}-\d{2}-\d{2})T(?<time>(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d)(?:\.\d+)?(?<offset>Z|[+-](?:[01]\d|2[0-3]):[0-5]\d)$/;
9355
- function assertNever$12(value) {
9354
+ function assertNever$11(value) {
9356
9355
  throw new Error(`Unhandled field validation variant: ${JSON.stringify(value)}`);
9357
9356
  }
9358
9357
  function validationContext(options = {}) {
@@ -9419,7 +9418,7 @@ function fieldIssueToMessage(issue$1) {
9419
9418
  case "invalidPhone":
9420
9419
  case "invalidTime":
9421
9420
  case "invalidUrl": return simpleIssueMessages[issue$1.kind];
9422
- default: return assertNever$12(issue$1);
9421
+ default: return assertNever$11(issue$1);
9423
9422
  }
9424
9423
  }
9425
9424
  function pluralize(label, count) {
@@ -9427,7 +9426,7 @@ function pluralize(label, count) {
9427
9426
  return label.endsWith("s") ? label : `${label}s`;
9428
9427
  }
9429
9428
  function valueContractForField(field) {
9430
- return field.ui?.valueContract === "boxBackground" ? { valueContract: "boxBackground" } : {};
9429
+ return field.ui?.valueContract !== undefined ? { valueContract: field.ui.valueContract } : {};
9431
9430
  }
9432
9431
  function deriveTabGroupValidationPlan(field, path$3, required) {
9433
9432
  return {
@@ -9541,13 +9540,14 @@ function deriveFieldValidationPlan(field, path$3 = [field.id]) {
9541
9540
  kind: "all",
9542
9541
  fields: deriveNestedFieldPlans(field.schema?.fields ?? [], path$3)
9543
9542
  },
9544
- allowNullChildren: field.type === "group" && field.ui?.widget === "locationPicker"
9543
+ allowNullChildren: field.type === "group" && field.ui?.widget === "locationPicker",
9544
+ ...valueContractForField(field)
9545
9545
  };
9546
9546
  case "tabGroup": return deriveTabGroupValidationPlan(field, path$3, required);
9547
9547
  case "presetOrCustom":
9548
9548
  case "contentTypeSelect":
9549
9549
  case "entryPicker": return makePlan("passthrough", "unknown", field, path$3, false, []);
9550
- default: return assertNever$12(field);
9550
+ default: return assertNever$11(field);
9551
9551
  }
9552
9552
  }
9553
9553
  function deriveRepeaterFieldValidationPlan(field, path$3) {
@@ -9656,7 +9656,7 @@ function resolveSelectConstraintSource(field) {
9656
9656
  kind: "runtime",
9657
9657
  source: source.kind
9658
9658
  };
9659
- default: return assertNever$12(source);
9659
+ default: return assertNever$11(source);
9660
9660
  }
9661
9661
  }
9662
9662
  function fieldPlanToNativeInputProps(plan) {
@@ -9708,7 +9708,7 @@ function fieldPlanToNativeInputProps(plan) {
9708
9708
  case "linkObject":
9709
9709
  case "referenceText":
9710
9710
  case "blockIconValue": break;
9711
- default: assertNever$12(constraint);
9711
+ default: assertNever$11(constraint);
9712
9712
  }
9713
9713
  }
9714
9714
  return props$1;
@@ -9716,32 +9716,6 @@ function fieldPlanToNativeInputProps(plan) {
9716
9716
  function normalizeFieldInput(plan, value, options = {}) {
9717
9717
  return normalizeFieldValue(plan, value, validationContext(options));
9718
9718
  }
9719
- /** Drop obsolete presentation containers only when reading persisted content.
9720
- * Flat data remains authoritative; unknown variants and legitimate groups survive.
9721
- */
9722
- function normalizeLegacyStoredGroupContainers(plans, content) {
9723
- if (!isPlainObject$6(content)) return content;
9724
- const planMap = new Map(plans.map((plan) => [plan.fieldId, plan]));
9725
- const entries = Object.entries(content).map(([key, value]) => {
9726
- const plan = planMap.get(key);
9727
- return [key, plan ? normalizeLegacyStoredField(plan, value) : value];
9728
- });
9729
- return entries.every(([key, value]) => value === content[key]) ? content : Object.fromEntries(entries);
9730
- }
9731
- function normalizeLegacyStoredField(plan, value) {
9732
- if (plan.kind === "group") {
9733
- return normalizeLegacyStoredGroupContainers(selectedGroupChildPlans(plan, value), value);
9734
- }
9735
- if (plan.kind !== "repeater" || !isUnknownArray$2(value)) return value;
9736
- const items = value.map((item) => {
9737
- if (!isPlainObject$6(item)) return item;
9738
- const selection = selectRepeaterItemPlan(plan, item);
9739
- if (selection.kind !== "fields") return item;
9740
- const retained = selection.flattenedGroupIds.some((key) => Object.prototype.hasOwnProperty.call(item, key)) ? Object.fromEntries(Object.entries(item).filter(([key]) => !selection.flattenedGroupIds.includes(key))) : item;
9741
- return normalizeLegacyStoredGroupContainers(selection.fields, retained);
9742
- });
9743
- return items.every((item, index) => item === value[index]) ? value : items;
9744
- }
9745
9719
  function normalizeStoredContentValues(plans, content, options = {}) {
9746
9720
  if (!content || typeof content !== "object" || Array.isArray(content)) {
9747
9721
  return {};
@@ -9770,7 +9744,9 @@ function normalizeStoredFieldValueWithContext(plan, value, ctx) {
9770
9744
  return undefined;
9771
9745
  }
9772
9746
  switch (plan.kind) {
9773
- case "group": return normalizeStoredObjectChildren(selectedGroupChildPlans(plan, value), value, childValidationContext(plan, ctx));
9747
+ case "group":
9748
+ if (plan.valueContract === "location") return normalizeLocationContract(value, ctx.mode);
9749
+ return normalizeStoredObjectChildren(selectedGroupChildPlans(plan, value), value, childValidationContext(plan, ctx));
9774
9750
  case "repeater": return normalizeStoredRepeaterItems(plan, value, ctx);
9775
9751
  case "string":
9776
9752
  case "number":
@@ -9781,7 +9757,7 @@ function normalizeStoredFieldValueWithContext(plan, value, ctx) {
9781
9757
  case "link":
9782
9758
  case "select":
9783
9759
  case "passthrough": return normalizeFieldValue(plan, value, ctx);
9784
- default: return assertNever$12(plan);
9760
+ default: return assertNever$11(plan);
9785
9761
  }
9786
9762
  }
9787
9763
  function normalizeStoredObjectChildren(children, value, ctx) {
@@ -9821,7 +9797,9 @@ function normalizeFieldValue(plan, value, ctx) {
9821
9797
  switch (plan.kind) {
9822
9798
  case "number": return normalizeNumberInput(value, ctx.allowNull);
9823
9799
  case "string": return acceptsOptionalBlankAsMissing(plan, value) ? undefined : value;
9824
- case "group": return normalizeObjectChildren(selectedGroupChildPlans(plan, value), value, childValidationContext(plan, ctx));
9800
+ case "group":
9801
+ if (plan.valueContract === "location") return normalizeLocationContract(value, ctx.mode);
9802
+ return normalizeObjectChildren(selectedGroupChildPlans(plan, value), value, childValidationContext(plan, ctx));
9825
9803
  case "repeater": return normalizeRepeaterItems(plan, value, ctx);
9826
9804
  case "link":
9827
9805
  case "boolean":
@@ -9830,7 +9808,7 @@ function normalizeFieldValue(plan, value, ctx) {
9830
9808
  case "select":
9831
9809
  case "passthrough": return value;
9832
9810
  case "media": return value;
9833
- default: return assertNever$12(plan);
9811
+ default: return assertNever$11(plan);
9834
9812
  }
9835
9813
  }
9836
9814
  function normalizeObjectChildren(children, value, ctx) {
@@ -9894,7 +9872,7 @@ function validateNormalizedFieldValue(plan, value, ctx) {
9894
9872
  case "repeater": return validateRepeaterPlan(plan, value, ctx);
9895
9873
  case "group": return validateGroupPlan(plan, value, ctx);
9896
9874
  case "passthrough": return [];
9897
- default: return assertNever$12(plan);
9875
+ default: return assertNever$11(plan);
9898
9876
  }
9899
9877
  }
9900
9878
  function validateMediaPlan(plan, value, ctx) {
@@ -9915,7 +9893,7 @@ function acceptsNullValue(plan, ctx) {
9915
9893
  return ctx.mode === "storable" ? !plan.required : ctx.allowNull || acceptsOptionalNullValue(plan);
9916
9894
  }
9917
9895
  function acceptsOptionalNullValue(plan) {
9918
- return !plan.required && (plan.kind === "media" || plan.kind === "number");
9896
+ return !plan.required && (plan.kind === "media" || plan.kind === "number" || plan.kind === "group" && plan.valueContract === "location");
9919
9897
  }
9920
9898
  function isMissingForPlan(plan, value, mode) {
9921
9899
  if (value === undefined) return true;
@@ -9999,7 +9977,7 @@ function validateNumberConstraint(plan, constraint, value) {
9999
9977
  case "numberType": return [];
10000
9978
  case "numberMin": return value < constraint.minimum ? [issue(plan, "tooSmall", { minimum: constraint.minimum })] : [];
10001
9979
  case "numberMax": return value > constraint.maximum ? [issue(plan, "tooLarge", { maximum: constraint.maximum })] : [];
10002
- default: return assertNever$12(constraint);
9980
+ default: return assertNever$11(constraint);
10003
9981
  }
10004
9982
  }
10005
9983
  function validateSelectPlan(plan, value) {
@@ -10021,7 +9999,7 @@ function validateRepeaterPlan(plan, value, ctx) {
10021
9999
  maximum: constraint.maximum,
10022
10000
  itemLabel: "item"
10023
10001
  })] : [];
10024
- default: return assertNever$12(constraint);
10002
+ default: return assertNever$11(constraint);
10025
10003
  }
10026
10004
  });
10027
10005
  return [...constraintIssues, ...value.flatMap((item, index) => validateRepeaterItem(plan, item, index, ctx))];
@@ -10088,6 +10066,7 @@ function validateFlattenedGroupContainers(groupIds, item, plan, index, ctx) {
10088
10066
  }] : []);
10089
10067
  }
10090
10068
  function validateGroupPlan(plan, value, ctx) {
10069
+ if (plan.valueContract === "location") return validateLocationGroupContract(plan, value, ctx);
10091
10070
  if (!isPlainObject$6(value)) return [issue(plan, "wrongType", { expected: "an object" })];
10092
10071
  if (plan.childSelection.kind === "discriminatedTabs") {
10093
10072
  const selectedType = value[plan.childSelection.activeTabField];
@@ -10103,10 +10082,7 @@ function validateGroupPlan(plan, value, ctx) {
10103
10082
  const childCtx = childValidationContext(plan, ctx);
10104
10083
  const childIssues = selectedGroupChildPlans(plan, value).flatMap((childPlan) => validateNormalizedFieldValue(childPlan, value[childPlan.fieldId], childCtx));
10105
10084
  if (childIssues.length > 0) return childIssues;
10106
- if (plan.valueContract === "boxBackground" && !(ctx.mode === "render" ? runtimeBoxBackgroundSchema : boxBackgroundSchema).safeParse(value).success) {
10107
- return [issue(plan, "invalidBoxBackground")];
10108
- }
10109
- return [];
10085
+ return validateGroupBackgroundContract(plan, value, ctx);
10110
10086
  }
10111
10087
  function childValidationContext(plan, ctx) {
10112
10088
  return plan.allowNullChildren ? {
@@ -10155,7 +10131,7 @@ function rebaseFieldPlanPath(plan, fromPrefix, toPrefix) {
10155
10131
  ...plan,
10156
10132
  path: path$3
10157
10133
  };
10158
- default: return assertNever$12(plan);
10134
+ default: return assertNever$11(plan);
10159
10135
  }
10160
10136
  }
10161
10137
  function validateInlineTextPlan(plan, value, ctx) {
@@ -10208,7 +10184,7 @@ function fieldPlanToObjectPropertyZod(plan, options = {}, layoutGridCoordinates
10208
10184
  switch (presence.kind) {
10209
10185
  case "required": return schema;
10210
10186
  case "optional": return schema.optional();
10211
- default: return assertNever$12(presence);
10187
+ default: return assertNever$11(presence);
10212
10188
  }
10213
10189
  }
10214
10190
  /** Validate stored or runtime fields without applying editor/write normalization. */
@@ -10225,7 +10201,8 @@ function fieldPlanToStrictObjectPropertyZod(plan, mode = "strict", layoutGridCoo
10225
10201
  addFieldIssueToZodContext(zodCtx, validationIssue, plan.path);
10226
10202
  });
10227
10203
  });
10228
- return plan.required ? schema : schema.optional();
10204
+ const projected = schema.transform((value) => mode === "render" && plan.kind === "group" && plan.valueContract === "location" ? normalizeLocationContract(value, "render") : value);
10205
+ return plan.required ? projected : projected.optional();
10229
10206
  }
10230
10207
  function fieldIssueToZodDetail(issue$1) {
10231
10208
  if (issue$1.kind === "required") return issue$1.emptyOrigin ? {
@@ -10297,7 +10274,7 @@ function findNestedFieldValidationPlan(plan, path$3) {
10297
10274
  case "link":
10298
10275
  case "select":
10299
10276
  case "passthrough": return null;
10300
- default: return assertNever$12(plan);
10277
+ default: return assertNever$11(plan);
10301
10278
  }
10302
10279
  }
10303
10280
  function fieldValidationDescriptor(plan) {
@@ -10418,6 +10395,32 @@ function isEmptyRichTextDoc(value) {
10418
10395
  const first = content[0];
10419
10396
  return first?.type === "paragraph" && (!Array.isArray(first.content) || first.content.length === 0);
10420
10397
  }
10398
+ function normalizeLocationContract(value, mode) {
10399
+ const canonical$1 = locationValueSchema.safeParse(value);
10400
+ if (canonical$1.success) return mode === "render" ? projectPublicLocation(canonical$1.data) : canonical$1.data;
10401
+ const publicValue = mode === "render" ? publicLocationSchema$1.safeParse(value) : null;
10402
+ return publicValue?.success ? publicValue.data : value;
10403
+ }
10404
+ function validateLocationGroupContract(plan, value, ctx) {
10405
+ if (isRenderLocationRecovery(value, ctx.mode)) return [];
10406
+ const schema = ctx.mode === "render" || ctx.mode === "render-source" ? z.union([locationValueSchema, publicLocationSchema$1]) : locationValueSchema;
10407
+ const parsed = schema.safeParse(value);
10408
+ if (!parsed.success) return [issue(plan, "wrongType", { expected: "a valid location" })];
10409
+ if (ctx.mode === "storable" || ctx.mode === "strict") {
10410
+ const canonical$1 = locationValueSchema.safeParse(value);
10411
+ if (canonical$1.success && decideLocationSave(canonical$1.data, "idle").kind === "blocked") return [issue(plan, "wrongType", { expected: "a confirmed address and pin" })];
10412
+ }
10413
+ return [];
10414
+ }
10415
+ function validateGroupBackgroundContract(plan, value, ctx) {
10416
+ if (plan.valueContract === "boxBackground" && !(ctx.mode === "render" ? runtimeBoxBackgroundSchema : boxBackgroundSchema).safeParse(value).success) {
10417
+ return [issue(plan, "invalidBoxBackground")];
10418
+ }
10419
+ return [];
10420
+ }
10421
+ function isRenderLocationRecovery(value, mode) {
10422
+ return (mode === "render" || mode === "render-source") && z.strictObject({ kind: z.literal("needs_place") }).safeParse(value).success;
10423
+ }
10421
10424
 
10422
10425
  //#endregion
10423
10426
  //#region ../blocks/src/system/manifest/fieldValidation/layoutGridRendering.ts
@@ -10465,7 +10468,7 @@ function projectLayoutGridPlansForRendering(plans, value, rootValues = layoutGri
10465
10468
  if (!values) return value;
10466
10469
  return plans.reduce((projected, plan) => {
10467
10470
  const fieldValue = projected[plan.fieldId];
10468
- const next = plan.kind === "group" ? projectLayoutGridPlansForRendering(allGroupChildPlans(plan), fieldValue, rootValues) : plan.kind === "repeater" && Array.isArray(fieldValue) ? projectGrid(plan, fieldValue, rootValues).map((item) => {
10471
+ const next = plan.kind === "group" && plan.valueContract === "location" ? recoverUnreadableLocation(fieldValue) : plan.kind === "group" ? projectLayoutGridPlansForRendering(allGroupChildPlans(plan), fieldValue, rootValues) : plan.kind === "repeater" && Array.isArray(fieldValue) ? projectGrid(plan, fieldValue, rootValues).map((item) => {
10469
10472
  const row$1 = layoutGridRecord(item);
10470
10473
  return row$1 ? projectLayoutGridPlansForRendering(resolveLayoutGridItemPlans(plan, row$1), row$1, rootValues) : item;
10471
10474
  }) : fieldValue;
@@ -10475,6 +10478,11 @@ function projectLayoutGridPlansForRendering(plans, value, rootValues = layoutGri
10475
10478
  };
10476
10479
  }, values);
10477
10480
  }
10481
+ /** Render recovery drops unreadable meaning rather than interpreting obsolete coordinates. */
10482
+ function recoverUnreadableLocation(value) {
10483
+ if (value == null || locationValueSchema.safeParse(value).success || publicLocationSchema$1.safeParse(value).success) return value;
10484
+ return { kind: "needs_place" };
10485
+ }
10478
10486
 
10479
10487
  //#endregion
10480
10488
  //#region ../blocks/src/system/manifest/validation.ts
@@ -10504,33 +10512,36 @@ function compileManifestContentContract(manifestOrFields, options = {}) {
10504
10512
  const plans = derivePlansFromManifestOrFields(manifestOrFields);
10505
10513
  const strictOptions = { allowNull: false };
10506
10514
  const strictStoredSchema = deriveStrictContentZodFromPlans(plans);
10507
- return Object.freeze({ [compiledManifestContentContract]: Object.freeze({
10508
- plans,
10509
- strictStoredSchema,
10510
- renderSourceSchema: deriveStrictContentZodFromPlans(plans, "render-source"),
10511
- writeSchema: deriveNormalizedContentZodFromPlans(plans, strictOptions, normalizeManifestContentForWrite).superRefine((value, ctx) => {
10512
- if (options.unknownFields !== "reject") return;
10513
- unknownManifestFieldPaths(plans, value).forEach((path$3) => {
10514
- ctx.addIssue({
10515
- code: "custom",
10516
- path: path$3,
10517
- message: `Unknown content field: ${path$3.join(".")}`
10515
+ return Object.freeze({
10516
+ fields: Array.isArray(manifestOrFields) ? manifestOrFields : manifestOrFields.fields,
10517
+ [compiledManifestContentContract]: Object.freeze({
10518
+ plans,
10519
+ strictStoredSchema,
10520
+ renderSourceSchema: deriveStrictContentZodFromPlans(plans, "render-source"),
10521
+ writeSchema: deriveNormalizedContentZodFromPlans(plans, strictOptions, normalizeManifestContentForWrite).superRefine((value, ctx) => {
10522
+ if (options.unknownFields !== "reject") return;
10523
+ unknownManifestFieldPaths(plans, value).forEach((path$3) => {
10524
+ ctx.addIssue({
10525
+ code: "custom",
10526
+ path: path$3,
10527
+ message: `Unknown content field: ${path$3.join(".")}`
10528
+ });
10518
10529
  });
10519
- });
10520
- }).transform((value) => canonicalizeObjectForWrite(plans, value)),
10521
- draftSchema: deriveNormalizedContentZodFromPlans(plans, {
10522
- allowNull: true,
10523
- allowIncomplete: true,
10524
- mode: "draft"
10525
- }, normalizeStoredContentValues),
10526
- renderDraftSchema: deriveNormalizedContentZodFromPlans(plans, {
10527
- allowNull: true,
10528
- allowIncomplete: true,
10529
- mode: "draft"
10530
- }, normalizeStoredContentValues, false),
10531
- renderSchema: deriveStrictContentZodFromPlans(plans, "render"),
10532
- findNonPortableMediaPaths: (content) => findNonPortableMediaPaths(plans, content)
10533
- }) });
10530
+ }).transform((value) => canonicalizeObjectForWrite(plans, value)),
10531
+ draftSchema: deriveNormalizedContentZodFromPlans(plans, {
10532
+ allowNull: true,
10533
+ allowIncomplete: true,
10534
+ mode: "draft"
10535
+ }, normalizeStoredContentValues),
10536
+ renderDraftSchema: deriveNormalizedContentZodFromPlans(plans, {
10537
+ allowNull: true,
10538
+ allowIncomplete: true,
10539
+ mode: "draft"
10540
+ }, normalizeStoredContentValues, false),
10541
+ renderSchema: deriveStrictContentZodFromPlans(plans, "render"),
10542
+ findNonPortableMediaPaths: (content) => findNonPortableMediaPaths(plans, content)
10543
+ })
10544
+ });
10534
10545
  }
10535
10546
  function unknownManifestFieldPaths(plans, value, parent = [], discriminator) {
10536
10547
  if (!isPlainRecord$1(value)) return [];
@@ -10539,7 +10550,7 @@ function unknownManifestFieldPaths(plans, value, parent = [], discriminator) {
10539
10550
  }
10540
10551
  function nestedUnknownManifestFieldPaths(plan, value, path$3) {
10541
10552
  if (plan.kind === "group") {
10542
- if (plan.valueContract === "boxBackground") return [];
10553
+ if (plan.valueContract !== undefined) return [];
10543
10554
  const selection = plan.childSelection;
10544
10555
  return unknownManifestFieldPaths(allGroupChildPlans(plan), value, path$3, selection.kind === "discriminatedTabs" ? selection.activeTabField : undefined);
10545
10556
  }
@@ -10566,8 +10577,7 @@ function findNonPortableManifestMediaPaths(contract, content) {
10566
10577
  /** Strictly admits already-persisted content without repairing it. */
10567
10578
  function admitStoredManifestContent(contract, content) {
10568
10579
  const state = contract[compiledManifestContentContract];
10569
- const normalized = normalizeLegacyStoredGroupContainers(state.plans, content);
10570
- const nonPortablePaths = state.findNonPortableMediaPaths(normalized);
10580
+ const nonPortablePaths = state.findNonPortableMediaPaths(content);
10571
10581
  if (nonPortablePaths.length > 0) {
10572
10582
  return {
10573
10583
  ok: false,
@@ -10577,20 +10587,23 @@ function admitStoredManifestContent(contract, content) {
10577
10587
  }
10578
10588
  };
10579
10589
  }
10580
- const parsed = state.strictStoredSchema.safeParse(normalized);
10590
+ const parsed = state.strictStoredSchema.safeParse(content);
10581
10591
  return parsed.success ? {
10582
10592
  ok: true,
10583
- value: normalized
10593
+ value: content
10584
10594
  } : {
10585
10595
  ok: false,
10586
10596
  error: zodAdmissionError(parsed.error)
10587
10597
  };
10588
10598
  }
10599
+ /** Presentation recovery preserves authored payloads and does not admit them for a write. */
10600
+ function projectStoredManifestContentForRendering(contract, content) {
10601
+ return projectLayoutGridPlansForRendering(contract[compiledManifestContentContract].plans, content);
10602
+ }
10589
10603
  /** Public reads alone may project invalid grid geometry. All other stored-shape and portability checks remain strict. */
10590
10604
  function admitStoredManifestContentForRendering(contract, content) {
10591
10605
  const state = contract[compiledManifestContentContract];
10592
- const normalized = normalizeLegacyStoredGroupContainers(state.plans, content);
10593
- const paths = state.findNonPortableMediaPaths(normalized);
10606
+ const paths = state.findNonPortableMediaPaths(content);
10594
10607
  if (paths.length > 0) return {
10595
10608
  ok: false,
10596
10609
  error: {
@@ -10598,7 +10611,7 @@ function admitStoredManifestContentForRendering(contract, content) {
10598
10611
  paths
10599
10612
  }
10600
10613
  };
10601
- const projected = projectLayoutGridPlansForRendering(state.plans, normalized);
10614
+ const projected = projectStoredManifestContentForRendering(contract, content);
10602
10615
  const parsed = state.renderSourceSchema.safeParse(projected);
10603
10616
  return parsed.success ? {
10604
10617
  ok: true,
@@ -10695,11 +10708,11 @@ function validateManifestWriteCandidate(contract, data) {
10695
10708
  */
10696
10709
  function deriveRenderableManifestContent(contract, stored, project) {
10697
10710
  const state = contract[compiledManifestContentContract];
10698
- const projected = projectLayoutGridPlansForRendering(state.plans, normalizeLegacyStoredGroupContainers(state.plans, project(stored)));
10711
+ const projected = projectLayoutGridPlansForRendering(state.plans, project(stored));
10699
10712
  const parsed = state.renderSchema.safeParse(projected);
10700
10713
  return parsed.success ? {
10701
10714
  ok: true,
10702
- value: projected
10715
+ value: parsed.data
10703
10716
  } : {
10704
10717
  ok: false,
10705
10718
  error: zodAdmissionError(parsed.error)
@@ -10712,11 +10725,11 @@ function deriveRenderableManifestContent(contract, stored, project) {
10712
10725
  */
10713
10726
  function admitTransportedRenderableManifestContent(contract, content) {
10714
10727
  const state = contract[compiledManifestContentContract];
10715
- const projected = projectLayoutGridPlansForRendering(state.plans, content);
10728
+ const projected = projectStoredManifestContentForRendering(contract, content);
10716
10729
  const parsed = state.renderSchema.safeParse(projected);
10717
10730
  return parsed.success ? {
10718
10731
  ok: true,
10719
- value: projected
10732
+ value: parsed.data
10720
10733
  } : {
10721
10734
  ok: false,
10722
10735
  error: zodAdmissionError(parsed.error)
@@ -10744,7 +10757,7 @@ function deriveContentZodFromPlans(plans, options, validateLayoutGrids = true) {
10744
10757
  });
10745
10758
  }
10746
10759
  function deriveStrictContentZodFromPlans(plans, mode = "strict") {
10747
- const shape = Object.fromEntries(plans.map((plan) => [plan.fieldId, fieldPlanToStrictObjectPropertyZod(plan, mode === "render" ? "render" : "strict", mode === "strict" ? "validate" : "projected")]));
10760
+ const shape = Object.fromEntries(plans.map((plan) => [plan.fieldId, fieldPlanToStrictObjectPropertyZod(plan, mode, mode === "strict" ? "validate" : "projected")]));
10748
10761
  return z.object(shape).catchall(z.unknown()).passthrough().superRefine((values, ctx) => {
10749
10762
  if (mode !== "strict") return;
10750
10763
  validateLayoutGridPlans(plans, values).forEach((issue$1) => {
@@ -10836,7 +10849,7 @@ function collectNonPortablePlannedMedia(plans, content, parentPath, paths) {
10836
10849
  visitPlannedMedia(plans, content, parentPath, (value, path$3, kind) => {
10837
10850
  if (kind === "richText") {
10838
10851
  collectNonPortableRichTextImages(value, path$3, paths);
10839
- } else if (isPlainRecord$1(value) && (hasEnvironmentSpecificMediaField(value) || hasNonPortablePoster(value))) {
10852
+ } else if (value !== null && value !== undefined && !mediaSchema.safeParse(value).success) {
10840
10853
  paths.add(formatFieldPath$1(path$3));
10841
10854
  }
10842
10855
  });
@@ -10857,10 +10870,6 @@ function isPlainRecord$1(value) {
10857
10870
  function hasEnvironmentSpecificMediaField(value) {
10858
10871
  return "assetId" in value || "storageBucket" in value || "storagePath" in value || "src" in value || "mimeType" in value || looksLikeUuid(value.id);
10859
10872
  }
10860
- function hasNonPortablePoster(value) {
10861
- if (value.poster === undefined) return false;
10862
- return !mediaPosterSchema.safeParse(value.poster).success;
10863
- }
10864
10873
 
10865
10874
  //#endregion
10866
10875
  //#region src/sync/validation.ts
@@ -11076,11 +11085,12 @@ function createVariantField(manifest) {
11076
11085
  return null;
11077
11086
  }
11078
11087
  const variantKeys = Object.keys(manifest.variants).filter((key) => !manifest.variantMeaning.lookOnlyKeys?.includes(key));
11088
+ if (variantKeys.length === 0) return null;
11079
11089
  const field = {
11080
11090
  id: "variant",
11081
11091
  type: "select",
11082
- label: "Variant",
11083
- description: "Choose how this block is laid out.",
11092
+ label: manifest.variantMeaning.kind === "arrangement" ? "Layout" : "Variant",
11093
+ ...manifest.variantMeaning.kind === "arrangement" ? {} : { description: "Choose how this block is laid out." },
11084
11094
  ui: { intent: "display" },
11085
11095
  required: false,
11086
11096
  defaultValue: manifest.defaultVariant ?? variantKeys[0],
@@ -14285,6 +14295,20 @@ function resolveFooterRootForeground(footer, palette, proseHoverCandidate) {
14285
14295
  }, palette, footerForegroundCandidates(footer, proseHoverCandidate), { compositeBase: "background" });
14286
14296
  }
14287
14297
  function resolveSurfaceForegroundStyles(value, context, options) {
14298
+ const resolved = cachedSectionSurface(value, context, options);
14299
+ const foreground = resolved.foreground;
14300
+ if (foreground.kind === "unknown") return { ...resolved.buttonStyles };
14301
+ return {
14302
+ ...arrangementSurfaceInk(foreground, context),
14303
+ ...resolved.buttonStyles,
14304
+ ...surfaceForegroundStyle(surfaceForegroundInputFromResolved(foreground, (token) => resolveBackgroundColorValue(token, context)))
14305
+ };
14306
+ }
14307
+ /** The section ground's resolved foreground, for decorations drawn on that ground (maps). */
14308
+ function resolveSectionSurfaceForeground(value, context, options) {
14309
+ return cachedSectionSurface(value, context, options).foreground;
14310
+ }
14311
+ function cachedSectionSurface(value, context, options) {
14288
14312
  const key = JSON.stringify([
14289
14313
  value,
14290
14314
  context.proseHoverCandidate,
@@ -14295,13 +14319,7 @@ function resolveSurfaceForegroundStyles(value, context, options) {
14295
14319
  if (!sectionSurfaceCache.has(context.theme)) sectionSurfaceCache.set(context.theme, cache);
14296
14320
  const resolved = cache.get(key) ?? resolveRuntimeSectionSurface(value, context, options);
14297
14321
  cache.set(key, resolved);
14298
- const foreground = resolved.foreground;
14299
- if (foreground.kind === "unknown") return { ...resolved.buttonStyles };
14300
- return {
14301
- ...arrangementSurfaceInk(foreground, context),
14302
- ...resolved.buttonStyles,
14303
- ...surfaceForegroundStyle(surfaceForegroundInputFromResolved(foreground, (token) => resolveBackgroundColorValue(token, context)))
14304
- };
14322
+ return resolved;
14305
14323
  }
14306
14324
  /** Cache only the owner's result; no foreground or button rules live here. */
14307
14325
  function resolveRuntimeSectionSurface(value, context, options) {
@@ -15835,7 +15853,7 @@ const heroCopyFragment = defineFragment({
15835
15853
  {
15836
15854
  id: "eyebrow",
15837
15855
  type: "text",
15838
- label: "Eyebrow",
15856
+ label: "Small heading above the title",
15839
15857
  description: "Optional short line above the headline",
15840
15858
  visibleRoles: ["designer", "admin"]
15841
15859
  },
@@ -16035,7 +16053,7 @@ function createButtonGroup(options = {}) {
16035
16053
  //#endregion
16036
16054
  //#region ../blocks/src/system/fields/ctas.ts
16037
16055
  function createCtasRepeater(options = {}) {
16038
- const { id = "ctas", label = "Calls to action", itemLabel = "CTA", minItems = 0, maxItems, button: button$1, defaultValue } = options;
16056
+ const { id = "ctas", label = "Buttons", itemLabel = "Button", minItems = 0, maxItems, button: button$1, defaultValue } = options;
16039
16057
  const fieldId = id;
16040
16058
  const buttonField = createButtonGroup({
16041
16059
  showGroupLabel: false,
@@ -16065,8 +16083,8 @@ const ctaRowFragment = defineFragment({
16065
16083
  title: "CTA Row",
16066
16084
  description: "Repeatable calls to action rendered inline.",
16067
16085
  fields: [createCtasRepeater({
16068
- label: "Calls to action",
16069
- itemLabel: "CTA",
16086
+ label: "Buttons",
16087
+ itemLabel: "Button",
16070
16088
  maxItems: 3
16071
16089
  })],
16072
16090
  layout: [ctaRow({
@@ -16080,8 +16098,8 @@ const ctaRowFragment = defineFragment({
16080
16098
  //#endregion
16081
16099
  //#region ../blocks/src/system/fragments/library/heroCtaRow.ts
16082
16100
  const heroCtaFields = [createCtasRepeater({
16083
- label: "Calls to action",
16084
- itemLabel: "CTA",
16101
+ label: "Buttons",
16102
+ itemLabel: "Button",
16085
16103
  maxItems: 3,
16086
16104
  defaultValue: [],
16087
16105
  button: {
@@ -16149,7 +16167,7 @@ const ctaCopyFragment = defineFragment({
16149
16167
  {
16150
16168
  id: "eyebrow",
16151
16169
  type: "text",
16152
- label: "Eyebrow",
16170
+ label: "Small heading above the title",
16153
16171
  description: "Optional short line above the title",
16154
16172
  visibleRoles: ["designer", "admin"]
16155
16173
  },
@@ -17028,7 +17046,7 @@ const faqHeadingFragment = defineFragment({
17028
17046
  {
17029
17047
  id: "eyebrow",
17030
17048
  type: "text",
17031
- label: "Eyebrow",
17049
+ label: "Small heading above the title",
17032
17050
  description: "Short label displayed above the title.",
17033
17051
  visibleRoles: ["designer", "admin"],
17034
17052
  maxLength: 60
@@ -18454,6 +18472,7 @@ function createBlockManifest(config$1) {
18454
18472
  icon: config$1.icon ?? "Box",
18455
18473
  layout,
18456
18474
  variants,
18475
+ arrangementOwnedFieldIds: config$1.arrangementOwnedFieldIds,
18457
18476
  variantMeaning: config$1.variantMeaning,
18458
18477
  defaultVariant: config$1.defaultVariant,
18459
18478
  variantOptions: config$1.variantOptions,
@@ -18532,7 +18551,12 @@ const lookSticker = text({
18532
18551
  as: "p",
18533
18552
  ...lookSlot("sticker")
18534
18553
  }, when("content._effectiveKnobs.stickerLine.value"), bind("content.stickerLine"));
18535
- const heroContentNodes = [lookCaption, ...heroCopyAndCta.layout];
18554
+ const heroActionsNote = richText({ className: "hero-actions-note" }, when("content.actionsNote"), bind("content.actionsNote"));
18555
+ const heroContentNodes = [
18556
+ lookCaption,
18557
+ ...heroCopyAndCta.layout,
18558
+ heroActionsNote
18559
+ ];
18536
18560
  function heroContentCard(children, gap, copyAtCard) {
18537
18561
  return styledContainer({
18538
18562
  bindFrom: "_contentCardStyles",
@@ -18661,7 +18685,8 @@ const headlineRowLayout = heroLookLayout([
18661
18685
  el("div", lookSlot("copy"), [
18662
18686
  lookCaption,
18663
18687
  ...heroCopyFragment.layout.slice(2),
18664
- ...heroCtaRowFragment.layout
18688
+ ...heroCtaRowFragment.layout,
18689
+ heroActionsNote
18665
18690
  ]),
18666
18691
  lookPhoto
18667
18692
  ]);
@@ -18748,6 +18773,17 @@ const heroConfig = {
18748
18773
  hidden: true
18749
18774
  }
18750
18775
  },
18776
+ {
18777
+ id: "actionsNote",
18778
+ type: "richText",
18779
+ label: "Line in place of the buttons",
18780
+ required: false,
18781
+ ui: {
18782
+ intent: "display",
18783
+ hidden: true,
18784
+ richTextVariant: "limited"
18785
+ }
18786
+ },
18751
18787
  createImageShapeField({
18752
18788
  id: "imageShape",
18753
18789
  label: "Image shape",
@@ -18778,6 +18814,11 @@ const heroConfig = {
18778
18814
  ]
18779
18815
  },
18780
18816
  defaultVariant: "classic",
18817
+ variantOptions: {
18818
+ micro: { label: "Compact" },
18819
+ split: { label: "Split, photo on the left" },
18820
+ splitReverse: { label: "Split, photo on the right" }
18821
+ },
18781
18822
  description: "A big opening headline, with a short line underneath and buttons.",
18782
18823
  tags: [
18783
18824
  "header",
@@ -19226,8 +19267,8 @@ const introConfig = {
19226
19267
  }
19227
19268
  }),
19228
19269
  createCtasRepeater({
19229
- label: "Calls to action",
19230
- itemLabel: "CTA",
19270
+ label: "Buttons",
19271
+ itemLabel: "Button",
19231
19272
  maxItems: 2
19232
19273
  })
19233
19274
  ],
@@ -19952,6 +19993,17 @@ function resolvedItemSurfaceProps(surface, slot, style = undefined) {
19952
19993
  }
19953
19994
  };
19954
19995
  }
19996
+ const resolvedSurfaceSchema = z.unknown().transform((value, context) => {
19997
+ try {
19998
+ return parseResolvedSurface(value);
19999
+ } catch {
20000
+ context.addIssue({
20001
+ code: "custom",
20002
+ message: "Invalid surface inputs"
20003
+ });
20004
+ return z.NEVER;
20005
+ }
20006
+ });
19955
20007
  const lookListPresentationSchemaShape = {
19956
20008
  sectionAction: z.object({
19957
20009
  label: z.string(),
@@ -19995,10 +20047,10 @@ const lookListPresentationSchemaShape = {
19995
20047
  "card",
19996
20048
  "statement",
19997
20049
  "highlight"
19998
- ]), z.custom((value) => isPlainObject$5(value) && (value.kind === "inherit" || value.kind === "owned"))).optional(),
20050
+ ]), resolvedSurfaceSchema).optional(),
19999
20051
  panelHeading: z.string().optional(),
20000
20052
  lookSlots: z.partialRecord(z.enum(arrangementSlotNames), z.enum(arrangementSlotNames)).optional(),
20001
- itemSurfaces: z.record(z.string(), z.custom((value) => isPlainObject$5(value) && (value.kind === "inherit" || value.kind === "owned"))).optional()
20053
+ itemSurfaces: z.record(z.string(), resolvedSurfaceSchema).optional()
20002
20054
  };
20003
20055
  function listLookSlot(presentation, slot) {
20004
20056
  const name = presentation.lookSlots?.[slot];
@@ -21606,7 +21658,7 @@ function planSiteChromePlacement(positioning) {
21606
21658
  headerRootClassName: "rb-fixed rb-top-0 rb-left-0 rb-right-0",
21607
21659
  standaloneShellClassName: "fixed left-0 right-0 top-0 z-40 w-full"
21608
21660
  };
21609
- default: return assertNever$11(positioning);
21661
+ default: return assertNever$10(positioning);
21610
21662
  }
21611
21663
  }
21612
21664
  function splitSiteChromePlacementClasses(className) {
@@ -22185,6 +22237,100 @@ function readRuntimeNow(value) {
22185
22237
  return parsed.value;
22186
22238
  }
22187
22239
 
22240
+ //#endregion
22241
+ //#region ../blocks/src/system/blocks/shared/teamMembers.ts
22242
+ const teamMemberSpecialtiesInputSchema = z.union([z.string(), z.array(z.string())]).nullish();
22243
+ function parseTeamMemberSpecialties(value) {
22244
+ const parsed = teamMemberSpecialtiesInputSchema.safeParse(value);
22245
+ if (!parsed.success) return [];
22246
+ const parts = typeof parsed.data === "string" ? parsed.data.split(/\r?\n|,/) : parsed.data ?? [];
22247
+ return [...new Set(parts.map((part) => part.trim()).filter(Boolean))];
22248
+ }
22249
+ const biographyTextSchema = z.string().transform((text$1) => text$1.split(/\r?\n\s*\r?\n/).map((paragraph) => paragraph.trim()).filter(Boolean));
22250
+ const biographySourceSchema = z.union([RichTextDocSchema, biographyTextSchema]).nullish().catch(null);
22251
+ const teamMemberBiographySchema = z.object({
22252
+ profileBio: biographySourceSchema,
22253
+ bio: biographySourceSchema,
22254
+ summary: biographySourceSchema
22255
+ });
22256
+ /**
22257
+ * The bio a section about one person shows, or null when they have none: the
22258
+ * bio from their profile when it says anything, else their short bio. A page
22259
+ * deciding whether someone has a bio and the block showing it both read this,
22260
+ * so a section is never promised words that aren't there.
22261
+ */
22262
+ function teamMemberBiography(member) {
22263
+ return firstBiography(member, [
22264
+ "profileBio",
22265
+ "bio",
22266
+ "summary"
22267
+ ]);
22268
+ }
22269
+ /**
22270
+ * The bio a compact card shows when a page asks for whichever bio the person
22271
+ * has: their short bio first, then their summary, and their profile bio only
22272
+ * when neither says anything.
22273
+ */
22274
+ function teamMemberCardBiography(member) {
22275
+ return firstBiography(member, [
22276
+ "bio",
22277
+ "summary",
22278
+ "profileBio"
22279
+ ]);
22280
+ }
22281
+ /**
22282
+ * What an older grid or stack card adds under its short bio slot: the card
22283
+ * bio, unless the short bio is already a rich-text document that slot shows.
22284
+ * That slot only renders documents, so a staff member's plain-text short bio
22285
+ * comes through here too, and the two never show together.
22286
+ */
22287
+ function teamMemberCardBiographyFallback(member) {
22288
+ const shortBio = firstBiography(member, ["bio"]);
22289
+ if (shortBio?.kind === "document") return null;
22290
+ const biography = teamMemberCardBiography(member);
22291
+ return biography ? teamMemberBiographyDocument(biography) : null;
22292
+ }
22293
+ /** A bio as one rich-text document, each plain paragraph its own paragraph. */
22294
+ function teamMemberBiographyDocument(biography) {
22295
+ if (biography.kind === "document") return biography.document;
22296
+ return {
22297
+ type: "doc",
22298
+ content: biography.paragraphs.map((text$1) => ({
22299
+ type: "paragraph",
22300
+ content: [{
22301
+ type: "text",
22302
+ text: text$1
22303
+ }]
22304
+ }))
22305
+ };
22306
+ }
22307
+ function firstBiography(member, order) {
22308
+ const parsed = teamMemberBiographySchema.safeParse(member);
22309
+ if (!parsed.success) return null;
22310
+ return order.map((key) => toBiography(parsed.data[key])).find((biography) => biography !== null) ?? null;
22311
+ }
22312
+ function toBiography(source) {
22313
+ if (source === null || source === undefined) return null;
22314
+ if (Array.isArray(source)) return source.length > 0 ? {
22315
+ kind: "text",
22316
+ paragraphs: source
22317
+ } : null;
22318
+ const document$1 = source;
22319
+ return hasText$1(document$1) ? {
22320
+ kind: "document",
22321
+ document: document$1
22322
+ } : null;
22323
+ }
22324
+ const textNodeSchema = z.object({
22325
+ text: z.string().optional(),
22326
+ content: z.array(z.unknown()).optional()
22327
+ });
22328
+ function hasText$1(node) {
22329
+ const parsed = textNodeSchema.safeParse(node);
22330
+ if (!parsed.success) return false;
22331
+ return (parsed.data.text?.trim().length ?? 0) > 0 || (parsed.data.content ?? []).some(hasText$1);
22332
+ }
22333
+
22188
22334
  //#endregion
22189
22335
  //#region ../blocks/src/system/transforms/registry/content.ts
22190
22336
  const supportedRichTextTokenSchema = z.enum(["year", "site_name"]);
@@ -22266,7 +22412,14 @@ const interpolateRichTextTokensTransform = {
22266
22412
  schema: interpolateRichTextTokensOptionsSchema,
22267
22413
  run: (value, options, context) => interpolateRichTextTokens(value, options, context)
22268
22414
  };
22269
- const contentTransforms = [interpolateRichTextTokensTransform];
22415
+ /** An older team card's bio when it has no short bio; see teamMemberCardBiographyFallback. */
22416
+ const teamMemberCardBiographyFallbackTransform = {
22417
+ id: "teamMember.cardBiographyFallback",
22418
+ kind: "formatter",
22419
+ summary: "A team member's card bio when they have no short bio",
22420
+ run: (value) => teamMemberCardBiographyFallback(value)
22421
+ };
22422
+ const contentTransforms = [interpolateRichTextTokensTransform, teamMemberCardBiographyFallbackTransform];
22270
22423
 
22271
22424
  //#endregion
22272
22425
  //#region ../blocks/src/system/transforms/typed.ts
@@ -23214,6 +23367,7 @@ const dataLoaders = { ...entriesLoader ? { entries: {
23214
23367
  }
23215
23368
  } } : {} };
23216
23369
  const testimonialsManifest = createBlockManifest({
23370
+ arrangementOwnedFieldIds: ["maxEntries", "avatarLayout"],
23217
23371
  variantMeaning: {
23218
23372
  kind: "arrangement",
23219
23373
  lookOnlyKeys: [
@@ -23231,7 +23385,7 @@ const testimonialsManifest = createBlockManifest({
23231
23385
  },
23232
23386
  promotedFields: ["maxEntries"],
23233
23387
  title: "Testimonials",
23234
- category: "marketing",
23388
+ category: "people",
23235
23389
  contentSource: { kind: "inline" },
23236
23390
  includeContainerStyles: true,
23237
23391
  layout: carouselLayout$1,
@@ -24183,7 +24337,7 @@ const featureCardsConfig = {
24183
24337
  {
24184
24338
  id: "eyebrow",
24185
24339
  type: "text",
24186
- label: "Eyebrow",
24340
+ label: "Small heading above the title",
24187
24341
  required: false,
24188
24342
  multiline: false,
24189
24343
  maxLength: 80
@@ -24281,8 +24435,8 @@ const featureCardsConfig = {
24281
24435
  ui: { richTextVariant: "limited" }
24282
24436
  },
24283
24437
  createCtasRepeater({
24284
- label: "Calls to action",
24285
- itemLabel: "CTA",
24438
+ label: "Buttons",
24439
+ itemLabel: "Button",
24286
24440
  maxItems: 1,
24287
24441
  button: { defaultVariant: "ghost" }
24288
24442
  })
@@ -24623,7 +24777,7 @@ const textCardStylesField = (() => {
24623
24777
  const mediaTextManifest = createBlockManifest({
24624
24778
  id: "block.media-text",
24625
24779
  title: "Media and text",
24626
- category: "layout",
24780
+ category: "text-and-images",
24627
24781
  contentSource: { kind: "inline" },
24628
24782
  includeContainerStyles: true,
24629
24783
  titleSource: "title",
@@ -24661,7 +24815,7 @@ const mediaTextManifest = createBlockManifest({
24661
24815
  {
24662
24816
  id: "eyebrow",
24663
24817
  type: "text",
24664
- label: "Eyebrow",
24818
+ label: "Small heading above the title",
24665
24819
  description: "Optional short label above the title",
24666
24820
  required: false,
24667
24821
  multiline: false,
@@ -25561,6 +25715,7 @@ const publicEventDestinationSchema = z.discriminatedUnion("kind", [z.object({
25561
25715
  * Zod schema for venue data
25562
25716
  */
25563
25717
  const eventVenueSchema = z.object({
25718
+ drawing: z.lazy(() => mapDrawingSchema).optional().catch(undefined),
25564
25719
  id: z.string(),
25565
25720
  name: z.string(),
25566
25721
  address: z.string().nullable(),
@@ -25570,6 +25725,14 @@ const eventVenueSchema = z.object({
25570
25725
  }).nullable()
25571
25726
  });
25572
25727
  /**
25728
+ * The map for an event details page: one drawing, for the venue of the event the page is about.
25729
+ * It travels beside the events rather than on any of them, so a list of events has no place for one.
25730
+ */
25731
+ const eventVenueDrawingSchema = z.object({
25732
+ venueId: z.string(),
25733
+ drawing: z.lazy(() => mapDrawingSchema)
25734
+ });
25735
+ /**
25573
25736
  * Zod schema for event category data
25574
25737
  */
25575
25738
  const eventCategorySchema = z.object({
@@ -26047,6 +26210,53 @@ function normalizeEventStaffMemberId(value) {
26047
26210
  return trimmed ? trimmed : null;
26048
26211
  }
26049
26212
 
26213
+ //#endregion
26214
+ //#region ../blocks/src/system/blocks/events/shared/detailsSelection.ts
26215
+ function isFutureOrNow(iso, nowIso) {
26216
+ const ts = Date.parse(iso);
26217
+ const now = Date.parse(nowIso);
26218
+ if (!Number.isFinite(ts) || !Number.isFinite(now)) return false;
26219
+ return ts >= now;
26220
+ }
26221
+ const localDateKey = (startsAt, timeZone) => getBookingLocalDateKey(toScheduledBookingDateTime({
26222
+ startsAt,
26223
+ timeZone
26224
+ }));
26225
+ function selectRequested(events, requested) {
26226
+ if (!requested) return null;
26227
+ const byId = events.find((event) => event.occurrenceId === requested.id || event.id === requested.id);
26228
+ if (byId) return byId;
26229
+ if (!requested.startsAt || !requested.timeZone) return null;
26230
+ const requestedDate = localDateKey(requested.startsAt, requested.timeZone);
26231
+ return events.find((event) => localDateKey(event.startsAt, event.timeZone) === requestedDate) ?? null;
26232
+ }
26233
+ function selectNextUpcoming(events, nowIso) {
26234
+ return [...events].filter((event) => isFutureOrNow(event.startsAt, nowIso)).sort((left, right) => Date.parse(left.startsAt) - Date.parse(right.startsAt))[0] ?? null;
26235
+ }
26236
+ function selectCompletedWholeSeries(events) {
26237
+ if (events.length === 0 || !events.every((event) => event.bookingScope === "whole_series")) {
26238
+ return null;
26239
+ }
26240
+ return [...events].sort((left, right) => Date.parse(right.startsAt) - Date.parse(left.startsAt))[0] ?? null;
26241
+ }
26242
+ function selectEventDetailsCandidate(events, requested, nowIso) {
26243
+ const selected = selectRequested(events, requested);
26244
+ if (selected) return {
26245
+ event: selected,
26246
+ mode: "selected"
26247
+ };
26248
+ const upcoming = selectNextUpcoming(events, nowIso);
26249
+ if (upcoming) return {
26250
+ event: upcoming,
26251
+ mode: "next"
26252
+ };
26253
+ const completed = selectCompletedWholeSeries(events);
26254
+ return completed ? {
26255
+ event: completed,
26256
+ mode: "completed"
26257
+ } : null;
26258
+ }
26259
+
26050
26260
  //#endregion
26051
26261
  //#region ../blocks/src/system/blocks/shop.shared.ts
26052
26262
  /**
@@ -30458,7 +30668,7 @@ function MembershipHero({ membershipName, classPrefix, onBookForSomeoneElse }) {
30458
30668
  * LICENSE file in the root directory of this source tree.
30459
30669
  */
30460
30670
  var require_react_dom_production = /* @__PURE__ */ __commonJSMin(((exports) => {
30461
- var React$79 = require_react();
30671
+ var React$81 = require_react();
30462
30672
  function formatProdErrorMessage(code) {
30463
30673
  var url = "https://react.dev/errors/" + code;
30464
30674
  if (1 < arguments.length) {
@@ -30495,7 +30705,7 @@ var require_react_dom_production = /* @__PURE__ */ __commonJSMin(((exports) => {
30495
30705
  implementation
30496
30706
  };
30497
30707
  }
30498
- var ReactSharedInternals = React$79.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;
30708
+ var ReactSharedInternals = React$81.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;
30499
30709
  function getCrossOriginStringAs(as, input) {
30500
30710
  if ("font" === as) return "";
30501
30711
  if ("string" === typeof input) return "use-credentials" === input ? input : "";
@@ -30638,7 +30848,7 @@ var require_react_dom_development = /* @__PURE__ */ __commonJSMin(((exports) =>
30638
30848
  return dispatcher;
30639
30849
  }
30640
30850
  "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(Error());
30641
- var React$88 = require_react(), Internals$1 = {
30851
+ var React$90 = require_react(), Internals$1 = {
30642
30852
  d: {
30643
30853
  f: noop$2,
30644
30854
  r: function() {
@@ -30654,7 +30864,7 @@ var require_react_dom_development = /* @__PURE__ */ __commonJSMin(((exports) =>
30654
30864
  },
30655
30865
  p: 0,
30656
30866
  findDOMNode: null
30657
- }, REACT_PORTAL_TYPE$1 = Symbol.for("react.portal"), ReactSharedInternals$1 = React$88.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;
30867
+ }, REACT_PORTAL_TYPE$1 = Symbol.for("react.portal"), ReactSharedInternals$1 = React$90.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;
30658
30868
  "function" === typeof Map && null != Map.prototype && "function" === typeof Map.prototype.forEach && "function" === typeof Set && null != Set.prototype && "function" === typeof Set.prototype.clear && "function" === typeof Set.prototype.forEach || console.error("React depends on Map and Set built-in types. Make sure that you load a polyfill in older browsers. https://reactjs.org/link/react-polyfills");
30659
30869
  exports.__DOM_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE = Internals$1;
30660
30870
  exports.createPortal = function(children, container) {
@@ -31707,20 +31917,20 @@ const FIELD_LABELS = {
31707
31917
  description: "Short, concrete examples you can refer back to when writing new copy."
31708
31918
  }
31709
31919
  };
31710
- const IDLE_FEEDBACK$2 = idleFeedback$3();
31711
- function idleFeedback$3() {
31920
+ const IDLE_FEEDBACK$2 = idleFeedback$2();
31921
+ function idleFeedback$2() {
31712
31922
  return { tag: "idle" };
31713
31923
  }
31714
31924
  function pendingFeedback$1() {
31715
31925
  return { tag: "pending" };
31716
31926
  }
31717
- function errorFeedback$3(message) {
31927
+ function errorFeedback$2(message) {
31718
31928
  return {
31719
31929
  tag: "error",
31720
31930
  message
31721
31931
  };
31722
31932
  }
31723
- function assertNever$10(value) {
31933
+ function assertNever$9(value) {
31724
31934
  throw new Error(`Unexpected value: ${String(value)}`);
31725
31935
  }
31726
31936
  function createAiBrandGuidelinesGenerationDialogState(sessionId, open$1) {
@@ -31760,7 +31970,7 @@ function aiBrandGuidelinesGenerationDialogReducer(state, action) {
31760
31970
  case "context-load-failed": return {
31761
31971
  ...state,
31762
31972
  context: null,
31763
- contextFeedback: errorFeedback$3(action.message)
31973
+ contextFeedback: errorFeedback$2(action.message)
31764
31974
  };
31765
31975
  case "use-site-content-changed": return state.useSiteContent === action.value ? state : {
31766
31976
  ...state,
@@ -31806,13 +32016,13 @@ function aiBrandGuidelinesGenerationDialogReducer(state, action) {
31806
32016
  if (!state.open || state.sessionId !== action.sessionId) return state;
31807
32017
  return {
31808
32018
  ...state,
31809
- generateFeedback: errorFeedback$3(action.message)
32019
+ generateFeedback: errorFeedback$2(action.message)
31810
32020
  };
31811
32021
  case "current-proposal-accepted":
31812
32022
  if (state.proposal === null) return state;
31813
32023
  return advanceWizardField(state, mergeLockedSettings(state.lockedSettings, state.proposal));
31814
32024
  case "current-proposal-skipped": return advanceWizardField(state, state.lockedSettings);
31815
- default: return assertNever$10(action);
32025
+ default: return assertNever$9(action);
31816
32026
  }
31817
32027
  }
31818
32028
  function advanceWizardField(state, nextLockedSettings) {
@@ -31894,8 +32104,8 @@ function mergeLockedSettings(lockedSettings, proposal) {
31894
32104
  ...proposal
31895
32105
  };
31896
32106
  }
31897
- const idleFeedback$2 = () => ({ tag: "idle" });
31898
- const errorFeedback$2 = (message) => ({
32107
+ const idleFeedback$1 = () => ({ tag: "idle" });
32108
+ const errorFeedback$1 = (message) => ({
31899
32109
  tag: "error",
31900
32110
  message
31901
32111
  });
@@ -31913,14 +32123,14 @@ const err$1 = (error$1) => ({
31913
32123
  error: error$1
31914
32124
  });
31915
32125
  function resetDialogFeedback(feedback) {
31916
- return feedback.tag === "idle" ? feedback : idleFeedback$2();
32126
+ return feedback.tag === "idle" ? feedback : idleFeedback$1();
31917
32127
  }
31918
32128
  function createDialogState(dialog) {
31919
32129
  switch (dialog.kind) {
31920
32130
  case "create-preview": return {
31921
32131
  tag: "create-preview",
31922
32132
  draft: { name: "" },
31923
- feedback: idleFeedback$2()
32133
+ feedback: idleFeedback$1()
31924
32134
  };
31925
32135
  case "create-content": return {
31926
32136
  tag: "create-content",
@@ -31928,19 +32138,19 @@ function createDialogState(dialog) {
31928
32138
  name: "",
31929
32139
  environment: "live"
31930
32140
  },
31931
- feedback: idleFeedback$2()
32141
+ feedback: idleFeedback$1()
31932
32142
  };
31933
32143
  case "create-management": return {
31934
32144
  tag: "create-management",
31935
32145
  draft: { name: "" },
31936
- feedback: idleFeedback$2()
32146
+ feedback: idleFeedback$1()
31937
32147
  };
31938
32148
  case "confirm-operation": return {
31939
32149
  tag: "confirm-operation",
31940
32150
  operation: dialog.operation,
31941
- feedback: idleFeedback$2()
32151
+ feedback: idleFeedback$1()
31942
32152
  };
31943
- default: return assertNever$9(dialog);
32153
+ default: return assertNever$8(dialog);
31944
32154
  }
31945
32155
  }
31946
32156
  function getOperationKeyType(operation) {
@@ -31951,7 +32161,7 @@ function getOperationKeyType(operation) {
31951
32161
  case "revoke-content": return "content";
31952
32162
  case "create-management":
31953
32163
  case "revoke-management": return "management";
31954
- default: return assertNever$9(operation);
32164
+ default: return assertNever$8(operation);
31955
32165
  }
31956
32166
  }
31957
32167
  function getRefreshToken(refresh$1, keyType) {
@@ -31959,7 +32169,7 @@ function getRefreshToken(refresh$1, keyType) {
31959
32169
  case "preview": return refresh$1.preview;
31960
32170
  case "content": return refresh$1.content;
31961
32171
  case "management": return refresh$1.management;
31962
- default: return assertNever$9(keyType);
32172
+ default: return assertNever$8(keyType);
31963
32173
  }
31964
32174
  }
31965
32175
  function isSameOperation(left, right) {
@@ -31971,7 +32181,7 @@ function isSameOperation(left, right) {
31971
32181
  case "revoke-preview":
31972
32182
  case "revoke-content":
31973
32183
  case "revoke-management": return "keyId" in right && left.keyId === right.keyId;
31974
- default: return assertNever$9(left);
32184
+ default: return assertNever$8(left);
31975
32185
  }
31976
32186
  }
31977
32187
  function matchesDialogOperation(dialog, operation) {
@@ -31982,7 +32192,7 @@ function matchesDialogOperation(dialog, operation) {
31982
32192
  case "confirm-operation": return isSameOperation(dialog.operation, operation);
31983
32193
  case "closed":
31984
32194
  case "show-new-key": return false;
31985
- default: return assertNever$9(dialog);
32195
+ default: return assertNever$8(dialog);
31986
32196
  }
31987
32197
  }
31988
32198
  function isFeedbackDialog(dialog) {
@@ -32038,7 +32248,7 @@ function reduceRefreshState(refresh$1, action) {
32038
32248
  ...refresh$1,
32039
32249
  management: action.refreshToken
32040
32250
  };
32041
- default: return assertNever$9(keyType);
32251
+ default: return assertNever$8(keyType);
32042
32252
  }
32043
32253
  }
32044
32254
  function reduceCommandState(command, action) {
@@ -32061,7 +32271,7 @@ function reduceCommandState(command, action) {
32061
32271
  case "preview-draft-invalid":
32062
32272
  case "data-refreshed":
32063
32273
  case "refresh-warning-reported": return command;
32064
- default: return assertNever$9(action);
32274
+ default: return assertNever$8(action);
32065
32275
  }
32066
32276
  }
32067
32277
  function reduceDialogState(dialog, action) {
@@ -32094,19 +32304,19 @@ function reduceDialogState(dialog, action) {
32094
32304
  } : dialog;
32095
32305
  case "preview-draft-invalid": return dialog.tag === "create-preview" ? {
32096
32306
  ...dialog,
32097
- feedback: errorFeedback$2(action.message)
32307
+ feedback: errorFeedback$1(action.message)
32098
32308
  } : dialog;
32099
32309
  case "content-draft-invalid": return dialog.tag === "create-content" ? {
32100
32310
  ...dialog,
32101
- feedback: errorFeedback$2(action.message)
32311
+ feedback: errorFeedback$1(action.message)
32102
32312
  } : dialog;
32103
32313
  case "command-started": return matchesDialogOperation(dialog, action.operation) && isFeedbackDialog(dialog) ? {
32104
32314
  ...dialog,
32105
- feedback: idleFeedback$2()
32315
+ feedback: idleFeedback$1()
32106
32316
  } : dialog;
32107
32317
  case "command-failed": return matchesDialogOperation(dialog, action.operation) && isFeedbackDialog(dialog) ? {
32108
32318
  ...dialog,
32109
- feedback: errorFeedback$2(action.message)
32319
+ feedback: errorFeedback$1(action.message)
32110
32320
  } : dialog;
32111
32321
  case "new-key-received": return {
32112
32322
  tag: "show-new-key",
@@ -32118,7 +32328,7 @@ function reduceDialogState(dialog, action) {
32118
32328
  case "page-feedback-reported":
32119
32329
  case "data-refreshed":
32120
32330
  case "refresh-warning-reported": return dialog;
32121
- default: return assertNever$9(action);
32331
+ default: return assertNever$8(action);
32122
32332
  }
32123
32333
  }
32124
32334
  function reduceDataState(data, action) {
@@ -32136,7 +32346,7 @@ function reduceDataState(data, action) {
32136
32346
  ...data,
32137
32347
  managementKeys: action.managementKeys
32138
32348
  };
32139
- default: return assertNever$9(action);
32349
+ default: return assertNever$8(action);
32140
32350
  }
32141
32351
  case "key-revoked": switch (action.operation.kind) {
32142
32352
  case "revoke-preview": return {
@@ -32151,7 +32361,7 @@ function reduceDataState(data, action) {
32151
32361
  ...data,
32152
32362
  managementKeys: data.managementKeys.filter((key) => key.id !== action.operation.keyId)
32153
32363
  };
32154
- default: return assertNever$9(action.operation);
32364
+ default: return assertNever$8(action.operation);
32155
32365
  }
32156
32366
  case "dialog-opened":
32157
32367
  case "dialog-closed":
@@ -32166,7 +32376,7 @@ function reduceDataState(data, action) {
32166
32376
  case "command-failed":
32167
32377
  case "new-key-received":
32168
32378
  case "refresh-warning-reported": return data;
32169
- default: return assertNever$9(action);
32379
+ default: return assertNever$8(action);
32170
32380
  }
32171
32381
  }
32172
32382
  function reducePageFeedback(pageFeedback, action) {
@@ -32189,7 +32399,7 @@ function reducePageFeedback(pageFeedback, action) {
32189
32399
  case "preview-draft-invalid":
32190
32400
  case "data-refreshed":
32191
32401
  case "command-failed": return pageFeedback;
32192
- default: return assertNever$9(action);
32402
+ default: return assertNever$8(action);
32193
32403
  }
32194
32404
  }
32195
32405
  function isBlockedWhilePending(action) {
@@ -32217,7 +32427,7 @@ function apiKeysSettingsReducer(state, action) {
32217
32427
  function isApiKeysCommandPending(command, operation) {
32218
32428
  return isPendingCommand(command, operation);
32219
32429
  }
32220
- function assertNever$9(value, message) {
32430
+ function assertNever$8(value, message) {
32221
32431
  throw new Error(message ?? `Unexpected value: ${String(value)}`);
32222
32432
  }
32223
32433
  function selectApiKeysSubmitting(state) {
@@ -32318,300 +32528,6 @@ function toggleAsset(selected, asset) {
32318
32528
  function selectAllAssets(assets) {
32319
32529
  return [...assets];
32320
32530
  }
32321
- const EMPTY_FIELD_ERRORS = [];
32322
- const EMPTY_COUNT_ENTRIES = [];
32323
- const IMPORT_COUNT_ENTRIES_CACHE = /* @__PURE__ */ new WeakMap();
32324
- const ZERO_SUMMARY = {
32325
- totalUpdated: 0,
32326
- totalFailed: 0
32327
- };
32328
- function parseBackupMembershipMode(value) {
32329
- switch (value) {
32330
- case "skip":
32331
- case "invite":
32332
- case "preview": return value;
32333
- default: throw new Error(`Unexpected membership mode: ${value}`);
32334
- }
32335
- }
32336
- function parseBackupApiKeyMode(value) {
32337
- switch (value) {
32338
- case "skip":
32339
- case "regenerate":
32340
- case "preview": return value;
32341
- default: throw new Error(`Unexpected API key mode: ${value}`);
32342
- }
32343
- }
32344
- function buildBackupImportCountEntries(result) {
32345
- if (result?.counts === void 0 || result.counts === null) return EMPTY_COUNT_ENTRIES;
32346
- const cachedEntries = IMPORT_COUNT_ENTRIES_CACHE.get(result);
32347
- if (cachedEntries !== void 0) return cachedEntries;
32348
- const entries = Object.entries(result.counts).map(([table, counts]) => ({
32349
- table,
32350
- counts
32351
- }));
32352
- IMPORT_COUNT_ENTRIES_CACHE.set(result, entries);
32353
- return entries;
32354
- }
32355
- function deriveBackupImportSummary(entries) {
32356
- if (entries.length === 0) return ZERO_SUMMARY;
32357
- return entries.reduce((sum, entry) => ({
32358
- totalUpdated: sum.totalUpdated + entry.counts.updated,
32359
- totalFailed: sum.totalFailed + entry.counts.failed
32360
- }), ZERO_SUMMARY);
32361
- }
32362
- function clearBackupImportOutcome(state) {
32363
- return {
32364
- ...state,
32365
- phase: "idle",
32366
- fileError: null,
32367
- fieldErrors: null,
32368
- feedback: idleFeedback$1()
32369
- };
32370
- }
32371
- function backupImportOptionsReducer(state, action) {
32372
- switch (action.type) {
32373
- case "clean-import-changed": return state.cleanImport === action.value ? state : {
32374
- ...state,
32375
- cleanImport: action.value
32376
- };
32377
- case "dry-run-changed": return state.dryRun === action.value ? state : {
32378
- ...state,
32379
- dryRun: action.value
32380
- };
32381
- case "membership-mode-changed": return state.membershipMode === action.value ? state : {
32382
- ...state,
32383
- membershipMode: action.value
32384
- };
32385
- case "api-key-mode-changed": return state.apiKeyMode === action.value ? state : {
32386
- ...state,
32387
- apiKeyMode: action.value
32388
- };
32389
- case "send-emails-changed": return state.sendEmails === action.value ? state : {
32390
- ...state,
32391
- sendEmails: action.value
32392
- };
32393
- default: return assertNever$8(action);
32394
- }
32395
- }
32396
- function backupExportStateReducer(state, action) {
32397
- switch (action.type) {
32398
- case "include-media-changed": return state.includeMedia === action.value ? state : {
32399
- ...state,
32400
- includeMedia: action.value
32401
- };
32402
- case "include-access-changed": return state.includeAccess === action.value ? state : {
32403
- ...state,
32404
- includeAccess: action.value
32405
- };
32406
- case "export-started": return state.exporting ? state : {
32407
- ...state,
32408
- exporting: true
32409
- };
32410
- case "export-finished": return state.exporting ? {
32411
- ...state,
32412
- exporting: false
32413
- } : state;
32414
- default: return assertNever$8(action);
32415
- }
32416
- }
32417
- function backupImportStateReducer(state, action) {
32418
- switch (action.type) {
32419
- case "import-file-cleared": return {
32420
- ...clearBackupImportOutcome(state),
32421
- file: null
32422
- };
32423
- case "import-file-invalid": return {
32424
- ...clearBackupImportOutcome(state),
32425
- file: null,
32426
- fileError: action.message
32427
- };
32428
- case "import-file-selected": return {
32429
- ...clearBackupImportOutcome(state),
32430
- file: action.file
32431
- };
32432
- case "import-failed": return {
32433
- ...clearBackupImportOutcome(state),
32434
- feedback: errorFeedback$1(action.message)
32435
- };
32436
- case "import-validation-errors-received": return {
32437
- ...clearBackupImportOutcome(state),
32438
- fieldErrors: action.errors
32439
- };
32440
- case "import-succeeded": return {
32441
- ...clearBackupImportOutcome(state),
32442
- feedback: successFeedback$1(action.result)
32443
- };
32444
- case "clean-import-changed":
32445
- case "dry-run-changed":
32446
- case "membership-mode-changed":
32447
- case "api-key-mode-changed":
32448
- case "send-emails-changed": {
32449
- const options = backupImportOptionsReducer(state.options, action);
32450
- return options === state.options ? state : {
32451
- ...state,
32452
- options
32453
- };
32454
- }
32455
- case "clean-confirm-opened": return state.cleanConfirmOpen ? state : {
32456
- ...state,
32457
- cleanConfirmOpen: true
32458
- };
32459
- case "clean-confirm-closed": return state.cleanConfirmOpen ? {
32460
- ...state,
32461
- cleanConfirmOpen: false
32462
- } : state;
32463
- case "import-confirmed": return {
32464
- ...clearBackupImportOutcome(state),
32465
- phase: "uploading",
32466
- cleanConfirmOpen: false
32467
- };
32468
- case "api-import-started": return state.phase === "calling-api" ? state : {
32469
- ...state,
32470
- phase: "calling-api"
32471
- };
32472
- case "import-finished": return state.phase === "idle" ? state : {
32473
- ...state,
32474
- phase: "idle"
32475
- };
32476
- default: return assertNever$8(action);
32477
- }
32478
- }
32479
- function createInitialBackupClientState() {
32480
- return {
32481
- exportState: {
32482
- exporting: false,
32483
- includeMedia: true,
32484
- includeAccess: false
32485
- },
32486
- importState: {
32487
- phase: "idle",
32488
- file: null,
32489
- fileError: null,
32490
- fieldErrors: null,
32491
- feedback: idleFeedback$1(),
32492
- cleanConfirmOpen: false,
32493
- options: {
32494
- cleanImport: false,
32495
- dryRun: false,
32496
- membershipMode: "skip",
32497
- apiKeyMode: "skip",
32498
- sendEmails: true
32499
- }
32500
- }
32501
- };
32502
- }
32503
- function backupClientReducer(state, action) {
32504
- switch (action.type) {
32505
- case "include-media-changed":
32506
- case "include-access-changed":
32507
- case "export-started":
32508
- case "export-finished": {
32509
- const exportState = backupExportStateReducer(state.exportState, action);
32510
- return exportState === state.exportState ? state : {
32511
- ...state,
32512
- exportState
32513
- };
32514
- }
32515
- case "import-file-cleared":
32516
- case "import-file-invalid":
32517
- case "import-file-selected":
32518
- case "import-failed":
32519
- case "import-validation-errors-received":
32520
- case "import-succeeded":
32521
- case "clean-import-changed":
32522
- case "dry-run-changed":
32523
- case "membership-mode-changed":
32524
- case "api-key-mode-changed":
32525
- case "send-emails-changed":
32526
- case "clean-confirm-opened":
32527
- case "clean-confirm-closed":
32528
- case "import-confirmed":
32529
- case "api-import-started":
32530
- case "import-finished": {
32531
- const importState = backupImportStateReducer(state.importState, action);
32532
- return importState === state.importState ? state : {
32533
- ...state,
32534
- importState
32535
- };
32536
- }
32537
- default: return assertNever$8(action);
32538
- }
32539
- }
32540
- function selectBackupExporting(state) {
32541
- return state.exportState.exporting;
32542
- }
32543
- function selectBackupImporting(state) {
32544
- return state.importState.phase !== "idle";
32545
- }
32546
- function selectBackupCleanConfirmOpen(state) {
32547
- return state.importState.cleanConfirmOpen;
32548
- }
32549
- function selectBackupShouldConfirmCleanImport(state) {
32550
- return state.importState.file !== null && state.importState.options.cleanImport && !state.importState.options.dryRun;
32551
- }
32552
- function selectBackupIncludeMedia(state) {
32553
- return state.exportState.includeMedia;
32554
- }
32555
- function selectBackupIncludeAccess(state) {
32556
- return state.exportState.includeAccess;
32557
- }
32558
- function selectBackupImportFile(state) {
32559
- return state.importState.file;
32560
- }
32561
- function selectBackupImportFileError(state) {
32562
- return state.importState.fileError;
32563
- }
32564
- function selectBackupCleanImport(state) {
32565
- return state.importState.options.cleanImport;
32566
- }
32567
- function selectBackupDryRun(state) {
32568
- return state.importState.options.dryRun;
32569
- }
32570
- function selectBackupMembershipMode(state) {
32571
- return state.importState.options.membershipMode;
32572
- }
32573
- function selectBackupApiKeyMode(state) {
32574
- return state.importState.options.apiKeyMode;
32575
- }
32576
- function selectBackupSendEmails(state) {
32577
- return state.importState.options.sendEmails;
32578
- }
32579
- function selectBackupImportResult(state) {
32580
- return state.importState.feedback.tag === "success" ? state.importState.feedback.result : null;
32581
- }
32582
- function selectBackupImportAccess(state) {
32583
- return selectBackupImportResult(state)?.access;
32584
- }
32585
- function selectBackupImportErrorMessage(state) {
32586
- return state.importState.feedback.tag === "error" ? state.importState.feedback.message : null;
32587
- }
32588
- function selectBackupImportFieldErrors(state) {
32589
- return state.importState.fieldErrors ?? EMPTY_FIELD_ERRORS;
32590
- }
32591
- function selectBackupImportSummary(state) {
32592
- return deriveBackupImportSummary(selectBackupImportCountEntries(state));
32593
- }
32594
- function selectBackupImportCountEntries(state) {
32595
- return buildBackupImportCountEntries(selectBackupImportResult(state));
32596
- }
32597
- function assertNever$8(value, message) {
32598
- throw new Error(message ?? `Unexpected value: ${String(value)}`);
32599
- }
32600
- function idleFeedback$1() {
32601
- return { tag: "idle" };
32602
- }
32603
- function errorFeedback$1(message) {
32604
- return {
32605
- tag: "error",
32606
- message
32607
- };
32608
- }
32609
- function successFeedback$1(result) {
32610
- return {
32611
- tag: "success",
32612
- result
32613
- };
32614
- }
32615
32531
  const ADD_CUSTOM_DOMAIN_SUCCESS_MESSAGE = "Custom domain added successfully! Redirecting...";
32616
32532
  const IDLE_FEEDBACK$1 = { tag: "idle" };
32617
32533
  const SUCCESS_FEEDBACK = {
@@ -38623,66 +38539,92 @@ function transitionOrderRefundStatusTo(from, to) {
38623
38539
  const unfinishedBookingAssistanceMessage = "We couldn’t safely find your unfinished booking. Please contact the organiser before trying to book again.";
38624
38540
  const eventRegistrationErrors = {
38625
38541
  registrationClosed: {
38542
+ endsCommand: false,
38626
38543
  message: "Booking is currently closed for this event. Please contact the organiser if you’d like to find out more.",
38627
38544
  action: "none"
38628
38545
  },
38629
38546
  paymentInvestigationRequired: {
38547
+ endsCommand: false,
38630
38548
  message: "We still can’t confirm your payment. Please don’t make another payment. Contact the organiser so they can check your booking.",
38631
38549
  action: "none"
38632
38550
  },
38633
38551
  paymentProviderUnavailable: {
38552
+ endsCommand: false,
38634
38553
  message: "We couldn’t reach the payment provider. Please try again in a minute.",
38635
38554
  action: "retry"
38636
38555
  },
38637
38556
  paymentHostUnavailable: {
38557
+ endsCommand: false,
38638
38558
  message: "Card payments aren’t available on this web address yet. Please contact the organiser to book.",
38639
38559
  action: "none"
38640
38560
  },
38641
38561
  paymentPageUnavailable: {
38562
+ endsCommand: false,
38642
38563
  message: "We couldn’t open the payment page. Please refresh this page and try again. If this keeps happening, contact the organiser for help.",
38643
38564
  action: "retry"
38644
38565
  },
38645
38566
  paymentUnavailable: {
38567
+ endsCommand: false,
38646
38568
  message: "Online payment is not available for this event right now. Please contact the organiser for help with booking.",
38647
38569
  action: "none"
38648
38570
  },
38649
38571
  capacityChanged: {
38572
+ endsCommand: false,
38650
38573
  message: "Sorry, there aren’t enough places left for your selection. Please check the available places and choose again.",
38651
38574
  action: "places"
38652
38575
  },
38653
38576
  selectionChanged: {
38577
+ endsCommand: false,
38654
38578
  message: "The booking options for this event have changed. Please check the latest options and choose your places again.",
38655
38579
  action: "places"
38656
38580
  },
38581
+ paymentSetupFailed: {
38582
+ endsCommand: true,
38583
+ message: "We couldn't set up payment for this booking, so your place hasn't been reserved and you haven't been charged. Please try again in a few minutes, or contact the organiser if it keeps happening.",
38584
+ action: "retry"
38585
+ },
38586
+ registrationAttemptEnded: {
38587
+ endsCommand: true,
38588
+ message: "That booking attempt has ended, so we couldn't finish it. You haven't been charged. Please start your booking again.",
38589
+ action: "start"
38590
+ },
38657
38591
  registrationPreparationChanged: {
38592
+ endsCommand: true,
38658
38593
  message: "The booking options for this event have changed. Please check the latest options and choose your places again.",
38659
38594
  action: "places"
38660
38595
  },
38661
38596
  registrationAlreadyExists: {
38597
+ endsCommand: false,
38662
38598
  message: "You already have a booking for this event. Please check your bookings to see its status. If you need help, contact the organiser.",
38663
38599
  action: "portal"
38664
38600
  },
38665
38601
  holdExpired: {
38602
+ endsCommand: false,
38666
38603
  message: "Your reservation has timed out. Please check availability and choose your places again.",
38667
38604
  action: "start"
38668
38605
  },
38669
38606
  waitlistUnavailable: {
38607
+ endsCommand: false,
38670
38608
  message: "Sorry, the waiting list place offered in this invitation is no longer available. Please check the event for available places or contact the organiser for help.",
38671
38609
  action: "event"
38672
38610
  },
38673
38611
  paymentContextMismatch: {
38612
+ endsCommand: false,
38674
38613
  message: "The payment options for this event have changed. Please check the latest options before continuing.",
38675
38614
  action: "payment-options"
38676
38615
  },
38677
38616
  verificationFailed: {
38617
+ endsCommand: false,
38678
38618
  message: "We couldn’t confirm this request came from a person. Please refresh the page and try again.",
38679
38619
  action: "none"
38680
38620
  },
38681
38621
  idempotencyConflict: {
38622
+ endsCommand: false,
38682
38623
  message: "You’ve already started booking this event. Please finish in the other tab if it’s still open, or check your booking status before starting again.",
38683
38624
  action: "portal"
38684
38625
  },
38685
38626
  invalidCommitInput: {
38627
+ endsCommand: false,
38686
38628
  message: "We couldn’t accept your booking details. Please check the information you entered and try again. If this keeps happening, contact the organiser for help.",
38687
38629
  action: "details"
38688
38630
  }
@@ -38690,6 +38632,11 @@ const eventRegistrationErrors = {
38690
38632
  function parseEventRegistrationErrorReason(value) {
38691
38633
  return typeof value === "string" && Object.prototype.hasOwnProperty.call(eventRegistrationErrors, value) ? value : null;
38692
38634
  }
38635
+ /** Only a server-confirmed refusal ends an identity; transport uncertainty retains it. */
38636
+ function eventRegistrationErrorEndsCommand(value) {
38637
+ const reason = parseEventRegistrationErrorReason(value);
38638
+ return reason !== null && eventRegistrationErrors[reason].endsCommand;
38639
+ }
38693
38640
 
38694
38641
  //#endregion
38695
38642
  //#region ../commerce/src/purchase/eventCheckoutRecoveryWindow.ts
@@ -40884,15 +40831,6 @@ function resolveAutoCtaPath(source, routes) {
40884
40831
  }
40885
40832
  return routeByNormalizedPath.get("/offerings") ?? null;
40886
40833
  }
40887
- function resolveOfferingsPreviewRunPath(run, routes) {
40888
- const routeIds = [run.eventSeriesId, run.eventOfferingId];
40889
- for (const entityId of routeIds) {
40890
- const route = (routes ?? []).find((candidate) => candidate.entityId === entityId);
40891
- const path$3 = normalizeRoutePath(route?.path);
40892
- if (path$3) return path$3;
40893
- }
40894
- return null;
40895
- }
40896
40834
  function preferredPathsForSource(source) {
40897
40835
  switch (source.kind) {
40898
40836
  case "eventPreset": switch (source.preset) {
@@ -41160,6 +41098,11 @@ function resolveEventRegistrationScopedEvents(events, context) {
41160
41098
  //#endregion
41161
41099
  //#region ../blocks/src/system/constants/events.ts
41162
41100
  /**
41101
+ * Event-related constants
41102
+ *
41103
+ * Shared constants for event content types and booking system integration.
41104
+ */
41105
+ /**
41163
41106
  * Content type slugs that represent event content.
41164
41107
  * These are the standard slugs used when creating event content types in the CMS.
41165
41108
  *
@@ -41314,6 +41257,8 @@ function getPreviewContext(contentTypeKey) {
41314
41257
  /** The calendar manifest owns its secondary arrangement axis. */
41315
41258
  const eventCalendarVariantMeaning = {
41316
41259
  kind: "mode",
41260
+ modes: arrangementModes,
41261
+ defaultMode: "list",
41317
41262
  arrangementField: "listLayout",
41318
41263
  keys: eventCalendarListLayoutValues,
41319
41264
  lookOnlyKeys: [
@@ -41950,6 +41895,17 @@ const eventRegistrationBlockDefinition = {
41950
41895
  }
41951
41896
  };
41952
41897
 
41898
+ //#endregion
41899
+ //#region ../blocks/src/system/node/fragments/mapDrawingStyle.ts
41900
+ /** Shared map token binding for the current section ground and site style. */
41901
+ const mapDrawingStyleBinding = { $bind: {
41902
+ from: "content._sectionStyles.background",
41903
+ transforms: [{
41904
+ id: "mapDrawing.resolveStyle",
41905
+ options: { fallbackToken: "background" }
41906
+ }]
41907
+ } };
41908
+
41953
41909
  //#endregion
41954
41910
  //#region ../blocks/src/system/runtime/api/schemas/events.ts
41955
41911
  const uuid = z.string().uuid();
@@ -42337,7 +42293,7 @@ const eventDetailsManifest = createBlockManifest({
42337
42293
  layout: [styledSection({
42338
42294
  baseClass: "",
42339
42295
  spacing: "spacious",
42340
- children: sectionContainer([text({ as: "h2" }, bind("content.heading"), when("content.heading")), el("event-details", withApiBindings({
42296
+ children: sectionContainer([text({ as: "h2" }, bind("content.heading"), when("content.heading")), el("div", { style: mapDrawingStyleBinding }, [el("event-details", withApiBindings({
42341
42297
  entryTitle: { $bind: {
42342
42298
  from: "$root.contentEntry.title",
42343
42299
  fallback: null
@@ -42356,6 +42312,10 @@ const eventDetailsManifest = createBlockManifest({
42356
42312
  fallback: null
42357
42313
  } },
42358
42314
  events: { $bind: { from: "data.eventDetailsData.events" } },
42315
+ venueDrawing: { $bind: {
42316
+ from: "data.eventDetailsData.venueDrawing",
42317
+ fallback: null
42318
+ } },
42359
42319
  showVenue: { $bind: { from: "content.showVenue" } },
42360
42320
  showTitle: { $bind: { from: "content.showTitle" } },
42361
42321
  showDescription: { $bind: { from: "content.showDescription" } },
@@ -42387,7 +42347,7 @@ const eventDetailsManifest = createBlockManifest({
42387
42347
  from: "data.eventDetailsData.autoApplyDiscount",
42388
42348
  fallback: null
42389
42349
  } }
42390
- }, { includeApiBaseUrl: false }))], { gap: "lg" })
42350
+ }, { includeApiBaseUrl: false }))])], { gap: "lg" })
42391
42351
  })]
42392
42352
  });
42393
42353
  const eventDetailsBlockDefinition = {
@@ -42395,6 +42355,7 @@ const eventDetailsBlockDefinition = {
42395
42355
  dataSchemas: {
42396
42356
  eventDetailsData: z.object({
42397
42357
  events: publicEventsArraySchema,
42358
+ venueDrawing: eventVenueDrawingSchema.optional().catch(undefined),
42398
42359
  sitePasses: publicPassProductCollectionSchema,
42399
42360
  siteMemberships: publicMembershipProductCollectionSchema,
42400
42361
  autoApplyDiscount: eventAutoApplyDiscountPreviewSchema.nullable().optional().default(null)
@@ -43820,14 +43781,21 @@ function resolveTargetAspectRatio(size) {
43820
43781
  }
43821
43782
  return undefined;
43822
43783
  }
43784
+ /**
43785
+ * The editor's "Add a photo" sits on the section's ground, so it takes the ground's rule colour where
43786
+ * the surface publishes one (light on light grounds, dark on dark) and reads in the ground's text ink.
43787
+ * A fixed light surface under ground-following muted text vanished on dark sections. Published
43788
+ * "Image unavailable" keeps its existing styling.
43789
+ */
43790
+ const AUTHORING_PLACEHOLDER_GROUND = { backgroundColor: "var(--rb-surface-line-color, rgb(var(--tb-surface)))" };
43823
43791
  function MediaPlaceholder({ className, style, fieldPath, authoring }) {
43824
43792
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
43825
43793
  "data-placeholder-field": authoring ? fieldPath : undefined,
43826
43794
  className: clsx_default("rb-flex rb-h-48 rb-w-full rb-items-center rb-justify-center", className),
43827
- style: mergeStyles(backgroundColorStyle("surface"), style),
43795
+ style: mergeStyles(authoring ? AUTHORING_PLACEHOLDER_GROUND : backgroundColorStyle("surface"), style),
43828
43796
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
43829
43797
  className: "rb-caption",
43830
- style: textColorStyle("mutedText"),
43798
+ style: textColorStyle(authoring ? "text" : "mutedText"),
43831
43799
  children: authoring ? "Add a photo" : "Image unavailable"
43832
43800
  })
43833
43801
  });
@@ -44449,14 +44417,23 @@ const partRenderers = {
44449
44417
  ...listLookSlot(presentation, "dates"),
44450
44418
  children: item.dates.map((date, index) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", {
44451
44419
  ...listLookSlot(presentation, "date"),
44452
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("time", {
44453
- dateTime: date.startsAt,
44454
- children: date.label
44455
- }), date.places ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
44456
- ...listLookSlot(presentation, "date-places"),
44457
- "data-availability": date.places.status,
44458
- children: date.places.label
44459
- }) : null]
44420
+ children: [
44421
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("time", {
44422
+ dateTime: date.startsAt,
44423
+ children: date.label
44424
+ }),
44425
+ date.places ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
44426
+ ...listLookSlot(presentation, "date-places"),
44427
+ "data-availability": date.places.status,
44428
+ children: date.places.label
44429
+ }) : null,
44430
+ date.booking ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ThemedButtonLink, {
44431
+ ...date.booking,
44432
+ variant: presentation.buttonVariant ?? "primary",
44433
+ size: "sm",
44434
+ extraClassName: "rb-card-list-date-booking"
44435
+ }) : null
44436
+ ]
44460
44437
  }, `${date.startsAt}-${index}`))
44461
44438
  }) : null,
44462
44439
  availability: ({ item, presentation }) => item.availability ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
@@ -44947,6 +44924,204 @@ function leadItemPresentation(presentation, index, count) {
44947
44924
  };
44948
44925
  }
44949
44926
 
44927
+ //#endregion
44928
+ //#region ../blocks/src/system/runtime/nodes/svg.tsx
44929
+ /**
44930
+ * Strict SVG-`transform` validator.
44931
+ *
44932
+ * Accepts only a whitespace/comma-separated list of the geometric transform
44933
+ * functions (`translate`/`rotate`/`scale`/`skewX`/`skewY`/`matrix`) whose
44934
+ * arguments are plain numbers. This deliberately rejects anything else —
44935
+ * `url(...)`, CSS functions, `javascript:`, angle/length units, stray letters —
44936
+ * so a persisted custom-block tree can't smuggle an executable or exfiltrating
44937
+ * value into the attribute.
44938
+ */
44939
+ const TRANSFORM_NUMBER = String.raw`-?(?:\d+\.?\d*|\.\d+)(?:e-?\d+)?`;
44940
+ const TRANSFORM_ARGS = String.raw`${TRANSFORM_NUMBER}(?:[\s,]+${TRANSFORM_NUMBER})*`;
44941
+ const TRANSFORM_FN = String.raw`(?:translate|rotate|scale|skewX|skewY|matrix)\(\s*${TRANSFORM_ARGS}\s*\)`;
44942
+ const SAFE_TRANSFORM_RE = new RegExp(String.raw`^\s*${TRANSFORM_FN}(?:[\s,]*${TRANSFORM_FN})*\s*$`);
44943
+ function safeTransform(value) {
44944
+ if (typeof value !== "string") return undefined;
44945
+ const trimmed = value.trim();
44946
+ if (trimmed.length === 0) return undefined;
44947
+ return SAFE_TRANSFORM_RE.test(trimmed) ? trimmed : undefined;
44948
+ }
44949
+ /**
44950
+ * Turn paint props into a CSS style object. Colour values pass through as-is so
44951
+ * they may reference theme tokens via `var()`, which only resolves in a CSS
44952
+ * property context (not in a bare presentation attribute).
44953
+ */
44954
+ function paintStyle(shape) {
44955
+ const style = {};
44956
+ if (shape.fill !== undefined) style.fill = shape.fill;
44957
+ if (shape.stroke !== undefined) style.stroke = shape.stroke;
44958
+ if (shape.strokeWidth !== undefined) style.strokeWidth = shape.strokeWidth;
44959
+ if (shape.fillOpacity !== undefined) style.fillOpacity = shape.fillOpacity;
44960
+ if (shape.strokeOpacity !== undefined) style.strokeOpacity = shape.strokeOpacity;
44961
+ if (shape.strokeLinecap !== undefined) style.strokeLinecap = shape.strokeLinecap;
44962
+ if (shape.strokeLinejoin !== undefined) style.strokeLinejoin = shape.strokeLinejoin;
44963
+ if (shape.strokeDasharray !== undefined) style.strokeDasharray = shape.strokeDasharray;
44964
+ return style;
44965
+ }
44966
+ function renderShape(shape, key) {
44967
+ const style = paintStyle(shape);
44968
+ const transform = safeTransform(shape.transform);
44969
+ switch (shape.kind) {
44970
+ case "text": return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("text", {
44971
+ className: shape.className,
44972
+ x: shape.x,
44973
+ y: shape.y,
44974
+ transform,
44975
+ children: shape.text
44976
+ }, key);
44977
+ case "path": return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", {
44978
+ d: shape.d,
44979
+ className: shape.className,
44980
+ fillRule: shape.fillRule,
44981
+ style,
44982
+ transform
44983
+ }, key);
44984
+ case "ellipse": return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ellipse", {
44985
+ cx: shape.cx,
44986
+ cy: shape.cy,
44987
+ rx: shape.rx,
44988
+ ry: shape.ry,
44989
+ style,
44990
+ transform
44991
+ }, key);
44992
+ case "circle": return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", {
44993
+ cx: shape.cx,
44994
+ cy: shape.cy,
44995
+ r: shape.r,
44996
+ style,
44997
+ transform
44998
+ }, key);
44999
+ case "rect": return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", {
45000
+ x: shape.x,
45001
+ y: shape.y,
45002
+ className: shape.className,
45003
+ width: shape.width,
45004
+ height: shape.height,
45005
+ rx: shape.rx,
45006
+ ry: shape.ry,
45007
+ style,
45008
+ transform
45009
+ }, key);
45010
+ case "line": return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", {
45011
+ x1: shape.x1,
45012
+ y1: shape.y1,
45013
+ x2: shape.x2,
45014
+ y2: shape.y2,
45015
+ style,
45016
+ transform
45017
+ }, key);
45018
+ default: return null;
45019
+ }
45020
+ }
45021
+ const SvgNode = ({ blockId: _blockId, blockKind: _blockKind, blockContent: _blockContent, fragmentRegistry: _fragmentRegistry, pathBase: _pathBase, viewBox, width, height, className, style, ariaHidden = true, ariaLabel, shapes }) => {
45022
+ const safeShapes = Array.isArray(shapes) ? shapes : [];
45023
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", {
45024
+ viewBox,
45025
+ width,
45026
+ height,
45027
+ className,
45028
+ style,
45029
+ "aria-hidden": ariaHidden || undefined,
45030
+ role: ariaLabel ? "img" : undefined,
45031
+ "aria-label": ariaLabel,
45032
+ xmlns: "http://www.w3.org/2000/svg",
45033
+ fill: "none",
45034
+ children: safeShapes.map((shape, index) => renderShape(shape, index))
45035
+ });
45036
+ };
45037
+
45038
+ //#endregion
45039
+ //#region ../blocks/src/system/runtime/nodes/shared/MapDrawingSvg.tsx
45040
+ const PIN_PATH = "M0 0C-3.5-9-13-15-13-25A13 13 0 1 1 13-25C13-15 3.5-9 0 0ZM0-20.5A4.5 4.5 0 1 0 0-29.5A4.5 4.5 0 1 0 0-20.5Z";
45041
+ const commands = (points) => points.map(([x$1, y$1], index) => `${index ? "L" : "M"}${x$1} ${y$1}`).join(" ");
45042
+ function pathShape(path$3) {
45043
+ return path$3.kind === "polygon" ? {
45044
+ kind: "path",
45045
+ className: path$3.className,
45046
+ fillRule: path$3.fillRule,
45047
+ d: path$3.rings.map((ring) => `${commands(ring)} Z`).join(" ")
45048
+ } : {
45049
+ kind: "path",
45050
+ className: path$3.className,
45051
+ d: commands(path$3.points)
45052
+ };
45053
+ }
45054
+ function labelShapes(label) {
45055
+ const [x$1, y$1] = label.point, transform = `rotate(${label.angle} ${x$1} ${y$1})`;
45056
+ return [label.haloClassName, label.className].map((className) => ({
45057
+ kind: "text",
45058
+ className,
45059
+ x: x$1,
45060
+ y: y$1,
45061
+ transform,
45062
+ text: label.text
45063
+ }));
45064
+ }
45065
+ /** The drawing the renderer below would show, or null when there's nothing it can draw. */
45066
+ function readableMapDrawing(drawing) {
45067
+ const parsed = mapDrawingSchema.safeParse(drawing);
45068
+ return parsed.success ? parsed.data : null;
45069
+ }
45070
+ /** Untrusted standalone callers retain boundary admission. */
45071
+ function MapDrawingSvg(props$1) {
45072
+ const drawing = readableMapDrawing(props$1.drawing);
45073
+ return drawing ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AdmittedMapDrawingSvg, {
45074
+ ...props$1,
45075
+ drawing
45076
+ }) : null;
45077
+ }
45078
+ /** Render an already admitted value without allocating another validation copy. */
45079
+ function AdmittedMapDrawingSvg(props$1) {
45080
+ const drawing = props$1.drawing;
45081
+ const name = props$1.wider ? "wider" : "neighbourhood", frame = drawing.frames[name];
45082
+ const shapes = [
45083
+ {
45084
+ kind: "rect",
45085
+ className: frame.backgroundClass,
45086
+ x: 0,
45087
+ y: 0,
45088
+ width: 800,
45089
+ height: 800
45090
+ },
45091
+ ...frame.paths.map(pathShape),
45092
+ ...frame.labels.flatMap(labelShapes),
45093
+ {
45094
+ kind: "path",
45095
+ className: frame.pin.className,
45096
+ fillRule: "evenodd",
45097
+ d: PIN_PATH,
45098
+ transform: `translate(${frame.pin.point.join(" ")})`
45099
+ }
45100
+ ];
45101
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("figure", {
45102
+ className: `rb-map-drawing ${props$1.className ?? ""}`.trim(),
45103
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
45104
+ className: "rb-map-drawing-crop",
45105
+ style: cropHeightStyle(Math.max(255, props$1.height ?? 320), props$1.heightAs ?? "fixed"),
45106
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SvgNode, {
45107
+ className: `map-${name}`,
45108
+ viewBox: frame.viewBox.join(" "),
45109
+ shapes,
45110
+ ariaHidden: false,
45111
+ ariaLabel: props$1.label ? `Map showing ${props$1.label}` : "Map showing the arrival pin"
45112
+ })
45113
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("figcaption", { children: ["© ", /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", {
45114
+ href: "https://www.openstreetmap.org/copyright",
45115
+ target: "_blank",
45116
+ rel: "noreferrer",
45117
+ children: "OpenStreetMap contributors"
45118
+ })] })]
45119
+ });
45120
+ }
45121
+ function cropHeightStyle(height, heightAs) {
45122
+ return heightAs === "minimum" ? { minHeight: height } : { height };
45123
+ }
45124
+
44950
45125
  //#endregion
44951
45126
  //#region ../blocks/src/system/runtime/nodes/events/shared/EventCardIcons.tsx
44952
45127
  function MapPinIcon({ className, size = 16, strokeWidth = 2 }) {
@@ -45059,7 +45234,7 @@ const EventCard = ({ event, cardRole = "default", buttonVariant = "primary", but
45059
45234
  formattedTime,
45060
45235
  hasImage,
45061
45236
  headingLevel: cardHeadingLevel,
45062
- mapSlot,
45237
+ mapSlot: resolveVenueMapSlot(event.venue, mapSlot),
45063
45238
  priceText,
45064
45239
  showMap,
45065
45240
  showSummary,
@@ -45070,6 +45245,13 @@ const EventCard = ({ event, cardRole = "default", buttonVariant = "primary", but
45070
45245
  })]
45071
45246
  });
45072
45247
  };
45248
+ function resolveVenueMapSlot(venue, override) {
45249
+ return override ?? (venue?.drawing ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MapDrawingSvg, {
45250
+ drawing: venue.drawing,
45251
+ label: venue.name,
45252
+ height: 255
45253
+ }) : null);
45254
+ }
45073
45255
  function EventCardMedia(props$1) {
45074
45256
  if (props$1.lookPresentation.lookSlots !== undefined) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EventLookDate, {
45075
45257
  event: props$1.event,
@@ -45471,25 +45653,33 @@ function EventQuickDates({ events, pathname, buttonVariant = "primary", dateStyl
45471
45653
  })]
45472
45654
  });
45473
45655
  }
45474
- /** Decide the formatted date and complete booking link before rendering. */
45475
- function quickDateCardPresentation(props$1) {
45476
- const event = props$1.event;
45477
- const date = formatEventQuickDate(event, props$1.dateStyle);
45656
+ /**
45657
+ * The complete link that books one date, shared by the strip and by date rows.
45658
+ * Null when the date has no registration path (closed, paused, not open yet,
45659
+ * no registration, or full with no waitlist), so no caller repeats that gate.
45660
+ */
45661
+ function eventDateBookingLink(event, pathname, dateLabel$1) {
45662
+ if (!isBookableEvent(event)) return null;
45478
45663
  const cta = resolveEventCta(event);
45479
45664
  const destination = resolveRuntimeEventDestination(event);
45480
- const ctaHref = destination.kind === "external" ? cta.href : resolveDedicatedBookingHref(props$1.pathname, {
45665
+ const href = destination.kind === "external" ? cta.href : resolveDedicatedBookingHref(pathname, {
45481
45666
  kind: "event_occurrence",
45482
45667
  occurrenceId: event.occurrenceId
45483
45668
  });
45669
+ return {
45670
+ href,
45671
+ target: cta.external ? "_blank" : undefined,
45672
+ rel: cta.external ? "noopener noreferrer" : undefined,
45673
+ "aria-label": `${cta.label} ${event.title}, ${dateLabel$1}`,
45674
+ label: cta.label
45675
+ };
45676
+ }
45677
+ /** Decide the formatted date and complete booking link before rendering. */
45678
+ function quickDateCardPresentation(props$1) {
45679
+ const date = formatEventQuickDate(props$1.event, props$1.dateStyle);
45484
45680
  return {
45485
45681
  date,
45486
- bookingLink: {
45487
- href: ctaHref,
45488
- target: cta.external ? "_blank" : undefined,
45489
- rel: cta.external ? "noopener noreferrer" : undefined,
45490
- "aria-label": `${cta.label} ${event.title}, ${date.label}`,
45491
- label: cta.label
45492
- }
45682
+ bookingLink: eventDateBookingLink(props$1.event, props$1.pathname, date.label)
45493
45683
  };
45494
45684
  }
45495
45685
  function EventQuickDateCard(props$1) {
@@ -45525,12 +45715,12 @@ function EventQuickDateCard(props$1) {
45525
45715
  children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
45526
45716
  className: "event-quick-date-price",
45527
45717
  children: formatEventPrice(event)
45528
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ThemedButtonLink, {
45718
+ }), bookingLink ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ThemedButtonLink, {
45529
45719
  variant: props$1.buttonVariant,
45530
45720
  size: "sm",
45531
45721
  extraClassName: "event-quick-date-cta",
45532
45722
  ...bookingLink
45533
- })]
45723
+ }) : null]
45534
45724
  })
45535
45725
  ]
45536
45726
  });
@@ -46550,7 +46740,7 @@ const eventListingLayout = [styledSection({
46550
46740
  children: styledContainer({
46551
46741
  rootType: "stack",
46552
46742
  rootProps: { gap: "lg" },
46553
- children: [...sectionHeaderLayoutNodes(), el("event-listing", withApiBindings({
46743
+ children: [...sectionHeaderLayoutNodes(), el("div", { style: mapDrawingStyleBinding }, [el("event-listing", withApiBindings({
46554
46744
  readAuthority: { $bind: { from: "$root.readAuthority" } },
46555
46745
  events: { $bind: { from: "data.events" } },
46556
46746
  stage: { $bind: {
@@ -46607,7 +46797,7 @@ const eventListingLayout = [styledSection({
46607
46797
  fallback: "any"
46608
46798
  } },
46609
46799
  emptyMessage: { $bind: { from: "content.emptyMessage" } }
46610
- }))]
46800
+ }))])]
46611
46801
  }),
46612
46802
  baseClass: "",
46613
46803
  spacing: "comfortable"
@@ -47597,7 +47787,7 @@ const eventCalendarAdditionalFields = [
47597
47787
  {
47598
47788
  id: "eyebrow",
47599
47789
  type: "text",
47600
- label: "Eyebrow",
47790
+ label: "Small heading above the title",
47601
47791
  required: false,
47602
47792
  multiline: false,
47603
47793
  maxLength: 80
@@ -48393,6 +48583,8 @@ const eventCalendarConfig = {
48393
48583
  promotedFields: [
48394
48584
  "variant",
48395
48585
  "listBy",
48586
+ "calendarTabViews",
48587
+ "defaultCalendarView",
48396
48588
  "eventSurface",
48397
48589
  "filterEventPresets",
48398
48590
  "scheduleScope",
@@ -48433,6 +48625,7 @@ const eventCalendarConfig = {
48433
48625
  icon: "CalendarDays",
48434
48626
  layout: eventCalendarLayout,
48435
48627
  variants: eventCalendarVariants,
48628
+ arrangementOwnedFieldIds: ["defaultCalendarView"],
48436
48629
  variantMeaning: eventCalendarVariantMeaning,
48437
48630
  defaultVariant: "combined",
48438
48631
  variantOptions: {
@@ -48600,7 +48793,7 @@ const recurringScheduleConfig = {
48600
48793
  {
48601
48794
  id: "eyebrow",
48602
48795
  type: "text",
48603
- label: "Eyebrow",
48796
+ label: "Small heading above the title",
48604
48797
  required: false,
48605
48798
  maxLength: 80
48606
48799
  },
@@ -48894,6 +49087,16 @@ const offeringsPreviewFields = [
48894
49087
  schema: { fields: groupOverrideFields }
48895
49088
  },
48896
49089
  createButtonVariantField(),
49090
+ {
49091
+ id: "oneOffering",
49092
+ type: "boolean",
49093
+ label: "Show one offering with its dates",
49094
+ required: false,
49095
+ ui: {
49096
+ intent: "display",
49097
+ hidden: true
49098
+ }
49099
+ },
48897
49100
  {
48898
49101
  id: "buttonText",
48899
49102
  type: "text",
@@ -48989,6 +49192,18 @@ function buildOfferingsCatalogueListing(input) {
48989
49192
  now: input.now
48990
49193
  });
48991
49194
  }
49195
+ function offeringsCatalogueShape(listing, cards) {
49196
+ return cards.oneOfferingRequested && cards.listDates && countListedOfferings(listing) === 1 ? "single" : "several";
49197
+ }
49198
+ function countListedOfferings(listing) {
49199
+ switch (listing.kind) {
49200
+ case "no-groups":
49201
+ case "nothing-to-show": return 0;
49202
+ case "by-date": return listing.items.length;
49203
+ case "by-type": return listing.groups.reduce((count, load) => count + (load.kind === "items" ? load.items.length : 0), 0);
49204
+ default: return assertNever(listing);
49205
+ }
49206
+ }
48992
49207
  function matchesGroup(group, event) {
48993
49208
  const source = group.source;
48994
49209
  switch (source.kind) {
@@ -49064,6 +49279,10 @@ const offeringsPreviewLayout = [styledSection({
49064
49279
  carouselRegion: { $bind: { from: "content.heading" } },
49065
49280
  renderInput: { $bind: { from: "content._offeringsPreviewInput" } },
49066
49281
  displayMode: { $bind: displayModeBinding },
49282
+ oneOffering: { $bind: {
49283
+ from: "content.oneOffering",
49284
+ fallback: false
49285
+ } },
49067
49286
  pathname: { $bind: { from: "$root.pathname" } },
49068
49287
  catalogueEvents: { $bind: { from: "data.catalogueEvents" } },
49069
49288
  quickDateEvents: { $bind: { from: "data.quickDateEvents" } },
@@ -49105,6 +49324,7 @@ const offeringsPreviewLayout = [styledSection({
49105
49324
  spacing: "comfortable"
49106
49325
  })];
49107
49326
  const offeringsPreviewConfig = {
49327
+ arrangementOwnedFieldIds: ["groupOverrides.presentation"],
49108
49328
  variantMeaning: {
49109
49329
  kind: "arrangement",
49110
49330
  lookOnlyKeys: [
@@ -49161,6 +49381,7 @@ const offeringsPreviewBlockDefinition = {
49161
49381
  contentNormalizer: {
49162
49382
  fieldIds: [
49163
49383
  "displayMode",
49384
+ "oneOffering",
49164
49385
  "heading",
49165
49386
  "description",
49166
49387
  "itemLimit",
@@ -49262,6 +49483,7 @@ function normalizeOfferingsPreviewBlockContent(value) {
49262
49483
  if (!record) return { displayMode: DEFAULT_OFFERINGS_PREVIEW_DISPLAY_MODE };
49263
49484
  const normalized = {
49264
49485
  displayMode: normalizeOfferingsPreviewDisplayMode(record.displayMode),
49486
+ ...oneOfferingContent(record.oneOffering),
49265
49487
  ...normalizeCardListContent(record)
49266
49488
  };
49267
49489
  if (typeof record.heading === "string" || record.heading === null) {
@@ -49302,6 +49524,9 @@ function normalizeOfferingsPreviewBlockContent(value) {
49302
49524
  }
49303
49525
  return normalized;
49304
49526
  }
49527
+ function oneOfferingContent(value) {
49528
+ return typeof value === "boolean" || value === null ? { oneOffering: value } : {};
49529
+ }
49305
49530
  function normalizeOfferingsPreviewDisplayMode(value) {
49306
49531
  return value === "catalogue" ? "catalogue" : DEFAULT_OFFERINGS_PREVIEW_DISPLAY_MODE;
49307
49532
  }
@@ -49669,6 +49894,7 @@ const imageGalleryFields = parseFieldDefinitions([
49669
49894
  minItems: 0,
49670
49895
  maxItems: 24,
49671
49896
  ui: {
49897
+ intent: "behavior",
49672
49898
  repeaterPreset: "thumbnailGrid",
49673
49899
  thumbnailField: "image",
49674
49900
  thumbnailAltField: "caption",
@@ -50462,7 +50688,7 @@ const baseImageGalleryManifest = createBlockManifest({
50462
50688
  icon: "Columns"
50463
50689
  },
50464
50690
  marquee: {
50465
- label: "Marquee (infinite scroll)",
50691
+ label: "Scrolling strip",
50466
50692
  description: "Infinite horizontal scrolling gallery",
50467
50693
  icon: "Repeat"
50468
50694
  }
@@ -50660,6 +50886,7 @@ const fields = parseFieldDefinitions([
50660
50886
  type: "repeater",
50661
50887
  label: "Videos",
50662
50888
  itemLabel: "Video",
50889
+ ui: { intent: "behavior" },
50663
50890
  minItems: 0,
50664
50891
  maxItems: 12,
50665
50892
  schema: { fields: [
@@ -50729,6 +50956,7 @@ const fields = parseFieldDefinitions([
50729
50956
  const videoGridManifest = createBlockManifest({
50730
50957
  variantMeaning: { kind: "arrangement" },
50731
50958
  id: "block.video-grid",
50959
+ promotedFields: ["videos"],
50732
50960
  title: "Video grid",
50733
50961
  category: "photos",
50734
50962
  contentSource: { kind: "inline" },
@@ -50890,7 +51118,7 @@ const fileDownloadManifest = createBlockManifest({
50890
51118
  id: "block.file-download",
50891
51119
  title: "File download",
50892
51120
  titleSource: ["title", "file.filename"],
50893
- category: "media",
51121
+ category: "text-and-images",
50894
51122
  contentSource: { kind: "inline" },
50895
51123
  description: "A link visitors can use to download a file, such as a PDF.",
50896
51124
  tags: [
@@ -51777,7 +52005,7 @@ const shopBlockRuntime = defineProgressiveBlockRuntime({
51777
52005
  buildRender: (source) => {
51778
52006
  const passPurchaseMode = source.passPurchaseMode ?? "add_to_cart";
51779
52007
  const subscribeButtonText = source.subscribeButtonText ?? "Subscribe";
51780
- const products = shopDisplayedProducts(source);
52008
+ const products = decideShopDisplayedCatalogue(source);
51781
52009
  const dateContext = source.dateContext ?? resolveDateRuntimeContext(undefined);
51782
52010
  return {
51783
52011
  display: buildPassesMembershipsDisplay({
@@ -52054,16 +52282,18 @@ function shopCardListPresentation(source) {
52054
52282
  [key]: source[key]
52055
52283
  }), {});
52056
52284
  }
52057
- function shopDisplayedProducts(source) {
52285
+ function decideShopDisplayedCatalogue(source) {
52286
+ const passes = source.showPasses === false ? [] : source.passes ?? [];
52287
+ const memberships = source.showMemberships === false ? [] : source.memberships ?? [];
52288
+ const featured = [...passes, ...memberships].some(({ id }) => id === source.featured) ? source.featured ?? null : null;
52058
52289
  return {
52059
- passes: source.showPasses === false ? [] : source.passes ?? [],
52060
- memberships: source.showMemberships === false ? [] : source.memberships ?? []
52290
+ passes,
52291
+ memberships,
52292
+ featured
52061
52293
  };
52062
52294
  }
52063
52295
  function shopFeaturedProduct(source, products) {
52064
- const selectedId = source.featured;
52065
- const visible = [...products.passes, ...products.memberships].some(({ id }) => id === selectedId);
52066
- return source.lookSlots && source.itemRoles?.featured && selectedId && visible ? { featured: selectedId } : {};
52296
+ return source.lookSlots && source.itemRoles?.featured && products.featured !== null ? { featured: products.featured } : {};
52067
52297
  }
52068
52298
  /** Server and hydrated cards share the same decided role and featured marker. */
52069
52299
  function shopProductPresentation(hydration, productId, index, count) {
@@ -52094,6 +52324,7 @@ function shopProductPresentation(hydration, productId, index, count) {
52094
52324
  * - Stripe handles payment security
52095
52325
  */
52096
52326
  const shopManifest = createBlockManifest({
52327
+ arrangementOwnedFieldIds: ["layout", "columns"],
52097
52328
  variantMeaning: {
52098
52329
  kind: "arrangement",
52099
52330
  lookOnlyKeys: [
@@ -52312,7 +52543,7 @@ const shopManifest = createBlockManifest({
52312
52543
  animation: false,
52313
52544
  paletteHidden: false
52314
52545
  },
52315
- category: "interactive",
52546
+ category: "shop",
52316
52547
  contentSource: { kind: "entries" },
52317
52548
  tags: [
52318
52549
  "shop",
@@ -53783,6 +54014,18 @@ const wrapVariant = (variantLayout) => styledSection({
53783
54014
  baseClass: "",
53784
54015
  spacing: "comfortable"
53785
54016
  });
54017
+ const cardBiographyFallbackNode = richText({ className: "rb-prose rb-max-w-none" }, when("content.cardBiography", { equals: "any" }), bind(ITEM_NAME, { transforms: [{ id: "teamMember.cardBiographyFallback" }] }));
54018
+ const teamMemberGridLayout = withCardBiographyFallback(teamMemberFragment.layout);
54019
+ function withCardBiographyFallback(layout) {
54020
+ const roots = Array.isArray(layout) ? layout : [layout];
54021
+ const [card] = roots;
54022
+ if (!card || roots.length !== 1) throw new Error("teamMember fragment must have one root node");
54023
+ const children = card.children ?? [];
54024
+ return {
54025
+ ...card,
54026
+ children: [...children, cardBiographyFallbackNode]
54027
+ };
54028
+ }
53786
54029
  const teamMemberStackLayout = el("div", { className: "rb-team-member rb-team-member--stack rb-flex rb-flex-col rb-md-flex-row rb-items-start rb-gap-3" }, [el("div", { className: "rb-team-member-photo-col rb-w-full rb-shrink-0" }, [el("div", { className: memberPhotoClassName("rb-team-member-photo-wrap rb-w-full") }, [media({
53787
54030
  className: "rb-team-member-photo rb-w-full rb-object-cover",
53788
54031
  style: { aspectRatio: "1 / 1" },
@@ -53805,12 +54048,42 @@ const teamMemberStackLayout = el("div", { className: "rb-team-member rb-team-mem
53805
54048
  as: "p",
53806
54049
  className: "rb-team-member-role"
53807
54050
  }, when("role"), bind("role")),
53808
- richText({ className: "rb-prose rb-max-w-none" }, when("bio"), bind("bio"))
54051
+ richText({ className: "rb-prose rb-max-w-none" }, when("bio"), bind("bio")),
54052
+ cardBiographyFallbackNode
53809
54053
  ])]);
54054
+ const onePersonAboutWhen = { equals: "about" };
54055
+ const notOnePersonAboutWhen = {
54056
+ equals: "about",
54057
+ not: true
54058
+ };
54059
+ const aboutVariant = styledSection({
54060
+ children: sectionContainer([el("div", {
54061
+ className: "rb-team-layout",
54062
+ "data-one-person": "about"
54063
+ }, [el("div", { className: "rb-team-head" }, [headingNode], when("content.heading")), el("team-members", {
54064
+ onePerson: { $bind: { from: "content.onePerson" } },
54065
+ source: { $bind: {
54066
+ from: "content.source",
54067
+ fallback: "manual"
54068
+ } },
54069
+ members: { $bind: {
54070
+ from: "content.members",
54071
+ fallback: []
54072
+ } },
54073
+ siteMembers: { $bind: {
54074
+ from: "data.members",
54075
+ fallback: []
54076
+ } },
54077
+ sectionHeading: { $bind: { from: "content.heading" } }
54078
+ })])], { gap: "md" }),
54079
+ baseClass: "",
54080
+ spacing: "comfortable"
54081
+ });
53810
54082
  const manualGridMembersNode = when("content.source", manualSourceWhen)(repeaterFragmentLayout({
53811
54083
  collectionPath: "content.members",
53812
54084
  itemName: ITEM_NAME,
53813
54085
  fragments: { teamMember: teamMemberFragment },
54086
+ layoutOverrides: { teamMember: teamMemberGridLayout },
53814
54087
  itemGap: "sm",
53815
54088
  itemClassName: memberCardClassName
53816
54089
  }));
@@ -53818,6 +54091,7 @@ const dynamicGridMembersNode = when("content.source", dynamicSourceWhen)(repeate
53818
54091
  collectionPath: "data.members",
53819
54092
  itemName: ITEM_NAME,
53820
54093
  fragments: { teamMember: teamMemberFragment },
54094
+ layoutOverrides: { teamMember: teamMemberGridLayout },
53821
54095
  itemGap: "sm",
53822
54096
  itemClassName: memberCardClassName
53823
54097
  }));
@@ -53853,14 +54127,23 @@ const stackVariant = wrapVariant({
53853
54127
  children: [manualStackMembersNode, dynamicStackMembersNode]
53854
54128
  });
53855
54129
  const cardListVariant = styledSection({
53856
- children: sectionContainer([el("div", { ...lookSlot("layout") }, [
53857
- el("div", { ...lookSlot("head") }, [text({
54130
+ children: sectionContainer([el("div", {
54131
+ className: "rb-team-layout",
54132
+ ...lookSlot("layout"),
54133
+ "data-one-person": { $bind: { from: "content.onePerson" } }
54134
+ }, [
54135
+ el("div", {
54136
+ className: "rb-team-head",
54137
+ ...lookSlot("head")
54138
+ }, [text({
53858
54139
  as: "h2",
53859
54140
  ...lookSlot("heading")
53860
54141
  }, bind("content.heading"), when("content.heading"))], when("content.heading")),
53861
54142
  el("team-members", {
53862
54143
  ...cardListPresentationBindings,
53863
54144
  biographySource: { $bind: { from: "content._effectiveLook.look.structure.teamBiography" } },
54145
+ onePerson: { $bind: { from: "content.onePerson" } },
54146
+ cardBiography: { $bind: { from: "content.cardBiography" } },
53864
54147
  source: { $bind: {
53865
54148
  from: "content.source",
53866
54149
  fallback: "manual"
@@ -53934,6 +54217,37 @@ const teamMembersManifest = createBlockManifest({
53934
54217
  }],
53935
54218
  ui: { intent: "behavior" }
53936
54219
  }),
54220
+ parseFieldDefinition({
54221
+ id: "onePerson",
54222
+ type: "select",
54223
+ label: "One person",
54224
+ required: false,
54225
+ options: [{
54226
+ value: "about",
54227
+ label: "The section is about them, with their bio"
54228
+ }, {
54229
+ value: "portrait",
54230
+ label: "One small portrait"
54231
+ }],
54232
+ ui: {
54233
+ intent: "display",
54234
+ hidden: true
54235
+ }
54236
+ }),
54237
+ parseFieldDefinition({
54238
+ id: "cardBiography",
54239
+ type: "select",
54240
+ label: "Card bio",
54241
+ required: false,
54242
+ options: [{
54243
+ value: "any",
54244
+ label: "Whichever bio the person has"
54245
+ }],
54246
+ ui: {
54247
+ intent: "display",
54248
+ hidden: true
54249
+ }
54250
+ }),
53937
54251
  parseFieldDefinition({
53938
54252
  id: "layoutAlign",
53939
54253
  type: "select",
@@ -54079,10 +54393,19 @@ const teamMembersManifest = createBlockManifest({
54079
54393
  ],
54080
54394
  layout: gridVariant,
54081
54395
  variants: {
54082
- grid: gridVariant,
54396
+ grid: [when("content.onePerson", notOnePersonAboutWhen)(gridVariant), when("content.onePerson", onePersonAboutWhen)(aboutVariant)],
54083
54397
  stack: [when("content._effectiveLook", { not: true })(stackVariant), when("content._effectiveLook")(cardListVariant)],
54084
54398
  ...Object.fromEntries(arrangementOnlyKeys.map((key) => [key, cardListVariant]))
54085
54399
  },
54400
+ arrangementOwnedFieldIds: [
54401
+ "layoutWidth",
54402
+ "thumbnailShape",
54403
+ "thumbnailPadding",
54404
+ "imageColSize",
54405
+ "stackImagePosition",
54406
+ "stackContentAlignment",
54407
+ "gap"
54408
+ ],
54086
54409
  variantMeaning: {
54087
54410
  kind: "arrangement",
54088
54411
  lookOnlyKeys: [...arrangementOnlyKeys]
@@ -54157,18 +54480,6 @@ function normalizeNumber(value, fallback) {
54157
54480
  }
54158
54481
  return fallback;
54159
54482
  }
54160
- function normalizeOptionalNumber(value) {
54161
- if (typeof value === "number" && Number.isFinite(value)) {
54162
- return value;
54163
- }
54164
- if (typeof value === "string") {
54165
- const parsed = Number.parseFloat(value);
54166
- if (Number.isFinite(parsed)) {
54167
- return parsed;
54168
- }
54169
- }
54170
- return null;
54171
- }
54172
54483
  function normalizeBoolean$1(value, fallback) {
54173
54484
  if (typeof value === "boolean") {
54174
54485
  return value;
@@ -54179,23 +54490,20 @@ function normalizeBoolean$1(value, fallback) {
54179
54490
  }
54180
54491
  return fallback;
54181
54492
  }
54182
- function normalizeLocationMapValueRecord(record) {
54183
- const addressText = typeof record.addressText === "string" ? record.addressText : typeof record.displayAddress === "string" ? record.displayAddress : null;
54184
- const normalized = {
54185
- addressText: normalizeLocationAddressText(addressText),
54186
- lat: normalizeOptionalNumber(record.lat),
54187
- lng: normalizeOptionalNumber(record.lng)
54188
- };
54189
- if (normalized.addressText === null && normalized.lat === null && normalized.lng === null) {
54190
- return null;
54191
- }
54192
- return normalized;
54193
- }
54194
- function normalizeLocationMapValue(value) {
54493
+ function normalizeLocationMapValue(value, siteCountry) {
54195
54494
  if (typeof value !== "object" || value === null) {
54196
54495
  return null;
54197
54496
  }
54198
- return normalizeLocationMapValueRecord(value);
54497
+ const projected = readLocationMapProjection(value, siteCountry);
54498
+ return projected === null ? null : {
54499
+ addressText: projected.displayAddress,
54500
+ ...projected.pin ?? {
54501
+ lat: null,
54502
+ lng: null
54503
+ },
54504
+ drawing: projected.drawing,
54505
+ doorNote: projected.doorNote
54506
+ };
54199
54507
  }
54200
54508
  function normalizeLocationMapSource(value) {
54201
54509
  return value === "business_address" || value === "venue" ? value : "custom";
@@ -54203,7 +54511,7 @@ function normalizeLocationMapSource(value) {
54203
54511
  function resolveLocationMapLocation(input) {
54204
54512
  const source = normalizeLocationMapSource(input.locationSource);
54205
54513
  if (source === "business_address") {
54206
- const locationValue$1 = normalizeLocationMapValue(input.businessAddress ?? input.location);
54514
+ const locationValue$1 = normalizeLocationMapValue(input.businessAddress, input.siteCountry);
54207
54515
  return locationValue$1 ? {
54208
54516
  kind: "business_address",
54209
54517
  locationValue: locationValue$1
@@ -54222,7 +54530,7 @@ function resolveLocationMapLocation(input) {
54222
54530
  reason: "missing_venue_id"
54223
54531
  };
54224
54532
  }
54225
- const locationValue$1 = input.venuesById ? normalizeLocationMapValue(input.venuesById[venueId] ?? null) : null;
54533
+ const locationValue$1 = input.venuesById ? normalizeLocationMapValue(input.venuesById[venueId] ?? null, input.siteCountry) : null;
54226
54534
  return locationValue$1 ? {
54227
54535
  kind: "venue",
54228
54536
  venueId,
@@ -54233,7 +54541,7 @@ function resolveLocationMapLocation(input) {
54233
54541
  reason: "missing_venue_location"
54234
54542
  };
54235
54543
  }
54236
- const locationValue = normalizeLocationMapValue(input.location);
54544
+ const locationValue = normalizeLocationMapValue(input.location, input.siteCountry);
54237
54545
  return locationValue ? {
54238
54546
  kind: "custom",
54239
54547
  locationValue
@@ -54260,11 +54568,12 @@ function normalizeLocationMapProps(input) {
54260
54568
  const locationValue = resolvedLocation.kind === "unresolved" ? null : resolvedLocation.locationValue;
54261
54569
  const directionsLabel = normalizeLocationAddressText(input.directionsLabel) ?? LOCATION_MAP_DEFAULTS.directionsLabel;
54262
54570
  return {
54571
+ ...locationMapDetails(locationValue),
54572
+ wider: input.wider === true,
54573
+ googleMapsLabel: normalizedGoogleMapsLabel(input.googleMapsLabel),
54263
54574
  resolvedLocation,
54264
54575
  locationValue,
54265
54576
  unresolvedMessage: describeUnresolvedLocationMapLocation(resolvedLocation),
54266
- addressText: locationValue?.addressText ?? null,
54267
- location: toLocationCoordinates(locationValue),
54268
54577
  zoom: Math.min(LOCATION_MAP_LIMITS.zoom.max, Math.max(LOCATION_MAP_LIMITS.zoom.min, Math.round(normalizeNumber(input.zoom, LOCATION_MAP_DEFAULTS.zoom)))),
54269
54578
  heightPx: Math.min(LOCATION_MAP_LIMITS.heightPx.max, Math.max(LOCATION_MAP_LIMITS.heightPx.min, Math.round(normalizeNumber(input.heightPx, LOCATION_MAP_DEFAULTS.heightPx)))),
54270
54579
  openingHours: parsedHours.ok ? parsedHours.value : null,
@@ -54275,29 +54584,26 @@ function normalizeLocationMapProps(input) {
54275
54584
  className: typeof input.className === "string" ? input.className : null
54276
54585
  };
54277
54586
  }
54278
- function toLocationMapHydrationProps(input) {
54279
- const normalized = normalizeLocationMapProps(input);
54587
+ /** All render-ready permitted details come from the same resolved source value. */
54588
+ function locationMapDetails(value) {
54280
54589
  return {
54281
- location: normalized.locationValue,
54282
- zoom: normalized.zoom,
54283
- heightPx: normalized.heightPx,
54284
- openingHours: normalized.openingHours,
54285
- showOpeningHours: normalized.showOpeningHours,
54286
- showAddressText: normalized.showAddressText,
54287
- showDirections: normalized.showDirections,
54288
- directionsLabel: normalized.directionsLabel,
54289
- className: normalized.className
54590
+ drawing: value?.drawing ?? null,
54591
+ doorNote: value?.doorNote ?? null,
54592
+ addressText: value?.addressText ?? null,
54593
+ location: toLocationCoordinates(value)
54290
54594
  };
54291
54595
  }
54596
+ function normalizedGoogleMapsLabel(value) {
54597
+ return normalizeLocationAddressText(value) ?? "Open in Google Maps";
54598
+ }
54292
54599
  function buildGoogleMapsDirectionsUrl(input) {
54293
- const destination = input.location ? `${input.location.lat},${input.location.lng}` : normalizeLocationAddressText(input.addressText);
54294
- if (!destination) {
54295
- return null;
54296
- }
54297
- const url = new URL("https://www.google.com/maps/dir/");
54298
- url.searchParams.set("api", "1");
54299
- url.searchParams.set("destination", destination);
54300
- return url.toString();
54600
+ return locationMapLinks(input).directions;
54601
+ }
54602
+ function readLocationMapProjection(value, siteCountry) {
54603
+ const canonical$1 = parseLocationValue(value);
54604
+ if (canonical$1.ok && canonical$1.value !== null) return projectPublicLocation(canonical$1.value, siteCountry);
54605
+ const projected = publicLocationSchema$1.safeParse(value);
54606
+ return projected.success ? projected.data : null;
54301
54607
  }
54302
54608
 
54303
54609
  //#endregion
@@ -54317,9 +54623,11 @@ function normalizeLocationMapContent(content) {
54317
54623
  const locationSource = normalizeLocationMapSource(record.locationSource);
54318
54624
  const venueId = typeof record.venueId === "string" && record.venueId.trim() ? record.venueId.trim() : null;
54319
54625
  return {
54626
+ wider: record.wider === true,
54627
+ googleMapsLabel: typeof record.googleMapsLabel === "string" ? record.googleMapsLabel : "Open in Google Maps",
54320
54628
  heading: typeof record.heading === "string" ? record.heading : undefined,
54321
54629
  locationSource,
54322
- ...authoredLocationMapSourceFields(locationSource, venueId, normalized.locationValue),
54630
+ ...authoredLocationMapSourceFields(locationSource, venueId, locationSource === "custom" ? parseAuthoredLocation(record.location) : null),
54323
54631
  showOpeningHours: record.showOpeningHours !== false,
54324
54632
  showAddressText: normalized.showAddressText,
54325
54633
  showDirections: normalized.showDirections,
@@ -54345,8 +54653,90 @@ function authoredLocationMapSourceFields(source, venueId, location) {
54345
54653
  };
54346
54654
  }
54347
54655
  }
54656
+ const locationMapNodeProps = {
54657
+ mapStyle: mapDrawingStyleBinding,
54658
+ siteCountry: { $bind: {
54659
+ from: "$root.site.siteCountry",
54660
+ fallback: null
54661
+ } },
54662
+ openingHours: { $bind: {
54663
+ from: "$root.openingHours",
54664
+ fallback: null
54665
+ } },
54666
+ showOpeningHours: { $bind: {
54667
+ from: "content.showOpeningHours",
54668
+ fallback: true
54669
+ } },
54670
+ location: { $bind: {
54671
+ from: "content.location",
54672
+ fallback: null
54673
+ } },
54674
+ businessAddress: { $bind: {
54675
+ from: "$root.site.businessAddress",
54676
+ fallback: null
54677
+ } },
54678
+ locationSource: { $bind: {
54679
+ from: "content.locationSource",
54680
+ fallback: "custom"
54681
+ } },
54682
+ venueId: { $bind: {
54683
+ from: "content.venueId",
54684
+ fallback: null
54685
+ } },
54686
+ venuesById: { $bind: {
54687
+ from: "$root.site.venuesById",
54688
+ fallback: null
54689
+ } },
54690
+ wider: { $bind: {
54691
+ from: "content.wider",
54692
+ fallback: false
54693
+ } },
54694
+ googleMapsLabel: { $bind: {
54695
+ from: "content.googleMapsLabel",
54696
+ fallback: "Open in Google Maps"
54697
+ } },
54698
+ zoom: { $bind: {
54699
+ from: "content.zoom",
54700
+ fallback: LOCATION_MAP_DEFAULTS.zoom
54701
+ } },
54702
+ heightPx: { $bind: {
54703
+ from: "content.heightPx",
54704
+ fallback: LOCATION_MAP_DEFAULTS.heightPx
54705
+ } },
54706
+ showAddressText: { $bind: {
54707
+ from: "content.showAddressText",
54708
+ fallback: LOCATION_MAP_DEFAULTS.showAddressText
54709
+ } },
54710
+ showDirections: { $bind: {
54711
+ from: "content.showDirections",
54712
+ fallback: LOCATION_MAP_DEFAULTS.showDirections
54713
+ } },
54714
+ directionsLabel: { $bind: {
54715
+ from: "content.directionsLabel",
54716
+ fallback: LOCATION_MAP_DEFAULTS.directionsLabel
54717
+ } }
54718
+ };
54719
+ /** Look-only layouts hand the details their compiler-resolved slot and surface (the wide map's sheet). */
54720
+ const lookPresentationProps = {
54721
+ lookSlots: { $bind: { from: "content._lookSlots" } },
54722
+ itemSurfaces: { $bind: { from: "content._effectiveLook.itemSurfaces" } }
54723
+ };
54724
+ const arrangedLayout = (body) => styledSection({
54725
+ baseClass: "",
54726
+ spacing: "comfortable",
54727
+ children: el("div", {
54728
+ className: "rb-container",
54729
+ ...lookSlot("layout")
54730
+ }, [el("div", lookSlot("head"), [text({
54731
+ as: "h2",
54732
+ ...lookSlot("heading")
54733
+ }, bind("content.heading"))], when("content.heading")), ...body])
54734
+ });
54348
54735
  const locationMapManifest = createBlockManifest({
54349
- variantMeaning: { kind: "arrangement" },
54736
+ variantMeaning: {
54737
+ kind: "arrangement",
54738
+ lookOnlyKeys: ["map-and-details", "photo-and-details"]
54739
+ },
54350
54740
  id: "block.location-map",
54351
54741
  title: "Map",
54352
54742
  titleSource: "heading",
@@ -54376,20 +54766,20 @@ const locationMapManifest = createBlockManifest({
54376
54766
  parseFieldDefinition({
54377
54767
  id: "locationSource",
54378
54768
  type: "select",
54379
- label: "Location source",
54769
+ label: "Which place?",
54380
54770
  defaultValue: "custom",
54381
54771
  options: [
54382
54772
  {
54383
54773
  value: "business_address",
54384
- label: "Use business address"
54774
+ label: "Your business address"
54385
54775
  },
54386
54776
  {
54387
54777
  value: "venue",
54388
- label: "Use a venue"
54778
+ label: "One of your venues"
54389
54779
  },
54390
54780
  {
54391
54781
  value: "custom",
54392
- label: "Custom address"
54782
+ label: "A different place"
54393
54783
  }
54394
54784
  ],
54395
54785
  ui: {
@@ -54419,6 +54809,7 @@ const locationMapManifest = createBlockManifest({
54419
54809
  required: false,
54420
54810
  ui: {
54421
54811
  widget: "locationPicker",
54812
+ valueContract: "location",
54422
54813
  intent: "content",
54423
54814
  visibleWhen: {
54424
54815
  field: "locationSource",
@@ -54454,6 +54845,15 @@ const locationMapManifest = createBlockManifest({
54454
54845
  }
54455
54846
  ] }
54456
54847
  }),
54848
+ parseFieldDefinition({
54849
+ id: "entrancePhoto",
54850
+ type: "media",
54851
+ label: "Entrance photo",
54852
+ description: "A photo of the door or the way in. It shows when this section uses the “Entrance photo beside the details” Look.",
54853
+ required: false,
54854
+ mediaKinds: ["image"],
54855
+ ui: { intent: "content" }
54856
+ }),
54457
54857
  parseFieldDefinition({
54458
54858
  id: "showOpeningHours",
54459
54859
  type: "boolean",
@@ -54490,18 +54890,19 @@ const locationMapManifest = createBlockManifest({
54490
54890
  }
54491
54891
  }),
54492
54892
  parseFieldDefinition({
54493
- id: "zoom",
54494
- type: "number",
54495
- label: "Zoom",
54496
- defaultValue: LOCATION_MAP_DEFAULTS.zoom,
54497
- min: LOCATION_MAP_LIMITS.zoom.min,
54498
- max: LOCATION_MAP_LIMITS.zoom.max,
54499
- step: 1,
54500
- ui: {
54501
- intent: "display",
54502
- widget: "slider",
54503
- showValue: true
54504
- }
54893
+ id: "wider",
54894
+ type: "boolean",
54895
+ label: "Show a wider area",
54896
+ defaultValue: false,
54897
+ ui: { intent: "display" }
54898
+ }),
54899
+ parseFieldDefinition({
54900
+ id: "googleMapsLabel",
54901
+ type: "text",
54902
+ label: "Google Maps button label",
54903
+ defaultValue: "Open in Google Maps",
54904
+ maxLength: 60,
54905
+ ui: { intent: "display" }
54505
54906
  }),
54506
54907
  parseFieldDefinition({
54507
54908
  id: "heightPx",
@@ -54514,64 +54915,27 @@ const locationMapManifest = createBlockManifest({
54514
54915
  ui: {
54515
54916
  intent: "display",
54516
54917
  widget: "slider",
54517
- showValue: true
54918
+ showValue: true,
54919
+ valueUnit: "pixels"
54518
54920
  }
54519
54921
  })
54520
54922
  ],
54521
54923
  layout: styledSection({
54522
54924
  baseClass: "",
54523
54925
  spacing: "comfortable",
54524
- children: sectionContainer([text({ as: "h2" }, bind("content.heading"), when("content.heading")), el("location-map", {
54525
- openingHours: { $bind: {
54526
- from: "$root.openingHours",
54527
- fallback: null
54528
- } },
54529
- showOpeningHours: { $bind: {
54530
- from: "content.showOpeningHours",
54531
- fallback: true
54532
- } },
54533
- location: { $bind: {
54534
- from: "content.location",
54535
- fallback: null
54536
- } },
54537
- businessAddress: { $bind: {
54538
- from: "site.businessAddress",
54539
- fallback: null
54540
- } },
54541
- locationSource: { $bind: {
54542
- from: "content.locationSource",
54543
- fallback: "custom"
54544
- } },
54545
- venueId: { $bind: {
54546
- from: "content.venueId",
54547
- fallback: null
54548
- } },
54549
- venuesById: { $bind: {
54550
- from: "site.venuesById",
54551
- fallback: null
54552
- } },
54553
- zoom: { $bind: {
54554
- from: "content.zoom",
54555
- fallback: LOCATION_MAP_DEFAULTS.zoom
54556
- } },
54557
- heightPx: { $bind: {
54558
- from: "content.heightPx",
54559
- fallback: LOCATION_MAP_DEFAULTS.heightPx
54560
- } },
54561
- showAddressText: { $bind: {
54562
- from: "content.showAddressText",
54563
- fallback: LOCATION_MAP_DEFAULTS.showAddressText
54564
- } },
54565
- showDirections: { $bind: {
54566
- from: "content.showDirections",
54567
- fallback: LOCATION_MAP_DEFAULTS.showDirections
54568
- } },
54569
- directionsLabel: { $bind: {
54570
- from: "content.directionsLabel",
54571
- fallback: LOCATION_MAP_DEFAULTS.directionsLabel
54572
- } }
54573
- })], { gap: "md" })
54574
- })
54926
+ children: sectionContainer([text({ as: "h2" }, bind("content.heading"), when("content.heading")), el("location-map", locationMapNodeProps)], { gap: "md" })
54927
+ }),
54928
+ variants: {
54929
+ "map-and-details": arrangedLayout([el("location-map", {
54930
+ ...locationMapNodeProps,
54931
+ ...lookPresentationProps
54932
+ })]),
54933
+ "photo-and-details": arrangedLayout([el("div", lookSlot("frame"), [el("div", lookSlot("media"), [media(lookSlot("photo"), bind("content.entrancePhoto"), when("content.entrancePhoto"))], when("content.entrancePhoto")), el("location-map", {
54934
+ ...locationMapNodeProps,
54935
+ ...lookPresentationProps,
54936
+ showMap: false
54937
+ })])])
54938
+ }
54575
54939
  });
54576
54940
  const locationMapBlockDefinition = {
54577
54941
  manifest: locationMapManifest,
@@ -54582,6 +54946,8 @@ const locationMapBlockDefinition = {
54582
54946
  "venueId",
54583
54947
  "location",
54584
54948
  "showAddressText",
54949
+ "wider",
54950
+ "googleMapsLabel",
54585
54951
  "showOpeningHours",
54586
54952
  "showDirections",
54587
54953
  "directionsLabel",
@@ -54591,6 +54957,14 @@ const locationMapBlockDefinition = {
54591
54957
  normalize: normalizeLocationMapContent
54592
54958
  }
54593
54959
  };
54960
+ function parseAuthoredLocation(value) {
54961
+ if (value == null) return null;
54962
+ const canonical$1 = parseLocationValue(value);
54963
+ if (canonical$1.ok) return canonical$1.value;
54964
+ const projected = publicLocationSchema$1.safeParse(value);
54965
+ if (projected.success) return projected.data;
54966
+ return { kind: "needs_place" };
54967
+ }
54594
54968
 
54595
54969
  //#endregion
54596
54970
  //#region ../blocks/src/system/blocks/index.ts
@@ -54911,7 +55285,7 @@ const systemBlockDefinitionsRaw = [
54911
55285
  })
54912
55286
  ]
54913
55287
  })),
54914
- withDesignCapability("block.location-map", locationMapBlockDefinition, sectionOnly(), defineBlockDesignMetadata({
55288
+ withDesignCapability("block.location-map", locationMapBlockDefinition, withLookCapability(sectionOnly()), defineBlockDesignMetadata({
54915
55289
  flow: utilityFlow,
54916
55290
  layoutProfiles: [layoutProfile({
54917
55291
  variantKey: "default",
@@ -55454,6 +55828,58 @@ function clearBlockDefinitions() {
55454
55828
  resetSystemBlockDefinitionRegistration();
55455
55829
  }
55456
55830
 
55831
+ //#endregion
55832
+ //#region ../blocks/src/system/manifest/storedLayout.ts
55833
+ /** The content field `parseStoredVariant` also reads; a block without stored variants keeps its layout there. */
55834
+ const layoutFieldId = "layout";
55835
+ function storedVariantKeys(manifest) {
55836
+ const lookOnly = manifest.variantMeaning.lookOnlyKeys ?? [];
55837
+ return Object.keys(manifest.variants ?? {}).filter((key) => !lookOnly.includes(key));
55838
+ }
55839
+ function optionValues(options) {
55840
+ return Array.isArray(options) ? options.flatMap((option) => typeof option === "object" && option !== null && "value" in option && typeof option.value === "string" ? [option.value] : []) : [];
55841
+ }
55842
+ /**
55843
+ * A block with no stored variants that offers a `layout` select (the shop)
55844
+ * declares its layouts there. Read as a mode's arrangement declaration, so the
55845
+ * same resolver decides: a stored value the block still has, or the default.
55846
+ */
55847
+ function layoutFieldDeclaration(manifest) {
55848
+ const field = (manifest.fields ?? []).find((candidate) => typeof candidate === "object" && candidate !== null && "id" in candidate && candidate.id === layoutFieldId && "type" in candidate && candidate.type === "select");
55849
+ const keys = optionValues(field?.options);
55850
+ const [firstKey] = keys;
55851
+ if (field === undefined || firstKey === undefined) return null;
55852
+ return {
55853
+ arrangementField: layoutFieldId,
55854
+ keys,
55855
+ defaultKey: typeof field.defaultValue === "string" && keys.includes(field.defaultValue) ? field.defaultValue : firstKey
55856
+ };
55857
+ }
55858
+ function fieldDeclaration(manifest) {
55859
+ if (manifest.variantMeaning.kind === "mode") return manifest.variantMeaning;
55860
+ return storedVariantKeys(manifest).length === 0 ? layoutFieldDeclaration(manifest) : null;
55861
+ }
55862
+ /** Every layout a block can store, for the block's own layout axis. Look-only arrangements are never stored. */
55863
+ function storedLayoutKeys(manifest) {
55864
+ return fieldDeclaration(manifest)?.keys ?? storedVariantKeys(manifest);
55865
+ }
55866
+ /**
55867
+ * The layout a block renders by when no Look arranges it: the stored value if
55868
+ * the block still has it, otherwise the default. The renderer's own resolvers
55869
+ * decide, so a reader of stored layouts cannot disagree with the page.
55870
+ */
55871
+ function resolveStoredLayout(manifest, content) {
55872
+ const field = fieldDeclaration(manifest);
55873
+ return field === null ? resolveEffectiveArrangement({
55874
+ manifest: arrangementManifestFromVariants(manifest),
55875
+ storedVariant: parseStoredVariant(manifest, content)
55876
+ }).key : resolveModeArrangement({
55877
+ declaration: field,
55878
+ content,
55879
+ mode: null
55880
+ }).key;
55881
+ }
55882
+
55457
55883
  //#endregion
55458
55884
  //#region ../blocks/src/system/data/selectBlockContent.ts
55459
55885
  /** Canonical admitted content: legacy publishedContent never selects a version. */
@@ -55626,6 +56052,101 @@ function toEditorPresentationPage(page) {
55626
56052
  };
55627
56053
  }
55628
56054
 
56055
+ //#endregion
56056
+ //#region ../blocks/src/system/customize/arrangementKnobs.ts
56057
+ /**
56058
+ * Content stage for knobs, shared by the renderer and the editor so what the
56059
+ * options show and what renders can't disagree. Knob buffets are the block's
56060
+ * customise facets; the Look exposes, forces or narrows them and the style's
56061
+ * offer can only remove or narrow further.
56062
+ */
56063
+ function resolveArrangementKnobs(input) {
56064
+ const length = input.blockKind === "block.hero" ? resolveHeroTitleLength({ ...input.content }, "look") : null;
56065
+ const exposure = arrangementKnobExposure(input.blockKind, input.look, length, storedSplitPhotoSide(input.blockKind, input.content));
56066
+ const knobs = resolveEffectiveKnobs({
56067
+ exposure,
56068
+ content: normalizedHeadlinePreference(input.content)
56069
+ });
56070
+ return {
56071
+ length,
56072
+ exposure,
56073
+ knobs
56074
+ };
56075
+ }
56076
+ /** The values an owner can choose for an exposed knob, before any length cap. */
56077
+ function arrangementKnobChoices(exposure) {
56078
+ return exposure.definition.values.filter((value) => (exposure.lookValues?.includes(value) ?? true) && (exposure.styleValues?.includes(value) ?? true));
56079
+ }
56080
+ function arrangementKnobExposure(blockKind, look, length, splitPhotoSide) {
56081
+ return systemCustomizeFacetDefinitionsForBlock(blockKind).flatMap((facet) => {
56082
+ if (facet.knob === undefined || facet.target.kind !== "content-field") return [];
56083
+ const id = facet.target.field;
56084
+ const defaults = look.look.structure.knobDefaults ?? {};
56085
+ const storedDefault = id === "imagePosition" ? splitPhotoSide : null;
56086
+ return [{
56087
+ definition: {
56088
+ id,
56089
+ defaultValue: defaults[id] ?? storedDefault ?? facet.defaultValue,
56090
+ values: facet.values.map((value) => value.value),
56091
+ ...knobKindMetadata(facet.knob)
56092
+ },
56093
+ exposed: exposedKnobIds(look).includes(id),
56094
+ forced: look.look.structure.forcedKnobs?.[id],
56095
+ lookValues: look.look.structure.knobValues?.[id],
56096
+ styleValues: look.knobValues[id],
56097
+ lengthValues: id === "titleSize" ? headlineAllowedValues(length) : undefined
56098
+ }];
56099
+ });
56100
+ }
56101
+ /**
56102
+ * A hero stored as "Split, photo on the left" or "Split, photo on the right"
56103
+ * already says which side its photo is on. Under a Look that side is the Photo
56104
+ * side default, so the photo stays where it was until the owner picks a side.
56105
+ */
56106
+ function storedSplitPhotoSide(blockKind, content) {
56107
+ if (blockKind !== "block.hero") return null;
56108
+ switch (content.variant) {
56109
+ case "split": return "left";
56110
+ case "splitReverse": return "right";
56111
+ default: return null;
56112
+ }
56113
+ }
56114
+ function knobKindMetadata(knob) {
56115
+ return knob.kind === "fixed" ? { ordered: knob.ordered } : {
56116
+ ordered: false,
56117
+ textMaxLength: knob.maxLength
56118
+ };
56119
+ }
56120
+ function headlineAllowedValues(length) {
56121
+ switch (length) {
56122
+ case "long": return ["quiet"];
56123
+ case "medium": return ["quiet", "auto"];
56124
+ case "short": return [
56125
+ "quiet",
56126
+ "auto",
56127
+ "display"
56128
+ ];
56129
+ case null: return undefined;
56130
+ }
56131
+ }
56132
+ /** `titleSize` keeps its five stored values; under a Look they read as three steps. */
56133
+ function normalizedHeadlinePreference(content) {
56134
+ switch (content.titleSize) {
56135
+ case "editorial": return {
56136
+ ...content,
56137
+ titleSize: "auto"
56138
+ };
56139
+ case "poster": return {
56140
+ ...content,
56141
+ titleSize: "display"
56142
+ };
56143
+ default: return content;
56144
+ }
56145
+ }
56146
+ function exposedKnobIds(look) {
56147
+ return [...look.look.structure.knobs, ...look.addKnobs ?? []].filter((id) => !look.removeKnobs.some((removed) => removed === id));
56148
+ }
56149
+
55629
56150
  //#endregion
55630
56151
  //#region ../blocks/src/system/customize/facets.ts
55631
56152
  function defineCustomizeFacet(definition$1) {
@@ -55933,87 +56454,6 @@ function omitRecordKey(content, key) {
55933
56454
  return Object.fromEntries(Object.entries(content).filter(([entryKey]) => entryKey !== key));
55934
56455
  }
55935
56456
 
55936
- //#endregion
55937
- //#region ../blocks/src/system/customize/arrangementKnobs.ts
55938
- /**
55939
- * Content stage for knobs, shared by the renderer and the editor so what the
55940
- * options show and what renders can't disagree. Knob buffets are the block's
55941
- * customise facets; the Look exposes, forces or narrows them and the style's
55942
- * offer can only remove or narrow further.
55943
- */
55944
- function resolveArrangementKnobs(input) {
55945
- const length = input.blockKind === "block.hero" ? resolveHeroTitleLength({ ...input.content }, "look") : null;
55946
- const exposure = arrangementKnobExposure(input.blockKind, input.look, length);
55947
- const knobs = resolveEffectiveKnobs({
55948
- exposure,
55949
- content: normalizedHeadlinePreference(input.content)
55950
- });
55951
- return {
55952
- length,
55953
- exposure,
55954
- knobs
55955
- };
55956
- }
55957
- /** The values an owner can choose for an exposed knob, before any length cap. */
55958
- function arrangementKnobChoices(exposure) {
55959
- return exposure.definition.values.filter((value) => (exposure.lookValues?.includes(value) ?? true) && (exposure.styleValues?.includes(value) ?? true));
55960
- }
55961
- function arrangementKnobExposure(blockKind, look, length) {
55962
- return systemCustomizeFacetDefinitionsForBlock(blockKind).flatMap((facet) => {
55963
- if (facet.knob === undefined || facet.target.kind !== "content-field") return [];
55964
- const id = facet.target.field;
55965
- const defaults = look.look.structure.knobDefaults ?? {};
55966
- return [{
55967
- definition: {
55968
- id,
55969
- defaultValue: defaults[id] ?? facet.defaultValue,
55970
- values: facet.values.map((value) => value.value),
55971
- ...knobKindMetadata(facet.knob)
55972
- },
55973
- exposed: exposedKnobIds(look).includes(id),
55974
- forced: look.look.structure.forcedKnobs?.[id],
55975
- lookValues: look.look.structure.knobValues?.[id],
55976
- styleValues: look.knobValues[id],
55977
- lengthValues: id === "titleSize" ? headlineAllowedValues(length) : undefined
55978
- }];
55979
- });
55980
- }
55981
- function knobKindMetadata(knob) {
55982
- return knob.kind === "fixed" ? { ordered: knob.ordered } : {
55983
- ordered: false,
55984
- textMaxLength: knob.maxLength
55985
- };
55986
- }
55987
- function headlineAllowedValues(length) {
55988
- switch (length) {
55989
- case "long": return ["quiet"];
55990
- case "medium": return ["quiet", "auto"];
55991
- case "short": return [
55992
- "quiet",
55993
- "auto",
55994
- "display"
55995
- ];
55996
- case null: return undefined;
55997
- }
55998
- }
55999
- /** `titleSize` keeps its five stored values; under a Look they read as three steps. */
56000
- function normalizedHeadlinePreference(content) {
56001
- switch (content.titleSize) {
56002
- case "editorial": return {
56003
- ...content,
56004
- titleSize: "auto"
56005
- };
56006
- case "poster": return {
56007
- ...content,
56008
- titleSize: "display"
56009
- };
56010
- default: return content;
56011
- }
56012
- }
56013
- function exposedKnobIds(look) {
56014
- return [...look.look.structure.knobs, ...look.addKnobs ?? []].filter((id) => !look.removeKnobs.some((removed) => removed === id));
56015
- }
56016
-
56017
56457
  //#endregion
56018
56458
  //#region ../blocks/src/system/transforms/registry/offeringsPreview.ts
56019
56459
  /** Reuse the existing occurrence read for the date strip and card date rows. */
@@ -56477,6 +56917,30 @@ function resolvePreResolvedLink(link$2) {
56477
56917
  return !kind && typeof link$2.href === "string" ? resolveExternalLink(link$2) : null;
56478
56918
  }
56479
56919
 
56920
+ //#endregion
56921
+ //#region ../blocks/src/system/transforms/registry/mapDrawing.ts
56922
+ /**
56923
+ * Map tokens for the section ground a drawing sits on. The value is the
56924
+ * section's `_sectionStyles.background`, resolved by the same owner as the
56925
+ * section's own foreground; theme-core decides every map colour from it.
56926
+ */
56927
+ const mapDrawingStyleTransform = {
56928
+ id: "mapDrawing.resolveStyle",
56929
+ kind: "formatter",
56930
+ summary: "Resolve map drawing tokens from the section ground and site style",
56931
+ run: (value, options, context) => mapDrawingStyle({
56932
+ foreground: resolveSectionSurfaceForeground(value ?? sectionFallbackBackground(options?.fallbackToken), context, { fallbackToken: options?.fallbackToken }),
56933
+ palette: context.theme.palette,
56934
+ skin: context.theme.skin
56935
+ })
56936
+ };
56937
+ function sectionFallbackBackground(token) {
56938
+ return token === undefined ? undefined : {
56939
+ type: "color",
56940
+ color: token
56941
+ };
56942
+ }
56943
+
56480
56944
  //#endregion
56481
56945
  //#region ../blocks/src/system/transforms/registry/eventCalendar.ts
56482
56946
  const selectionParamSchema = z.object({ key: z.enum([
@@ -56581,7 +57045,8 @@ const builtinTransformDefinitions = [
56581
57045
  ...linksTransforms,
56582
57046
  ...boxStylesTransforms,
56583
57047
  ...contentTransforms,
56584
- ...headerRuntimeTransforms
57048
+ ...headerRuntimeTransforms,
57049
+ mapDrawingStyleTransform
56585
57050
  ];
56586
57051
  const defaultTransforms = createTransformRegistry(builtinTransformDefinitions);
56587
57052
 
@@ -57449,6 +57914,144 @@ function renderMark(mark, key, child) {
57449
57914
  }
57450
57915
  }
57451
57916
 
57917
+ //#endregion
57918
+ //#region ../blocks/src/system/runtime/nodes/shared/LocationMapActions.tsx
57919
+ /**
57920
+ * `compact` (event details) is one plain Google Maps text link under the venue;
57921
+ * `block` (the map block) leads with a secondary directions button and keeps
57922
+ * the same Google Maps text link beside it.
57923
+ */
57924
+ function LocationMapActions(props$1) {
57925
+ const links = locationMapLinks(props$1);
57926
+ const directionsLabel = props$1.directionsLabel ?? "Get directions";
57927
+ const googleMapsLabel = props$1.googleMapsLabel ?? "Open in Google Maps";
57928
+ if (props$1.layout === "block") {
57929
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
57930
+ className: "rb-location-map-actions",
57931
+ children: [links.directions ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ThemedButtonLink, {
57932
+ href: links.directions,
57933
+ target: "_blank",
57934
+ rel: "noreferrer",
57935
+ variant: "secondary",
57936
+ size: "sm",
57937
+ label: directionsLabel
57938
+ }) : null, links.googleMaps ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", {
57939
+ className: "rb-location-map-link",
57940
+ href: links.googleMaps,
57941
+ target: "_blank",
57942
+ rel: "noreferrer",
57943
+ children: googleMapsLabel
57944
+ }) : null]
57945
+ });
57946
+ }
57947
+ return links.googleMaps ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", {
57948
+ className: "rb-location-map-link",
57949
+ href: links.googleMaps,
57950
+ target: "_blank",
57951
+ rel: "noreferrer",
57952
+ children: googleMapsLabel
57953
+ }) }) : null;
57954
+ }
57955
+
57956
+ //#endregion
57957
+ //#region ../blocks/src/system/runtime/nodes/location-map.view.tsx
57958
+ function OpeningHoursTable({ hours: hours$1, lookLayout }) {
57959
+ if (!hours$1) return null;
57960
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
57961
+ className: "rb-location-map-hours",
57962
+ "data-slot": lookLayout ? "schedule" : undefined,
57963
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("table", { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("caption", { children: "Opening hours" }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("tbody", { children: formatOpeningHoursRows(hours$1).map((row$1) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("tr", {
57964
+ "data-slot": lookLayout ? "row" : undefined,
57965
+ "data-closed": row$1.kind === "closed" ? true : undefined,
57966
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", {
57967
+ scope: "row",
57968
+ "data-slot": lookLayout ? "fact-label" : undefined,
57969
+ children: row$1.label
57970
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", {
57971
+ "data-slot": lookLayout ? "fact-value" : undefined,
57972
+ children: row$1.hours
57973
+ })]
57974
+ }, row$1.label)) })] }), hours$1.note ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { children: hours$1.note }) : null]
57975
+ });
57976
+ }
57977
+ function LocationMapView(props$1) {
57978
+ const { addressText, location } = props$1;
57979
+ const hours$1 = props$1.showOpeningHours === false ? null : props$1.openingHours ?? null;
57980
+ if (![
57981
+ location,
57982
+ addressText,
57983
+ hours$1
57984
+ ].some(Boolean)) {
57985
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
57986
+ className: "rb-caption",
57987
+ style: textColorStyle("mutedText"),
57988
+ children: props$1.unresolvedMessage ?? "Location details coming soon."
57989
+ });
57990
+ }
57991
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LocationMapDetails, {
57992
+ ...props$1,
57993
+ openingHours: hours$1
57994
+ });
57995
+ }
57996
+ /** The entrance-photo Look leaves the drawing out; Look layouts treat the authored height as a minimum. */
57997
+ function LocationMapDrawing(props$1) {
57998
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AdmittedMapDrawingSvg, {
57999
+ drawing: props$1.drawing,
58000
+ wider: props$1.wider,
58001
+ label: props$1.addressText ?? undefined,
58002
+ height: props$1.heightPx,
58003
+ heightAs: props$1.lookLayout ? "minimum" : "fixed"
58004
+ });
58005
+ }
58006
+ /**
58007
+ * `data-map="none"` marks details shown without a drawing (none yet, or the entrance photo
58008
+ * takes its place), so map Looks lay the details out on their own instead of beside an empty space.
58009
+ */
58010
+ function LocationMapDetails(props$1) {
58011
+ const drawing = props$1.showMap === false ? null : readableMapDrawing(props$1.drawing);
58012
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
58013
+ className: "rb-location-map",
58014
+ "data-map": drawing ? "drawing" : "none",
58015
+ children: [drawing ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LocationMapDrawing, {
58016
+ ...props$1,
58017
+ drawing
58018
+ }) : null, /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
58019
+ className: "rb-location-map-details",
58020
+ ...props$1.detailsSlot,
58021
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(LocationMapPlace, { ...props$1 }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(OpeningHoursTable, {
58022
+ lookLayout: props$1.lookLayout,
58023
+ hours: props$1.openingHours ?? null
58024
+ })]
58025
+ })]
58026
+ });
58027
+ }
58028
+ /** Address, door note and the directions actions. */
58029
+ function LocationMapPlace(props$1) {
58030
+ const address$1 = props$1.showAddressText && props$1.addressText ? props$1.addressText : null;
58031
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
58032
+ className: "rb-location-map-place",
58033
+ "data-slot": props$1.lookLayout ? "copy" : undefined,
58034
+ children: [
58035
+ address$1 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
58036
+ className: "rb-location-map-address",
58037
+ "data-slot": props$1.lookLayout ? "headline" : undefined,
58038
+ children: address$1
58039
+ }) : null,
58040
+ props$1.doorNote ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
58041
+ className: "rb-location-map-door",
58042
+ children: props$1.doorNote
58043
+ }) : null,
58044
+ props$1.showDirections ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LocationMapActions, {
58045
+ layout: "block",
58046
+ location: props$1.location,
58047
+ addressText: props$1.addressText,
58048
+ directionsLabel: props$1.directionsLabel,
58049
+ googleMapsLabel: props$1.googleMapsLabel
58050
+ }) : null
58051
+ ]
58052
+ });
58053
+ }
58054
+
57452
58055
  //#endregion
57453
58056
  //#region ../blocks/src/system/runtime/nodes/basic.tsx
57454
58057
  const TextNode = ({ value, children, blockContent, inlineTextFallbackPath, ...rest }) => {
@@ -58095,7 +58698,7 @@ function getIslandRootProps(kind, id) {
58095
58698
  return resolved;
58096
58699
  }
58097
58700
  function serializeIslandProps(value) {
58098
- return JSON.stringify(value).replace(/</g, "\\u003c");
58701
+ return JSON.stringify(serializeSurfaceTree(value)).replace(/</g, "\\u003c");
58099
58702
  }
58100
58703
  function IslandPropsScript({ value }) {
58101
58704
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("script", {
@@ -58449,105 +59052,6 @@ function HeaderControlNode({ className, children, "aria-label": label, "aria-exp
58449
59052
  });
58450
59053
  }
58451
59054
 
58452
- //#endregion
58453
- //#region ../blocks/src/system/runtime/nodes/svg.tsx
58454
- /**
58455
- * Strict SVG-`transform` validator.
58456
- *
58457
- * Accepts only a whitespace/comma-separated list of the geometric transform
58458
- * functions (`translate`/`rotate`/`scale`/`skewX`/`skewY`/`matrix`) whose
58459
- * arguments are plain numbers. This deliberately rejects anything else —
58460
- * `url(...)`, CSS functions, `javascript:`, angle/length units, stray letters —
58461
- * so a persisted custom-block tree can't smuggle an executable or exfiltrating
58462
- * value into the attribute.
58463
- */
58464
- const TRANSFORM_NUMBER = String.raw`-?(?:\d+\.?\d*|\.\d+)(?:e-?\d+)?`;
58465
- const TRANSFORM_ARGS = String.raw`${TRANSFORM_NUMBER}(?:[\s,]+${TRANSFORM_NUMBER})*`;
58466
- const TRANSFORM_FN = String.raw`(?:translate|rotate|scale|skewX|skewY|matrix)\(\s*${TRANSFORM_ARGS}\s*\)`;
58467
- const SAFE_TRANSFORM_RE = new RegExp(String.raw`^\s*${TRANSFORM_FN}(?:[\s,]*${TRANSFORM_FN})*\s*$`);
58468
- function safeTransform(value) {
58469
- if (typeof value !== "string") return undefined;
58470
- const trimmed = value.trim();
58471
- if (trimmed.length === 0) return undefined;
58472
- return SAFE_TRANSFORM_RE.test(trimmed) ? trimmed : undefined;
58473
- }
58474
- /**
58475
- * Turn paint props into a CSS style object. Colour values pass through as-is so
58476
- * they may reference theme tokens via `var()`, which only resolves in a CSS
58477
- * property context (not in a bare presentation attribute).
58478
- */
58479
- function paintStyle(shape) {
58480
- const style = {};
58481
- if (shape.fill !== undefined) style.fill = shape.fill;
58482
- if (shape.stroke !== undefined) style.stroke = shape.stroke;
58483
- if (shape.strokeWidth !== undefined) style.strokeWidth = shape.strokeWidth;
58484
- if (shape.fillOpacity !== undefined) style.fillOpacity = shape.fillOpacity;
58485
- if (shape.strokeOpacity !== undefined) style.strokeOpacity = shape.strokeOpacity;
58486
- if (shape.strokeLinecap !== undefined) style.strokeLinecap = shape.strokeLinecap;
58487
- if (shape.strokeLinejoin !== undefined) style.strokeLinejoin = shape.strokeLinejoin;
58488
- if (shape.strokeDasharray !== undefined) style.strokeDasharray = shape.strokeDasharray;
58489
- return style;
58490
- }
58491
- function renderShape(shape, key) {
58492
- const style = paintStyle(shape);
58493
- const transform = safeTransform(shape.transform);
58494
- switch (shape.kind) {
58495
- case "path": return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", {
58496
- d: shape.d,
58497
- style,
58498
- transform
58499
- }, key);
58500
- case "ellipse": return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ellipse", {
58501
- cx: shape.cx,
58502
- cy: shape.cy,
58503
- rx: shape.rx,
58504
- ry: shape.ry,
58505
- style,
58506
- transform
58507
- }, key);
58508
- case "circle": return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", {
58509
- cx: shape.cx,
58510
- cy: shape.cy,
58511
- r: shape.r,
58512
- style,
58513
- transform
58514
- }, key);
58515
- case "rect": return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", {
58516
- x: shape.x,
58517
- y: shape.y,
58518
- width: shape.width,
58519
- height: shape.height,
58520
- rx: shape.rx,
58521
- ry: shape.ry,
58522
- style,
58523
- transform
58524
- }, key);
58525
- case "line": return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", {
58526
- x1: shape.x1,
58527
- y1: shape.y1,
58528
- x2: shape.x2,
58529
- y2: shape.y2,
58530
- style,
58531
- transform
58532
- }, key);
58533
- default: return null;
58534
- }
58535
- }
58536
- const SvgNode = ({ blockId: _blockId, blockKind: _blockKind, blockContent: _blockContent, fragmentRegistry: _fragmentRegistry, pathBase: _pathBase, viewBox, width, height, className, style, ariaHidden = true, shapes }) => {
58537
- const safeShapes = Array.isArray(shapes) ? shapes : [];
58538
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", {
58539
- viewBox,
58540
- width,
58541
- height,
58542
- className,
58543
- style,
58544
- "aria-hidden": ariaHidden,
58545
- xmlns: "http://www.w3.org/2000/svg",
58546
- fill: "none",
58547
- children: safeShapes.map((shape, index) => renderShape(shape, index))
58548
- });
58549
- };
58550
-
58551
59055
  //#endregion
58552
59056
  //#region ../blocks/src/system/runtime/nodes/appointment-services.tsx
58553
59057
  const publicVenueSchema = z.object({
@@ -58614,6 +59118,15 @@ const publicAppointmentServicesSchema = z.union([z.array(publicAppointmentServic
58614
59118
  services: z.array(publicAppointmentServiceSchema),
58615
59119
  categories: z.array(publicServiceCategorySchema)
58616
59120
  })]);
59121
+ /**
59122
+ * How many services the loader's data lists, or null when the data isn't the
59123
+ * catalogue at all (a failed load). For composers deciding whether the block
59124
+ * has anything to show, so they read the data the way the block does.
59125
+ */
59126
+ function countPublicAppointmentServices(value) {
59127
+ const result = publicAppointmentServicesSchema.safeParse(value);
59128
+ return result.success ? result.data.services.length : null;
59129
+ }
58617
59130
  const EMPTY_MESSAGE = "No appointments are available right now.";
58618
59131
  const ERROR_MESSAGE = "Appointments are temporarily unavailable. Please try again shortly.";
58619
59132
  const OTHER_GROUP_KEY = "other";
@@ -58962,16 +59475,6 @@ function appointmentServicesListing(view, arrangement) {
58962
59475
  } : view;
58963
59476
  }
58964
59477
 
58965
- //#endregion
58966
- //#region ../blocks/src/system/blocks/shared/teamMembers.ts
58967
- const teamMemberSpecialtiesInputSchema = z.union([z.string(), z.array(z.string())]).nullish();
58968
- function parseTeamMemberSpecialties(value) {
58969
- const parsed = teamMemberSpecialtiesInputSchema.safeParse(value);
58970
- if (!parsed.success) return [];
58971
- const parts = typeof parsed.data === "string" ? parsed.data.split(/\r?\n|,/) : parsed.data ?? [];
58972
- return [...new Set(parts.map((part) => part.trim()).filter(Boolean))];
58973
- }
58974
-
58975
59478
  //#endregion
58976
59479
  //#region ../blocks/src/system/runtime/nodes/team-members.tsx
58977
59480
  const teamMemberCardSchema = z.object({
@@ -58981,12 +59484,13 @@ const teamMemberCardSchema = z.object({
58981
59484
  bio: z.union([z.string(), RichTextDocSchema]).nullish(),
58982
59485
  profileBio: RichTextDocSchema.nullish(),
58983
59486
  photo: runtimeMediaSchema.refine((value) => value.type === "image").nullish(),
59487
+ summary: z.string().nullish(),
58984
59488
  profilePath: z.string().nullish(),
58985
59489
  specialties: z.unknown().transform(parseTeamMemberSpecialties)
58986
59490
  });
58987
59491
  /** Staff and manual members meet at one boundary; Look data chooses biography length. */
58988
- function teamMemberCardContent(member, index, biographySource) {
58989
- const biography = biographySource === "profile" && member.profileBio ? member.profileBio : member.bio;
59492
+ function teamMemberCardContent(member, index, biographySource, cardBiography) {
59493
+ const biography = cardBiography === "any" ? cardText(teamMemberCardBiography(member)) : biographySource === "profile" && member.profileBio ? member.profileBio : member.bio;
58990
59494
  const href = sanitizeHref(member.profilePath);
58991
59495
  return {
58992
59496
  id: member.id ?? `member-${index}`,
@@ -59004,12 +59508,84 @@ function teamMemberCardContent(member, index, biographySource) {
59004
59508
  } } : {}
59005
59509
  };
59006
59510
  }
59511
+ function cardText(biography) {
59512
+ if (!biography) return null;
59513
+ return biography.kind === "document" ? biography.document : biography.paragraphs.join("\n\n");
59514
+ }
59515
+ /**
59516
+ * The quiet line under an "About" heading: the person's name and role. The
59517
+ * name is left out when the heading already says it, so it isn't read twice.
59518
+ */
59519
+ function teamMemberAboutLine(input) {
59520
+ const name = input.name.trim();
59521
+ const said = name.length > 0 && (input.heading ?? "").toLocaleLowerCase().includes(name.toLocaleLowerCase());
59522
+ const parts = [said ? "" : name, input.role?.trim() ?? ""].filter(Boolean);
59523
+ return parts.length > 0 ? parts.join(", ") : null;
59524
+ }
59525
+ /** The one person a section can be about: the list's only member, with a bio to read. */
59526
+ function personToWriteAbout(members) {
59527
+ const [member, ...others] = members;
59528
+ const biography = member && others.length === 0 ? teamMemberBiography(member) : null;
59529
+ return member && biography ? {
59530
+ member,
59531
+ biography
59532
+ } : null;
59533
+ }
59534
+ /**
59535
+ * One person given the section: their photo in the look's frame, a name and
59536
+ * role line, and their bio in full. The section's heading stays where the
59537
+ * block puts it; the stylesheet sets it beside the photo.
59538
+ */
59539
+ function TeamMemberAbout({ member, biography, props: props$1 }) {
59540
+ const line = teamMemberAboutLine({
59541
+ heading: props$1.sectionHeading,
59542
+ name: member.name,
59543
+ role: member.role
59544
+ });
59545
+ const photo = props$1.showPhotos === false ? null : member.photo;
59546
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
59547
+ className: "rb-team-about",
59548
+ "data-team-about": true,
59549
+ "data-has-photo": String(Boolean(photo)),
59550
+ children: [
59551
+ photo ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
59552
+ className: "rb-team-about-photo",
59553
+ ...listLookSlot(props$1, "item-media"),
59554
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MediaNodeServer, {
59555
+ value: photo,
59556
+ size: ImagePresets.hero,
59557
+ ...listLookSlot(props$1, "photo")
59558
+ })
59559
+ }) : null,
59560
+ line ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
59561
+ className: "rb-team-about-line",
59562
+ ...listLookSlot(props$1, "item-meta"),
59563
+ children: line
59564
+ }) : null,
59565
+ biography.kind === "document" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RichText, {
59566
+ doc: biography.document,
59567
+ className: "rb-team-about-bio",
59568
+ ...listLookSlot(props$1, "item-text"),
59569
+ lookSlots: props$1.lookSlots
59570
+ }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
59571
+ className: "rb-team-about-bio",
59572
+ ...listLookSlot(props$1, "item-text"),
59573
+ children: biography.paragraphs.map((paragraph, index) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { children: paragraph }, index))
59574
+ })
59575
+ ]
59576
+ });
59577
+ }
59007
59578
  function TeamMembersNode(props$1) {
59008
59579
  const parsed = z.array(teamMemberCardSchema).safeParse(props$1.source === "site_staff" ? props$1.siteMembers : props$1.members);
59009
59580
  if (!parsed.success) return null;
59581
+ const about = props$1.onePerson === "about" ? personToWriteAbout(parsed.data) : null;
59582
+ if (about) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TeamMemberAbout, {
59583
+ ...about,
59584
+ props: props$1
59585
+ });
59010
59586
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CardListItems, {
59011
59587
  Carousel: props$1.Carousel,
59012
- items: parsed.data.map((member, index) => teamMemberCardContent(member, index, props$1.biographySource)),
59588
+ items: parsed.data.map((member, index) => teamMemberCardContent(member, index, props$1.biographySource, props$1.cardBiography)),
59013
59589
  presentation: {
59014
59590
  ...props$1,
59015
59591
  bodyParts: [
@@ -59140,77 +59716,68 @@ function getBookingRedirectStateFromLocation(location) {
59140
59716
  return { kind: "none" };
59141
59717
  }
59142
59718
  function resolveAppointmentCheckoutVerificationState(input) {
59143
- if (!input.config) {
59144
- return { tag: "idle" };
59719
+ if (!input.config) return { tag: "idle" };
59720
+ const sessionId = input.config.sessionId;
59721
+ if (input.pollingStatus === "completed") {
59722
+ const confirmed = confirmedAppointmentCheckout(sessionId, input.result);
59723
+ if (confirmed) return confirmed;
59145
59724
  }
59146
59725
  const appointmentId = input.result?.appointmentId ?? null;
59147
- const paymentStatus = input.result?.paymentStatus ?? null;
59148
- const appointmentStatus = input.result?.appointmentStatus ?? null;
59149
- if (input.pollingStatus === "completed" && appointmentId && (paymentStatus === "completed" || paymentStatus === "not_required")) {
59150
- return {
59151
- tag: "confirmed",
59152
- sessionId: input.config.sessionId,
59153
- appointmentId,
59154
- resourceName: input.result?.resourceName ?? null,
59155
- paymentStatus
59156
- };
59157
- }
59158
- if (input.pollingStatus === "timeout") {
59159
- return {
59726
+ switch (input.pollingStatus) {
59727
+ case "timeout": return {
59160
59728
  tag: "timeout",
59161
- sessionId: input.config.sessionId,
59729
+ sessionId,
59162
59730
  appointmentId,
59163
59731
  message: checkoutCopy.checkoutStillConfirming
59164
59732
  };
59165
- }
59166
- if (input.pollingStatus === "failed") {
59167
- if (paymentStatus === "refunded") {
59168
- return {
59169
- tag: "failed",
59170
- sessionId: input.config.sessionId,
59171
- reason: "payment_refunded",
59172
- message: "Payment was refunded. Please contact support.",
59173
- appointmentId
59174
- };
59175
- }
59176
- if (paymentStatus === "cancelled") {
59177
- return {
59178
- tag: "failed",
59179
- sessionId: input.config.sessionId,
59180
- reason: "checkout_cancelled",
59181
- message: "Checkout was cancelled before the appointment could be confirmed.",
59182
- appointmentId
59183
- };
59184
- }
59185
- if (appointmentStatus === "cancelled") {
59186
- return {
59187
- tag: "failed",
59188
- sessionId: input.config.sessionId,
59189
- reason: "appointment_cancelled",
59190
- message: "The appointment was cancelled before it could be confirmed.",
59191
- appointmentId
59192
- };
59193
- }
59194
- if (paymentStatus === "failed") {
59195
- return {
59196
- tag: "failed",
59197
- sessionId: input.config.sessionId,
59198
- reason: "payment_failed",
59199
- message: "Payment could not be verified. Please try again.",
59200
- appointmentId
59201
- };
59202
- }
59203
- return {
59733
+ case "failed": return {
59204
59734
  tag: "failed",
59205
- sessionId: input.config.sessionId,
59206
- reason: "unknown",
59207
- message: input.error?.message ?? "Payment could not be verified. Please try again.",
59208
- appointmentId
59735
+ sessionId,
59736
+ appointmentId,
59737
+ ...appointmentCheckoutFailure(input.result, input.error)
59738
+ };
59739
+ case "completed":
59740
+ case "idle":
59741
+ case "polling": return {
59742
+ tag: "verifying",
59743
+ sessionId
59209
59744
  };
59210
59745
  }
59746
+ }
59747
+ /** Verified payment carries its booked facts instead of asking the view to rebuild them. */
59748
+ function confirmedAppointmentCheckout(sessionId, result) {
59749
+ if (!result || !result.appointmentId) return null;
59750
+ if (result.paymentStatus !== "completed" && result.paymentStatus !== "not_required") return null;
59211
59751
  return {
59212
- tag: "verifying",
59213
- sessionId: input.config.sessionId
59752
+ tag: "confirmed",
59753
+ sessionId,
59754
+ appointmentId: result.appointmentId,
59755
+ appointment: result.appointment,
59756
+ resourceName: result.resourceName,
59757
+ paymentStatus: result.paymentStatus
59758
+ };
59759
+ }
59760
+ /** Failure priority is shared by every polling failure, including missing provider evidence. */
59761
+ function appointmentCheckoutFailure(result, error$1) {
59762
+ if (result?.paymentStatus === "refunded") return {
59763
+ reason: "payment_refunded",
59764
+ message: "Payment was refunded. Please contact support."
59765
+ };
59766
+ if (result?.paymentStatus === "cancelled") return {
59767
+ reason: "checkout_cancelled",
59768
+ message: "Checkout was cancelled before the appointment could be confirmed."
59769
+ };
59770
+ if (result?.appointmentStatus === "cancelled") return {
59771
+ reason: "appointment_cancelled",
59772
+ message: "The appointment was cancelled before it could be confirmed."
59773
+ };
59774
+ if (result?.paymentStatus === "failed") return {
59775
+ reason: "payment_failed",
59776
+ message: "Payment could not be verified. Please try again."
59777
+ };
59778
+ return {
59779
+ reason: "unknown",
59780
+ message: error$1?.message ?? "Payment could not be verified. Please try again."
59214
59781
  };
59215
59782
  }
59216
59783
  function deriveBookingFormViewState(input) {
@@ -60288,12 +60855,6 @@ function parseLimit$1(value, fallback) {
60288
60855
  const n$1 = typeof value === "string" ? parseInt(value, 10) : typeof value === "number" ? value : NaN;
60289
60856
  return Number.isFinite(n$1) && n$1 > 0 ? n$1 : fallback;
60290
60857
  }
60291
- function isFutureOrNow(iso, nowIso) {
60292
- const ts = Date.parse(iso);
60293
- const now = Date.parse(nowIso);
60294
- if (!Number.isFinite(ts) || !Number.isFinite(now)) return false;
60295
- return ts >= now;
60296
- }
60297
60858
  function uniqByOccurrenceId(events) {
60298
60859
  const seen = new Set();
60299
60860
  const out = [];
@@ -60305,45 +60866,6 @@ function uniqByOccurrenceId(events) {
60305
60866
  }
60306
60867
  return out;
60307
60868
  }
60308
- function selectFromOccurrenceContext(events, occurrenceContext) {
60309
- if (!occurrenceContext) return null;
60310
- const byId = events.find((event) => event.occurrenceId === occurrenceContext.id || event.id === occurrenceContext.id);
60311
- if (byId) return byId;
60312
- const contextDate = getBookingLocalDateKey(toScheduledBookingDateTime({
60313
- startsAt: occurrenceContext.startsAt,
60314
- timeZone: occurrenceContext.timeZone
60315
- }));
60316
- return events.find((event) => getBookingLocalDateKey(toScheduledBookingDateTime({
60317
- startsAt: event.startsAt,
60318
- timeZone: event.timeZone
60319
- })) === contextDate) ?? null;
60320
- }
60321
- function selectNextUpcoming(events, nowIso) {
60322
- return [...events].filter((event) => isFutureOrNow(event.startsAt, nowIso)).sort((left, right) => Date.parse(left.startsAt) - Date.parse(right.startsAt))[0] ?? null;
60323
- }
60324
- function selectCompletedWholeSeries(events) {
60325
- if (events.length === 0 || !events.every((event) => event.bookingScope === "whole_series")) {
60326
- return null;
60327
- }
60328
- return [...events].sort((left, right) => Date.parse(right.startsAt) - Date.parse(left.startsAt))[0] ?? null;
60329
- }
60330
- function selectEventCandidate(events, occurrenceContext, nowIso) {
60331
- const selected = selectFromOccurrenceContext(events, occurrenceContext);
60332
- if (selected) return {
60333
- event: selected,
60334
- mode: "selected"
60335
- };
60336
- const upcoming = selectNextUpcoming(events, nowIso);
60337
- if (upcoming) return {
60338
- event: upcoming,
60339
- mode: "next"
60340
- };
60341
- const completed = selectCompletedWholeSeries(events);
60342
- return completed ? {
60343
- event: completed,
60344
- mode: "completed"
60345
- } : null;
60346
- }
60347
60869
  function isWholeSeriesEvent(event) {
60348
60870
  return event.bookingScope === "whole_series";
60349
60871
  }
@@ -60378,7 +60900,7 @@ function selectEventDetails(args) {
60378
60900
  const all = uniqByOccurrenceId(scopedEvents);
60379
60901
  const occurrenceContext = args.occurrenceContext ?? null;
60380
60902
  const otherLimit = parseLimit$1(args.otherDatesLimit, 5);
60381
- const candidate = selectEventCandidate(all, occurrenceContext, args.nowIso);
60903
+ const candidate = selectEventDetailsCandidate(all, occurrenceContext, args.nowIso);
60382
60904
  const rawTz = candidate?.event.timeZone ?? all[0]?.timeZone ?? null;
60383
60905
  const timeZone = toBookingTimeZone(rawTz);
60384
60906
  if (!candidate) return emptySelection(timeZone);
@@ -60445,6 +60967,10 @@ function resolveEligibility(input, selected) {
60445
60967
  applicableMemberships: filterMembershipsForEvent(input.siteMemberships?.memberships ?? null, selected)
60446
60968
  };
60447
60969
  }
60970
+ /** The response's one drawing belongs to the selected event only when it is for that event's venue. */
60971
+ function resolveSelectedVenueDrawing(venueDrawing, selected) {
60972
+ return venueDrawing && selected?.venue?.id === venueDrawing.venueId ? venueDrawing.drawing : null;
60973
+ }
60448
60974
  function resolveEventDetailsPresentation(input) {
60449
60975
  const selection = resolveSelection(input);
60450
60976
  const selected = selection.kind === "empty" ? null : selection.selected;
@@ -60458,7 +60984,8 @@ function resolveEventDetailsPresentation(input) {
60458
60984
  panelHeading: input.panelHeading,
60459
60985
  ...resolveDisplaySettings(input),
60460
60986
  ...resolveEligibility(input, selected),
60461
- autoApplyDiscount: input.autoApplyDiscount ?? null
60987
+ autoApplyDiscount: input.autoApplyDiscount ?? null,
60988
+ selectedVenueDrawing: resolveSelectedVenueDrawing(input.venueDrawing, selected)
60462
60989
  };
60463
60990
  }
60464
60991
 
@@ -60900,7 +61427,11 @@ function EventVenueFact({ venue }) {
60900
61427
  venue.address ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
60901
61428
  className: "rb-caption",
60902
61429
  children: venue.address
60903
- }) : null
61430
+ }) : null,
61431
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LocationMapActions, {
61432
+ location: venue.location,
61433
+ addressText: venue.address
61434
+ })
60904
61435
  ]
60905
61436
  }) : null;
60906
61437
  }
@@ -61041,11 +61572,11 @@ function acceptedProductNames(props$1) {
61041
61572
  const memberships = props$1.showAcceptedMemberships !== false ? (props$1.applicableMemberships ?? []).map(({ name }) => name) : [];
61042
61573
  return [...passes, ...memberships];
61043
61574
  }
61044
- function EventVenueMap({ venue, showMap, mapHeight, mapClassName, renderVenueMap }) {
61045
- if (!showMap || !renderVenueMap || !venue?.location) return null;
61046
- return renderVenueMap({
61047
- venueName: venue.name,
61048
- location: venue.location,
61575
+ function EventVenueMap({ venue, drawing, showMap, mapHeight, mapClassName }) {
61576
+ if (!showMap || !venue || !drawing) return null;
61577
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MapDrawingSvg, {
61578
+ drawing,
61579
+ label: venue.name,
61049
61580
  className: mapClassName,
61050
61581
  height: mapHeight
61051
61582
  });
@@ -61064,7 +61595,7 @@ function selectedEventPricing(event, showCost) {
61064
61595
  };
61065
61596
  }
61066
61597
  function SelectedEventDetailsView(props$1) {
61067
- const { selection, showVenue, showMap, showOtherDates, showTitle, showDescription, showCapacity, mapHeight, mapClassName, renderVenueMap, acceptedItems } = props$1;
61598
+ const { selection, showVenue, showMap, showOtherDates, showTitle, showDescription, showCapacity, mapHeight, mapClassName, acceptedItems } = props$1;
61068
61599
  const selected = selection.selected;
61069
61600
  const venue = showVenue ? selected.venue : undefined;
61070
61601
  const pricing = selectedEventPricing(selected, props$1.showCost);
@@ -61096,7 +61627,7 @@ function SelectedEventDetailsView(props$1) {
61096
61627
  showMap,
61097
61628
  mapHeight,
61098
61629
  mapClassName,
61099
- renderVenueMap
61630
+ drawing: props$1.selectedVenueDrawing
61100
61631
  })]
61101
61632
  }),
61102
61633
  showOtherDates ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(OtherEventDates, { selection }) : null
@@ -61121,9 +61652,9 @@ function LegacyEventDetailsView(props$1) {
61121
61652
  showDescription: props$1.showDescription ?? false,
61122
61653
  showCapacity: props$1.showCapacity ?? false,
61123
61654
  autoApplyDiscount: props$1.autoApplyDiscount ?? null,
61655
+ selectedVenueDrawing: props$1.selectedVenueDrawing,
61124
61656
  mapHeight: props$1.mapHeight ?? 200,
61125
61657
  mapClassName: props$1.mapClassName ?? "event-details-map",
61126
- renderVenueMap: props$1.renderVenueMap,
61127
61658
  acceptedItems: acceptedProductNames(props$1)
61128
61659
  });
61129
61660
  }
@@ -61164,22 +61695,6 @@ function EventDetailsView(props$1) {
61164
61695
 
61165
61696
  //#endregion
61166
61697
  //#region ../blocks/src/system/runtime/nodes/event-details.server.tsx
61167
- function ServerVenueMap({ venueName, className, height }) {
61168
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
61169
- className: "event-details-map-wrap rb-w-full rb-ml-auto",
61170
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
61171
- className,
61172
- style: {
61173
- height: height ?? 200,
61174
- width: "100%",
61175
- borderRadius: "0.5rem",
61176
- overflow: "hidden",
61177
- backgroundColor: "rgb(var(--tb-surface))"
61178
- },
61179
- "aria-label": `Map showing ${venueName}`
61180
- })
61181
- });
61182
- }
61183
61698
  function EventDetailsHydration({ props: props$1, presentation, scopedEvents, subject, nowIso }) {
61184
61699
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IslandPropsScript, { value: {
61185
61700
  ...props$1.arrangement ? {
@@ -61193,6 +61708,7 @@ function EventDetailsHydration({ props: props$1, presentation, scopedEvents, sub
61193
61708
  occurrenceContext: props$1.occurrenceContext ?? null,
61194
61709
  subject,
61195
61710
  events: scopedEvents,
61711
+ venueDrawing: props$1.venueDrawing ?? null,
61196
61712
  showVenue: presentation.showVenue,
61197
61713
  showMap: presentation.showMap,
61198
61714
  showOtherDates: presentation.showOtherDates,
@@ -61239,8 +61755,7 @@ function EventDetailsSSR(props$1) {
61239
61755
  }),
61240
61756
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EventDetailsView, {
61241
61757
  ...presentation,
61242
- mapClassName: "venue-map event-details-map",
61243
- renderVenueMap: ServerVenueMap
61758
+ mapClassName: "venue-map event-details-map"
61244
61759
  }),
61245
61760
  children
61246
61761
  ]
@@ -61248,100 +61763,34 @@ function EventDetailsSSR(props$1) {
61248
61763
  }
61249
61764
  var event_details_server_default = EventDetailsSSR;
61250
61765
 
61251
- //#endregion
61252
- //#region ../blocks/src/system/runtime/nodes/location-map.view.tsx
61253
- function OpeningHoursTable({ hours: hours$1 }) {
61254
- if (!hours$1) return null;
61255
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("table", { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("caption", { children: "Opening hours" }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("tbody", { children: formatOpeningHoursRows(hours$1).map((row$1) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("tr", {
61256
- "data-closed": row$1.kind === "closed" ? true : undefined,
61257
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", {
61258
- scope: "row",
61259
- children: row$1.label
61260
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { children: row$1.hours })]
61261
- }, row$1.label)) })] }), hours$1.note ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { children: hours$1.note }) : null] });
61262
- }
61263
- function LocationMapDirections({ url, label }) {
61264
- return url ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ThemedButtonLink, {
61265
- href: url,
61266
- target: "_blank",
61267
- rel: "noreferrer",
61268
- variant: "ghost",
61269
- size: "sm",
61270
- extraClassName: "rb-w-fit",
61271
- label
61272
- }) : null;
61273
- }
61274
- function LocationMapView(props$1) {
61275
- const { addressText, location, renderMap, zoom, heightPx, showAddressText, directionsLabel } = props$1;
61276
- const directionsUrl = props$1.showDirections ? buildGoogleMapsDirectionsUrl({
61277
- addressText,
61278
- location
61279
- }) : null;
61280
- const hours$1 = props$1.showOpeningHours === false ? null : props$1.openingHours ?? null;
61281
- if (![
61282
- location,
61283
- addressText,
61284
- directionsUrl,
61285
- hours$1
61286
- ].some(Boolean)) {
61287
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
61288
- className: "rb-caption",
61289
- style: textColorStyle("mutedText"),
61290
- children: props$1.unresolvedMessage ?? "Location details coming soon."
61291
- });
61292
- }
61293
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
61294
- className: "rb-flex rb-flex-col rb-gap-4 rb-text-left",
61295
- children: [
61296
- location && renderMap ? renderMap({
61297
- addressText,
61298
- location,
61299
- className: "rb-location-map-canvas",
61300
- height: heightPx,
61301
- zoom
61302
- }) : null,
61303
- showAddressText && addressText ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
61304
- className: "rb-caption",
61305
- style: textColorStyle("mutedText"),
61306
- children: addressText
61307
- }) : null,
61308
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(OpeningHoursTable, { hours: hours$1 }),
61309
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LocationMapDirections, {
61310
- url: directionsUrl,
61311
- label: directionsLabel
61312
- })
61313
- ]
61314
- });
61315
- }
61316
-
61317
61766
  //#endregion
61318
61767
  //#region ../blocks/src/system/runtime/nodes/location-map.server.tsx
61768
+ const lookPresentationSchema = z.object({
61769
+ lookSlots: lookListPresentationSchemaShape.lookSlots,
61770
+ itemSurfaces: lookListPresentationSchemaShape.itemSurfaces
61771
+ });
61319
61772
  function LocationMapSSR(props$1) {
61320
61773
  const normalized = normalizeLocationMapProps(props$1);
61321
- const hydrationProps = toLocationMapHydrationProps(props$1);
61774
+ if (normalized.resolvedLocation.kind === "unresolved") return null;
61322
61775
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
61323
61776
  className: `location-map ${normalized.className ?? ""}`.trim(),
61324
61777
  "data-block": "location-map",
61325
- ...getIslandRootProps("location-map", props$1.blockId),
61326
- children: [
61327
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IslandPropsScript, { value: hydrationProps }),
61328
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LocationMapView, {
61329
- ...normalized,
61330
- renderMap: ({ addressText, className, height }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
61331
- className,
61332
- style: {
61333
- height,
61334
- width: "100%",
61335
- borderRadius: "0.75rem",
61336
- overflow: "hidden",
61337
- backgroundColor: "rgb(var(--tb-surface))"
61338
- },
61339
- "aria-label": addressText ? `Map showing ${addressText}` : "Map showing business location"
61340
- })
61341
- }),
61342
- props$1.children
61343
- ]
61778
+ style: props$1.mapStyle ?? undefined,
61779
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(LocationMapView, {
61780
+ ...normalized,
61781
+ showMap: props$1.showMap !== false,
61782
+ lookLayout: props$1.lookSlots != null,
61783
+ detailsSlot: lookDetailsSlot(props$1)
61784
+ }), props$1.children]
61785
+ });
61786
+ }
61787
+ /** Legacy and automatic-Look markup carries no slot; Look-only layouts mark the details as the panel. */
61788
+ function lookDetailsSlot(props$1) {
61789
+ const presentation = lookPresentationSchema.safeParse({
61790
+ lookSlots: props$1.lookSlots ?? undefined,
61791
+ itemSurfaces: props$1.itemSurfaces ?? undefined
61344
61792
  });
61793
+ return presentation.success ? listLookSlot(presentation.data, "panel") : {};
61345
61794
  }
61346
61795
  var location_map_server_default = LocationMapSSR;
61347
61796
 
@@ -61546,9 +61995,8 @@ var EventCombined_server_default = EventCombinedSSR;
61546
61995
  //#endregion
61547
61996
  //#region ../blocks/src/system/blocks/offerings-preview/itemData.ts
61548
61997
  function buildItemDataMap(props$1) {
61549
- const routeCandidates = props$1.routeCandidates?.routes ?? [];
61550
61998
  const entries = OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS.map((definition$1) => [definition$1.sourceKey, eventDataFromMaybeArray(props$1[definition$1.dataKey])]);
61551
- return new Map([...entries, ["course", runDataFromMaybeArray(props$1.wholeSeriesRunEvents, routeCandidates)]]);
61999
+ return new Map([...entries, ["course", runDataFromMaybeArray(props$1.wholeSeriesRunEvents)]]);
61552
62000
  }
61553
62001
  function eventDataFromMaybeArray(events) {
61554
62002
  return events ? {
@@ -61562,7 +62010,7 @@ function eventDataFromMaybeArray(events) {
61562
62010
  reason: "not_loaded"
61563
62011
  };
61564
62012
  }
61565
- function runDataFromMaybeArray(events, routes) {
62013
+ function runDataFromMaybeArray(events) {
61566
62014
  if (!events) return {
61567
62015
  kind: "failed",
61568
62016
  reason: "not_loaded"
@@ -61570,7 +62018,7 @@ function runDataFromMaybeArray(events, routes) {
61570
62018
  const items = [...groupPublicEventsByRun(events)].map((run) => ({
61571
62019
  kind: "run",
61572
62020
  run,
61573
- path: resolveOfferingsPreviewRunPath(run.run, routes)
62021
+ path: run.representative.destination.kind === "native" ? run.representative.destination.path : null
61574
62022
  }));
61575
62023
  return {
61576
62024
  kind: "ready",
@@ -61601,9 +62049,9 @@ function buildLoadedOfferingsPreviewListing(input) {
61601
62049
  //#endregion
61602
62050
  //#region ../blocks/src/system/runtime/nodes/events/shared/offeringNextDates.ts
61603
62051
  /** One occurrence batch supplies every occurrence-targeted card in the block. */
61604
- function offeringDatesBySeries(events, now) {
62052
+ function offeringDatesBySeries(events, now, booking) {
61605
62053
  const groups = events.reduce((result, event) => new Map([...result, [event.seriesId, [...result.get(event.seriesId) ?? [], event]]]), new Map());
61606
- return new Map([...groups].map(([seriesId, occurrences]) => [seriesId, orderedUniqueEventOccurrences(occurrences.filter((event) => event.bookingScope !== "whole_series" && Date.parse(event.startsAt) >= now.getTime())).slice(0, 3).map((event) => offeringDateRow(event, event))]));
62054
+ return new Map([...groups].map(([seriesId, occurrences]) => [seriesId, orderedUniqueEventOccurrences(occurrences.filter((event) => event.bookingScope !== "whole_series" && Date.parse(event.startsAt) >= now.getTime())).slice(0, 3).map((event) => offeringDateRow(event, event, booking))]));
61607
62055
  }
61608
62056
  /** Whole-series sessions share the run-level booking capacity, by contract. */
61609
62057
  function offeringRunDates(event, now) {
@@ -61611,7 +62059,7 @@ function offeringRunDates(event, now) {
61611
62059
  const nextStart = nextLiveRunSessionStartMs(event.run.sessions, now);
61612
62060
  return nextStart === null ? [] : orderedLiveRunSessions(event.run.sessions).filter((session) => Date.parse(session.startsAt) >= nextStart).slice(0, 3).map((session) => offeringDateRow(session, event));
61613
62061
  }
61614
- function offeringDateRow(session, event) {
62062
+ function offeringDateRow(session, event, booking) {
61615
62063
  const options = eventDateOptions({
61616
62064
  ...event,
61617
62065
  timeZone: session.timeZone
@@ -61619,9 +62067,12 @@ function offeringDateRow(session, event) {
61619
62067
  const date = formatEventCompactDateRail(session.startsAt, options, "as-written");
61620
62068
  const capacity = getEventAvailability(event);
61621
62069
  const status = getEventAvailabilityStatus(event);
62070
+ const label = `${date.weekday} ${date.day} ${date.month}, ${formatTime(session.startsAt, options)}`;
62071
+ const bookingLink = booking?.(event, label) ?? null;
61622
62072
  return {
61623
62073
  startsAt: session.startsAt,
61624
- label: `${date.weekday} ${date.day} ${date.month}, ${formatTime(session.startsAt, options)}`,
62074
+ label,
62075
+ ...bookingLink ? { booking: bookingLink } : {},
61625
62076
  places: capacity.available === null ? null : {
61626
62077
  label: capacity.isFull ? "Sold out" : `${capacity.available} place${capacity.available === 1 ? "" : "s"} left`,
61627
62078
  status: capacity.isFull ? "full" : status.status === "filling" ? "low" : "available"
@@ -61640,6 +62091,10 @@ function OfferingsCatalogue(props$1) {
61640
62091
  presets: props$1.bookingOfferingPresets,
61641
62092
  events: props$1.catalogueEvents
61642
62093
  });
62094
+ const shape = offeringsCatalogueShape(state, {
62095
+ listDates: props$1.lookSlots !== undefined && props$1.datesMode === "next-dates",
62096
+ oneOfferingRequested: props$1.oneOffering === true
62097
+ });
61643
62098
  switch (state.kind) {
61644
62099
  case "no-groups": return renderCatalogueEmpty({
61645
62100
  props: props$1,
@@ -61652,7 +62107,8 @@ function OfferingsCatalogue(props$1) {
61652
62107
  case "by-date": return renderCatalogueMergedList({
61653
62108
  props: props$1,
61654
62109
  listing: state,
61655
- now
62110
+ now,
62111
+ shape
61656
62112
  });
61657
62113
  case "by-type": return props$1.lookSlots ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
61658
62114
  ...listLookSlot(props$1, "layout"),
@@ -61665,26 +62121,37 @@ function OfferingsCatalogue(props$1) {
61665
62121
  now,
61666
62122
  children: undefined
61667
62123
  },
61668
- groups: state.groups
62124
+ groups: state.groups,
62125
+ shape
61669
62126
  }) })]
61670
62127
  }) : renderOfferingsCatalogueGroups({
61671
62128
  props: {
61672
62129
  ...props$1,
61673
62130
  now
61674
62131
  },
61675
- groups: state.groups
62132
+ groups: state.groups,
62133
+ shape
61676
62134
  });
61677
62135
  default: return assertNever(state);
61678
62136
  }
61679
62137
  }
61680
- function renderOfferingsCatalogueGroups({ props: props$1, groups }) {
62138
+ /** The hook the single-offering layout hangs from; absent for several. */
62139
+ function catalogueShapeHook(shape) {
62140
+ return shape === "single" ? { "data-has-one-offering": "true" } : {};
62141
+ }
62142
+ /** One offering has room for a Book link on each date; several keep plain rows. */
62143
+ function catalogueDateBooking(shape, pathname) {
62144
+ return shape === "single" ? (event, dateLabel$1) => eventDateBookingLink(event, pathname ?? "/", dateLabel$1) : undefined;
62145
+ }
62146
+ function renderOfferingsCatalogueGroups({ props: props$1, groups, shape }) {
61681
62147
  const enabledSeriesIds = new Set(groups.flatMap((load) => load.kind === "items" ? load.items.map((item) => item.kind === "event" ? item.event.seriesId : item.run.eventSeriesId) : []));
61682
- const quickDateEvents = selectQuickDateEvents((props$1.quickDateEvents ?? []).filter((event) => enabledSeriesIds.has(event.seriesId)));
62148
+ const quickDateEvents = shape === "single" ? [] : selectQuickDateEvents((props$1.quickDateEvents ?? []).filter((event) => enabledSeriesIds.has(event.seriesId)));
61683
62149
  const populated = groups.flatMap(catalogueGroupItems);
61684
62150
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
61685
62151
  className: "offerings-preview rb-flex rb-flex-col rb-gap-6",
61686
62152
  "data-block": "offerings-preview",
61687
62153
  "data-offerings-mode": "catalogue",
62154
+ ...catalogueShapeHook(shape),
61688
62155
  children: [
61689
62156
  quickDateEvents.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
61690
62157
  className: "offerings-preview-quick-dates rb-flex rb-flex-col rb-gap-4",
@@ -61701,28 +62168,30 @@ function renderOfferingsCatalogueGroups({ props: props$1, groups }) {
61701
62168
  children: populated.map(({ group, items }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", {
61702
62169
  className: "rb-flex rb-flex-col rb-gap-5",
61703
62170
  "data-offering-source": group.sourceKey,
61704
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", {
62171
+ children: [shape === "single" ? null : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", {
61705
62172
  ...listLookSlot(props$1, "heading"),
61706
62173
  children: group.title
61707
62174
  }), renderCatalogueItems({
61708
62175
  props: props$1,
61709
- items
62176
+ items,
62177
+ shape,
62178
+ groupTitle: group.title
61710
62179
  })]
61711
62180
  }, group.sourceKey))
61712
62181
  })
61713
62182
  ]
61714
62183
  });
61715
62184
  }
61716
- function renderCatalogueItems({ props: props$1, items }) {
62185
+ function renderCatalogueItems({ props: props$1, items, shape, groupTitle }) {
61717
62186
  const events = items.map((item) => item.kind === "event" ? item.event : item.run.representative);
61718
62187
  if (props$1.lookSlots) {
61719
62188
  const now = props$1.now;
61720
- const dates = offeringDatesBySeries(props$1.quickDateEvents ?? [], now);
62189
+ const dates = offeringDatesBySeries(props$1.quickDateEvents ?? [], now, catalogueDateBooking(shape, props$1.pathname));
61721
62190
  return CardListItems({
61722
62191
  Carousel: props$1.Carousel,
61723
- Title: "h4",
62192
+ Title: shape === "single" ? "h3" : "h4",
61724
62193
  presentation: props$1,
61725
- items: items.map((item) => catalogueCardContent(item, now, dates))
62194
+ items: items.map((item) => catalogueCardContent(item, now, dates, shape === "single" ? groupTitle : undefined))
61726
62195
  });
61727
62196
  }
61728
62197
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
@@ -61757,11 +62226,12 @@ function renderCatalogueEmpty({ props: props$1, failed }) {
61757
62226
  })]
61758
62227
  });
61759
62228
  }
61760
- function renderCatalogueMergedList({ props: props$1, listing, now }) {
61761
- const dates = offeringDatesBySeries(props$1.quickDateEvents ?? [], now);
62229
+ function renderCatalogueMergedList({ props: props$1, listing, now, shape }) {
62230
+ const dates = offeringDatesBySeries(props$1.quickDateEvents ?? [], now, catalogueDateBooking(shape, props$1.pathname));
61762
62231
  const items = listing.items.map(({ item, group }) => catalogueCardContent(item, now, dates, group.singularLabel));
61763
62232
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
61764
62233
  ...listLookSlot(props$1, "layout"),
62234
+ ...catalogueShapeHook(shape),
61765
62235
  children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("header", {
61766
62236
  ...listLookSlot(props$1, "head"),
61767
62237
  children: props$1.children
@@ -67426,7 +67896,7 @@ function prepareBlockRender(input) {
67426
67896
  resolvedThemeConfig: resolveThemeConfigForBindings(input.themeConfig),
67427
67897
  viewModelOverrides: input.viewModelOverrides
67428
67898
  }),
67429
- themeForTransforms: withButtonSystem(input.theme, input.themeConfig),
67899
+ themeForTransforms: withThemeRuntimeFacts(input.theme, input.themeConfig),
67430
67900
  proseHoverCandidate: parseThemeColorToken(input.themeConfig?.typography.proseLinkStyle?.hoverColorToken) ?? undefined
67431
67901
  };
67432
67902
  }
@@ -67446,11 +67916,13 @@ function buildBlockViewModel(input) {
67446
67916
  }
67447
67917
  };
67448
67918
  }
67449
- function withButtonSystem(theme, themeConfig) {
67919
+ /** The theme facts transforms decide from: button system, and the arrangement skin map tokens follow. */
67920
+ function withThemeRuntimeFacts(theme, themeConfig) {
67450
67921
  if (!themeConfig) return theme;
67451
67922
  return {
67452
67923
  ...theme,
67453
- buttons: themeConfig.buttons ?? generateDefaultButtonSystem(themeConfig)
67924
+ buttons: themeConfig.buttons ?? generateDefaultButtonSystem(themeConfig),
67925
+ ...themeConfig.skin === undefined ? {} : { skin: themeConfig.skin }
67454
67926
  };
67455
67927
  }
67456
67928
  function beginBlockRenderMeasurement() {
@@ -68385,12 +68857,31 @@ function getRenderableContent(block, previewStage = "published") {
68385
68857
  return selectBlockContent(block, previewStage);
68386
68858
  }
68387
68859
  function arrangementRuntime(content) {
68388
- const value = content._arrangementLooks;
68389
- return isObjectRecord(value) && isObjectRecord(value.byMode) && Array.isArray(value.available) && Array.isArray(value.rhythm) ? value : null;
68860
+ const value = parseSurfaceTree(content._arrangementLooks);
68861
+ return isObjectRecord(value) && isObjectRecord(value.byMode) && Array.isArray(value.available) && Array.isArray(value.rhythm) ? restoreArrangementRuntime(value) : null;
68862
+ }
68863
+ /** JSON transports carry resolver inputs; rebuild every surface at this boundary. */
68864
+ function restoreCompiledLook(look) {
68865
+ return {
68866
+ ...look,
68867
+ itemSurfaces: Object.fromEntries(Object.entries(look.itemSurfaces).map(([slot, surface]) => [slot, parseResolvedSurface(surface)])),
68868
+ ...look.roleSurfaces ? { roleSurfaces: {
68869
+ card: parseResolvedSurface(look.roleSurfaces.card),
68870
+ statement: parseResolvedSurface(look.roleSurfaces.statement),
68871
+ highlight: parseResolvedSurface(look.roleSurfaces.highlight)
68872
+ } } : {}
68873
+ };
68874
+ }
68875
+ function restoreArrangementRuntime(runtime) {
68876
+ return {
68877
+ ...runtime,
68878
+ available: runtime.available.map(restoreCompiledLook),
68879
+ byMode: Object.fromEntries(Object.entries(runtime.byMode).map(([mode, look]) => [mode, restoreCompiledLook(look)]))
68880
+ };
68390
68881
  }
68391
68882
  function effectiveLookFromContent(content) {
68392
68883
  const value = content._effectiveLook;
68393
- return isObjectRecord(value) && isObjectRecord(value.look) ? value : null;
68884
+ return isObjectRecord(value) && isObjectRecord(value.look) ? restoreCompiledLook(value) : null;
68394
68885
  }
68395
68886
  function planArrangementContent(blockKind, manifest, content, audience) {
68396
68887
  const runtime = arrangementRuntime(content);
@@ -68425,6 +68916,7 @@ function planArrangementContent(blockKind, manifest, content, audience) {
68425
68916
  });
68426
68917
  return {
68427
68918
  ...activeContent,
68919
+ ...mode !== null ? { variant: mode } : {},
68428
68920
  ...effectiveContent,
68429
68921
  ...photoContent,
68430
68922
  ...arrangementShapeContent(effective.look.id, {
@@ -68433,6 +68925,7 @@ function planArrangementContent(blockKind, manifest, content, audience) {
68433
68925
  }),
68434
68926
  ...arrangementPanelContent(activeContent, effective, mode),
68435
68927
  ...arrangementQuoteContent(blockKind, effective, values),
68928
+ _arrangementLooks: runtime,
68436
68929
  _effectiveLook: effective,
68437
68930
  _lookHooks: arrangementContentHooks(effective, mode, length, {
68438
68931
  ...facts,
@@ -68492,7 +68985,8 @@ function arrangementContentFacts(content) {
68492
68985
  facts: Array.isArray(content.facts) && content.facts.length > 0,
68493
68986
  featured,
68494
68987
  outcome: typeof content.outcome === "string" && content.outcome.length > 0,
68495
- figure: typeof content.figure === "string" && content.figure.trim().length > 0
68988
+ figure: typeof content.figure === "string" && content.figure.trim().length > 0,
68989
+ entrance: isObjectRecord(content.entrancePhoto)
68496
68990
  }
68497
68991
  };
68498
68992
  }
@@ -68501,7 +68995,7 @@ function arrangementPhotoCount(content) {
68501
68995
  if (Array.isArray(content.cards)) return content.cards.filter((card) => isObjectRecord(card) && isObjectRecord(card.media)).length;
68502
68996
  if (Array.isArray(content.members)) return content.members.filter((member) => isObjectRecord(member) && isObjectRecord(member.photo)).length;
68503
68997
  if (Array.isArray(content.images)) return content.images.filter((item) => isObjectRecord(item) && isObjectRecord(item.image)).length;
68504
- if (isObjectRecord(content.media)) return 1;
68998
+ if (isObjectRecord(content.media) || isObjectRecord(content.entrancePhoto)) return 1;
68505
68999
  const section$2 = isObjectRecord(content._sectionStyles) ? content._sectionStyles : {};
68506
69000
  const background = isObjectRecord(section$2.background) ? section$2.background : {};
68507
69001
  return isObjectRecord(background.image) ? 1 : 0;
@@ -76927,11 +77421,11 @@ function isManagementPage(value) {
76927
77421
  function isManagementBlock(value) {
76928
77422
  return "kind" in value;
76929
77423
  }
76930
- function singlePlannedCommand(commands) {
76931
- if (commands.length !== 1) {
76932
- throw new Error(`Expected exactly one one-off site command, got ${commands.length}.`);
77424
+ function singlePlannedCommand(commands$1) {
77425
+ if (commands$1.length !== 1) {
77426
+ throw new Error(`Expected exactly one one-off site command, got ${commands$1.length}.`);
76933
77427
  }
76934
- const plannedCommand = commands[0];
77428
+ const plannedCommand = commands$1[0];
76935
77429
  if (!plannedCommand) {
76936
77430
  throw new Error("Expected one one-off site command, got none.");
76937
77431
  }
@@ -77418,7 +77912,7 @@ function parseJson(text$1) {
77418
77912
  }
77419
77913
  /** The revision a push must present: whatever the page holds right now. */
77420
77914
  function expectedRevisionFor(read) {
77421
- return read.kind === "absent" ? { kind: "absent" } : read.revision;
77915
+ return read.revision;
77422
77916
  }
77423
77917
  /** Plain data with object keys in a fixed order, so equal designs compare equal. */
77424
77918
  function canonical(value) {
@@ -79405,7 +79899,7 @@ async function loadConfig(configPath, output) {
79405
79899
  return { errorMessage: "No config path provided." };
79406
79900
  }
79407
79901
  try {
79408
- const { loadConfigFile: loadConfigFile$1 } = await import("../load-config-C7Rd822n.mjs");
79902
+ const { loadConfigFile: loadConfigFile$1 } = await import("../load-config-zu397zDX.mjs");
79409
79903
  const rawConfig = await loadConfigFile$1(configPath);
79410
79904
  const parsed = riverbankSiteConfigSchema.safeParse(rawConfig);
79411
79905
  if (!parsed.success) {
@@ -79490,64 +79984,6 @@ const createInitDocsCommand = () => new Command("init-docs").description("Scaffo
79490
79984
  await runInitDocs(options, command);
79491
79985
  }));
79492
79986
 
79493
- //#endregion
79494
- //#region src/commands/identifiers.ts
79495
- /**
79496
- * Identifiers Command
79497
- *
79498
- * Manage SDK identifiers for pages, blocks, and entries.
79499
- *
79500
- * Usage:
79501
- * riverbankcms identifiers backfill # Backfill identifiers for content without them
79502
- */
79503
- function createBackfillCommand() {
79504
- return new Command("backfill").description("Backfill identifiers for pages, blocks, and entries that don't have one").addHelpText("after", `
79505
- This command generates stable identifiers for content created before the SDK was available.
79506
- Identifiers are generated from titles (slugified) and are idempotent - running this
79507
- command multiple times won't overwrite existing identifiers.
79508
-
79509
- Examples:
79510
- $ riverbankcms identifiers backfill
79511
- $ riverbankcms identifiers backfill --env=remote
79512
- `).action(withErrorHandling(async (_options, command) => {
79513
- const { output, client } = createCommandContext(command);
79514
- output.info("Backfilling identifiers for pages, blocks, and entries...");
79515
- const result = await client.identifiers.backfill();
79516
- const totalUpdated = result.pages.pagesUpdated + result.blocks.total + result.entries.entriesUpdated;
79517
- if (totalUpdated === 0) {
79518
- output.success("All content already has identifiers - nothing to backfill");
79519
- return;
79520
- }
79521
- output.success("Backfill complete", {
79522
- pages: {
79523
- updated: result.pages.pagesUpdated,
79524
- identifiers: result.pages.identifiersAssigned
79525
- },
79526
- blocks: {
79527
- updated: result.blocks.total,
79528
- byPage: Object.keys(result.blocks.byPage).length > 0 ? result.blocks.byPage : undefined
79529
- },
79530
- entries: {
79531
- updated: result.entries.entriesUpdated,
79532
- identifiers: result.entries.identifiersAssigned
79533
- }
79534
- });
79535
- }));
79536
- }
79537
- function createIdentifiersCommand() {
79538
- return new Command("identifiers").description("Manage SDK identifiers").addHelpText("after", `
79539
- Identifiers are stable, human-readable names used to reference content in the SDK.
79540
- They are automatically generated when content is created via the SDK, but older
79541
- content may need backfilling.
79542
-
79543
- Commands:
79544
- backfill Generate identifiers for content that doesn't have one
79545
-
79546
- Examples:
79547
- $ riverbankcms identifiers backfill
79548
- `).addCommand(createBackfillCommand());
79549
- }
79550
-
79551
79987
  //#endregion
79552
79988
  //#region src/constants.ts
79553
79989
  /** Default directory used by the deploy command for generated prebuild data. */
@@ -90802,6 +91238,13 @@ function parsePreviewRefreshResponse(value) {
90802
91238
  };
90803
91239
  }
90804
91240
  const previewStopRequestSchema = z.object({ accessToken: z.string().min(1).max(8192) }).strict();
91241
+ /** Shared by the framed frontend reporter and the dashboard receiver. */
91242
+ const previewFrameHeightMessageSchema = z.object({
91243
+ type: z.literal("riverbank:preview-height"),
91244
+ height: z.number().finite().positive()
91245
+ }).strict();
91246
+ /** Sent by a framed request that has no preview authority, so the dashboard stops waiting. */
91247
+ const previewFrameFailedMessageSchema = z.object({ type: z.literal("riverbank:preview-failed") }).strict();
90805
91248
 
90806
91249
  //#endregion
90807
91250
  //#region ../api/src/footerSettings.ts
@@ -90902,9 +91345,11 @@ const allowedPathPrefixes = [
90902
91345
  "/sites/{siteId}/bookings/event-offerings",
90903
91346
  "/sites/{siteId}/bookings/event-series",
90904
91347
  "/sites/{siteId}/bookings/event-attendees",
91348
+ "/sites/{siteId}/bookings/attendees/",
90905
91349
  "/sites/{siteId}/bookings/event-categories",
90906
91350
  "/sites/{siteId}/bookings/venues",
90907
- "/sites/{siteId}/bookings/geocode",
91351
+ "/sites/{siteId}/location/geocode",
91352
+ "/sites/{siteId}/location/drawing-preview",
90908
91353
  "/sites/{siteId}/bookings/customers",
90909
91354
  "/sites/{siteId}/bookings/people",
90910
91355
  "/sites/{siteId}/bookings/person-records",
@@ -92433,11 +92878,12 @@ const appointmentSetupVenueChoiceSchema = z.discriminatedUnion("kind", [
92433
92878
  title: z.string().trim().min(1),
92434
92879
  description: z.string().nullable(),
92435
92880
  timezone: z.string().trim().min(1).nullable(),
92436
- addressJson: z.record(z.string(), z.unknown()),
92881
+ locationValue: locationValueSchema.nullable().optional(),
92882
+ addressJson: z.record(z.string(), z.unknown()).optional(),
92437
92883
  locationJson: z.object({
92438
92884
  lat: z.number(),
92439
92885
  lng: z.number()
92440
- }).nullable()
92886
+ }).nullable().optional()
92441
92887
  })
92442
92888
  ]);
92443
92889
  const appointmentSetupPaymentDraftSchema = z.discriminatedUnion("kind", [
@@ -92593,29 +93039,6 @@ const DEFAULT_ANALYTICS_COOKIE_BANNER_COPY = {
92593
93039
  policyLinkLabel: "Cookie policy"
92594
93040
  };
92595
93041
 
92596
- //#endregion
92597
- //#region ../api/src/eventAttendanceLabels.ts
92598
- function getEventAttendanceModeLabel(mode) {
92599
- switch (mode) {
92600
- case "in_person": return "In person";
92601
- case "online": return "Online";
92602
- }
92603
- }
92604
- function getEventDeliveryModeLabel(mode) {
92605
- switch (mode) {
92606
- case "in_person": return "In person";
92607
- case "online": return "Online";
92608
- case "hybrid": return "In person and online";
92609
- }
92610
- }
92611
- function getEventPricingOptionAttendanceScopeLabel(scope) {
92612
- switch (scope) {
92613
- case "both": return "In person and online";
92614
- case "in_person": return "In person only";
92615
- case "online": return "Online only";
92616
- }
92617
- }
92618
-
92619
93042
  //#endregion
92620
93043
  //#region ../api/src/siteBanner.ts
92621
93044
  const SITE_BANNER_SCOPE_VALUES = ["homepage", "all-pages"];
@@ -93035,6 +93458,14 @@ function isSiteBannerTone(value) {
93035
93458
 
93036
93459
  //#endregion
93037
93460
  //#region ../api/src/privacyPolicy.ts
93461
+ const SITE_LEGAL_JURISDICTIONS = [
93462
+ "UK",
93463
+ "US",
93464
+ "EU",
93465
+ "CA",
93466
+ "AU",
93467
+ "OTHER"
93468
+ ];
93038
93469
  /**
93039
93470
  * A legal profile saved before the source flags existed carries values an
93040
93471
  * administrator typed by hand, so a saved value is an override and only an
@@ -93075,6 +93506,17 @@ function isSitePrivacyIdentityReady(identity) {
93075
93506
  return identity.entityName !== null;
93076
93507
  }
93077
93508
  /**
93509
+ * Whether a site links to and serves its managed privacy policy. An
93510
+ * administrator has to have turned it on, and it has to be able to name a
93511
+ * controller. Every producer of the link calls this.
93512
+ */
93513
+ function resolveManagedPrivacyPolicyLink(input) {
93514
+ return {
93515
+ path: MANAGED_PRIVACY_POLICY_PATH,
93516
+ enabled: input.isPublished && isSitePrivacyIdentityReady(input.identity)
93517
+ };
93518
+ }
93519
+ /**
93078
93520
  * EU member states, used both to place a site in the EU privacy jurisdiction
93079
93521
  * and to seed the shop's default shipping countries.
93080
93522
  */
@@ -93499,6 +93941,11 @@ async function restorePageVersion(apiClient, input) {
93499
93941
  }));
93500
93942
  }
93501
93943
 
93944
+ //#endregion
93945
+ //#region ../api/src/contentVersionHistory.ts
93946
+ /** Page restore uses the journal's document revision; entries retain their own draft marker. */
93947
+ const restorePageVersionRequestSchema = z.object({ expectedRevision: z.number().int().nonnegative() }).strict();
93948
+
93502
93949
  //#endregion
93503
93950
  //#region ../api/src/blocksKeys.ts
93504
93951
  const blocksKeys = {
@@ -93763,8 +94210,7 @@ async function mutateBlockContent(apiClient, args) {
93763
94210
  const payload$1 = {
93764
94211
  data: args.data,
93765
94212
  optimistic_hash: args.optimisticHash ?? undefined,
93766
- expected_entry_slot_hash: args.expectedEntrySlotHash,
93767
- expected_surface_slot_hash: args.expectedSurfaceSlotHash,
94213
+ expected_slot_hash: args.expectedSlotHash,
93768
94214
  expected_mailing_list_provider_scope: args.expectedMailingListProviderScope
93769
94215
  };
93770
94216
  return unwrapResponse(await apiClient({
@@ -93778,8 +94224,7 @@ async function mutateBlockContent(apiClient, args) {
93778
94224
  path: args.path,
93779
94225
  value: args.value,
93780
94226
  optimistic_hash: args.optimisticHash ?? undefined,
93781
- expected_entry_slot_hash: args.expectedEntrySlotHash,
93782
- expected_surface_slot_hash: args.expectedSurfaceSlotHash,
94227
+ expected_slot_hash: args.expectedSlotHash,
93783
94228
  expected_mailing_list_provider_scope: args.expectedMailingListProviderScope
93784
94229
  };
93785
94230
  return unwrapResponse(await apiClient({
@@ -93902,6 +94347,16 @@ async function updateRouteMetadata(apiClient, { siteId, routeId, body, options }
93902
94347
  return normalizeApiError(error$1, "Failed to update route metadata");
93903
94348
  }
93904
94349
  }
94350
+ /** Metadata has one canonical editor representation, including an empty homepage slug. */
94351
+ function savedRouteMetadataValues(route) {
94352
+ return {
94353
+ draftTitle: route.draftTitle,
94354
+ draftSlug: route.draftSlug ?? "",
94355
+ draftMetaTitle: route.draftMetaTitle ?? null,
94356
+ draftMetaDescription: route.draftMetaDescription ?? null,
94357
+ ogImageId: route.ogImageId ?? null
94358
+ };
94359
+ }
93905
94360
 
93906
94361
  //#endregion
93907
94362
  //#region ../api/src/emailSettings.ts
@@ -94476,16 +94931,6 @@ async function changePlan(apiClient, request) {
94476
94931
  return normalizeApiError(error$1, "Failed to update billing plan");
94477
94932
  }
94478
94933
  }
94479
- async function createBillingPortalSession(apiClient, options) {
94480
- try {
94481
- return unwrapResponse(await apiClient({
94482
- endpoint: "createBillingPortalSession",
94483
- options
94484
- }));
94485
- } catch (error$1) {
94486
- return normalizeApiError(error$1, "Failed to open billing details");
94487
- }
94488
- }
94489
94934
  async function billingCheckout(apiClient, { attemptId, planId, continuation, options }) {
94490
94935
  try {
94491
94936
  return unwrapResponse(await apiClient({
@@ -94508,9 +94953,8 @@ async function billingCheckout(apiClient, { attemptId, planId, continuation, opt
94508
94953
  //#endregion
94509
94954
  //#region ../api/src/aiPlayground.ts
94510
94955
  const PreparedPagePreconditionSchema = z.object({
94511
- schemaVersion: z.literal(1),
94512
94956
  pageId: z.string().uuid(),
94513
- fingerprint: z.string().regex(/^[a-f0-9]{64}$/)
94957
+ revision: z.number().int().nonnegative()
94514
94958
  }).strict();
94515
94959
  /**
94516
94960
  * RFC-6902 JSON Patch Operations
@@ -98786,7 +99230,6 @@ function createProgram(dependencies = {}) {
98786
99230
  program.addCommand(createContentCommand());
98787
99231
  program.addCommand(createDraftsCommand());
98788
99232
  program.addCommand(createInitDocsCommand());
98789
- program.addCommand(createIdentifiersCommand());
98790
99233
  program.addCommand(createDeployCommand());
98791
99234
  program.addCommand(createContentTypeCommand());
98792
99235
  program.addCommand(createVerifyCommand());