riverbankcms 0.26.0 → 0.28.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, $r as mapDrawingStyle, An as walkAndCollectImageAttrs, Ar as introCompositionTreatmentValues, At as generateHeaderScrollTreatmentStyles, Bn as getImageUrl, Br as serializeSurfaceTree, Bt as getComponentBorderWidthPx, C as sortRecord, Cn as boxBackgroundOverlaySchema, Cr as defineBlockDesignCapability, Ct as deriveSiteStyleBlockPolicy, D as mapEventCommandContent, Dn as stripStaleTransitionStyleGroup, Dr as eyebrowTreatmentValues, Dt as getGradientPreset, En as siteChromeBackgroundOverrideOwner, Er as eventListTreatmentValues, Et as gradientToCss, F as pageIdentifierForBlockCommand, Fn as isExplicitRectCrop, Fr as toNonEmptyReadonlyArray, Ft as BREAKPOINT_MD, G as ianaTimezoneSchema, Gn as buildRenderableMediaAssetIndex, Gr as surfaceForegroundValue, Gt as themeButtonExtraClassesWithTrailingIcon, H as bookingPaymentTermsSchema, Hn as mediaSchema, Hr as surfaceForegroundDeclarations, Ht as ICON_CONFIG, I as pageIdentifierForCommand, In as parseAspectRatioValue, Ir as visibleHeadingDecorationFamilyValues, It as BREAKPOINT_SM, J as createCommandRef, Jn as mediaIdentifierSchema, Jr as backgroundColorStyle, Jt as parseThemeForPersistence, K as createBlockRef, Kn as resolveManagedMediaReference, Kr as surfaceInkDeclarations, Kt as themeButtonSizeClassName, L as pagePathForCommand, Ln as resolveMediaTransformForAspect, Lr as parseResolvedSurface, Lt as BREAKPOINT_XL, M as blockIdentifierForCommand, Mn as looksLikeUuid, Mr as offeringsPreviewCompositionTreatmentValues, Mt as getHeaderPaintTargets, N as blockOrderIdentifiersForCommand, Nn as rotateNormalizedPoint, Nr as testimonialsCompositionTreatmentValues, Nt as renderHeaderPaintTargetRules, On as collectPortableMediaReferencesFromContent, Or as featureCardCompositionTreatmentValues, Ot as parseGradientPresetId, P as entryIdentifierForCommand, Pn as normalizeWidthCandidates, Pr as tileTreatmentValues, Pt as BREAKPOINT_LG, Q as createFooterRef, Qr as textColorStyle, Qt as normalizeCardRole, R as hasConfiguredBookingVertical, Rn as getDirectImageUrlForRelativePath, Rr as parseSurfaceTree, Rt as MQ_MD_DOWN, S as venueManagementFields, Sn as sectionForegroundBackground, Sr as assertNever$10, St as resolvePublishedLook, Tn as runtimeBoxBackgroundSchema, Tr as defineNoBlockDesignCapability, Tt as compiledRuntimeStyleFieldNames, U as require_jsx_runtime, Un as persistableMediaSchema, Ur as surfaceForegroundInputFromResolved, Ut as generateDefaultButtonSystem, V as bookingPaymentCollectionOptionSchema, Vn as isSiteScopedDirectImageStoragePath, Vr as surfaceDecorationColors, Vt as getComponentShadowVar, W as require_react, Wn as runtimeMediaSchema, Wr as surfaceForegroundStyle, Wt as parseThemeButtonVariantId, X as createEventCategoryRef, Xn as parseCanonicalMediaIdentifier, Xr as mergeStyles, Xt as cardRoleSchema, Y as createContentEntryRef, Yn as buildMediaIdentifierFromFilename, Yr as borderColorStyle, Yt as renderCssDeclarations, Z as createEventSeriesRef, Zn as parseMediaIdentifier, Zr as rgbColorValue, Zt as cardVariantRoleValues, _i as __toESM, _n as deriveSectionGround, _t as resolveLookSlotSurfaces, ai as PUBLIC_BUTTON_ROLES, b as isEventVisibility, bn as resolveSectionBackground, bt as resolveEffectiveArrangement, c as customLinkSchema$1, ci as resolveSurfaceForeground, cn as generateNavLinkCSS, ct as headerLeafTextColor, d as internalLinkSchema, di as defaultThemeTokens, dr as parseSafeDownloadFilename, ei as opaqueSurfaceDeclarations, er as deriveVideoSlotPolicy, et as createNavigationRef, f as internalResolvedLinkSchema, fi as expandPalette, fn as headerNeedsPhotoShade, fr as defineBlockDesignMetadata, ft as mergeHeaderNavTypographyPreference, g as linkSchema, gi as __commonJSMin, gn as sectionFactsForContent, gr as arrangementModes, gt as resolveItemSurface, h as isResolvedInternalLinkEntityType, hi as parseBlockColorToken, hn as composeBoundary, hr as cardListKnobBlocks, ht as arrangementSlotNames, ii as resolveTokenOrCssColorValue, ir as asRecord, it as refSlug, j as eventManagementTiming, jn as deleteEnvSpecificKeys, jr as makeBoundaryId, jt as generateMobileOverlayBackdropFilterFix, kn as summarizePortableMediaReferences, kr as headingDecorationColorTokenValues, kt as themeSchema, l as entryLinkSchema$1, li as surfaceInkPublication, lr as classifyKnownMimeType, lt as transparentHeaderForegroundInput, mi as parseThemeColorToken, mn as boundaryLayout, mr as cardListFamilyBlocks, mt as arrangementLookHooks, ni as resolveOnColorForThemeToken, o as classifySdkEventBookingOffer, oi as selectLogoVariant, on as footerForegroundCandidates, or as parseRelativeStoragePath, ot as effectiveHeaderNavLinkStyle, p as internalRouteOnlyLinkSchema, pi as getTextColorForBackground, pn as headerRootPaint, pr as resolveEffectiveKnobs, pt as readHeaderNavFontSizePreference, q as createBlocksRef, qn as mediaTypeDiscriminants, qr as surfaceInkStyle, qt as themeButtonVariantClassNames, ri as resolveThemeColorReferenceValue, rr as getMimeType, rt as createVenueRef, s as RESOLVED_INTERNAL_LINK_ENTITY_TYPES, si as surfaceToneFromForegroundToken, sn as buildTextContrastShadow, sr as FILE_SIZE_LIMITS, st as headerForegroundCandidates, t as classifySdkEventTiming, ti as isCssColorLiteral, tr as resolveVideoSelectionIntentForMediaField, tt as createPageRef, u as externalLinkSchema$1, ui as TokenResolver, ur as managementMediaLibraryUploadLimitForMimeType, ut as readOpeningForegroundProjection, v as pageLinkSchema$1, vn as heroPhotoPaintsGround, vr as asDesignBlockId, vt as arrangementManifestFromVariants, w as stableStringify, wn as boxBackgroundSchema, wr as defineFrameCapability, wt as requireCuratedSiteStyle, xn as resolveSectionPhotoPlacement, xr as asSiteStyleId, xt as resolveModeArrangement, yn as parseCanonicalRuntimeBackground, yr as asLayoutVariantKey, yt as readStoredMode, z as eventCommandScheduleSchema, zn as getDirectImageUrlForSiteScopedPath, zr as resolveSurface, zt as headerVariantValues } from "../sdk-event-upsert-CH3xwzuX.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-DsR6-gBQ.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-61TwBBCA.mjs";
5
- import { r as CLI_VERSION, t as loadConfigFile } from "../load-config-C7Ght4_r.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-zAAQrjXE.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-DB3FQqwH.mjs";
2
+ import { $ as createEventSeriesRef, $n as isSiteScopedDirectImageStoragePath, $r as surfaceDecorationColors, $t as themeButtonSizeClassName, An as resolveCompiledSectionContextFromContent, Ar as asDesignBlockId, At as deriveSiteStyleBlockPolicy, B as eventCommandScheduleSchema, Bn as collectPortableMediaReferencesFromContent, Br as featureCardCompositionTreatmentValues, Bt as renderHeaderPaintTargetRules, C as sortRecord, Ci as surfaceInkDeclarations, Cn as sectionFactsForContent, Cr as parseSafeDownloadFilename, Ct as resolveItemSurface, D as resolveEventSeriesWaitlistMapping, Di as parseBlockColorToken, Dn as applyLookPhotoTreatment, Dr as cardListKnobBlocks, Dt as resolveEffectiveArrangement, Ei as parseThemeColorToken, En as sectionShapeHook, Er as cardListFamilyBlocks, Et as readStoredMode, F as entryIdentifierForCommand, Fn as boxBackgroundSchema, Fr as defineBlockDesignCapability, Ft as parseGradientPresetId, G as require_react, Gn as rotateNormalizedPoint, Gr as testimonialsCompositionTreatmentValues, Gt as MQ_MD_DOWN, H as bookingPaymentCollectionOptionSchema, Hn as walkAndCollectImageAttrs, Hr as introCompositionTreatmentValues, Ht as BREAKPOINT_MD, I as pageIdentifierForBlockCommand, In as runtimeBoxBackgroundSchema, Ir as defineFrameCapability, It as themeSchema, J as createBlockRef, Jn as parseAspectRatioValue, Jr as visibleHeadingDecorationFamilyValues, Jt as getComponentShadowVar, Kn as normalizeWidthCandidates, Kr as tileTreatmentValues, Kt as headerVariantValues, L as pageIdentifierForCommand, Ln as siteChromeBackgroundOverrideOwner, Lr as defineNoBlockDesignCapability, Lt as generateHeaderScrollTreatmentStyles, M as eventManagementTiming, Mn as resolveSectionPhotoPlacement, Mt as compiledRuntimeStyleFieldNames, N as blockIdentifierForCommand, Nn as sectionForegroundBackground, Nr as asSiteStyleId, Nt as gradientToCss, O as mapEventCommandContent, Oi as __commonJSMin, On as deriveSectionGround, Or as arrangementModes, Ot as resolveModeArrangement, P as blockOrderIdentifiersForCommand, Pn as boxBackgroundOverlaySchema, Pr as assertNever$10, Pt as getGradientPreset, Q as createEventCategoryRef, Qn as getImageUrl, Qr as serializeSurfaceTree, Qt as themeButtonExtraClassesWithTrailingIcon, R as pagePathForCommand, Rn as stripStaleTransitionStyleGroup, Rr as eventListTreatmentValues, Rt as generateMobileOverlayBackdropFilterFix, S as venueManagementFields, Si as surfaceForegroundValue, Sn as composeBoundary, Sr as managementMediaLibraryUploadLimitForMimeType, St as arrangementSlotNames, Ti as PUBLIC_BUTTON_ROLES, Tn as sectionShapeFromContent, Tr as resolveEffectiveKnobs, Tt as arrangementManifestFromVariants, U as bookingPaymentTermsSchema, Un as deleteEnvSpecificKeys, Ur as makeBoundaryId, Ut as BREAKPOINT_SM, Vn as summarizePortableMediaReferences, Vr as headingDecorationColorTokenValues, Vt as BREAKPOINT_LG, W as require_jsx_runtime, Wn as looksLikeUuid, Wr as offeringsPreviewCompositionTreatmentValues, Wt as BREAKPOINT_XL, X as createCommandRef, Xn as getDirectImageUrlForRelativePath, Xr as parseSurfaceTree, Xt as generateDefaultButtonSystem, Y as createBlocksRef, Yn as resolveMediaTransformForAspect, Yr as parseResolvedSurface, Yt as ICON_CONFIG, Z as createContentEntryRef, Zn as getDirectImageUrlForSiteScopedPath, Zr as resolveSurface, Zt as parseThemeButtonVariantId, _i as TokenResolver, _t as mergeHeaderNavTypographyPreference, ai as borderColorStyle, an as normalizeCardRole, ar as mediaTypeDiscriminants, at as createVenueRef, b as isEventVisibility, bi as surfaceForegroundInputFromResolved, bn as headerRootPaint, bt as arrangementAppearancePresets, c as customLinkSchema$1, ci as textColorStyle, cr as parseCanonicalMediaIdentifier, d as internalLinkSchema, di as selectLogoVariant, dt as headerForegroundCandidates, ei as isCssColorLiteral, en as themeButtonVariantClassNames, er as mediaSchema, et as createFooterRef, f as internalResolvedLinkSchema, fi as surfaceToneFromForegroundToken, fr as deriveVideoSlotPolicy, ft as headerLeafTextColor, g as linkSchema, gi as getTextColorForBackground, gr as asRecord, h as isResolvedInternalLinkEntityType, hi as expandPalette, hn as generateNavLinkCSS, hr as getMimeType, ht as readOpeningToneProjection, i as sdkEventUpsertOptionalFieldSchemas, ii as backgroundColorStyle, in as cardVariantRoleValues, ir as resolveManagedMediaReference, jn as resolveSectionBackground, jr as asLayoutVariantKey, jt as requireCuratedSiteStyle, ki as __toESM, kn as parseCanonicalRuntimeBackground, kt as resolvePublishedLook, l as entryLinkSchema$1, li as mapDrawingStyle, lr as parseMediaIdentifier, lt as heroPhotoPaintsGround, mi as surfaceInkPublication, mn as buildTextContrastShadow, mt as readOpeningForegroundProjection, ni as resolveThemeColorReferenceValue, nn as renderCssDeclarations, nr as runtimeMediaSchema, nt as createNavigationRef, o as classifySdkEventBookingOffer, oi as mergeStyles, or as mediaIdentifierSchema, ot as refSlug, p as internalRouteOnlyLinkSchema, pi as resolveSurfaceForeground, pn as footerForegroundCandidates, pr as resolveVideoSelectionIntentForMediaField, pt as transparentHeaderForegroundInput, q as ianaTimezoneSchema, qn as isExplicitRectCrop, qr as toNonEmptyReadonlyArray, qt as getComponentBorderWidthPx, ri as resolveTokenOrCssColorValue, rn as cardRoleSchema, rr as buildRenderableMediaAssetIndex, rt as createPageRef, s as RESOLVED_INTERNAL_LINK_ENTITY_TYPES, si as rgbColorValue, sr as buildMediaIdentifierFromFilename, t as classifySdkEventTiming, ti as resolveOnColorForThemeToken, tn as parseThemeForPersistence, tr as persistableMediaSchema, tt as createFormRef, u as externalLinkSchema$1, ui as opaqueSurfaceDeclarations, ut as effectiveHeaderNavLinkStyle, v as pageLinkSchema$1, vi as defaultThemeTokens, vr as parseRelativeStoragePath, vt as readHeaderNavFontSizePreference, w as stableStringify, wi as surfaceInkStyle, wn as sectionShapeForGround, wr as defineBlockDesignMetadata, wt as resolveLookSlotSurfaces, xi as surfaceForegroundStyle, xn as boundaryLayout, xr as classifyKnownMimeType, xt as arrangementLookHooks, yi as surfaceForegroundDeclarations, yn as headerNeedsPhotoShade, yr as FILE_SIZE_LIMITS, yt as storedSectionPhoto, z as hasConfiguredBookingVertical, zn as themeV2CompilerOwnedFieldNames, zr as eyebrowTreatmentValues, zt as getHeaderPaintTargets } from "../sdk-event-upsert-BrJvTQ-D.mjs";
3
+ import { $ as parseLocationValue, $t as resolveExactOrFreePriceDisplay, A as parseMailingListRuntimeContext, B as DEFAULT_MAILING_LIST_TARGETING, Bn as unsafeAsMediaAssetId, Bt as omitZeroAmountFutureRows, C as createSecret, Ct as parseLocalScheduleTime, D as parseMailingListBlockId, Dn as parseUserId, Dt as toBookingTimeZone, E as slugify, En as parseSiteTermsVersionId, Et as resolveBookingTimeZoneId, F as DEFAULT_MAILING_LIST_SUCCESS_MESSAGE, Ft as addIntervalPreservingMonthAnchor, G as parseWeeklyOpeningHours, Gt as parseEventPageSurfaceSubject, H as isCanonicalRichTextDoc, Ht as resolveFlexibleBalanceDueAt, I as parseMailingListProviderScope, In as unsafeAsEventInstanceId, It as clampConfiguredAmount, J as decideLocationSave, Jt as isPublicEventPricingOptionDisplayable, K as assertAllowedPublicUrl, Kn as unsafeAsPricingOptionId, Kt as formatBookingPriceDisplay, L as parseFooterCompositionV1, Lt as getBookingInstalmentDepositRefundability, Mt as isLiveOrderInstalmentPlanStatus, Nn as unsafeAsDemoCapability, Nt as isSettleableFlexibleBalanceContractStatus, O as parseMailingListContentVersionId, Ot as toScheduledBookingDateTime, P as DEFAULT_MAILING_LIST_PRIVACY_NOTE, Pt as isSettleableOrderInstalmentPlanStatus, Q as normalizeLocationAddressText, Qt as publicEventPricingType, Rt as getBookingInstalmentPlanIntervalCount, S as resolveWholeSeriesRunLifecycle, Sn as parseMembershipId, St as parseBookingLocalDate, T as parseManagementKey, Tn as parseSiteId, Tt as resolveBookingBusinessTimeZone, U as formatOpeningHoursRows, Un as unsafeAsPassId, Ut as resolveFlexibleBalanceInitialPaymentCents, V as planMailingListChoicePresentation, Vn as unsafeAsOccurrenceId, Vt as splitAmountWithRemainderInFirst, Wn as unsafeAsPositiveByteCount, Wt as deriveTotalTicketQuantity, X as locationMapLinks, Xt as publicEventPricingDisplay, Yt as publicEventPricingCurrency, Z as locationValueSchema, Zt as publicEventPricingOptions, _n as parseDatedOfferingCapacityHoldAuditRef, _t as formatLocalScheduleTime, a as NAVIGATION_LOCATIONS, an as parseNonNegativeCents, ar as blockInteractionContextSchema, at as selectCategoryView, b as orderedLiveRunSessions, bn as parseEventSeriesId, bt as getLocalScheduleTime, cn as toNonNegativeCents, ct as formatDateTime, dn as formatCurrencyAmount, dt as formatTimeRange, en as resolvePricingOptionsPriceDisplay, et as projectPublicLocation, f as EVENT_PRESET_VALUES, fn as parseCurrencyCode, ft as inferSiteDateLocale, gn as parseCustomerId, gt as formatLocalScheduleDate, h as WHOLE_SERIES_EVENT_PRESET_VALUES, hn as parseApiKeyId, ht as compareLocalScheduleDates, i as EVENT_PRESET_VOCABULARY, in as isNonNegativeWholeCents$1, ir as ok, it as mapDrawingSchema, j as assessMailingListTargeting, jn as unsafeAsCheckoutLineId, jt as validateBookingPaymentOptionKinds, k as parseMailingListSignedSourceToken, kt as toUtcIsoDateTimeString, ln as unsafeAsNonNegativeCents, lt as formatDateTimeRange, m as SURFACE_EVENT_PRESET_VALUES, mn as formatDurationUnitLabel, mt as buildBookingUtcDateWindow, nt as toLocationCoordinates, on as parsePositiveCents, ot as formatDate, pn as assertNever, pt as resolveBookingDisplayContext, qt as formatEventPricing, rn as mapReadonlyNonEmptyArray, rr as err, sn as toCents, st as formatDateRange, tn as fromArray, tt as publicLocationSchema$1, u as resolveSiteVerticalBookingConfig, un as unsafeAsPositiveCents, ut as formatTime$1, v as CANCELLED_SESSION_STATUS, vn as parseDatedOfferingCapacityHoldId, vt as getBookingLocalDateKey, w as exposeSecret, wn as parseRetiredCourseId, wt as parseUtcIsoDateTimeString, x as resolveWholeSeriesBookingPhase, y as nextLiveRunSessionStartMs, yt as getLocalScheduleDate, z as parseMailingListPlacementTargeting, zt as getBookingInstalmentProtectedDepositAmountCents } from "../src-D9-RAM-l.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 ApiRequestError, K as applyLocalMediaPush, Kt as createBearerAPIClient, 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 deriveCmsApiUrlFromDashboardUrl, 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-Bus1LjSx.mjs";
5
+ import { r as CLI_VERSION, t as loadConfigFile } from "../load-config-9DBnYiBm.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-COwkcsq7.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-DU4T2YGq.mjs";
8
8
  import { config } from "dotenv";
9
9
  import { Command, CommanderError } from "commander";
10
10
  import * as fs$2 from "fs/promises";
@@ -1274,16 +1274,22 @@ function parseLocalEventRun(raw, filePath) {
1274
1274
  if ("schedule" in raw) throw new LegacyEventScheduleShapeError(filePath);
1275
1275
  const identity = parseLocalEventRunScheduleIdentity(raw, filePath);
1276
1276
  const fields$1 = raw;
1277
+ const questions = sdkEventUpsertOptionalFieldSchemas.bookingQuestions.safeParse(fields$1.bookingQuestions);
1278
+ if (!questions.success) throw new InvalidLocalEventScheduleIdentityError(filePath, "bookingQuestions must name a valid question set and collection settings");
1277
1279
  assertLocalEventRunName(fields$1, identity.bookingScope, filePath);
1278
1280
  assertLocalEventRunRefs(fields$1, filePath);
1279
1281
  assertLocalEventRunVisibility(fields$1, filePath);
1282
+ if (!sdkEventUpsertOptionalFieldSchemas.waitlistMode.safeParse(fields$1.waitlistMode).success) {
1283
+ throw new InvalidLocalEventScheduleIdentityError(filePath, "waitlistMode must be inherit, off or on");
1284
+ }
1280
1285
  if ("categoryRef" in fields$1) {
1281
1286
  throw new InvalidLocalEventScheduleIdentityError(filePath, "Move categoryRef to the parent Event file");
1282
1287
  }
1283
1288
  const { presentation: _retiredPresentation, ...run } = raw;
1284
1289
  return {
1285
1290
  ...run,
1286
- ...identity
1291
+ ...identity,
1292
+ bookingQuestions: questions.data
1287
1293
  };
1288
1294
  }
1289
1295
  async function readEventRuns(contentDir) {
@@ -2191,6 +2197,7 @@ function mapEventRunToComparable(run) {
2191
2197
  authoredSchedule: run.authoredSchedule,
2192
2198
  occurrences: run.occurrences,
2193
2199
  capacity: run.capacity,
2200
+ waitlistMode: run.waitlistMode,
2194
2201
  bookingOffer: run.bookingOffer,
2195
2202
  venueRef: run.venueRef,
2196
2203
  formRef: run.formRef,
@@ -4090,6 +4097,7 @@ function normalizeRemoteRun(run) {
4090
4097
  authoredSchedule: run.authoredSchedule ?? null,
4091
4098
  occurrences: [...run.occurrences],
4092
4099
  capacity: run.capacity,
4100
+ waitlistMode: nullishToNull(run.waitlistMode),
4093
4101
  bookingOffer: normalizeCanonicalBookingOffer(run.bookingOffer),
4094
4102
  venueRef: run.venueRef,
4095
4103
  formRef: run.formRef,
@@ -4111,6 +4119,7 @@ function normalizeLocalRun(local, remote) {
4111
4119
  authoredSchedule: local.authoredSchedule ?? null,
4112
4120
  occurrences: [...local.occurrences],
4113
4121
  capacity: overrideWhenDefined(local.capacity, base.capacity, (value) => typeof value === "number" ? value : null),
4122
+ waitlistMode: local.waitlistMode === undefined ? base.waitlistMode : local.waitlistMode,
4114
4123
  bookingOffer: overrideWhenDefined(local.bookingOffer, base.bookingOffer, normalizeCanonicalBookingOffer),
4115
4124
  venueRef: overrideWhenDefined(local.venueRef, base.venueRef, normalizeNullableString),
4116
4125
  formRef: overrideWhenDefined(local.formRef, base.formRef, normalizeNullableString),
@@ -4149,6 +4158,7 @@ function normalizeNewLocalRun(run) {
4149
4158
  authoredSchedule: run.authoredSchedule ?? null,
4150
4159
  occurrences: [...run.occurrences],
4151
4160
  capacity: run.capacity ?? null,
4161
+ waitlistMode: nullishToNull(run.waitlistMode),
4152
4162
  bookingOffer: normalizeCanonicalBookingOffer(run.bookingOffer),
4153
4163
  venueRef: run.venueRef ?? null,
4154
4164
  formRef: run.formRef ?? null,
@@ -4848,7 +4858,9 @@ function buildEventSeriesCommand(event, run, schedule, offer) {
4848
4858
  venueIdentifier: run.venueRef ?? undefined,
4849
4859
  categoryIdentifier: event.categoryRef ?? undefined,
4850
4860
  formIdentifier: run.formRef ?? undefined,
4861
+ bookingQuestions: run.bookingQuestions,
4851
4862
  capacity: eventCapacity(run.capacity),
4863
+ ...run.waitlistMode === undefined ? {} : { waitlist: { kind: run.waitlistMode === "on" ? "enabled_when_full" : run.waitlistMode === "off" ? "disabled" : "inherit" } },
4852
4864
  bookingOffer: offer.bookingOffer,
4853
4865
  ...schedule.schedule !== undefined ? { schedule: schedule.schedule } : { occurrences: schedule.occurrences },
4854
4866
  content: eventContent(event.content),
@@ -5085,6 +5097,8 @@ function preferredRef(identifier, ref) {
5085
5097
  }
5086
5098
  function eventRunUpsertInput(command, eventIdentifier) {
5087
5099
  const { input } = command;
5100
+ const waitlist = resolveEventSeriesWaitlistMapping(input.waitlist);
5101
+ if (waitlist.kind === "unsupported") throw new Error(waitlist.gap.message);
5088
5102
  return {
5089
5103
  identifier: input.slug,
5090
5104
  eventRef: eventIdentifier,
@@ -5096,6 +5110,7 @@ function eventRunUpsertInput(command, eventIdentifier) {
5096
5110
  status: input.status,
5097
5111
  ...input.bookingScope === "whole_series" ? {} : { visibility: managementVisibility(input.visibility) },
5098
5112
  capacity: capacityLimit(input.capacity),
5113
+ ...waitlist.waitlistMode === undefined ? {} : { waitlistMode: waitlist.waitlistMode },
5099
5114
  bookingOffer: input.bookingOffer,
5100
5115
  attendeeMigration: input.attendeeMigration,
5101
5116
  venueRef: preferredRef(input.venueIdentifier, input.venueRef),
@@ -5294,10 +5309,10 @@ function formCommandDisplayIdentifier(command) {
5294
5309
  return command.input.slug;
5295
5310
  }
5296
5311
  function managementFormSchema(schema) {
5297
- return {
5312
+ return "fields" in schema ? {
5298
5313
  ...schema,
5299
5314
  fields: schema.fields.map((field) => ({ ...field }))
5300
- };
5315
+ } : schema;
5301
5316
  }
5302
5317
  function incrementFormSuccess(result, subject, effect) {
5303
5318
  if (!effect) {
@@ -7076,6 +7091,7 @@ const uiSchema = z.object({
7076
7091
  "behavior",
7077
7092
  "style"
7078
7093
  ]).optional(),
7094
+ underLooks: z.literal("owner").optional(),
7079
7095
  valueContract: z.enum(["boxBackground", "location"]).optional()
7080
7096
  }).partial().superRefine((ui, ctx) => {
7081
7097
  if (ui.layoutGridColumns !== undefined && ui.layoutGridColumnsFields !== undefined) {
@@ -7601,7 +7617,6 @@ const manifestSchema = z.object({
7601
7617
  }).optional()
7602
7618
  }).optional(),
7603
7619
  promotedFields: z.array(z.string().min(1)).optional(),
7604
- arrangementOwnedFieldIds: z.array(z.string().min(1)).readonly().optional(),
7605
7620
  variantMeaning: z.discriminatedUnion("kind", [z.object({
7606
7621
  kind: z.literal("arrangement"),
7607
7622
  lookOnlyKeys: z.array(z.string().min(1)).readonly().optional()
@@ -7873,6 +7888,16 @@ const MARK_ORDER = {
7873
7888
  function plainTextToInlineText(value) {
7874
7889
  return normalizeInlineText(value.length > 0 ? [{ text: value }] : []);
7875
7890
  }
7891
+ /** One authored inline value decides both fields; adapters execute through their existing write contract. */
7892
+ function deriveInlineTextFieldChanges(value, fields$1) {
7893
+ return [{
7894
+ path: fields$1.formatted,
7895
+ value
7896
+ }, {
7897
+ path: fields$1.plain,
7898
+ value: inlineTextToPlainText(value)
7899
+ }];
7900
+ }
7876
7901
  function inlineTextToPlainText(value) {
7877
7902
  return value.map((run) => run.text).join("");
7878
7903
  }
@@ -11049,6 +11074,13 @@ function formatValidationResult(pageIdentifier, blockIdentifier$1, blockKind, re
11049
11074
  return lines;
11050
11075
  }
11051
11076
 
11077
+ //#endregion
11078
+ //#region ../blocks/src/system/registryStore.ts
11079
+ const REGISTRY_SYMBOL$1 = Symbol.for("@riverbankcms/blocks/system/definitions");
11080
+ const isBlocksTestRuntime$1 = typeof process !== "undefined" && typeof process.env !== "undefined" && process.env.RIVERBANK_BLOCKS_TEST === "1";
11081
+ const globalScope$1 = globalThis;
11082
+ const blockStore = isBlocksTestRuntime$1 ? new Map() : globalScope$1[REGISTRY_SYMBOL$1] ??= new Map();
11083
+
11052
11084
  //#endregion
11053
11085
  //#region ../blocks/src/system/manifest/augmentManifest.ts
11054
11086
  /**
@@ -11263,10 +11295,10 @@ function resolveBlockTitle(manifest, blockContent, blockKind) {
11263
11295
 
11264
11296
  //#endregion
11265
11297
  //#region ../blocks/src/system/manifest/registry.ts
11266
- const REGISTRY_SYMBOL$1 = Symbol.for("@riverbankcms/blocks/manifest-registry");
11267
- const isBlocksTestRuntime$1 = typeof process !== "undefined" && typeof process.env !== "undefined" && process.env.RIVERBANK_BLOCKS_TEST === "1";
11268
- const globalScope$1 = globalThis;
11269
- const manifestStore = isBlocksTestRuntime$1 ? new Map() : globalScope$1[REGISTRY_SYMBOL$1] ??= new Map();
11298
+ const REGISTRY_SYMBOL = Symbol.for("@riverbankcms/blocks/manifest-registry");
11299
+ const isBlocksTestRuntime = typeof process !== "undefined" && typeof process.env !== "undefined" && process.env.RIVERBANK_BLOCKS_TEST === "1";
11300
+ const globalScope = globalThis;
11301
+ const manifestStore = isBlocksTestRuntime ? new Map() : globalScope[REGISTRY_SYMBOL] ??= new Map();
11270
11302
  function registerManifest(manifest) {
11271
11303
  manifestStore.set(manifest.name, manifest);
11272
11304
  return manifest;
@@ -11391,6 +11423,274 @@ function blockDesignMetadataMapFromDefinitions(definitions$1) {
11391
11423
  }));
11392
11424
  }
11393
11425
 
11426
+ //#endregion
11427
+ //#region ../blocks/src/system/helpers/api-bindings.ts
11428
+ /**
11429
+ * Standard API bindings that all interactive blocks need.
11430
+ */
11431
+ const apiBindings = {
11432
+ now: { $bind: { from: "$root.now" } },
11433
+ siteId: { $bind: { from: "$root.siteId" } },
11434
+ apiBaseUrl: { $bind: { from: "$root.apiBaseUrl" } }
11435
+ };
11436
+ function withApiBindings(props$1, options) {
11437
+ const includeApiBaseUrl = options?.includeApiBaseUrl ?? true;
11438
+ const bindings = includeApiBaseUrl ? apiBindings : {
11439
+ siteId: apiBindings.siteId,
11440
+ now: apiBindings.now
11441
+ };
11442
+ return {
11443
+ ...bindings,
11444
+ ...props$1
11445
+ };
11446
+ }
11447
+
11448
+ //#endregion
11449
+ //#region ../blocks/src/utils/env.ts
11450
+ /**
11451
+ * Environment detection utilities
11452
+ *
11453
+ * Provides type-safe environment detection without relying on `any`-typed globals.
11454
+ */
11455
+ /**
11456
+ * Check if the current environment is development.
11457
+ *
11458
+ * Returns true if NODE_ENV is not 'production', or if NODE_ENV cannot be determined
11459
+ * (which is the safe default for validation and warnings).
11460
+ *
11461
+ * @returns true if in development mode, false if in production
11462
+ */
11463
+ function isDevEnvironment() {
11464
+ try {
11465
+ if (typeof process !== "undefined" && process.env?.NODE_ENV !== undefined) {
11466
+ return process.env.NODE_ENV !== "production";
11467
+ }
11468
+ return true;
11469
+ } catch {
11470
+ return true;
11471
+ }
11472
+ }
11473
+
11474
+ //#endregion
11475
+ //#region ../blocks/src/system/node/types.ts
11476
+ /**
11477
+ * List of reserved keys (for runtime validation).
11478
+ * Kept in sync with the ReservedNodeKeys type above.
11479
+ */
11480
+ const RESERVED_KEYS = [
11481
+ "children",
11482
+ "key",
11483
+ "$bind",
11484
+ "$when",
11485
+ "$repeat",
11486
+ "$scopes"
11487
+ ];
11488
+ /**
11489
+ * Type guard to check if props contain reserved keys at runtime.
11490
+ * Use this in development mode to catch bugs early.
11491
+ *
11492
+ * @param props - Props object to validate
11493
+ * @returns Array of reserved keys found in props, or empty array if none
11494
+ */
11495
+ function findReservedKeysInProps(props$1) {
11496
+ if (!props$1) return [];
11497
+ return RESERVED_KEYS.filter((key) => key in props$1);
11498
+ }
11499
+ /**
11500
+ * Validates that props don't contain reserved keys.
11501
+ * Throws in development, warns in production.
11502
+ *
11503
+ * @param props - Props to validate
11504
+ * @param context - Context for error message (e.g., "el('grid', ...)")
11505
+ */
11506
+ function validateProps(props$1, context = "node builder") {
11507
+ const reserved = findReservedKeysInProps(props$1);
11508
+ if (reserved.length === 0) return;
11509
+ const message = `[blocks:${context}] Reserved keys found in props: ${reserved.join(", ")}. ` + `These should be passed as separate parameters or modifiers, not in props. ` + `For example, 'children' should be the 3rd parameter to el(), not in the props object.`;
11510
+ if (isDevEnvironment()) {
11511
+ throw new TypeError(message);
11512
+ } else {
11513
+ console.error(message);
11514
+ }
11515
+ }
11516
+
11517
+ //#endregion
11518
+ //#region ../blocks/src/system/node/builder.ts
11519
+ function normalizeChildren(children) {
11520
+ if (!children) return undefined;
11521
+ const flat = children.flat().filter(Boolean);
11522
+ return flat.length > 0 ? flat : undefined;
11523
+ }
11524
+ function el(type, props$1, children, ...mods) {
11525
+ validateProps(props$1, `el('${type}', ...)`);
11526
+ const node = {
11527
+ type,
11528
+ ...props$1 && Object.keys(props$1).length > 0 ? { props: props$1 } : {},
11529
+ ...children && children.length ? { children: normalizeChildren(children) } : {}
11530
+ };
11531
+ if (mods && mods.length > 0) {
11532
+ const validMods = mods.filter((mod) => typeof mod === "function");
11533
+ if (validMods.length > 0) {
11534
+ const modified = validMods.reduce((acc, fn) => fn(acc), node);
11535
+ return devValidate(modified);
11536
+ }
11537
+ }
11538
+ return devValidate(node);
11539
+ }
11540
+ const section$1 = (props$1, children, ...mods) => el("section", props$1, children, ...mods);
11541
+ const headerSection = (props$1, children, ...mods) => el("headerSection", props$1, children, ...mods);
11542
+ const stack = (props$1, children, ...mods) => el("stack", props$1, children, ...mods);
11543
+ const inline = (props$1, children, ...mods) => el("inline", props$1, children, ...mods);
11544
+ const accordion = (props$1, children, ...mods) => el("accordion", props$1, children, ...mods);
11545
+ const accordionItem = (props$1, children, ...mods) => el("accordionItem", props$1, children, ...mods);
11546
+ const carousel = (props$1, children, ...mods) => el("carousel", {
11547
+ mode: "legacy",
11548
+ ...props$1
11549
+ }, children, ...mods);
11550
+ const text = (props$1, ...mods) => el("text", props$1, undefined, ...mods);
11551
+ const richText = (props$1, ...mods) => el("richText", props$1, undefined, ...mods);
11552
+ const icon = (props$1, ...mods) => el("icon", props$1, undefined, ...mods);
11553
+ const media = (props$1, ...mods) => el("media", props$1, undefined, ...mods);
11554
+ const fileDownload = (props$1, ...mods) => el("file-download", props$1, undefined, ...mods);
11555
+ const videoEmbed = (props$1, ...mods) => el("videoEmbed", props$1, undefined, ...mods);
11556
+ const spinner = (props$1, ...mods) => el("spinner", props$1, undefined, ...mods);
11557
+ const button = (props$1, children, ...mods) => el("button", props$1, children, ...mods);
11558
+ const link$1 = (props$1, children, ...mods) => el("link", props$1, children, ...mods);
11559
+ const form = (props$1, children, ...mods) => el("form", props$1, children, ...mods);
11560
+ const bookingForm = (props$1, children, ...mods) => el("booking-form", props$1, children, ...mods);
11561
+ const eventRegistration = (props$1, children, ...mods) => el("event-registration", props$1, children, ...mods);
11562
+ const shop = (props$1, children, ...mods) => el("shop", props$1, children, ...mods);
11563
+ const productList = (props$1, children, ...mods) => el("product-list", props$1, children, ...mods);
11564
+ const productDetail = (props$1, children, ...mods) => el("product-detail", props$1, children, ...mods);
11565
+ const cart = (props$1, children, ...mods) => el("cart", props$1, children, ...mods);
11566
+ const checkout = (props$1, children, ...mods) => el("checkout", props$1, children, ...mods);
11567
+ const gifting = (props$1, children, ...mods) => el("gifting", props$1, children, ...mods);
11568
+ function bind(from, options) {
11569
+ return (node) => ({
11570
+ ...node,
11571
+ $bind: {
11572
+ from,
11573
+ ...options?.fallback !== undefined ? { fallback: options.fallback } : {},
11574
+ ...options?.transforms ? { transforms: options.transforms } : {},
11575
+ ...options?.pick ? { pick: options.pick } : {},
11576
+ ...options?.coerce ? { coerce: options.coerce } : {}
11577
+ }
11578
+ });
11579
+ }
11580
+ function when(path$3, options) {
11581
+ return (node) => ({
11582
+ ...node,
11583
+ $when: {
11584
+ when: { from: path$3 },
11585
+ ...options?.equals !== undefined ? { equals: options.equals } : {},
11586
+ ...options?.not ? { not: true } : {},
11587
+ ...options?.authoringPresence ? { authoringPresence: options.authoringPresence } : {}
11588
+ }
11589
+ });
11590
+ }
11591
+ function scopes(entries) {
11592
+ const scoped = entries.map((entry) => ({
11593
+ name: entry.name,
11594
+ from: {
11595
+ from: entry.from.from,
11596
+ transforms: entry.from.transforms ?? [],
11597
+ pick: entry.from.pick ?? "value",
11598
+ ...entry.from.fallback !== undefined ? { fallback: entry.from.fallback } : {},
11599
+ ...entry.from.coerce ? { coerce: entry.from.coerce } : {}
11600
+ }
11601
+ }));
11602
+ return (node) => ({
11603
+ ...node,
11604
+ $scopes: scoped
11605
+ });
11606
+ }
11607
+ function repeat(collectionPath, itemName = "item", options) {
11608
+ return (node) => ({
11609
+ ...node,
11610
+ $repeat: {
11611
+ collection: {
11612
+ from: collectionPath,
11613
+ pick: "collection"
11614
+ },
11615
+ itemName,
11616
+ ...options?.indexName ? { indexName: options.indexName } : {},
11617
+ ...options?.limit ? { limit: options.limit } : {},
11618
+ ...options?.sortBy ? { sortBy: {
11619
+ path: options.sortBy.path,
11620
+ direction: options.sortBy.direction ?? "asc"
11621
+ } } : {}
11622
+ }
11623
+ });
11624
+ }
11625
+ function props(extra) {
11626
+ validateProps(extra, "props() modifier");
11627
+ return (node) => ({
11628
+ ...node,
11629
+ props: {
11630
+ ...node.props ?? {},
11631
+ ...extra
11632
+ }
11633
+ });
11634
+ }
11635
+ function accordionList({ collection, itemName = "item", indexName, accordionProps = null, itemProps = null, triggerFrom, contentFrom, valueFrom }, ...mods) {
11636
+ const resolvedIndexName = indexName ?? `${itemName}Index`;
11637
+ const resolvedValuePath = valueFrom === null ? null : valueFrom ?? resolvedIndexName;
11638
+ const baseItemProps = {
11639
+ ...itemProps ?? {},
11640
+ trigger: { $bind: { from: triggerFrom } }
11641
+ };
11642
+ if (contentFrom) {
11643
+ baseItemProps.content = { $bind: { from: contentFrom } };
11644
+ }
11645
+ if (resolvedValuePath) {
11646
+ baseItemProps.value = { $bind: { from: resolvedValuePath } };
11647
+ }
11648
+ return accordion(accordionProps ?? undefined, [accordionItem(baseItemProps, undefined, repeat(collection, itemName, { indexName: resolvedIndexName }))], ...mods);
11649
+ }
11650
+ function devValidate(node) {
11651
+ try {
11652
+ if (isDevEnvironment()) {
11653
+ const res = NodeSchema.safeParse(node);
11654
+ if (!res.success) {
11655
+ console.warn("[blocks:builder] Invalid node produced by builder", res.error.format());
11656
+ }
11657
+ }
11658
+ } catch {}
11659
+ return node;
11660
+ }
11661
+
11662
+ //#endregion
11663
+ //#region ../blocks/src/system/blocks/hero-newsletter.ts
11664
+ const heroNewsletterAction = stack({
11665
+ gap: "md",
11666
+ className: "hero-newsletter rb-w-full rb-min-w-0",
11667
+ style: {
11668
+ maxWidth: "32rem",
11669
+ overflowWrap: "anywhere"
11670
+ }
11671
+ }, [
11672
+ text({
11673
+ as: "p",
11674
+ className: "rb-body"
11675
+ }, bind("data.heroNewsletter.lead")),
11676
+ text({
11677
+ as: "p",
11678
+ className: "rb-body"
11679
+ }, bind("data.heroNewsletter.intro")),
11680
+ el("newsletter-form", withApiBindings({
11681
+ source: { $bind: { from: "data.heroNewsletter.runtime.source" } },
11682
+ sourceRef: { $bind: { from: "data.heroNewsletter.runtime.sourceRef" } },
11683
+ mailingList: { $bind: { from: "data.heroNewsletter.runtime.mailingList" } },
11684
+ targeting: { $bind: { from: "data.heroNewsletter.runtime.targeting" } },
11685
+ buttonVariant: "primary",
11686
+ spamProtectionEnabled: { $bind: { from: "$root.spamProtectionEnabled" } }
11687
+ }), []),
11688
+ el("div", { className: "rb-body" }, [text({
11689
+ as: "span",
11690
+ value: "Or email "
11691
+ }), link$1({ href: { $bind: { from: "data.heroNewsletter.contact.href" } } }, [text({ as: "span" }, bind("data.heroNewsletter.contact.email"))])], when("data.heroNewsletter.contact"))
11692
+ ], when("data.heroNewsletter"));
11693
+
11394
11694
  //#endregion
11395
11695
  //#region ../blocks/src/system/transforms/registry/core.ts
11396
11696
  /**
@@ -12347,220 +12647,6 @@ function createImageShapeField(options = {}) {
12347
12647
  };
12348
12648
  }
12349
12649
 
12350
- //#endregion
12351
- //#region ../blocks/src/utils/env.ts
12352
- /**
12353
- * Environment detection utilities
12354
- *
12355
- * Provides type-safe environment detection without relying on `any`-typed globals.
12356
- */
12357
- /**
12358
- * Check if the current environment is development.
12359
- *
12360
- * Returns true if NODE_ENV is not 'production', or if NODE_ENV cannot be determined
12361
- * (which is the safe default for validation and warnings).
12362
- *
12363
- * @returns true if in development mode, false if in production
12364
- */
12365
- function isDevEnvironment() {
12366
- try {
12367
- if (typeof process !== "undefined" && process.env?.NODE_ENV !== undefined) {
12368
- return process.env.NODE_ENV !== "production";
12369
- }
12370
- return true;
12371
- } catch {
12372
- return true;
12373
- }
12374
- }
12375
-
12376
- //#endregion
12377
- //#region ../blocks/src/system/node/types.ts
12378
- /**
12379
- * List of reserved keys (for runtime validation).
12380
- * Kept in sync with the ReservedNodeKeys type above.
12381
- */
12382
- const RESERVED_KEYS = [
12383
- "children",
12384
- "key",
12385
- "$bind",
12386
- "$when",
12387
- "$repeat",
12388
- "$scopes"
12389
- ];
12390
- /**
12391
- * Type guard to check if props contain reserved keys at runtime.
12392
- * Use this in development mode to catch bugs early.
12393
- *
12394
- * @param props - Props object to validate
12395
- * @returns Array of reserved keys found in props, or empty array if none
12396
- */
12397
- function findReservedKeysInProps(props$1) {
12398
- if (!props$1) return [];
12399
- return RESERVED_KEYS.filter((key) => key in props$1);
12400
- }
12401
- /**
12402
- * Validates that props don't contain reserved keys.
12403
- * Throws in development, warns in production.
12404
- *
12405
- * @param props - Props to validate
12406
- * @param context - Context for error message (e.g., "el('grid', ...)")
12407
- */
12408
- function validateProps(props$1, context = "node builder") {
12409
- const reserved = findReservedKeysInProps(props$1);
12410
- if (reserved.length === 0) return;
12411
- const message = `[blocks:${context}] Reserved keys found in props: ${reserved.join(", ")}. ` + `These should be passed as separate parameters or modifiers, not in props. ` + `For example, 'children' should be the 3rd parameter to el(), not in the props object.`;
12412
- if (isDevEnvironment()) {
12413
- throw new TypeError(message);
12414
- } else {
12415
- console.error(message);
12416
- }
12417
- }
12418
-
12419
- //#endregion
12420
- //#region ../blocks/src/system/node/builder.ts
12421
- function normalizeChildren(children) {
12422
- if (!children) return undefined;
12423
- const flat = children.flat().filter(Boolean);
12424
- return flat.length > 0 ? flat : undefined;
12425
- }
12426
- function el(type, props$1, children, ...mods) {
12427
- validateProps(props$1, `el('${type}', ...)`);
12428
- const node = {
12429
- type,
12430
- ...props$1 && Object.keys(props$1).length > 0 ? { props: props$1 } : {},
12431
- ...children && children.length ? { children: normalizeChildren(children) } : {}
12432
- };
12433
- if (mods && mods.length > 0) {
12434
- const validMods = mods.filter((mod) => typeof mod === "function");
12435
- if (validMods.length > 0) {
12436
- const modified = validMods.reduce((acc, fn) => fn(acc), node);
12437
- return devValidate(modified);
12438
- }
12439
- }
12440
- return devValidate(node);
12441
- }
12442
- const section$1 = (props$1, children, ...mods) => el("section", props$1, children, ...mods);
12443
- const headerSection = (props$1, children, ...mods) => el("headerSection", props$1, children, ...mods);
12444
- const stack = (props$1, children, ...mods) => el("stack", props$1, children, ...mods);
12445
- const inline = (props$1, children, ...mods) => el("inline", props$1, children, ...mods);
12446
- const accordion = (props$1, children, ...mods) => el("accordion", props$1, children, ...mods);
12447
- const accordionItem = (props$1, children, ...mods) => el("accordionItem", props$1, children, ...mods);
12448
- const carousel = (props$1, children, ...mods) => el("carousel", {
12449
- mode: "legacy",
12450
- ...props$1
12451
- }, children, ...mods);
12452
- const text = (props$1, ...mods) => el("text", props$1, undefined, ...mods);
12453
- const richText = (props$1, ...mods) => el("richText", props$1, undefined, ...mods);
12454
- const icon = (props$1, ...mods) => el("icon", props$1, undefined, ...mods);
12455
- const media = (props$1, ...mods) => el("media", props$1, undefined, ...mods);
12456
- const fileDownload = (props$1, ...mods) => el("file-download", props$1, undefined, ...mods);
12457
- const videoEmbed = (props$1, ...mods) => el("videoEmbed", props$1, undefined, ...mods);
12458
- const spinner = (props$1, ...mods) => el("spinner", props$1, undefined, ...mods);
12459
- const button = (props$1, children, ...mods) => el("button", props$1, children, ...mods);
12460
- const link$1 = (props$1, children, ...mods) => el("link", props$1, children, ...mods);
12461
- const form = (props$1, children, ...mods) => el("form", props$1, children, ...mods);
12462
- const bookingForm = (props$1, children, ...mods) => el("booking-form", props$1, children, ...mods);
12463
- const eventRegistration = (props$1, children, ...mods) => el("event-registration", props$1, children, ...mods);
12464
- const shop = (props$1, children, ...mods) => el("shop", props$1, children, ...mods);
12465
- const productList = (props$1, children, ...mods) => el("product-list", props$1, children, ...mods);
12466
- const productDetail = (props$1, children, ...mods) => el("product-detail", props$1, children, ...mods);
12467
- const cart = (props$1, children, ...mods) => el("cart", props$1, children, ...mods);
12468
- const checkout = (props$1, children, ...mods) => el("checkout", props$1, children, ...mods);
12469
- const gifting = (props$1, children, ...mods) => el("gifting", props$1, children, ...mods);
12470
- function bind(from, options) {
12471
- return (node) => ({
12472
- ...node,
12473
- $bind: {
12474
- from,
12475
- ...options?.fallback !== undefined ? { fallback: options.fallback } : {},
12476
- ...options?.transforms ? { transforms: options.transforms } : {},
12477
- ...options?.pick ? { pick: options.pick } : {},
12478
- ...options?.coerce ? { coerce: options.coerce } : {}
12479
- }
12480
- });
12481
- }
12482
- function when(path$3, options) {
12483
- return (node) => ({
12484
- ...node,
12485
- $when: {
12486
- when: { from: path$3 },
12487
- ...options?.equals !== undefined ? { equals: options.equals } : {},
12488
- ...options?.not ? { not: true } : {},
12489
- ...options?.authoringPresence ? { authoringPresence: options.authoringPresence } : {}
12490
- }
12491
- });
12492
- }
12493
- function scopes(entries) {
12494
- const scoped = entries.map((entry) => ({
12495
- name: entry.name,
12496
- from: {
12497
- from: entry.from.from,
12498
- transforms: entry.from.transforms ?? [],
12499
- pick: entry.from.pick ?? "value",
12500
- ...entry.from.fallback !== undefined ? { fallback: entry.from.fallback } : {},
12501
- ...entry.from.coerce ? { coerce: entry.from.coerce } : {}
12502
- }
12503
- }));
12504
- return (node) => ({
12505
- ...node,
12506
- $scopes: scoped
12507
- });
12508
- }
12509
- function repeat(collectionPath, itemName = "item", options) {
12510
- return (node) => ({
12511
- ...node,
12512
- $repeat: {
12513
- collection: {
12514
- from: collectionPath,
12515
- pick: "collection"
12516
- },
12517
- itemName,
12518
- ...options?.indexName ? { indexName: options.indexName } : {},
12519
- ...options?.limit ? { limit: options.limit } : {},
12520
- ...options?.sortBy ? { sortBy: {
12521
- path: options.sortBy.path,
12522
- direction: options.sortBy.direction ?? "asc"
12523
- } } : {}
12524
- }
12525
- });
12526
- }
12527
- function props(extra) {
12528
- validateProps(extra, "props() modifier");
12529
- return (node) => ({
12530
- ...node,
12531
- props: {
12532
- ...node.props ?? {},
12533
- ...extra
12534
- }
12535
- });
12536
- }
12537
- function accordionList({ collection, itemName = "item", indexName, accordionProps = null, itemProps = null, triggerFrom, contentFrom, valueFrom }, ...mods) {
12538
- const resolvedIndexName = indexName ?? `${itemName}Index`;
12539
- const resolvedValuePath = valueFrom === null ? null : valueFrom ?? resolvedIndexName;
12540
- const baseItemProps = {
12541
- ...itemProps ?? {},
12542
- trigger: { $bind: { from: triggerFrom } }
12543
- };
12544
- if (contentFrom) {
12545
- baseItemProps.content = { $bind: { from: contentFrom } };
12546
- }
12547
- if (resolvedValuePath) {
12548
- baseItemProps.value = { $bind: { from: resolvedValuePath } };
12549
- }
12550
- return accordion(accordionProps ?? undefined, [accordionItem(baseItemProps, undefined, repeat(collection, itemName, { indexName: resolvedIndexName }))], ...mods);
12551
- }
12552
- function devValidate(node) {
12553
- try {
12554
- if (isDevEnvironment()) {
12555
- const res = NodeSchema.safeParse(node);
12556
- if (!res.success) {
12557
- console.warn("[blocks:builder] Invalid node produced by builder", res.error.format());
12558
- }
12559
- }
12560
- } catch {}
12561
- return node;
12562
- }
12563
-
12564
12650
  //#endregion
12565
12651
  //#region ../blocks/src/system/node/fragments/backgroundLayer.ts
12566
12652
  const BACKGROUND_FRAME_BASE_CLASS = "rb-background-frame rb-absolute rb-inset-0 rb-z-neg-10 rb-h-full rb-w-full rb-isolate rb-pointer-events-none";
@@ -13817,10 +13903,9 @@ function generateHeaderCss(options) {
13817
13903
  }));
13818
13904
  cssChunks.push(generateLogoTextBehaviorStyles(header.logoText, themeId));
13819
13905
  cssChunks.push(generateHeaderNavLinkStyles(header, themeId, tokens, theme, headerContrastTreatment, headerNavTextSize));
13820
- const menuHeader = contextualDropdownHeader(header);
13821
- const dropdown = resolveDropdownSurface(menuHeader, theme, tokens, solvedInks);
13822
- cssChunks.push(generateDropdownContainerStyles(menuHeader, themeId, tokens, dropdown));
13823
- cssChunks.push(generateDropdownLinkStyles(menuHeader, themeId, tokens, theme, dropdown));
13906
+ const dropdown = resolveDropdownSurface(header, theme, tokens, solvedInks);
13907
+ cssChunks.push(generateDropdownContainerStyles(themeId, tokens, dropdown));
13908
+ cssChunks.push(generateDropdownLinkStyles(header, themeId, tokens, theme, dropdown));
13824
13909
  cssChunks.push(generateDropdownCaretStyles(themeId));
13825
13910
  cssChunks.push(generateDropdownTriggerOverrides(header, themeId));
13826
13911
  cssChunks.push(generateMobilePanelStyles(themeId, dropdown));
@@ -13935,10 +14020,10 @@ function generateLogoTextBehaviorStyles(logoText, themeId) {
13935
14020
  /**
13936
14021
  * Generate dropdown menu container styles
13937
14022
  */
13938
- function generateDropdownContainerStyles(header, themeId, tokens, surface) {
14023
+ function generateDropdownContainerStyles(themeId, tokens, surface) {
13939
14024
  const selector = `:where([data-theme-scope="${themeId}"]) .nav-dropdown-menu`;
13940
14025
  const rules = [];
13941
- const dropdownStyle = header.dropdownStyle;
14026
+ const dropdownStyle = surface.style;
13942
14027
  rules.push(...NAV_DROPDOWN_CONTAINER_RAIL_CSS_RULES);
13943
14028
  rules.push(`background-color: ${surface.backgroundColor};`);
13944
14029
  rules.push(...surface.foregroundDeclarations);
@@ -13977,8 +14062,9 @@ function dropdownLinkEffects(style, textToken, opacity) {
13977
14062
  options: { hoverColorToken: style.hoverTextColor }
13978
14063
  }] : []];
13979
14064
  }
13980
- function dropdownNavLinkStyle(header, textToken) {
13981
- const style = header.dropdownStyle;
14065
+ function dropdownNavLinkStyle(header, surface) {
14066
+ const style = surface.style;
14067
+ const textToken = surface.textToken;
13982
14068
  return {
13983
14069
  name: "Dropdown",
13984
14070
  typography: "body",
@@ -14014,11 +14100,11 @@ function generateDropdownLinkStyles(header, themeId, tokens, theme, surface) {
14014
14100
  themeId,
14015
14101
  tokens,
14016
14102
  theme,
14017
- style: dropdownNavLinkStyle(header, surface.textToken),
14103
+ style: dropdownNavLinkStyle(header, surface),
14018
14104
  className: "nav-dropdown-link"
14019
14105
  });
14020
14106
  const selector = `:where([data-theme-scope="${themeId}"]) .nav-dropdown-link`;
14021
- return baseCSS + `\n${selector} {\n ${dropdownTypographyRules(header.dropdownStyle).join("\n ")}\n}\n`;
14107
+ return baseCSS + `\n${selector} {\n ${dropdownTypographyRules(surface.style).join("\n ")}\n}\n`;
14022
14108
  }
14023
14109
  function generateDropdownCaretStyles(themeId) {
14024
14110
  const selector = `:where([data-theme-scope="${themeId}"]) .nav-caret`;
@@ -14050,37 +14136,32 @@ ${selector} {
14050
14136
  `.trim();
14051
14137
  }
14052
14138
  /** Reuse the header's decided opening tone; unknown openings retain opaque paint. */
14053
- function contextualDropdownHeader(header) {
14139
+ function contextualDropdownStyle(header) {
14054
14140
  const style = header.dropdownStyle;
14055
14141
  const treatment = style?.surfaceTreatment;
14056
- if (!style || treatment?.kind !== "frosted" || treatment.tone !== "opening") return header;
14057
- const opening = header.scrollTreatment;
14058
- if (!opening) return {
14059
- ...header,
14060
- dropdownStyle: {
14061
- ...style,
14062
- surfaceTreatment: { kind: "solid" }
14063
- }
14142
+ if (!style || treatment?.kind !== "frosted" || treatment.tone !== "opening") return style;
14143
+ const tone = readOpeningToneProjection(header);
14144
+ if (!tone) return {
14145
+ ...style,
14146
+ surfaceTreatment: { kind: "solid" }
14064
14147
  };
14065
- const dark = opening.backgroundTone === "dark";
14066
- const textColor = dark ? "neutral-50" : "neutral-950";
14148
+ const textColor = tone === "dark" ? "neutral-50" : "neutral-950";
14067
14149
  return {
14068
- ...header,
14069
- dropdownStyle: {
14070
- ...style,
14071
- background: dark ? "neutral-950" : "neutral-50",
14072
- textColor,
14073
- hoverBackground: textColor,
14074
- borderColor: null
14075
- }
14150
+ ...style,
14151
+ background: tone === "dark" ? "neutral-950" : "neutral-50",
14152
+ textColor,
14153
+ hoverBackground: textColor,
14154
+ borderColor: null
14076
14155
  };
14077
14156
  }
14078
- function dropdownTextCandidate(header) {
14079
- return header.dropdownStyle?.textColor ?? ((header.navColor ?? header.textColor)?.trim() || "text");
14157
+ /** Menu text wins; only an absent preference falls back to the header's ink. */
14158
+ function dropdownTextCandidate(style, header) {
14159
+ return style?.textColor ?? ((header.navColor ?? header.textColor)?.trim() || "text");
14080
14160
  }
14081
14161
  function resolveDropdownSurface(header, theme, tokens, solvedInks) {
14082
- const backgroundToken = header.dropdownStyle?.background ?? "surface";
14083
- const candidate = dropdownTextCandidate(header);
14162
+ const style = contextualDropdownStyle(header);
14163
+ const backgroundToken = style?.background ?? "surface";
14164
+ const candidate = dropdownTextCandidate(style, header);
14084
14165
  const foreground = resolveSurfaceForeground({
14085
14166
  type: "color",
14086
14167
  color: backgroundToken,
@@ -14090,7 +14171,8 @@ function resolveDropdownSurface(header, theme, tokens, solvedInks) {
14090
14171
  backgroundColor: tokens.getColor(backgroundToken),
14091
14172
  textToken: foreground.kind === "known" ? foreground.roles.text : candidate,
14092
14173
  foregroundDeclarations: [...foreground.kind === "known" ? surfaceForegroundDeclarations(surfaceForegroundInputFromResolved(foreground, (token) => tokens.getColor(token))) : [`color: ${tokens.getColor(candidate)};`], ...surfaceInkDeclarations(surfaceInkPublication(foreground, solvedInks))],
14093
- treatment: header.dropdownStyle?.surfaceTreatment
14174
+ treatment: style?.surfaceTreatment,
14175
+ style
14094
14176
  };
14095
14177
  }
14096
14178
  /** Solid paint is the fallback. Blur is enhancement, never the readability mechanism. */
@@ -15148,17 +15230,14 @@ const semanticGapTransform = {
15148
15230
  *
15149
15231
  * Use this transform when binding gap as an inline style rather than a class.
15150
15232
  * The output values use CSS calc() with --space-mult for theme-aware sizing.
15233
+ * An unset or unknown gap gives nothing, so the binding's fallback supplies
15234
+ * the default and a Look-owned gap stays unset.
15151
15235
  */
15152
15236
  const semanticGapValueTransform = {
15153
15237
  id: "boxStyles.semanticGapValue",
15154
15238
  kind: "string",
15155
15239
  summary: "Map semantic gap value to CSS gap value for inline styles",
15156
- run: (value, options, context) => {
15157
- if (options?.legacyOnly && asPartialObject(context.viewModel?.content)?._lookSlots !== undefined) return undefined;
15158
- const fallback = options?.fallback ?? "medium";
15159
- const gap = isSemanticSpacing(value) ? value : fallback;
15160
- return GAP_VALUE_MAP[gap];
15161
- }
15240
+ run: (value) => isSemanticSpacing(value) ? GAP_VALUE_MAP[value] : undefined
15162
15241
  };
15163
15242
  const boxStylesTransforms = [
15164
15243
  spacingTransform,
@@ -15200,14 +15279,8 @@ function twoColumnProps(config$1) {
15200
15279
  } },
15201
15280
  ...config$1.gapFrom ? { style: { gap: { $bind: {
15202
15281
  from: config$1.gapFrom,
15203
- transforms: [{
15204
- id: "boxStyles.semanticGapValue",
15205
- options: {
15206
- fallback,
15207
- legacyOnly: config$1.lookSlots === true
15208
- }
15209
- }],
15210
- ...config$1.lookSlots ? {} : { fallback: GAP_VALUE_MAP[fallback] }
15282
+ transforms: [{ id: "boxStyles.semanticGapValue" }],
15283
+ fallback: GAP_VALUE_MAP[fallback]
15211
15284
  } } } } : {}
15212
15285
  };
15213
15286
  }
@@ -16043,6 +16116,7 @@ function createButtonGroup(options = {}) {
16043
16116
  ...defaultVariant ? { defaultValue: defaultVariant } : {},
16044
16117
  ui: {
16045
16118
  intent: "style",
16119
+ underLooks: "owner",
16046
16120
  widget: "buttonVariant"
16047
16121
  }
16048
16122
  },
@@ -16083,6 +16157,7 @@ function createButtonGroup(options = {}) {
16083
16157
  maxLength: 64,
16084
16158
  ui: {
16085
16159
  intent: "style",
16160
+ underLooks: "owner",
16086
16161
  widget: "iconPicker",
16087
16162
  iconPickerPreset: "cta"
16088
16163
  }
@@ -16095,6 +16170,7 @@ function createButtonGroup(options = {}) {
16095
16170
  maxLength: 64,
16096
16171
  ui: {
16097
16172
  intent: "style",
16173
+ underLooks: "owner",
16098
16174
  widget: "iconPicker",
16099
16175
  iconPickerPreset: "cta"
16100
16176
  }
@@ -16852,28 +16928,6 @@ const formCopyFragment = defineFragment({
16852
16928
  } }), bind("content.intro"))]
16853
16929
  });
16854
16930
 
16855
- //#endregion
16856
- //#region ../blocks/src/system/helpers/api-bindings.ts
16857
- /**
16858
- * Standard API bindings that all interactive blocks need.
16859
- */
16860
- const apiBindings = {
16861
- now: { $bind: { from: "$root.now" } },
16862
- siteId: { $bind: { from: "$root.siteId" } },
16863
- apiBaseUrl: { $bind: { from: "$root.apiBaseUrl" } }
16864
- };
16865
- function withApiBindings(props$1, options) {
16866
- const includeApiBaseUrl = options?.includeApiBaseUrl ?? true;
16867
- const bindings = includeApiBaseUrl ? apiBindings : {
16868
- siteId: apiBindings.siteId,
16869
- now: apiBindings.now
16870
- };
16871
- return {
16872
- ...bindings,
16873
- ...props$1
16874
- };
16875
- }
16876
-
16877
16931
  //#endregion
16878
16932
  //#region ../blocks/src/system/fragments/library/formEmbed.ts
16879
16933
  const formEmbedFragment = defineFragment({
@@ -18395,6 +18449,7 @@ const newsletterFormFragment = defineFragment({
18395
18449
  }
18396
18450
  ],
18397
18451
  layout: [el("newsletter-form", withApiBindings({
18452
+ interactionContext: { $bind: { from: "$root.interactionContext" } },
18398
18453
  lookSlots: { $bind: { from: "content._lookSlots" } },
18399
18454
  source: { $bind: {
18400
18455
  from: "mailingListSource",
@@ -18541,7 +18596,6 @@ function createBlockManifest(config$1) {
18541
18596
  icon: config$1.icon ?? "Box",
18542
18597
  layout,
18543
18598
  variants,
18544
- arrangementOwnedFieldIds: config$1.arrangementOwnedFieldIds,
18545
18599
  variantMeaning: config$1.variantMeaning,
18546
18600
  defaultVariant: config$1.defaultVariant,
18547
18601
  variantOptions: config$1.variantOptions,
@@ -18624,7 +18678,8 @@ const heroActionsNote = richText({ className: "hero-actions-note" }, when("conte
18624
18678
  const heroContentNodes = [
18625
18679
  lookCaption,
18626
18680
  ...heroCopyAndCta.layout,
18627
- heroActionsNote
18681
+ heroActionsNote,
18682
+ heroNewsletterAction
18628
18683
  ];
18629
18684
  function heroContentCard(children, gap, copyAtCard) {
18630
18685
  return styledContainer({
@@ -18755,7 +18810,8 @@ const headlineRowLayout = heroLookLayout([
18755
18810
  lookCaption,
18756
18811
  ...heroCopyFragment.layout.slice(2),
18757
18812
  ...heroCtaRowFragment.layout,
18758
- heroActionsNote
18813
+ heroActionsNote,
18814
+ heroNewsletterAction
18759
18815
  ]),
18760
18816
  lookPhoto
18761
18817
  ]);
@@ -19295,26 +19351,20 @@ const introConfig = {
19295
19351
  gapSelectField({
19296
19352
  label: "Gap between media and text",
19297
19353
  defaultValue: "comfortable",
19298
- visibleWhen: { allOf: [{
19354
+ visibleWhen: {
19299
19355
  field: "variant",
19300
19356
  equals: "media-copy"
19301
- }, {
19302
- field: "blockLook",
19303
- notEquals: "intro-photo-beside-text"
19304
- }] }
19357
+ }
19305
19358
  }),
19306
19359
  createImageColSizeField({
19307
19360
  id: "ratio",
19308
19361
  label: "Media column size",
19309
19362
  defaultValue: "1/2",
19310
19363
  uiIntent: "display",
19311
- visibleWhen: { allOf: [{
19364
+ visibleWhen: {
19312
19365
  field: "variant",
19313
19366
  equals: "media-copy"
19314
- }, {
19315
- field: "blockLook",
19316
- notEquals: "intro-photo-beside-text"
19317
- }] }
19367
+ }
19318
19368
  }),
19319
19369
  createAspectRatioField({
19320
19370
  id: "aspectRatio",
@@ -19818,6 +19868,7 @@ const ctaFullConfig = {
19818
19868
  },
19819
19869
  id: "block.cta-full",
19820
19870
  title: "Call to action",
19871
+ titleSource: "title",
19821
19872
  category: "text-and-images",
19822
19873
  contentSource: { kind: "inline" },
19823
19874
  fragments: [{
@@ -19942,7 +19993,8 @@ function readinessStage(surface) {
19942
19993
  //#region ../blocks/src/system/blocks/readiness.ts
19943
19994
  const newsletterReadiness = {
19944
19995
  needs: ["mailingList"],
19945
- assess: (content, facts) => {
19996
+ assess: (content, facts, interaction) => {
19997
+ if (interaction?.kind === "demo") return ready;
19946
19998
  if (facts.mailingList.kind === "Unavailable") return unknownReadiness;
19947
19999
  const targeting = parseMailingListPlacementTargeting(content.targeting ?? { mode: "default" });
19948
20000
  if (!targeting.ok) return unknownReadiness;
@@ -22942,6 +22994,7 @@ const footerStandardContactBindings = {
22942
22994
  successMessage: { $bind: { from: "module.engagement.runtime.successMessage" } }
22943
22995
  };
22944
22996
  const footerMailingListBindings = {
22997
+ buttonVariant: { $bind: { from: "module.engagement.runtime.buttonVariant" } },
22945
22998
  source: { $bind: { from: "module.engagement.runtime.source" } },
22946
22999
  sourceRef: { $bind: { from: "module.engagement.runtime.sourceRef" } },
22947
23000
  mailingList: { $bind: { from: "module.engagement.runtime.mailingList" } },
@@ -23446,7 +23499,6 @@ const dataLoaders = { ...entriesLoader ? { entries: {
23446
23499
  }
23447
23500
  } } : {} };
23448
23501
  const testimonialsManifest = createBlockManifest({
23449
- arrangementOwnedFieldIds: ["maxEntries", "avatarLayout"],
23450
23502
  variantMeaning: {
23451
23503
  kind: "arrangement",
23452
23504
  lookOnlyKeys: [
@@ -23464,6 +23516,7 @@ const testimonialsManifest = createBlockManifest({
23464
23516
  },
23465
23517
  promotedFields: ["maxEntries"],
23466
23518
  title: "Testimonials",
23519
+ titleSource: "heading",
23467
23520
  category: "people",
23468
23521
  contentSource: { kind: "inline" },
23469
23522
  includeContainerStyles: true,
@@ -25052,7 +25105,10 @@ const mediaTextManifest = createBlockManifest({
25052
25105
  leadParagraphSlot: { $bind: { from: "content._lookSlots.lede" } },
25053
25106
  lookSlots: { $bind: { from: "content._lookSlots" } }
25054
25107
  };
25055
- return [styledCard([richText(props$1, bind("content.text"))], mediaTextCardOptions, when("content.wrapTextInCard")), richText(props$1, when("content.wrapTextInCard", { not: true }), bind("content.text"))];
25108
+ return [styledCard([richText(props$1, bind("content.text"))], mediaTextCardOptions, when("content.wrapTextInCard")), richText(props$1, when("content.wrapTextInCard", {
25109
+ equals: true,
25110
+ not: true
25111
+ }), bind("content.text"))];
25056
25112
  };
25057
25113
  const bodyTextColumn = el("div", {}, textContentNodes("rb-prose rb-max-w-none"));
25058
25114
  const defaultTextColumn = el("div", {}, [lookCopyHeading, ...textContentNodes("rb-prose rb-max-w-none")]);
@@ -26128,7 +26184,7 @@ const eventDisplayFields = [
26128
26184
  description: "Shows the venue's name and address.",
26129
26185
  required: false,
26130
26186
  defaultValue: true,
26131
- ui: { intent: "display" }
26187
+ ui: { intent: "behavior" }
26132
26188
  },
26133
26189
  {
26134
26190
  id: "showMap",
@@ -26137,7 +26193,7 @@ const eventDisplayFields = [
26137
26193
  description: "Shows a map when the event's venue has a location set.",
26138
26194
  required: false,
26139
26195
  defaultValue: true,
26140
- ui: { intent: "display" }
26196
+ ui: { intent: "behavior" }
26141
26197
  },
26142
26198
  {
26143
26199
  id: "showCapacity",
@@ -26146,7 +26202,7 @@ const eventDisplayFields = [
26146
26202
  description: "Shows how many places are left.",
26147
26203
  required: false,
26148
26204
  defaultValue: true,
26149
- ui: { intent: "display" }
26205
+ ui: { intent: "behavior" }
26150
26206
  }
26151
26207
  ];
26152
26208
  /**
@@ -26161,7 +26217,7 @@ const emptyStateField = {
26161
26217
  multiline: false,
26162
26218
  defaultValue: "No upcoming events scheduled.",
26163
26219
  maxLength: 200,
26164
- ui: { intent: "display" }
26220
+ ui: { intent: "behavior" }
26165
26221
  };
26166
26222
  /**
26167
26223
  * Layout selection field with grid/stack options
@@ -26952,6 +27008,31 @@ function resolveEventCta(event, buttonText) {
26952
27008
  hidden: false
26953
27009
  };
26954
27010
  }
27011
+ /**
27012
+ * The CTA for a catalogue card that stands for a whole dated series. The card
27013
+ * carries the next occurrence's capacity, but the visitor picks from the
27014
+ * series' upcoming dates, so it says "Sold out" (or offers the waitlist) only
27015
+ * when none of `upcomingDates` can be booked. The first date with places
27016
+ * decides; failing that, the first full date with a waitlist; failing both,
27017
+ * the next occurrence as {@link resolveEventCta} reads it. The link always
27018
+ * goes to the series, never to the date that decided.
27019
+ *
27020
+ * Whole-series events share one run capacity, so they need no dates and read
27021
+ * exactly as {@link resolveEventCta}; so does a dated series with none listed.
27022
+ */
27023
+ function resolveDatedSeriesCta(series, upcomingDates, buttonText) {
27024
+ const deciding = series.bookingScope === "single_occurrence" ? upcomingDates.find((date) => isOpenForBooking(date) && !isEventFull(date)) ?? upcomingDates.find((date) => isOpenForBooking(date) && isEventFull(date) && canJoinEventWaitlistOnAnyMode(date)) : undefined;
27025
+ if (!deciding) return resolveEventCta(series, buttonText);
27026
+ const cta = resolveEventCta(deciding, buttonText);
27027
+ return {
27028
+ ...cta,
27029
+ href: resolveEventHref(series),
27030
+ external: resolveRuntimeEventDestination(series).kind === "external"
27031
+ };
27032
+ }
27033
+ function isOpenForBooking(event) {
27034
+ return event.bookingAvailability.kind !== "closed";
27035
+ }
26955
27036
 
26956
27037
  //#endregion
26957
27038
  //#region ../calendar/dist/grid.js
@@ -29304,6 +29385,7 @@ function buildEventListWeek(anchor, startOfWeek, timeZone) {
29304
29385
  timeZone
29305
29386
  });
29306
29387
  return {
29388
+ days: viewport.days.map(formatDateKey),
29307
29389
  title: formatDateRange({
29308
29390
  kind: "civil",
29309
29391
  value: viewport.days[0]
@@ -29326,6 +29408,70 @@ function eventListWindowEvents(events, window$1) {
29326
29408
  return instant >= start && instant <= end;
29327
29409
  });
29328
29410
  }
29411
+ /** Server and client describe the shown week the same way, from the same inputs. */
29412
+ function eventListWeekDays(week, today, timeZone) {
29413
+ return {
29414
+ days: week.days,
29415
+ today: formatDateKey(today),
29416
+ timeZone
29417
+ };
29418
+ }
29419
+ /**
29420
+ * All seven days of the shown week, in week order and including empty ones.
29421
+ * A session goes under the day it starts on in its own zone, the day its tile
29422
+ * time describes. One whose own date falls outside the week (only possible in
29423
+ * another zone) goes under its day in the site zone, so it still shows.
29424
+ * Sessions arrive in start order, so with more pages to load a day is only
29425
+ * known to be empty when a later day already has a session.
29426
+ */
29427
+ function weekColumnDays(week, events, allLoaded) {
29428
+ const siteDay = groupItemsByDate(events, {
29429
+ getStartsAt: (event) => event.startsAt,
29430
+ getTimeZone: () => week.timeZone
29431
+ });
29432
+ const siteKey = new Map([...siteDay].flatMap(([key, items]) => items.map((item) => [item, key])));
29433
+ const columnKey = (event) => {
29434
+ const own = eventLocalDateKey(event);
29435
+ return week.days.includes(own) ? own : siteKey.get(event);
29436
+ };
29437
+ const options = eventDateOptions({
29438
+ siteTimeZone: week.timeZone,
29439
+ timeZone: week.timeZone
29440
+ });
29441
+ const lastLoaded = events.map(columnKey).filter((key) => key !== undefined).sort().at(-1);
29442
+ return week.days.map((dateKey) => {
29443
+ const date = {
29444
+ kind: "civil",
29445
+ value: parseBookingLocalDate(dateKey)
29446
+ };
29447
+ const dayEvents = events.filter((event) => columnKey(event) === dateKey).sort((left, right) => new Date(left.startsAt).getTime() - new Date(right.startsAt).getTime());
29448
+ return {
29449
+ dateKey,
29450
+ isToday: dateKey === week.today,
29451
+ label: {
29452
+ weekday: formatDate(date, options, {
29453
+ date: "omit",
29454
+ weekday: "short",
29455
+ year: "omit"
29456
+ }),
29457
+ fullWeekday: formatDate(date, options, {
29458
+ date: "omit",
29459
+ weekday: "long",
29460
+ year: "omit"
29461
+ }),
29462
+ day: formatDate(date, options, {
29463
+ date: "omit",
29464
+ day: "numeric",
29465
+ year: "omit"
29466
+ })
29467
+ },
29468
+ sessions: dayEvents.length > 0 ? {
29469
+ kind: "some",
29470
+ events: dayEvents
29471
+ } : allLoaded || lastLoaded !== undefined && dateKey < lastLoaded ? { kind: "none" } : { kind: "unknown" }
29472
+ };
29473
+ });
29474
+ }
29329
29475
 
29330
29476
  //#endregion
29331
29477
  //#region ../blocks/src/system/runtime/shared/bookingPaymentOptionCopy.ts
@@ -30747,7 +30893,7 @@ function MembershipHero({ membershipName, classPrefix, onBookForSomeoneElse }) {
30747
30893
  * LICENSE file in the root directory of this source tree.
30748
30894
  */
30749
30895
  var require_react_dom_production = /* @__PURE__ */ __commonJSMin(((exports) => {
30750
- var React$81 = require_react();
30896
+ var React$82 = require_react();
30751
30897
  function formatProdErrorMessage(code) {
30752
30898
  var url = "https://react.dev/errors/" + code;
30753
30899
  if (1 < arguments.length) {
@@ -30784,7 +30930,7 @@ var require_react_dom_production = /* @__PURE__ */ __commonJSMin(((exports) => {
30784
30930
  implementation
30785
30931
  };
30786
30932
  }
30787
- var ReactSharedInternals = React$81.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;
30933
+ var ReactSharedInternals = React$82.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;
30788
30934
  function getCrossOriginStringAs(as, input) {
30789
30935
  if ("font" === as) return "";
30790
30936
  if ("string" === typeof input) return "use-credentials" === input ? input : "";
@@ -30927,7 +31073,7 @@ var require_react_dom_development = /* @__PURE__ */ __commonJSMin(((exports) =>
30927
31073
  return dispatcher;
30928
31074
  }
30929
31075
  "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(Error());
30930
- var React$90 = require_react(), Internals$1 = {
31076
+ var React$91 = require_react(), Internals$1 = {
30931
31077
  d: {
30932
31078
  f: noop$2,
30933
31079
  r: function() {
@@ -30943,7 +31089,7 @@ var require_react_dom_development = /* @__PURE__ */ __commonJSMin(((exports) =>
30943
31089
  },
30944
31090
  p: 0,
30945
31091
  findDOMNode: null
30946
- }, REACT_PORTAL_TYPE$1 = Symbol.for("react.portal"), ReactSharedInternals$1 = React$90.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;
31092
+ }, REACT_PORTAL_TYPE$1 = Symbol.for("react.portal"), ReactSharedInternals$1 = React$91.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;
30947
31093
  "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");
30948
31094
  exports.__DOM_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE = Internals$1;
30949
31095
  exports.createPortal = function(children, container) {
@@ -36205,37 +36351,6 @@ function buildTransferredAttendeeConfirmationEmailPaymentSummary(options) {
36205
36351
  }
36206
36352
  return assertNever$7(options.paymentMethod);
36207
36353
  }
36208
- function toConfirmationEmailTemplatePaymentFields(summary) {
36209
- if (!summary) {
36210
- return {};
36211
- }
36212
- switch (summary.kind) {
36213
- case "free": return { paymentMethod: "free" };
36214
- case "manual_due": return { paymentMethod: "manual" };
36215
- case "managed_balance_due": return {
36216
- paymentMethod: "manual",
36217
- managedBalanceDueAt: summary.dueAt
36218
- };
36219
- case "waived": return { paymentMethod: "waived" };
36220
- case "pass": return {
36221
- paymentMethod: "pass",
36222
- passName: summary.passName,
36223
- passCreditsUsed: summary.passCreditsUsed
36224
- };
36225
- case "membership": return {
36226
- paymentMethod: "membership",
36227
- membershipName: summary.membershipName
36228
- };
36229
- case "monetary": return {
36230
- paymentMethod: "stripe",
36231
- amountPaid: summary.amountPaidCents,
36232
- amountOutstanding: summary.amountOutstandingCents,
36233
- currency: summary.currency,
36234
- managedBalanceDueAt: summary.dueAt
36235
- };
36236
- }
36237
- return assertNever$7(summary);
36238
- }
36239
36354
 
36240
36355
  //#endregion
36241
36356
  //#region ../commerce/src/purchase/discountApplication.ts
@@ -38697,11 +38812,6 @@ const eventRegistrationErrors = {
38697
38812
  message: "The payment options for this event have changed. Please check the latest options before continuing.",
38698
38813
  action: "payment-options"
38699
38814
  },
38700
- verificationFailed: {
38701
- endsCommand: false,
38702
- message: "We couldn’t confirm this request came from a person. Please refresh the page and try again.",
38703
- action: "none"
38704
- },
38705
38815
  idempotencyConflict: {
38706
38816
  endsCommand: false,
38707
38817
  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.",
@@ -39348,8 +39458,11 @@ function getStepLabel(step) {
39348
39458
  function visitorHoldsOwnPlace(input) {
39349
39459
  return input.hasWaitlistClaim || input.retryingHeldPlace;
39350
39460
  }
39351
- function getTicketSelectionPurpose(admission) {
39352
- return admission.kind === "waitlist" ? "waitlist" : "book";
39461
+ /** A first quote needs a selection, including when all published tickets are full.
39462
+ * Cached capacity permits requesting waitlist places; fresh admission still owns continuation. */
39463
+ function getTicketSelectionPurpose(input) {
39464
+ if (input.admission.kind === "waitlist") return "waitlist";
39465
+ return input.admission.kind === "checking" && input.event && canJoinEventWaitlist(input.event, { attendanceMode: input.attendanceMode }) ? "waitlist" : "book";
39353
39466
  }
39354
39467
  function resolveRegistrationAdmission(input) {
39355
39468
  if (input.holdsOwnPlace) return { kind: "resume" };
@@ -40714,6 +40827,20 @@ function normalizeOfferingsPreviewGroupOrder(value) {
40714
40827
  keys
40715
40828
  } : { kind: "default" };
40716
40829
  }
40830
+ /** Choosing a target opens its effective existing override, or supplies a complete target for one append. */
40831
+ function planOfferingPreviewCardSelection(overrides, sourceKey) {
40832
+ const existing = overrides.map((override, index) => ({
40833
+ override,
40834
+ index
40835
+ })).filter((item) => item.override.sourceKey === sourceKey).at(-1);
40836
+ return existing ? {
40837
+ kind: "open",
40838
+ index: existing.index
40839
+ } : {
40840
+ kind: "append",
40841
+ value: { sourceKey }
40842
+ };
40843
+ }
40717
40844
  function inferLegacyOfferingsPreviewGroupOrder(overrides) {
40718
40845
  const keys = uniqueOfferingsPreviewSourceKeys((overrides ?? []).map((override) => override.sourceKey));
40719
40846
  return keys.length >= 2 ? keys : [];
@@ -41220,7 +41347,11 @@ const eventCalendarListLayoutValues = [
41220
41347
  "grid",
41221
41348
  "compact"
41222
41349
  ];
41223
- const arrangementOnlyListLayouts = ["ledger", "day-groups"];
41350
+ const arrangementOnlyListLayouts = [
41351
+ "ledger",
41352
+ "day-groups",
41353
+ "week-columns"
41354
+ ];
41224
41355
  const eventListArrangementValues = [...eventCalendarListLayoutValues, ...arrangementOnlyListLayouts];
41225
41356
  const eventCalendarListLayoutOptions = [
41226
41357
  {
@@ -41462,7 +41593,6 @@ const eventRegistrationCommonSchemaShape = {
41462
41593
  successMessage: z.string().optional(),
41463
41594
  buttonVariant: registrationButtonVariantSchema.optional(),
41464
41595
  host: bookingHostSchema.optional(),
41465
- spamProtectionEnabled: z.boolean().optional(),
41466
41596
  supportEmail: z.string().optional(),
41467
41597
  sitePasses: publicPassProductCollectionSchema.nullable().optional(),
41468
41598
  siteMemberships: publicMembershipProductCollectionSchema.nullable().optional(),
@@ -41662,7 +41792,6 @@ const eventRegistrationBlockRuntime = defineClientOwnedBlockRuntime({
41662
41792
  successMessage: source.successMessage,
41663
41793
  buttonVariant: source.buttonVariant,
41664
41794
  host: source.host ?? "overlay",
41665
- spamProtectionEnabled: source.spamProtectionEnabled,
41666
41795
  supportEmail: source.supportEmail,
41667
41796
  sitePasses: source.sitePasses ?? null,
41668
41797
  siteMemberships: source.siteMemberships ?? null,
@@ -42276,7 +42405,7 @@ const eventDetailsManifest = createBlockManifest({
42276
42405
  label: "Show venue",
42277
42406
  required: false,
42278
42407
  defaultValue: true,
42279
- ui: { intent: "display" }
42408
+ ui: { intent: "behavior" }
42280
42409
  },
42281
42410
  {
42282
42411
  id: "showTitle",
@@ -42284,7 +42413,7 @@ const eventDetailsManifest = createBlockManifest({
42284
42413
  label: "Show event title",
42285
42414
  required: false,
42286
42415
  defaultValue: false,
42287
- ui: { intent: "display" }
42416
+ ui: { intent: "behavior" }
42288
42417
  },
42289
42418
  {
42290
42419
  id: "showDescription",
@@ -42292,7 +42421,7 @@ const eventDetailsManifest = createBlockManifest({
42292
42421
  label: "Show event description",
42293
42422
  required: false,
42294
42423
  defaultValue: false,
42295
- ui: { intent: "display" }
42424
+ ui: { intent: "behavior" }
42296
42425
  },
42297
42426
  {
42298
42427
  id: "showMap",
@@ -42301,7 +42430,7 @@ const eventDetailsManifest = createBlockManifest({
42301
42430
  description: "Shows a map, as long as the venue's location is set.",
42302
42431
  required: false,
42303
42432
  defaultValue: true,
42304
- ui: { intent: "display" }
42433
+ ui: { intent: "behavior" }
42305
42434
  },
42306
42435
  {
42307
42436
  id: "showOtherDates",
@@ -42309,7 +42438,7 @@ const eventDetailsManifest = createBlockManifest({
42309
42438
  label: "Show other dates",
42310
42439
  required: false,
42311
42440
  defaultValue: true,
42312
- ui: { intent: "display" }
42441
+ ui: { intent: "behavior" }
42313
42442
  },
42314
42443
  {
42315
42444
  id: "otherDatesLimit",
@@ -42336,7 +42465,7 @@ const eventDetailsManifest = createBlockManifest({
42336
42465
  label: "All dates"
42337
42466
  }
42338
42467
  ],
42339
- ui: { intent: "display" }
42468
+ ui: { intent: "behavior" }
42340
42469
  },
42341
42470
  {
42342
42471
  id: "showCapacity",
@@ -42344,7 +42473,7 @@ const eventDetailsManifest = createBlockManifest({
42344
42473
  label: "Show capacity",
42345
42474
  required: false,
42346
42475
  defaultValue: false,
42347
- ui: { intent: "display" }
42476
+ ui: { intent: "behavior" }
42348
42477
  },
42349
42478
  {
42350
42479
  id: "showCost",
@@ -42353,7 +42482,7 @@ const eventDetailsManifest = createBlockManifest({
42353
42482
  description: "Shows the ticket price for paid events.",
42354
42483
  required: false,
42355
42484
  defaultValue: true,
42356
- ui: { intent: "display" }
42485
+ ui: { intent: "behavior" }
42357
42486
  },
42358
42487
  {
42359
42488
  id: "showAcceptedPasses",
@@ -42362,7 +42491,7 @@ const eventDetailsManifest = createBlockManifest({
42362
42491
  description: "Shows which passes can be used for this event.",
42363
42492
  required: false,
42364
42493
  defaultValue: true,
42365
- ui: { intent: "display" }
42494
+ ui: { intent: "behavior" }
42366
42495
  },
42367
42496
  {
42368
42497
  id: "showAcceptedMemberships",
@@ -42371,7 +42500,7 @@ const eventDetailsManifest = createBlockManifest({
42371
42500
  description: "Shows which memberships include this event.",
42372
42501
  required: false,
42373
42502
  defaultValue: true,
42374
- ui: { intent: "display" }
42503
+ ui: { intent: "behavior" }
42375
42504
  }
42376
42505
  ],
42377
42506
  layout: [styledSection({
@@ -42711,6 +42840,7 @@ function getCardOrientation(layout) {
42711
42840
  case "grid": return "vertical";
42712
42841
  case "ledger":
42713
42842
  case "day-groups":
42843
+ case "week-columns":
42714
42844
  case "compact": return "vertical";
42715
42845
  }
42716
42846
  }
@@ -44177,19 +44307,33 @@ function mediaImageHostProps(props$1, style) {
44177
44307
  }
44178
44308
 
44179
44309
  //#endregion
44180
- //#region ../blocks/src/primitives/content/components/RichText.tsx
44310
+ //#region ../blocks/src/primitives/content/richTextImageSize.ts
44181
44311
  function parseDimension(value) {
44182
- if (typeof value === "number" && Number.isFinite(value) && value > 0) {
44183
- return Math.round(value);
44184
- }
44185
- if (typeof value === "string" && value.trim().length > 0) {
44186
- const parsed = Number(value);
44187
- if (Number.isFinite(parsed) && parsed > 0) {
44188
- return Math.round(parsed);
44189
- }
44190
- }
44191
- return undefined;
44312
+ const parsed = typeof value === "number" || typeof value === "string" ? Number(value) : NaN;
44313
+ return Number.isFinite(parsed) && parsed > 0 ? Math.round(parsed) : undefined;
44314
+ }
44315
+ /** View and editor images must request the same resource to preserve browser cache reuse. */
44316
+ function getRichTextImageSize(attrs) {
44317
+ const width = parseDimension(attrs.width);
44318
+ const height = parseDimension(attrs.height);
44319
+ const urlOptions = width ? {
44320
+ width,
44321
+ resize: "contain",
44322
+ quality: 85
44323
+ } : height ? {
44324
+ height,
44325
+ resize: "contain",
44326
+ quality: 85
44327
+ } : ImagePresets.full;
44328
+ return {
44329
+ width,
44330
+ height,
44331
+ urlOptions
44332
+ };
44192
44333
  }
44334
+
44335
+ //#endregion
44336
+ //#region ../blocks/src/primitives/content/components/RichText.tsx
44193
44337
  function normalizeRel(target, rel) {
44194
44338
  const normalizedRel = rel?.trim();
44195
44339
  if (target !== "_blank") {
@@ -44268,20 +44412,7 @@ function renderSimpleNode(node, key, children, context) {
44268
44412
  default: return null;
44269
44413
  }
44270
44414
  }
44271
- function richTextImageOptions(width, height) {
44272
- if (width) return {
44273
- width,
44274
- resize: "contain",
44275
- quality: 85
44276
- };
44277
- if (height) return {
44278
- height,
44279
- resize: "contain",
44280
- quality: 85
44281
- };
44282
- return ImagePresets.full;
44283
- }
44284
- function resolveRichTextImageSource(attrs, width, height, context) {
44415
+ function resolveRichTextImageSource(attrs, context) {
44285
44416
  if (attrs.identifier !== undefined && attrs.identifier !== null) {
44286
44417
  const parsed = parseCanonicalMediaIdentifier(attrs.identifier);
44287
44418
  if (!parsed.ok) return undefined;
@@ -44289,7 +44420,7 @@ function resolveRichTextImageSource(attrs, width, height, context) {
44289
44420
  return resolveImageUrlWithContext({
44290
44421
  type: "image",
44291
44422
  identifier: parsed.value
44292
- }, richTextImageOptions(width, height), context);
44423
+ }, getRichTextImageSize(attrs).urlOptions, context);
44293
44424
  }
44294
44425
  return typeof attrs.src === "string" ? attrs.src.trim() || undefined : undefined;
44295
44426
  }
@@ -44297,9 +44428,8 @@ function resolveRichTextImageSource(attrs, width, height, context) {
44297
44428
  }
44298
44429
  function renderRichTextImage(node, key, context) {
44299
44430
  const attrs = node.attrs ?? {};
44300
- const width = parseDimension(attrs.width);
44301
- const height = parseDimension(attrs.height);
44302
- const src = resolveRichTextImageSource(attrs, width, height, context.imageResolveContext);
44431
+ const { width, height } = getRichTextImageSize(attrs);
44432
+ const src = resolveRichTextImageSource(attrs, context.imageResolveContext);
44303
44433
  if (!src) return null;
44304
44434
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", {
44305
44435
  src,
@@ -44719,6 +44849,12 @@ const eventItemParts = {
44719
44849
  "description",
44720
44850
  "action"
44721
44851
  ],
44852
+ "week-columns": [
44853
+ "time",
44854
+ "title",
44855
+ "meta",
44856
+ "places"
44857
+ ],
44722
44858
  grid: [
44723
44859
  "image",
44724
44860
  "date",
@@ -44745,11 +44881,17 @@ const eventItemParts = {
44745
44881
  function eventItemFacts(props$1) {
44746
44882
  const options = eventDateOptions(props$1.event);
44747
44883
  const availability = getEventAvailabilityStatus(props$1.event);
44884
+ const time = formatEventTimeRange(props$1.event, options);
44885
+ const price$1 = formatEventPrice(props$1.event);
44748
44886
  return {
44749
44887
  date: formatEventCompactDateRail(props$1.event.startsAt, options, "as-written"),
44750
- time: formatEventTimeRange(props$1.event, options),
44751
- price: formatEventPrice(props$1.event),
44752
- meta: eventItemMeta(props$1),
44888
+ time,
44889
+ price: price$1,
44890
+ link: resolveEventLinkProps(props$1.event),
44891
+ meta: eventItemMeta(props$1, {
44892
+ time,
44893
+ price: price$1
44894
+ }),
44753
44895
  venueIcon: props$1.arrangement === "compact" && props$1.showVenue !== false && Boolean(props$1.event.venue),
44754
44896
  places: props$1.showCapacity ? formatEventRemainingPlaces(props$1.event, { full: "Sold out" }) : null,
44755
44897
  availability: availability.isFull ? "full" : availability.status === "filling" ? "low" : "available",
@@ -44757,12 +44899,12 @@ function eventItemFacts(props$1) {
44757
44899
  };
44758
44900
  }
44759
44901
  /** Compact rows keep pricing in the details rail and time in the action rail. */
44760
- function eventItemMeta(props$1) {
44902
+ function eventItemMeta(props$1, formatted) {
44761
44903
  const parts = props$1.parts ?? eventItemParts[props$1.arrangement];
44762
44904
  const venue = props$1.showVenue !== false ? props$1.event.venue?.name : null;
44763
44905
  const teacher = formatEventTeacherLine(props$1.event);
44764
- const time = parts.includes("time") ? null : formatEventTimeRange(props$1.event, eventDateOptions(props$1.event));
44765
- const price$1 = props$1.arrangement === "compact" && !parts.includes("price") ? formatEventPrice(props$1.event) : null;
44906
+ const time = parts.includes("time") ? null : formatted.time;
44907
+ const price$1 = props$1.arrangement === "compact" && !parts.includes("price") ? formatted.price : null;
44766
44908
  return (props$1.arrangement === "compact" ? [
44767
44909
  venue,
44768
44910
  teacher,
@@ -44824,11 +44966,11 @@ function renderCalendarTrailingParts(props$1, parts, renderPart) {
44824
44966
  }) : content;
44825
44967
  }
44826
44968
  function eventItemTag(arrangement) {
44827
- return arrangement === "ledger" || arrangement === "day-groups" ? "li" : "article";
44969
+ return arrangement === "ledger" || arrangement === "day-groups" || arrangement === "week-columns" ? "li" : "article";
44828
44970
  }
44829
44971
  function renderEventItemContentPart({ part, props: props$1, facts }) {
44830
44972
  switch (part) {
44831
- case "image": return renderEventItemImage(props$1);
44973
+ case "image": return renderEventItemImage(props$1, facts.link);
44832
44974
  case "date": return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("time", {
44833
44975
  ...listLookSlot(props$1, "date"),
44834
44976
  dateTime: props$1.event.startsAt,
@@ -44851,7 +44993,7 @@ function renderEventItemContentPart({ part, props: props$1, facts }) {
44851
44993
  case "title": return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", {
44852
44994
  ...listLookSlot(props$1, "item-title"),
44853
44995
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", {
44854
- ...resolveEventLinkProps(props$1.event),
44996
+ ...facts.link,
44855
44997
  children: props$1.event.title
44856
44998
  })
44857
44999
  });
@@ -44879,8 +45021,7 @@ function renderEventItemContentPart({ part, props: props$1, facts }) {
44879
45021
  item: {
44880
45022
  id: props$1.event.id,
44881
45023
  title: props$1.event.title,
44882
- text: facts.description,
44883
- action: { label: "" }
45024
+ text: facts.description
44884
45025
  },
44885
45026
  presentation: props$1
44886
45027
  });
@@ -44902,8 +45043,7 @@ function renderEventItemMeta({ props: props$1, facts }) {
44902
45043
  ]
44903
45044
  }) : null;
44904
45045
  }
44905
- function renderEventItemImage(props$1) {
44906
- const link$2 = resolveEventLinkProps(props$1.event);
45046
+ function renderEventItemImage(props$1, link$2) {
44907
45047
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CardListContentPart, {
44908
45048
  part: "media",
44909
45049
  item: {
@@ -45318,7 +45458,7 @@ function eventCardCategoryBadge(category) {
45318
45458
  *
45319
45459
  * This component is server-safe (uses no client APIs like Intl).
45320
45460
  */
45321
- const EventCard = ({ event, cardRole = "default", buttonVariant = "primary", buttonText, showVenue = true, showMap = true, mapSlot, allowMap = true, lookSlots, itemSurfaces, showCapacity = true, showImage = true, showCategory = true, showSummary = true, orientation = "vertical", presentation, headingLevel, imageResolveContext }) => {
45461
+ const EventCard = ({ event, cardRole = "default", buttonVariant = "primary", buttonText, showVenue = true, showMap = true, mapSlot, allowMap = true, lookSlots, itemSurfaces, showCapacity = true, showImage = true, showCategory = true, showSummary = true, orientation = "vertical", presentation, headingLevel, imageResolveContext, upcomingDates }) => {
45322
45462
  const { presentationClass, cardHeadingLevel, formattedDate, formattedTime, cta, cardClass, title, summary, image, category, categoryBadge, hasImage, dateFact, priceText, teacherLine, capacityText, orientationClass } = eventCardFacts({
45323
45463
  event,
45324
45464
  presentation,
@@ -45328,7 +45468,8 @@ const EventCard = ({ event, cardRole = "default", buttonVariant = "primary", but
45328
45468
  showCategory,
45329
45469
  showImage,
45330
45470
  showCapacity,
45331
- orientation
45471
+ orientation,
45472
+ upcomingDates
45332
45473
  });
45333
45474
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("article", {
45334
45475
  ...listLookSlot({
@@ -45606,13 +45747,13 @@ function EventLookDate({ event, ...presentation }) {
45606
45747
  })]
45607
45748
  });
45608
45749
  }
45609
- function eventCardFacts({ event, presentation, headingLevel, buttonText, cardRole, showCategory, showImage, showCapacity, orientation }) {
45750
+ function eventCardFacts({ event, presentation, headingLevel, buttonText, cardRole, showCategory, showImage, showCapacity, orientation, upcomingDates }) {
45610
45751
  const { presentation: cardPresentation, presentationClass, headingLevel: cardHeadingLevel } = resolveEventCardOptions({
45611
45752
  presentation,
45612
45753
  headingLevel
45613
45754
  });
45614
45755
  const { formattedDate, formattedTime } = formatEventCardWhen(event);
45615
- const cta = resolveEventCta(event, buttonText);
45756
+ const cta = resolveDatedSeriesCta(event, upcomingDates ?? [], buttonText);
45616
45757
  const cardClass = boxStyleClassNames({ role: cardRole }, { baseClass: "event-card" });
45617
45758
  const title = event.title;
45618
45759
  const summary = event.presentation?.summary ?? event.description;
@@ -46086,6 +46227,157 @@ function canonicalEventSeriesScope(seriesIds) {
46086
46227
  return seriesIds == null ? null : [...new Set(seriesIds.split(",").filter(Boolean))].sort().join(",");
46087
46228
  }
46088
46229
 
46230
+ //#endregion
46231
+ //#region ../blocks/src/system/runtime/hooks/loadStateError.ts
46232
+ function toError(error$1, fallbackMessage) {
46233
+ return error$1 instanceof Error ? error$1 : new Error(fallbackMessage);
46234
+ }
46235
+
46236
+ //#endregion
46237
+ //#region ../blocks/src/system/runtime/hooks/useEventPagination.state.ts
46238
+ function createInitialEventPaginationLoadState(events, scope) {
46239
+ return {
46240
+ kind: "ready",
46241
+ requestId: 0,
46242
+ page: {
46243
+ scope,
46244
+ events,
46245
+ hasMore: hasMoreEventPages(events, scope.pageSize)
46246
+ }
46247
+ };
46248
+ }
46249
+ function eventPaginationLoadReducer(state, action) {
46250
+ switch (action.type) {
46251
+ case "started": return {
46252
+ kind: "loading",
46253
+ requestId: state.requestId + 1,
46254
+ operation: action.operation
46255
+ };
46256
+ case "succeeded": return state.kind === "loading" && state.requestId === action.requestId ? {
46257
+ kind: "ready",
46258
+ requestId: state.requestId,
46259
+ page: acceptEventPage(state.operation, action.events)
46260
+ } : state;
46261
+ case "failed": return state.kind === "loading" && state.requestId === action.requestId ? {
46262
+ ...state,
46263
+ kind: "error",
46264
+ error: action.error
46265
+ } : state;
46266
+ case "synced": return {
46267
+ ...createInitialEventPaginationLoadState(action.events, action.scope),
46268
+ requestId: state.requestId + 1
46269
+ };
46270
+ default: return assertNever$4(action);
46271
+ }
46272
+ }
46273
+ function eventPageOperationScope(operation) {
46274
+ switch (operation.kind) {
46275
+ case "replace": return operation.scope;
46276
+ case "append": return operation.page.scope;
46277
+ default: return assertNever$4(operation);
46278
+ }
46279
+ }
46280
+ function eventPageOperationQuery(operation) {
46281
+ switch (operation.kind) {
46282
+ case "replace": return operation.scope.query;
46283
+ case "append": return operation.query;
46284
+ default: return assertNever$4(operation);
46285
+ }
46286
+ }
46287
+ function acceptEventPage(operation, events) {
46288
+ const scope = eventPageOperationScope(operation);
46289
+ const hasMore = hasMoreEventPages(events, scope.pageSize);
46290
+ switch (operation.kind) {
46291
+ case "replace": return {
46292
+ scope,
46293
+ events,
46294
+ hasMore
46295
+ };
46296
+ case "append": return {
46297
+ scope,
46298
+ events: mergeEventPaginationEvents(operation.page.events, events),
46299
+ hasMore
46300
+ };
46301
+ default: return assertNever$4(operation);
46302
+ }
46303
+ }
46304
+ /** Retry consumes the recorded operation. Load more is possible only from an accepted page. */
46305
+ function planEventPageOperation(state, scope, intent) {
46306
+ if (scope.query.seriesIds === "") return null;
46307
+ switch (intent) {
46308
+ case "replace": return {
46309
+ kind: "replace",
46310
+ scope
46311
+ };
46312
+ case "retry": return state.kind === "error" && eventPageOperationScope(state.operation).key === scope.key ? state.operation : null;
46313
+ case "append": {
46314
+ if (state.kind !== "ready" || state.page.scope.key !== scope.key || !state.page.hasMore) return null;
46315
+ const cursor = state.page.events.at(-1);
46316
+ return {
46317
+ kind: "append",
46318
+ page: state.page,
46319
+ query: {
46320
+ ...scope.query,
46321
+ afterStartsAt: cursor?.startsAt,
46322
+ afterId: cursor?.occurrenceId
46323
+ }
46324
+ };
46325
+ }
46326
+ default: return assertNever$4(intent);
46327
+ }
46328
+ }
46329
+ /** A changed scope is pending even before the effect starts its replacement request. */
46330
+ function getEventPaginationView(state, scope) {
46331
+ const stateScope = state.kind === "ready" ? state.page.scope : eventPageOperationScope(state.operation);
46332
+ if (stateScope.key !== scope.key) return {
46333
+ events: [],
46334
+ loading: true,
46335
+ error: null,
46336
+ hasMore: false
46337
+ };
46338
+ switch (state.kind) {
46339
+ case "ready": return {
46340
+ ...state.page,
46341
+ loading: false,
46342
+ error: null
46343
+ };
46344
+ case "loading": return {
46345
+ ...getOperationPage(state.operation),
46346
+ loading: true,
46347
+ error: null
46348
+ };
46349
+ case "error": return {
46350
+ ...getOperationPage(state.operation),
46351
+ loading: false,
46352
+ error: state.error
46353
+ };
46354
+ default: return assertNever$4(state);
46355
+ }
46356
+ }
46357
+ function getOperationPage(operation) {
46358
+ switch (operation.kind) {
46359
+ case "replace": return {
46360
+ events: [],
46361
+ hasMore: false
46362
+ };
46363
+ case "append": return operation.page;
46364
+ default: return assertNever$4(operation);
46365
+ }
46366
+ }
46367
+ function getEventIdentity(event) {
46368
+ return event.occurrenceId || event.id;
46369
+ }
46370
+ function mergeEventPaginationEvents(existingEvents, newEvents) {
46371
+ const existingIds = new Set(existingEvents.map(getEventIdentity));
46372
+ return [...existingEvents, ...newEvents.filter((event) => !existingIds.has(getEventIdentity(event)))];
46373
+ }
46374
+ function toEventPaginationLoadError(error$1) {
46375
+ return toError(error$1, "Unknown error");
46376
+ }
46377
+ function hasMoreEventPages(events, pageSize) {
46378
+ return events.length >= pageSize;
46379
+ }
46380
+
46089
46381
  //#endregion
46090
46382
  //#region ../blocks/src/system/blocks/events/shared/calendarWindow.ts
46091
46383
  function resolveCalendarReadProfile(content) {
@@ -46437,6 +46729,7 @@ function buildEventCollectionHydration(source) {
46437
46729
  function buildEventCollectionListingDisplay(display, prefetchedEvents, className) {
46438
46730
  const initialEvents = display.events.slice(0, display.eventsPerPage);
46439
46731
  return {
46732
+ allLoaded: prefetchedEvents && !hasMoreEventPages(display.events, display.eventsPerPage),
46440
46733
  kind: "event-listing",
46441
46734
  sectionAction: display.sectionAction,
46442
46735
  panelHeading: display.panelHeading,
@@ -46515,7 +46808,13 @@ const eventListingDisplaySchema = z.object({
46515
46808
  showCapacity: z.boolean(),
46516
46809
  showPhotos: z.boolean().optional(),
46517
46810
  orientation: cardOrientationSchema,
46518
- events: z.array(publicEventSchema)
46811
+ events: z.array(publicEventSchema),
46812
+ week: z.object({
46813
+ days: z.array(z.string()).length(7),
46814
+ today: z.string(),
46815
+ timeZone: z.string()
46816
+ }).optional(),
46817
+ allLoaded: z.boolean().optional()
46519
46818
  });
46520
46819
  const eventListingHydrationSchema = z.object({
46521
46820
  siteId: z.string(),
@@ -47013,6 +47312,115 @@ const eventListingBlockDefinition = {
47013
47312
  } }
47014
47313
  };
47015
47314
 
47315
+ //#endregion
47316
+ //#region ../blocks/src/system/blocks/events/eventSelectionChips.ts
47317
+ /** The event types a calendar can be narrowed to, in the order they're offered. */
47318
+ const EVENT_SELECTION_TYPE_OPTIONS = [
47319
+ {
47320
+ value: "course",
47321
+ label: "Courses"
47322
+ },
47323
+ {
47324
+ value: "class",
47325
+ label: "Classes"
47326
+ },
47327
+ {
47328
+ value: "workshop",
47329
+ label: "Workshops"
47330
+ },
47331
+ {
47332
+ value: "retreat",
47333
+ label: "Retreats"
47334
+ },
47335
+ {
47336
+ value: "performance",
47337
+ label: "Performances"
47338
+ }
47339
+ ];
47340
+ /** Regular and one-off, as the chips' second row names them. */
47341
+ const EVENT_SELECTION_SCOPE_OPTIONS = [
47342
+ {
47343
+ value: "any",
47344
+ label: "Regular and one-off"
47345
+ },
47346
+ {
47347
+ value: "recurring",
47348
+ label: "Regular only"
47349
+ },
47350
+ {
47351
+ value: "oneOff",
47352
+ label: "One-off only"
47353
+ }
47354
+ ];
47355
+ const SPECIAL_DATED_PRESETS = [
47356
+ "workshop",
47357
+ "retreat",
47358
+ "performance"
47359
+ ];
47360
+ /**
47361
+ * Reads the stored fields as chips. The named presets show as the chips that
47362
+ * mean the same thing, so "Regular class schedule" reads as Classes, regular
47363
+ * only, matching how the event loader expands them.
47364
+ */
47365
+ function readEventSelectionChips(fields$1) {
47366
+ switch (fields$1.eventSurface) {
47367
+ case "regularClassSchedule": return {
47368
+ types: ["class"],
47369
+ scope: "recurring"
47370
+ };
47371
+ case "specialDatedEvents": return {
47372
+ types: SPECIAL_DATED_PRESETS,
47373
+ scope: "any"
47374
+ };
47375
+ case "custom": return {
47376
+ types: fields$1.filterEventPresets ?? [],
47377
+ scope: fields$1.scheduleScope ?? "any"
47378
+ };
47379
+ case "all":
47380
+ case undefined: return {
47381
+ types: [],
47382
+ scope: fields$1.scheduleScope ?? "any"
47383
+ };
47384
+ }
47385
+ }
47386
+ /**
47387
+ * The stored fields for a chip choice. Choosing types stores them as Custom;
47388
+ * clearing every type goes back to All events and drops the old type list, so
47389
+ * nothing stale keeps filtering.
47390
+ */
47391
+ function writeEventSelectionChips(chips) {
47392
+ return chips.types.length === 0 && chips.scope === "any" ? {
47393
+ eventSurface: "all",
47394
+ filterEventPresets: [],
47395
+ scheduleScope: "any"
47396
+ } : {
47397
+ eventSurface: "custom",
47398
+ filterEventPresets: chips.types,
47399
+ scheduleScope: chips.scope
47400
+ };
47401
+ }
47402
+ /** "All events": every type, regular and one-off. */
47403
+ function chooseAllEvents() {
47404
+ return {
47405
+ types: [],
47406
+ scope: "any"
47407
+ };
47408
+ }
47409
+ /** Adds or removes one type, keeping the list in the order the options give. */
47410
+ function toggleEventType(chips, type, order) {
47411
+ const next = chips.types.includes(type) ? chips.types.filter((t$1) => t$1 !== type) : [...chips.types, type];
47412
+ return {
47413
+ ...chips,
47414
+ types: order.filter((t$1) => next.includes(t$1))
47415
+ };
47416
+ }
47417
+ function chooseScheduleScope(chips, scope) {
47418
+ return {
47419
+ ...chips,
47420
+ scope
47421
+ };
47422
+ }
47423
+
47016
47424
  //#endregion
47017
47425
  //#region ../blocks/src/system/blocks/events/recurring-schedule-projection.ts
47018
47426
  const weekdayOrder = [
@@ -47981,7 +48389,7 @@ const eventCalendarAdditionalFields = [
47981
48389
  label: "Week"
47982
48390
  }],
47983
48391
  ui: {
47984
- intent: "display",
48392
+ intent: "behavior",
47985
48393
  visibleWhen: {
47986
48394
  field: "variant",
47987
48395
  equals: "list"
@@ -48095,7 +48503,7 @@ const eventCalendarAdditionalFields = [
48095
48503
  }
48096
48504
  ],
48097
48505
  ui: {
48098
- intent: "display",
48506
+ intent: "behavior",
48099
48507
  visibleWhen: {
48100
48508
  field: "variant",
48101
48509
  oneOf: ["combined", "list"]
@@ -48125,7 +48533,7 @@ const eventCalendarAdditionalFields = [
48125
48533
  }
48126
48534
  ],
48127
48535
  ui: {
48128
- intent: "display",
48536
+ intent: "behavior",
48129
48537
  visibleWhen: {
48130
48538
  field: "variant",
48131
48539
  oneOf: ["combined", "list"]
@@ -48138,7 +48546,7 @@ const eventCalendarAdditionalFields = [
48138
48546
  label: "Link to the full list",
48139
48547
  required: false,
48140
48548
  ui: {
48141
- intent: "display",
48549
+ intent: "behavior",
48142
48550
  visibleWhen: { anyOf: [{ allOf: [{
48143
48551
  field: "variant",
48144
48552
  oneOf: ["combined", "list"]
@@ -48160,7 +48568,7 @@ const eventCalendarAdditionalFields = [
48160
48568
  multiline: false,
48161
48569
  defaultValue: "Load more events",
48162
48570
  ui: {
48163
- intent: "display",
48571
+ intent: "behavior",
48164
48572
  visibleWhen: {
48165
48573
  field: "variant",
48166
48574
  oneOf: [
@@ -48187,7 +48595,7 @@ const eventCalendarAdditionalFields = [
48187
48595
  label: "Monday"
48188
48596
  }],
48189
48597
  ui: {
48190
- intent: "display",
48598
+ intent: "behavior",
48191
48599
  visibleWhen: {
48192
48600
  field: "variant",
48193
48601
  oneOf: [
@@ -48223,7 +48631,7 @@ const eventCalendarAdditionalFields = [
48223
48631
  }
48224
48632
  ],
48225
48633
  ui: {
48226
- intent: "display",
48634
+ intent: "behavior",
48227
48635
  visibleWhen: {
48228
48636
  field: "variant",
48229
48637
  equals: "combined"
@@ -48267,7 +48675,7 @@ const eventCalendarAdditionalFields = [
48267
48675
  required: false,
48268
48676
  defaultValue: true,
48269
48677
  ui: {
48270
- intent: "display",
48678
+ intent: "behavior",
48271
48679
  visibleWhen: {
48272
48680
  field: "variant",
48273
48681
  oneOf: [
@@ -48303,7 +48711,7 @@ const eventCalendarAdditionalFields = [
48303
48711
  }
48304
48712
  ],
48305
48713
  ui: {
48306
- intent: "display",
48714
+ intent: "behavior",
48307
48715
  visibleWhen: { allOf: [{
48308
48716
  field: "variant",
48309
48717
  oneOf: [
@@ -48327,7 +48735,7 @@ const eventCalendarAdditionalFields = [
48327
48735
  required: false,
48328
48736
  defaultValue: false,
48329
48737
  ui: {
48330
- intent: "display",
48738
+ intent: "behavior",
48331
48739
  visibleWhen: { allOf: [{
48332
48740
  field: "variant",
48333
48741
  oneOf: [
@@ -48351,7 +48759,7 @@ const eventCalendarAdditionalFields = [
48351
48759
  required: false,
48352
48760
  defaultValue: true,
48353
48761
  ui: {
48354
- intent: "display",
48762
+ intent: "behavior",
48355
48763
  visibleWhen: { allOf: [{
48356
48764
  field: "variant",
48357
48765
  oneOf: [
@@ -48457,8 +48865,7 @@ const eventCalendarAdditionalFields = [
48457
48865
  {
48458
48866
  id: "eventSurface",
48459
48867
  type: "select",
48460
- label: "Event types",
48461
- description: "Choose whether this block shows everything, regular classes, or workshops and special events.",
48868
+ label: "Which events",
48462
48869
  required: false,
48463
48870
  multiple: false,
48464
48871
  defaultValue: "all",
@@ -48480,7 +48887,10 @@ const eventCalendarAdditionalFields = [
48480
48887
  label: "Custom"
48481
48888
  }
48482
48889
  ],
48483
- ui: { intent: "behavior" }
48890
+ ui: {
48891
+ intent: "behavior",
48892
+ widget: "eventSelectionChips"
48893
+ }
48484
48894
  },
48485
48895
  {
48486
48896
  id: "filterEventPresets",
@@ -48490,34 +48900,10 @@ const eventCalendarAdditionalFields = [
48490
48900
  required: false,
48491
48901
  multiple: true,
48492
48902
  defaultValue: [],
48493
- options: [
48494
- {
48495
- value: "course",
48496
- label: "Courses"
48497
- },
48498
- {
48499
- value: "class",
48500
- label: "Classes"
48501
- },
48502
- {
48503
- value: "workshop",
48504
- label: "Workshops"
48505
- },
48506
- {
48507
- value: "retreat",
48508
- label: "Retreats"
48509
- },
48510
- {
48511
- value: "performance",
48512
- label: "Performances"
48513
- }
48514
- ],
48903
+ options: EVENT_SELECTION_TYPE_OPTIONS.map((option) => ({ ...option })),
48515
48904
  ui: {
48516
48905
  intent: "behavior",
48517
- visibleWhen: {
48518
- field: "eventSurface",
48519
- equals: "custom"
48520
- }
48906
+ hidden: true
48521
48907
  }
48522
48908
  },
48523
48909
  {
@@ -48544,10 +48930,7 @@ const eventCalendarAdditionalFields = [
48544
48930
  ],
48545
48931
  ui: {
48546
48932
  intent: "behavior",
48547
- visibleWhen: {
48548
- field: "eventSurface",
48549
- equals: "custom"
48550
- }
48933
+ hidden: true
48551
48934
  }
48552
48935
  },
48553
48936
  createSiteOptionSelectField({
@@ -48594,13 +48977,7 @@ const eventCalendarAdditionalFields = [
48594
48977
  intent: field.id === "_cardStyles" || field.id === "buttonVariant" ? "style" : "content"
48595
48978
  }
48596
48979
  })),
48597
- {
48598
- ...emptyStateField,
48599
- ui: {
48600
- ...emptyStateField.ui ?? {},
48601
- intent: "display"
48602
- }
48603
- },
48980
+ emptyStateField,
48604
48981
  sectionStylesField({
48605
48982
  id: "_sectionStyles",
48606
48983
  label: "Section styles",
@@ -48754,7 +49131,6 @@ const eventCalendarConfig = {
48754
49131
  icon: "CalendarDays",
48755
49132
  layout: eventCalendarLayout,
48756
49133
  variants: eventCalendarVariants,
48757
- arrangementOwnedFieldIds: ["defaultCalendarView"],
48758
49134
  variantMeaning: eventCalendarVariantMeaning,
48759
49135
  defaultVariant: "combined",
48760
49136
  variantOptions: {
@@ -48772,7 +49148,11 @@ const eventCalendarManifest = {
48772
49148
  fields: generatedEventCalendarManifest.fields?.map((field) => field.id === "variant" ? {
48773
49149
  ...field,
48774
49150
  label: "Show events as",
48775
- description: undefined
49151
+ description: undefined,
49152
+ ui: {
49153
+ ...field.ui,
49154
+ widget: "segmented"
49155
+ }
48776
49156
  } : field)
48777
49157
  };
48778
49158
  const eventCalendarBlockDefinition = {
@@ -49081,7 +49461,7 @@ const groupOverrideFields = [
49081
49461
  label: "Hide this card",
49082
49462
  required: false,
49083
49463
  defaultValue: false,
49084
- ui: { intent: "display" }
49464
+ ui: { intent: "behavior" }
49085
49465
  },
49086
49466
  {
49087
49467
  id: "presentation",
@@ -49184,7 +49564,7 @@ const offeringsPreviewFields = [
49184
49564
  label: "6 items"
49185
49565
  }
49186
49566
  ],
49187
- ui: { intent: "display" }
49567
+ ui: { intent: "behavior" }
49188
49568
  },
49189
49569
  {
49190
49570
  id: "groupOrder",
@@ -49198,7 +49578,7 @@ const offeringsPreviewFields = [
49198
49578
  label: labelForOfferingPreviewSourceKey(sourceKey)
49199
49579
  })),
49200
49580
  ui: {
49201
- intent: "display",
49581
+ intent: "behavior",
49202
49582
  widget: "offeringGroupOrder"
49203
49583
  }
49204
49584
  },
@@ -49212,7 +49592,10 @@ const offeringsPreviewFields = [
49212
49592
  itemLabel: "Offering card",
49213
49593
  itemLabelSource: "title",
49214
49594
  allowConversion: false,
49215
- ui: { intent: "content" },
49595
+ ui: {
49596
+ intent: "content",
49597
+ widget: "offeringCardChanges"
49598
+ },
49216
49599
  schema: { fields: groupOverrideFields }
49217
49600
  },
49218
49601
  createButtonVariantField(),
@@ -49453,7 +49836,6 @@ const offeringsPreviewLayout = [styledSection({
49453
49836
  spacing: "comfortable"
49454
49837
  })];
49455
49838
  const offeringsPreviewConfig = {
49456
- arrangementOwnedFieldIds: ["groupOverrides.presentation"],
49457
49839
  variantMeaning: {
49458
49840
  kind: "arrangement",
49459
49841
  lookOnlyKeys: [
@@ -50215,7 +50597,7 @@ const imageGalleryFields = parseFieldDefinitions([
50215
50597
  label: "Show arrows",
50216
50598
  defaultValue: true,
50217
50599
  ui: {
50218
- intent: "behavior",
50600
+ intent: "display",
50219
50601
  visibleWhen: {
50220
50602
  field: "variant",
50221
50603
  equals: "carousel"
@@ -50228,7 +50610,7 @@ const imageGalleryFields = parseFieldDefinitions([
50228
50610
  label: "Show dots",
50229
50611
  defaultValue: false,
50230
50612
  ui: {
50231
- intent: "behavior",
50613
+ intent: "display",
50232
50614
  visibleWhen: {
50233
50615
  field: "variant",
50234
50616
  equals: "carousel"
@@ -50241,7 +50623,7 @@ const imageGalleryFields = parseFieldDefinitions([
50241
50623
  label: "Autoplay",
50242
50624
  defaultValue: false,
50243
50625
  ui: {
50244
- intent: "behavior",
50626
+ intent: "display",
50245
50627
  visibleWhen: {
50246
50628
  field: "variant",
50247
50629
  equals: "carousel"
@@ -50272,7 +50654,7 @@ const imageGalleryFields = parseFieldDefinitions([
50272
50654
  }
50273
50655
  ],
50274
50656
  ui: {
50275
- intent: "behavior",
50657
+ intent: "display",
50276
50658
  visibleWhen: {
50277
50659
  field: "variant",
50278
50660
  equals: "carousel"
@@ -50292,7 +50674,7 @@ const imageGalleryFields = parseFieldDefinitions([
50292
50674
  label: "Show on hover"
50293
50675
  }],
50294
50676
  ui: {
50295
- intent: "behavior",
50677
+ intent: "display",
50296
50678
  visibleWhen: {
50297
50679
  field: "variant",
50298
50680
  equals: "carousel"
@@ -50305,7 +50687,7 @@ const imageGalleryFields = parseFieldDefinitions([
50305
50687
  label: "Loop slides",
50306
50688
  defaultValue: true,
50307
50689
  ui: {
50308
- intent: "behavior",
50690
+ intent: "display",
50309
50691
  visibleWhen: {
50310
50692
  field: "variant",
50311
50693
  equals: "carousel"
@@ -50365,7 +50747,7 @@ const imageGalleryFields = parseFieldDefinitions([
50365
50747
  label: "Pause on hover",
50366
50748
  defaultValue: true,
50367
50749
  ui: {
50368
- intent: "behavior",
50750
+ intent: "display",
50369
50751
  visibleWhen: {
50370
50752
  field: "variant",
50371
50753
  equals: "marquee"
@@ -50403,6 +50785,16 @@ const imageGalleryFields = parseFieldDefinitions([
50403
50785
  }
50404
50786
  }
50405
50787
  },
50788
+ {
50789
+ id: "blackAndWhite",
50790
+ type: "boolean",
50791
+ required: false,
50792
+ label: "Black and white",
50793
+ ui: {
50794
+ intent: "display",
50795
+ hidden: true
50796
+ }
50797
+ },
50406
50798
  {
50407
50799
  id: "imageFilter",
50408
50800
  type: "select",
@@ -52453,7 +52845,6 @@ function shopProductPresentation(hydration, productId, index, count) {
52453
52845
  * - Stripe handles payment security
52454
52846
  */
52455
52847
  const shopManifest = createBlockManifest({
52456
- arrangementOwnedFieldIds: ["layout", "columns"],
52457
52848
  variantMeaning: {
52458
52849
  kind: "arrangement",
52459
52850
  lookOnlyKeys: [
@@ -52494,7 +52885,7 @@ const shopManifest = createBlockManifest({
52494
52885
  description: "Lets visitors buy your class passes.",
52495
52886
  required: false,
52496
52887
  defaultValue: true,
52497
- ui: { intent: "display" }
52888
+ ui: { intent: "behavior" }
52498
52889
  },
52499
52890
  {
52500
52891
  id: "showMemberships",
@@ -52503,7 +52894,7 @@ const shopManifest = createBlockManifest({
52503
52894
  description: "Lets visitors buy your memberships.",
52504
52895
  required: false,
52505
52896
  defaultValue: true,
52506
- ui: { intent: "display" }
52897
+ ui: { intent: "behavior" }
52507
52898
  },
52508
52899
  {
52509
52900
  id: "layout",
@@ -52564,7 +52955,7 @@ const shopManifest = createBlockManifest({
52564
52955
  description: "Shows the description under each one.",
52565
52956
  required: false,
52566
52957
  defaultValue: true,
52567
- ui: { intent: "display" }
52958
+ ui: { intent: "behavior" }
52568
52959
  },
52569
52960
  {
52570
52961
  id: "showValidityPeriod",
@@ -52573,7 +52964,7 @@ const shopManifest = createBlockManifest({
52573
52964
  description: "Shows how long each pass lasts, like 'Valid for 30 days'.",
52574
52965
  required: false,
52575
52966
  defaultValue: true,
52576
- ui: { intent: "display" }
52967
+ ui: { intent: "behavior" }
52577
52968
  },
52578
52969
  {
52579
52970
  id: "showPricePerCredit",
@@ -52582,7 +52973,7 @@ const shopManifest = createBlockManifest({
52582
52973
  description: "Shows what each credit works out at, for passes and packs.",
52583
52974
  required: false,
52584
52975
  defaultValue: true,
52585
- ui: { intent: "display" }
52976
+ ui: { intent: "behavior" }
52586
52977
  },
52587
52978
  createButtonVariantField({
52588
52979
  label: "Button style",
@@ -53650,6 +54041,7 @@ function withOptionalPhone(fields$1, includePhone) {
53650
54041
 
53651
54042
  //#endregion
53652
54043
  //#region ../blocks/src/system/runtime/nodes/newsletter-form.interactive.ts
54044
+ const NEWSLETTER_DEMO_MESSAGE = "This is a demo. No signup has been saved.";
53653
54045
  const NEWSLETTER_SIGNUPS_PAUSED_MESSAGE = "We can’t accept signups right now. Please try again later.";
53654
54046
  function newsletterBlockSubmissionMessage(target) {
53655
54047
  if (target.tag === "block-source") {
@@ -53709,6 +54101,7 @@ const newsletterSourceCommonSchema = z.object({
53709
54101
  siteId: z.string().optional(),
53710
54102
  apiBaseUrl: z.string().optional(),
53711
54103
  mailingList: mailingListContextSchema.optional(),
54104
+ interactionContext: blockInteractionContextSchema.optional(),
53712
54105
  targeting: mailingListTargetingSchema.optional(),
53713
54106
  buttonVariant: newsletterButtonVariantSchema.nullable().optional(),
53714
54107
  spamProtectionEnabled: z.boolean().optional(),
@@ -53729,7 +54122,7 @@ const newsletterSourceSchema = z.discriminatedUnion("source", [
53729
54122
  ])
53730
54123
  }),
53731
54124
  newsletterSourceCommonSchema.extend({
53732
- source: z.literal("signed-footer"),
54125
+ source: z.enum(["signed-footer", "signed-hosted-booking"]),
53733
54126
  sourceRef: z.object({
53734
54127
  tag: z.literal("signed_source_ref"),
53735
54128
  token: signedMailingListSourceTokenSchema
@@ -53759,12 +54152,13 @@ const newsletterHydrationSchema = z.object({
53759
54152
  sourceRef: mailingListSignupBlockSourceRefSchema.nullable()
53760
54153
  }),
53761
54154
  z.object({
53762
- tag: z.literal("signed-footer-source"),
54155
+ tag: z.literal("signed-source"),
53763
54156
  sourceRef: z.object({
53764
54157
  tag: z.literal("signed_source_ref"),
53765
54158
  token: signedMailingListSourceTokenSchema
53766
54159
  })
53767
54160
  }),
54161
+ z.object({ tag: z.literal("demo") }),
53768
54162
  z.object({ tag: z.literal("preview") }),
53769
54163
  z.object({
53770
54164
  tag: z.literal("unpublished-preview"),
@@ -53793,27 +54187,30 @@ const newsletterIslandMetaCodec = createZodCodec(z.object({
53793
54187
  apiBaseUrl: z.string().optional()
53794
54188
  }));
53795
54189
  const newsletterIslandMetaKeys = defineInteractiveIslandMetaKeys("siteId", "apiBaseUrl");
53796
- function buildNewsletterDisplay(source) {
53797
- const context = source.mailingList;
53798
- const form$1 = context?.tag === "configured" ? context.form : {
54190
+ function newsletterGlobalForm(context) {
54191
+ return context?.tag === "configured" ? context.form : {
53799
54192
  fields: { preset: "emailOnly" },
53800
54193
  includeOptionalPhone: false,
53801
54194
  buttonLabel: "Subscribe",
53802
54195
  successMessage: DEFAULT_MAILING_LIST_SUCCESS_MESSAGE,
53803
54196
  privacyNote: null
53804
54197
  };
54198
+ }
54199
+ function buildNewsletterDisplay(source) {
54200
+ const context = source.mailingList;
54201
+ const form$1 = newsletterGlobalForm(context);
53805
54202
  const targeting = source.targeting ?? { mode: "default" };
53806
54203
  const assessment = assessMailingListTargeting(context, targeting);
53807
54204
  const choices = resolveRuntimeChoices(assessment);
53808
54205
  return {
53809
54206
  kind: "newsletter-form",
53810
54207
  ...source.lookSlots ? { lookSlots: source.lookSlots } : {},
53811
- availability: assessment.tag === "available" ? "ready" : "unavailable",
54208
+ availability: source.interactionContext?.kind === "demo" || assessment.tag === "available" ? "ready" : "unavailable",
53812
54209
  className: source.className ?? null,
53813
54210
  buttonLabel: form$1.buttonLabel,
53814
- successMessage: form$1.successMessage,
54211
+ successMessage: source.interactionContext?.kind === "demo" ? NEWSLETTER_DEMO_MESSAGE : form$1.successMessage,
53815
54212
  buttonVariant: source.buttonVariant ?? "primary",
53816
- privacyNote: form$1.privacyNote,
54213
+ privacyNote: newsletterPrivacyNote(source.source, form$1.privacyNote),
53817
54214
  fields: getGlobalFormFields(form$1, source),
53818
54215
  choices
53819
54216
  };
@@ -53834,12 +54231,13 @@ const newsletterFormBlockRuntime = defineProgressiveBlockRuntime({
53834
54231
  setupRevision: source.mailingList?.tag === "configured" ? source.mailingList.revision : null,
53835
54232
  choiceProvider: targeting.mode === "custom" ? targeting.provider : null,
53836
54233
  choicePresentation: presentation.tag,
53837
- spamProtectionEnabled: source.spamProtectionEnabled
54234
+ spamProtectionEnabled: source.interactionContext?.kind === "demo" ? false : source.spamProtectionEnabled
53838
54235
  }
53839
54236
  };
53840
54237
  }
53841
54238
  });
53842
54239
  function projectNewsletterFormHydrationTarget(source) {
54240
+ if (source.interactionContext?.kind === "demo") return { tag: "demo" };
53843
54241
  switch (source.source) {
53844
54242
  case "block": {
53845
54243
  switch (source.newsletterBlockSubmission.tag) {
@@ -53859,8 +54257,9 @@ function projectNewsletterFormHydrationTarget(source) {
53859
54257
  default: return assertNever(source.newsletterBlockSubmission);
53860
54258
  }
53861
54259
  }
54260
+ case "signed-hosted-booking":
53862
54261
  case "signed-footer": return {
53863
- tag: "signed-footer-source",
54262
+ tag: "signed-source",
53864
54263
  sourceRef: source.sourceRef
53865
54264
  };
53866
54265
  case "preview": return { tag: "preview" };
@@ -53916,6 +54315,10 @@ function parseRequiredMailingListSignedSourceToken(value) {
53916
54315
  }
53917
54316
  return parsed;
53918
54317
  }
54318
+ /** Hosted signup always explains preferences, alongside any owner-authored note. */
54319
+ function newsletterPrivacyNote(source, privacyNote) {
54320
+ return source !== "signed-hosted-booking" || privacyNote?.includes(DEFAULT_MAILING_LIST_PRIVACY_NOTE) ? privacyNote : [privacyNote, DEFAULT_MAILING_LIST_PRIVACY_NOTE].filter(Boolean).join(" ");
54321
+ }
53919
54322
 
53920
54323
  //#endregion
53921
54324
  //#region ../blocks/src/system/blocks/newsletter-signup.ts
@@ -54526,15 +54929,6 @@ const teamMembersManifest = createBlockManifest({
54526
54929
  stack: [when("content._effectiveLook", { not: true })(stackVariant), when("content._effectiveLook")(cardListVariant)],
54527
54930
  ...Object.fromEntries(arrangementOnlyKeys.map((key) => [key, cardListVariant]))
54528
54931
  },
54529
- arrangementOwnedFieldIds: [
54530
- "layoutWidth",
54531
- "thumbnailShape",
54532
- "thumbnailPadding",
54533
- "imageColSize",
54534
- "stackImagePosition",
54535
- "stackContentAlignment",
54536
- "gap"
54537
- ],
54538
54932
  variantMeaning: {
54539
54933
  kind: "arrangement",
54540
54934
  lookOnlyKeys: [...arrangementOnlyKeys]
@@ -54988,21 +55382,21 @@ const locationMapManifest = createBlockManifest({
54988
55382
  type: "boolean",
54989
55383
  label: "Show opening hours",
54990
55384
  defaultValue: true,
54991
- ui: { intent: "display" }
55385
+ ui: { intent: "behavior" }
54992
55386
  }),
54993
55387
  parseFieldDefinition({
54994
55388
  id: "showAddressText",
54995
55389
  type: "boolean",
54996
55390
  label: "Show the address",
54997
55391
  defaultValue: true,
54998
- ui: { intent: "display" }
55392
+ ui: { intent: "behavior" }
54999
55393
  }),
55000
55394
  parseFieldDefinition({
55001
55395
  id: "showDirections",
55002
55396
  type: "boolean",
55003
55397
  label: "Show directions button",
55004
55398
  defaultValue: true,
55005
- ui: { intent: "display" }
55399
+ ui: { intent: "behavior" }
55006
55400
  }),
55007
55401
  parseFieldDefinition({
55008
55402
  id: "directionsLabel",
@@ -55011,7 +55405,7 @@ const locationMapManifest = createBlockManifest({
55011
55405
  defaultValue: LOCATION_MAP_DEFAULTS.directionsLabel,
55012
55406
  maxLength: 60,
55013
55407
  ui: {
55014
- intent: "display",
55408
+ intent: "behavior",
55015
55409
  visibleWhen: {
55016
55410
  field: "showDirections",
55017
55411
  equals: true
@@ -55023,7 +55417,7 @@ const locationMapManifest = createBlockManifest({
55023
55417
  type: "boolean",
55024
55418
  label: "Show a wider area",
55025
55419
  defaultValue: false,
55026
- ui: { intent: "display" }
55420
+ ui: { intent: "behavior" }
55027
55421
  }),
55028
55422
  parseFieldDefinition({
55029
55423
  id: "googleMapsLabel",
@@ -55031,7 +55425,7 @@ const locationMapManifest = createBlockManifest({
55031
55425
  label: "Google Maps button label",
55032
55426
  defaultValue: "Open in Google Maps",
55033
55427
  maxLength: 60,
55034
- ui: { intent: "display" }
55428
+ ui: { intent: "behavior" }
55035
55429
  }),
55036
55430
  parseFieldDefinition({
55037
55431
  id: "heightPx",
@@ -55907,10 +56301,6 @@ function normalizeBlockContent(definition$1, content) {
55907
56301
  ...Object.fromEntries(Object.entries(normalized).filter(([key]) => owned.has(key)))
55908
56302
  };
55909
56303
  }
55910
- const REGISTRY_SYMBOL = Symbol.for("@riverbankcms/blocks/system/definitions");
55911
- const isBlocksTestRuntime = typeof process !== "undefined" && typeof process.env !== "undefined" && process.env.RIVERBANK_BLOCKS_TEST === "1";
55912
- const globalScope = globalThis;
55913
- const blockStore = isBlocksTestRuntime ? new Map() : globalScope[REGISTRY_SYMBOL] ??= new Map();
55914
56304
  function ensureDefaults() {
55915
56305
  ensureSystemBlockDefinitionsRegistered();
55916
56306
  }
@@ -55957,230 +56347,6 @@ function clearBlockDefinitions() {
55957
56347
  resetSystemBlockDefinitionRegistration();
55958
56348
  }
55959
56349
 
55960
- //#endregion
55961
- //#region ../blocks/src/system/manifest/storedLayout.ts
55962
- /** The content field `parseStoredVariant` also reads; a block without stored variants keeps its layout there. */
55963
- const layoutFieldId = "layout";
55964
- function storedVariantKeys(manifest) {
55965
- const lookOnly = manifest.variantMeaning.lookOnlyKeys ?? [];
55966
- return Object.keys(manifest.variants ?? {}).filter((key) => !lookOnly.includes(key));
55967
- }
55968
- function optionValues(options) {
55969
- return Array.isArray(options) ? options.flatMap((option) => typeof option === "object" && option !== null && "value" in option && typeof option.value === "string" ? [option.value] : []) : [];
55970
- }
55971
- /**
55972
- * A block with no stored variants that offers a `layout` select (the shop)
55973
- * declares its layouts there. Read as a mode's arrangement declaration, so the
55974
- * same resolver decides: a stored value the block still has, or the default.
55975
- */
55976
- function layoutFieldDeclaration(manifest) {
55977
- const field = (manifest.fields ?? []).find((candidate) => typeof candidate === "object" && candidate !== null && "id" in candidate && candidate.id === layoutFieldId && "type" in candidate && candidate.type === "select");
55978
- const keys = optionValues(field?.options);
55979
- const [firstKey] = keys;
55980
- if (field === undefined || firstKey === undefined) return null;
55981
- return {
55982
- arrangementField: layoutFieldId,
55983
- keys,
55984
- defaultKey: typeof field.defaultValue === "string" && keys.includes(field.defaultValue) ? field.defaultValue : firstKey
55985
- };
55986
- }
55987
- function fieldDeclaration(manifest) {
55988
- if (manifest.variantMeaning.kind === "mode") return manifest.variantMeaning;
55989
- return storedVariantKeys(manifest).length === 0 ? layoutFieldDeclaration(manifest) : null;
55990
- }
55991
- /** Every layout a block can store, for the block's own layout axis. Look-only arrangements are never stored. */
55992
- function storedLayoutKeys(manifest) {
55993
- return fieldDeclaration(manifest)?.keys ?? storedVariantKeys(manifest);
55994
- }
55995
- /**
55996
- * The layout a block renders by when no Look arranges it: the stored value if
55997
- * the block still has it, otherwise the default. The renderer's own resolvers
55998
- * decide, so a reader of stored layouts cannot disagree with the page.
55999
- */
56000
- function resolveStoredLayout(manifest, content) {
56001
- const field = fieldDeclaration(manifest);
56002
- return field === null ? resolveEffectiveArrangement({
56003
- manifest: arrangementManifestFromVariants(manifest),
56004
- storedVariant: parseStoredVariant(manifest, content)
56005
- }).key : resolveModeArrangement({
56006
- declaration: field,
56007
- content,
56008
- mode: null
56009
- }).key;
56010
- }
56011
-
56012
- //#endregion
56013
- //#region ../blocks/src/system/data/selectBlockContent.ts
56014
- /** Canonical admitted content: legacy publishedContent never selects a version. */
56015
- function selectBlockContent(block, stage = "published") {
56016
- const source = stage === "preview" && block.draftContent ? block.draftContent : block.content;
56017
- return isObjectRecord(source) ? stripStaleTransitionStyleGroup(source) : {};
56018
- }
56019
-
56020
- //#endregion
56021
- //#region ../blocks/src/system/data/readinessPresentation.ts
56022
- /** Presentation-only wording; domain assessments and tests use closed reason codes. */
56023
- const READINESS_REASON_COPY = {
56024
- mailing_destination: "Pick where sign-ups go. Until you do, this signup stays hidden from visitors.",
56025
- mailing_setup: "Pick where sign-ups go. Until you do, this signup stays hidden from visitors.",
56026
- form_not_chosen: "Choose a form. Until you do, this block stays hidden from visitors.",
56027
- form_deleted: "The form this block used has been deleted. Choose another one. Until you do, this block stays hidden from visitors.",
56028
- testimonials_none: "Add a testimonial to show here. Until you do, this block stays hidden from visitors.",
56029
- testimonials_unpublished: "Publish a testimonial to show it here. Until you do, this block stays hidden from visitors.",
56030
- testimonials_empty: "There are no testimonials to show here yet. Until there are, this block stays hidden from visitors.",
56031
- team_empty: "Add people to your team to show them here. Until you do, this block stays hidden from visitors.",
56032
- members_empty: "Add someone to show here. Until you do, this block stays hidden from visitors.",
56033
- product_not_chosen: "Choose a product. Until you do, this block stays hidden from visitors.",
56034
- product_gone: "The product this block showed is no longer available. Choose another one. Until you do, this block stays hidden from visitors.",
56035
- gallery_empty: "Add a photo. Until you do, this gallery stays hidden from visitors."
56036
- };
56037
-
56038
- //#endregion
56039
- //#region ../blocks/src/system/data/readinessFacts.ts
56040
- const countSchema = z.array(z.unknown()).transform((entries) => entries.length);
56041
- const formSchema = z.union([z.null(), z.object({
56042
- id: z.string(),
56043
- slug: z.string().optional()
56044
- })]).transform((form$1) => form$1 !== null);
56045
- const productsSchema = z.object({ products: z.array(z.object({ slug: z.string() })) });
56046
- /** Both producers pass raw facts through the same stage admission. */
56047
- function readinessFactsFromLoaders(stage, input) {
56048
- const facts = {
56049
- mailingList: loaderFactProducers.mailingList(input),
56050
- testimonials: loaderFactProducers.testimonials(input),
56051
- team: loaderFactProducers.team(input),
56052
- forms: loaderFactProducers.forms(input),
56053
- products: loaderFactProducers.products(input),
56054
- template: loaderFactProducers.template(input)
56055
- };
56056
- return admitReadinessFacts(stage, {
56057
- stage: input.prefetched?.loaderSnapshot?.stage ?? (input.previewStage === "preview" ? "draft" : "published"),
56058
- facts
56059
- });
56060
- }
56061
- const loaderFactProducers = {
56062
- mailingList: (input) => input.mailingList === undefined ? unavailableReadinessFact : loadedReadinessFact(input.mailingList),
56063
- testimonials: (input) => mapFact(firstLoaderFact(input, "testimonials", "entries", countSchema), (count) => ({
56064
- count,
56065
- total: "unknown"
56066
- })),
56067
- team: (input) => firstLoaderFact(input, "team", "members", countSchema),
56068
- forms: (input) => new Map(projections(input, "forms").flatMap(({ id, block }) => {
56069
- const selection = chosenString(block.requests.form?.params.formSlug ?? block.requests.form?.params.formId);
56070
- return selection ? [[selection, loaderFact(input, id, "form", formSchema)]] : [];
56071
- })),
56072
- products: (input) => new Map(projections(input, "products").flatMap(({ id, block }) => {
56073
- const selection = chosenString(block.content.productSlug);
56074
- return selection ? [[selection, mapFact(loaderFact(input, id, "products", productsSchema), ({ products }) => products.some((product) => product.slug === selection))]] : [];
56075
- })),
56076
- template: (input) => loadedReadinessFact(input.template)
56077
- };
56078
- function projections(input, need) {
56079
- return Object.entries(input.prefetched?.loaderSnapshot?.blocks ?? {}).flatMap(([id, block]) => getBlockDefinition(block.kind)?.readiness?.needs.includes(need) ? [{
56080
- id,
56081
- block
56082
- }] : []);
56083
- }
56084
- function firstLoaderFact(input, need, key, schema) {
56085
- const source = projections(input, need)[0];
56086
- return source ? loaderFact(input, source.id, key, schema) : unavailableReadinessFact;
56087
- }
56088
- function loaderFact(input, id, key, schema) {
56089
- const prefetched = input.prefetched;
56090
- if (!prefetched) return unavailableReadinessFact;
56091
- if (!prefetched.loaderSnapshot.blocks[id]?.requests[key] || prefetched.loaderFailures[id]?.[key]) return unavailableReadinessFact;
56092
- const parsed = schema.safeParse(prefetched.resolvedData[id]?.[key]);
56093
- return parsed.success ? loadedReadinessFact(parsed.data) : unavailableReadinessFact;
56094
- }
56095
- function mapFact(fact, project) {
56096
- return fact.kind === "Loaded" ? loadedReadinessFact(project(fact.value)) : fact;
56097
- }
56098
-
56099
- //#endregion
56100
- //#region ../blocks/src/system/data/pageReadiness.ts
56101
- function assessPageReadiness(blocks, facts) {
56102
- return blocks.map((block) => ({
56103
- blockId: block.id,
56104
- readiness: getBlockDefinition(block.kind)?.readiness?.assess(selectBlockContent(block, "preview"), facts) ?? ready
56105
- }));
56106
- }
56107
- const PUBLISH_READINESS_COPY = {
56108
- title: "Some blocks aren't set up yet",
56109
- body: "These won't show on your live site until they're set up:",
56110
- publish: "Publish anyway",
56111
- cancel: "Not yet",
56112
- repair: "Set up"
56113
- };
56114
- function publishReadinessWarning(blocks, facts) {
56115
- return assessPageReadiness(blocks, facts).flatMap(({ blockId, readiness }) => readiness.kind === "NeedsSetup" ? [{
56116
- blockId,
56117
- ...readiness
56118
- }] : []);
56119
- }
56120
- function declaredReadinessNeeds(blocks) {
56121
- return new Set(blocks.flatMap((block) => getBlockDefinition(block.kind)?.readiness?.needs ?? []));
56122
- }
56123
- function publishedReadinessFactsPayload(facts) {
56124
- return {
56125
- ...facts,
56126
- stage: "published",
56127
- forms: [...facts.forms],
56128
- products: [...facts.products]
56129
- };
56130
- }
56131
- function readinessFactsFromPayload(stage, payload) {
56132
- return admitReadinessFacts(stage, {
56133
- stage: payload.stage,
56134
- facts: {
56135
- ...payload,
56136
- forms: new Map(payload.forms),
56137
- products: new Map(payload.products)
56138
- }
56139
- });
56140
- }
56141
-
56142
- //#endregion
56143
- //#region ../blocks/src/pageRenderAdmission.ts
56144
- function toPresentationPage(page) {
56145
- if (!page) return null;
56146
- return {
56147
- ...page,
56148
- blocks: page.blocks.map((block) => {
56149
- const presentationMetadata = {
56150
- id: block.id,
56151
- kind: block.kind,
56152
- purpose: block.purpose,
56153
- ...block.contentVersionId ? { contentVersionId: block.contentVersionId } : {},
56154
- ...block.draftContentId !== undefined ? { draftContentId: block.draftContentId } : {},
56155
- publishedPlacement: block.publishedPlacement,
56156
- ...block.bindings ? { bindings: block.bindings } : {}
56157
- };
56158
- return block.admission.kind === "renderable" ? {
56159
- ...presentationMetadata,
56160
- content: block.admission.content,
56161
- presentationAdmission: { kind: "renderable" }
56162
- } : {
56163
- ...presentationMetadata,
56164
- presentationAdmission: {
56165
- kind: "invalid",
56166
- error: block.admission.error
56167
- }
56168
- };
56169
- })
56170
- };
56171
- }
56172
- function toEditorPresentationPage(page) {
56173
- if (!page) return null;
56174
- return {
56175
- ...page,
56176
- blocks: page.blocks.map((block) => ({
56177
- ...block,
56178
- publishedPlacement: block.publishedPlacement,
56179
- presentationAdmission: { kind: "editor" }
56180
- }))
56181
- };
56182
- }
56183
-
56184
56350
  //#endregion
56185
56351
  //#region ../blocks/src/system/customize/arrangementKnobs.ts
56186
56352
  /**
@@ -56332,6 +56498,20 @@ const onOff = [{
56332
56498
  value: "false",
56333
56499
  label: "Off"
56334
56500
  }];
56501
+ const columnCounts = [
56502
+ {
56503
+ value: "2",
56504
+ label: "2"
56505
+ },
56506
+ {
56507
+ value: "3",
56508
+ label: "3"
56509
+ },
56510
+ {
56511
+ value: "4",
56512
+ label: "4"
56513
+ }
56514
+ ];
56335
56515
  const systemCustomizeFacetDefinitions = [
56336
56516
  eventCalendarListLayoutFacet,
56337
56517
  fixedKnob("block.offerings-preview", "dates", "Dates", [{
@@ -56424,6 +56604,9 @@ const systemCustomizeFacetDefinitions = [
56424
56604
  ...fixedKnob("block.feature-cards", "showPhotos", "Show photos", onOff, "true", false, true),
56425
56605
  blockKinds: cardListFamilyBlocks
56426
56606
  },
56607
+ fixedKnob("block.feature-cards", "columns", "Columns", columnCounts, "3", true),
56608
+ fixedKnob("block.image-gallery", "blackAndWhite", "Black and white", onOff, "false", false, true),
56609
+ fixedKnob("block.event-calendar", "listColumns", "Columns", columnCounts, "3", true),
56427
56610
  fixedKnob("block.event-calendar", "showPhotos", "Photos", [{
56428
56611
  value: "true",
56429
56612
  label: "Show"
@@ -56586,6 +56769,392 @@ function omitRecordKey(content, key) {
56586
56769
  return Object.fromEntries(Object.entries(content).filter(([entryKey]) => entryKey !== key));
56587
56770
  }
56588
56771
 
56772
+ //#endregion
56773
+ //#region ../blocks/src/system/customize/fieldOwnership.ts
56774
+ /**
56775
+ * Values with their own owner, whatever their fields are tagged: the Background
56776
+ * row and Photo control edit `_sectionStyles`, and the style compiler writes the
56777
+ * other style groups (card, container and text-card styles), which the editor
56778
+ * already hides on styles with a page design.
56779
+ */
56780
+ const dedicatedPaths = ["_sectionStyles", ...themeV2CompilerOwnedFieldNames];
56781
+ /**
56782
+ * One owner for "does this setting belong to the Look?". The editor form, the
56783
+ * renderer's bindings, publish validation and the catalogue all ask here.
56784
+ * With no arrangement Look resolved (older styles, recipes, blocks without
56785
+ * Looks on a newer style), every field stays with the owner.
56786
+ */
56787
+ function resolveFieldOwnership(input) {
56788
+ if (!input.arrangementLook) return { kind: "no-look" };
56789
+ const knobFields = new Set(systemCustomizeFacetDefinitionsForBlock(input.blockKind).flatMap((facet) => facet.knob && facet.target.kind === "content-field" ? [facet.target.field] : []));
56790
+ const meaning = input.manifest.variantMeaning;
56791
+ const arrangementField = meaning?.kind === "mode" ? meaning.arrangementField : meaning ? "variant" : null;
56792
+ const modeField = meaning?.kind === "mode" ? "variant" : null;
56793
+ const paths = new Map();
56794
+ const dataPaths = new Map();
56795
+ const visit = (fields$1, parent, inherited, inRepeaterItem = false) => {
56796
+ fields$1.forEach((field) => {
56797
+ const path$3 = parent.schema ? `${parent.schema}.${field.id}` : field.id;
56798
+ const flattened = inRepeaterItem && field.type === "group" && field.ui?.flattenInRepeater === true;
56799
+ const dataPath = flattened ? parent.data : parent.data ? `${parent.data}.${field.id}` : field.id;
56800
+ const owner = ownerOf(field, path$3, inherited, {
56801
+ knobFields,
56802
+ arrangementField,
56803
+ modeField
56804
+ });
56805
+ paths.set(path$3, owner);
56806
+ if (!flattened) dataPaths.set(dataPath, owner);
56807
+ childFields(field).forEach((children) => visit(children, {
56808
+ schema: path$3,
56809
+ data: dataPath
56810
+ }, owner, field.type === "repeater"));
56811
+ });
56812
+ };
56813
+ visit(input.manifest.fields ?? [], {
56814
+ schema: "",
56815
+ data: ""
56816
+ }, "owner");
56817
+ knobFields.forEach((field) => {
56818
+ if (!paths.has(field)) paths.set(field, "knob");
56819
+ if (!dataPaths.has(field)) dataPaths.set(field, "knob");
56820
+ });
56821
+ return {
56822
+ kind: "look",
56823
+ paths,
56824
+ dataPaths
56825
+ };
56826
+ }
56827
+ const blocksWithLooks = new Set(arrangementAppearancePresets.flatMap((preset) => preset.blockKinds));
56828
+ /**
56829
+ * Whether any style can show this block through an arrangement Look. Docs and
56830
+ * the catalogue, which describe a block rather than one placed on a page, use
56831
+ * it to say which fields a Look would take over.
56832
+ */
56833
+ function blockHasArrangementLooks(blockKind) {
56834
+ return blocksWithLooks.has(blockKind);
56835
+ }
56836
+ /** A stored content path's owner; item indices are ignored and unlisted descendants take their parent's. */
56837
+ function fieldOwnerAt(ownership, path$3) {
56838
+ if (ownership.kind === "no-look") return "owner";
56839
+ const segments = path$3.split(".").filter((segment) => !/^\d+$/u.test(segment));
56840
+ const innermostFirst = segments.map((_$1, index) => segments.slice(0, segments.length - index).join("."));
56841
+ return innermostFirst.map((prefix) => ownership.dataPaths.get(prefix)).find((owner) => owner !== undefined) ?? "owner";
56842
+ }
56843
+ /** Schema paths with a given owner, outermost first, without repeating covered descendants. */
56844
+ function fieldPathsOwnedBy(ownership, owners) {
56845
+ return ownership.kind === "no-look" ? [] : outermost(ownership.paths, owners);
56846
+ }
56847
+ /** Content paths with a given owner, for the renderer, outermost first. */
56848
+ function contentPathsOwnedBy(ownership, owners) {
56849
+ return ownership.kind === "no-look" ? [] : outermost(ownership.dataPaths, owners);
56850
+ }
56851
+ function outermost(paths, owners) {
56852
+ const matching = [...paths].filter(([, owner]) => owners.includes(owner)).map(([path$3]) => path$3);
56853
+ return matching.filter((path$3) => !matching.some((other) => path$3.startsWith(`${other}.`)));
56854
+ }
56855
+ /**
56856
+ * Content with the owner's values for Look-owned paths taken out, so nothing
56857
+ * that renders the block (bindings, views, media delivery) can read them.
56858
+ */
56859
+ function withoutLookOwnedContent(content, paths) {
56860
+ return paths.reduce((current, path$3) => withoutPath(current, path$3.split(".")), { ...content });
56861
+ }
56862
+ function withoutPath(value, [key, ...rest]) {
56863
+ if (key === undefined || !(key in value)) return { ...value };
56864
+ if (rest.length === 0) return Object.fromEntries(Object.entries(value).filter(([entry]) => entry !== key));
56865
+ const child = value[key];
56866
+ const stripped = Array.isArray(child) ? child.map((item) => isContentRecord(item) ? withoutPath(item, rest) : item) : isContentRecord(child) ? withoutPath(child, rest) : child;
56867
+ return {
56868
+ ...value,
56869
+ [key]: stripped
56870
+ };
56871
+ }
56872
+ function isContentRecord(value) {
56873
+ return typeof value === "object" && value !== null && !Array.isArray(value);
56874
+ }
56875
+ function ownerOf(field, path$3, inherited, facts) {
56876
+ return inheritedOwner(path$3, inherited) ?? lookSectionOwner(field, path$3, facts) ?? keptByOwner(field, path$3, facts) ?? intentOwner(field, inherited);
56877
+ }
56878
+ /** Below a dedicated or Look-owned container, everything goes with it. */
56879
+ function inheritedOwner(path$3, inherited) {
56880
+ if (inherited === "dedicated" || dedicatedPaths.includes(path$3)) return "dedicated";
56881
+ return inherited === "look" ? "look" : null;
56882
+ }
56883
+ function lookSectionOwner(field, path$3, facts) {
56884
+ if (!path$3.includes(".") && facts.knobFields.has(path$3)) return "knob";
56885
+ if (field.ui?.hidden === true || field.ui?.renderInHeader === true) return "dedicated";
56886
+ return path$3 === facts.arrangementField ? "arrangement" : null;
56887
+ }
56888
+ function keptByOwner(field, path$3, facts) {
56889
+ return path$3 === facts.modeField || field.ui?.underLooks === "owner" ? "owner" : null;
56890
+ }
56891
+ function intentOwner(field, inherited) {
56892
+ switch (field.ui?.intent) {
56893
+ case "display":
56894
+ case "style": return "look";
56895
+ case "content":
56896
+ case "behavior": return "owner";
56897
+ case undefined: return inherited;
56898
+ }
56899
+ }
56900
+ function childFields(field) {
56901
+ if (field.type === "group" || field.type === "modal") return [field.schema.fields];
56902
+ if (field.type === "repeater") return [field.schema?.fields ?? [], ...Object.values(field.itemTypes ?? {}).map((item) => item.fields)];
56903
+ if (field.type === "tabGroup") return field.tabs.map((tab) => tab.fields);
56904
+ return [];
56905
+ }
56906
+
56907
+ //#endregion
56908
+ //#region ../blocks/src/system/manifest/storedLayout.ts
56909
+ /** The content field `parseStoredVariant` also reads; a block without stored variants keeps its layout there. */
56910
+ const layoutFieldId = "layout";
56911
+ function storedVariantKeys(manifest) {
56912
+ const lookOnly = manifest.variantMeaning.lookOnlyKeys ?? [];
56913
+ return Object.keys(manifest.variants ?? {}).filter((key) => !lookOnly.includes(key));
56914
+ }
56915
+ function optionValues(options) {
56916
+ return Array.isArray(options) ? options.flatMap((option) => typeof option === "object" && option !== null && "value" in option && typeof option.value === "string" ? [option.value] : []) : [];
56917
+ }
56918
+ /**
56919
+ * A block with no stored variants that offers a `layout` select (the shop)
56920
+ * declares its layouts there. Read as a mode's arrangement declaration, so the
56921
+ * same resolver decides: a stored value the block still has, or the default.
56922
+ */
56923
+ function layoutFieldDeclaration(manifest) {
56924
+ const field = (manifest.fields ?? []).find((candidate) => typeof candidate === "object" && candidate !== null && "id" in candidate && candidate.id === layoutFieldId && "type" in candidate && candidate.type === "select");
56925
+ const keys = optionValues(field?.options);
56926
+ const [firstKey] = keys;
56927
+ if (field === undefined || firstKey === undefined) return null;
56928
+ return {
56929
+ arrangementField: layoutFieldId,
56930
+ keys,
56931
+ defaultKey: typeof field.defaultValue === "string" && keys.includes(field.defaultValue) ? field.defaultValue : firstKey
56932
+ };
56933
+ }
56934
+ function fieldDeclaration(manifest) {
56935
+ if (manifest.variantMeaning.kind === "mode") return manifest.variantMeaning;
56936
+ return storedVariantKeys(manifest).length === 0 ? layoutFieldDeclaration(manifest) : null;
56937
+ }
56938
+ /** Every layout a block can store, for the block's own layout axis. Look-only arrangements are never stored. */
56939
+ function storedLayoutKeys(manifest) {
56940
+ return fieldDeclaration(manifest)?.keys ?? storedVariantKeys(manifest);
56941
+ }
56942
+ /**
56943
+ * The layout a block renders by when no Look arranges it: the stored value if
56944
+ * the block still has it, otherwise the default. The renderer's own resolvers
56945
+ * decide, so a reader of stored layouts cannot disagree with the page.
56946
+ */
56947
+ function resolveStoredLayout(manifest, content) {
56948
+ const field = fieldDeclaration(manifest);
56949
+ return field === null ? resolveEffectiveArrangement({
56950
+ manifest: arrangementManifestFromVariants(manifest),
56951
+ storedVariant: parseStoredVariant(manifest, content)
56952
+ }).key : resolveModeArrangement({
56953
+ declaration: field,
56954
+ content,
56955
+ mode: null
56956
+ }).key;
56957
+ }
56958
+
56959
+ //#endregion
56960
+ //#region ../blocks/src/system/data/selectBlockContent.ts
56961
+ /** Canonical admitted content: legacy publishedContent never selects a version. */
56962
+ function selectBlockContent(block, stage = "published") {
56963
+ const source = stage === "preview" && block.draftContent ? block.draftContent : block.content;
56964
+ return isObjectRecord(source) ? stripStaleTransitionStyleGroup(source) : {};
56965
+ }
56966
+
56967
+ //#endregion
56968
+ //#region ../blocks/src/system/data/readinessPresentation.ts
56969
+ /** Presentation-only wording; domain assessments and tests use closed reason codes. */
56970
+ const READINESS_REASON_COPY = {
56971
+ mailing_destination: "Pick where sign-ups go. Until you do, this signup stays hidden from visitors.",
56972
+ mailing_setup: "Pick where sign-ups go. Until you do, this signup stays hidden from visitors.",
56973
+ form_not_chosen: "Choose a form. Until you do, this block stays hidden from visitors.",
56974
+ form_deleted: "The form this block used has been deleted. Choose another one. Until you do, this block stays hidden from visitors.",
56975
+ testimonials_none: "Add a testimonial to show here. Until you do, this block stays hidden from visitors.",
56976
+ testimonials_unpublished: "Publish a testimonial to show it here. Until you do, this block stays hidden from visitors.",
56977
+ testimonials_empty: "There are no testimonials to show here yet. Until there are, this block stays hidden from visitors.",
56978
+ team_empty: "Add people to your team to show them here. Until you do, this block stays hidden from visitors.",
56979
+ members_empty: "Add someone to show here. Until you do, this block stays hidden from visitors.",
56980
+ product_not_chosen: "Choose a product. Until you do, this block stays hidden from visitors.",
56981
+ product_gone: "The product this block showed is no longer available. Choose another one. Until you do, this block stays hidden from visitors.",
56982
+ gallery_empty: "Add a photo. Until you do, this gallery stays hidden from visitors."
56983
+ };
56984
+
56985
+ //#endregion
56986
+ //#region ../blocks/src/system/data/readinessFacts.ts
56987
+ const countSchema = z.array(z.unknown()).transform((entries) => entries.length);
56988
+ const formSchema = z.union([z.null(), z.object({
56989
+ id: z.string(),
56990
+ slug: z.string().optional()
56991
+ })]).transform((form$1) => form$1 !== null);
56992
+ const productsSchema = z.object({ products: z.array(z.object({ slug: z.string() })) });
56993
+ /** Both producers pass raw facts through the same stage admission. */
56994
+ function readinessFactsFromLoaders(stage, input) {
56995
+ const facts = {
56996
+ mailingList: loaderFactProducers.mailingList(input),
56997
+ testimonials: loaderFactProducers.testimonials(input),
56998
+ team: loaderFactProducers.team(input),
56999
+ forms: loaderFactProducers.forms(input),
57000
+ products: loaderFactProducers.products(input),
57001
+ template: loaderFactProducers.template(input)
57002
+ };
57003
+ return admitReadinessFacts(stage, {
57004
+ stage: input.prefetched?.loaderSnapshot?.stage ?? (input.previewStage === "preview" ? "draft" : "published"),
57005
+ facts
57006
+ });
57007
+ }
57008
+ const loaderFactProducers = {
57009
+ mailingList: (input) => input.mailingList === undefined ? unavailableReadinessFact : loadedReadinessFact(input.mailingList),
57010
+ testimonials: (input) => mapFact(firstLoaderFact(input, "testimonials", "entries", countSchema), (count) => ({
57011
+ count,
57012
+ total: "unknown"
57013
+ })),
57014
+ team: (input) => firstLoaderFact(input, "team", "members", countSchema),
57015
+ forms: (input) => new Map(projections(input, "forms").flatMap(({ id, block }) => {
57016
+ const selection = chosenString(block.requests.form?.params.formSlug ?? block.requests.form?.params.formId);
57017
+ return selection ? [[selection, loaderFact(input, id, "form", formSchema)]] : [];
57018
+ })),
57019
+ products: (input) => new Map(projections(input, "products").flatMap(({ id, block }) => {
57020
+ const selection = chosenString(block.content.productSlug);
57021
+ return selection ? [[selection, mapFact(loaderFact(input, id, "products", productsSchema), ({ products }) => products.some((product) => product.slug === selection))]] : [];
57022
+ })),
57023
+ template: (input) => loadedReadinessFact(input.template)
57024
+ };
57025
+ function projections(input, need) {
57026
+ return Object.entries(input.prefetched?.loaderSnapshot?.blocks ?? {}).flatMap(([id, block]) => getBlockDefinition(block.kind)?.readiness?.needs.includes(need) ? [{
57027
+ id,
57028
+ block
57029
+ }] : []);
57030
+ }
57031
+ function firstLoaderFact(input, need, key, schema) {
57032
+ const source = projections(input, need)[0];
57033
+ return source ? loaderFact(input, source.id, key, schema) : unavailableReadinessFact;
57034
+ }
57035
+ function loaderFact(input, id, key, schema) {
57036
+ const prefetched = input.prefetched;
57037
+ if (!prefetched) return unavailableReadinessFact;
57038
+ if (!prefetched.loaderSnapshot.blocks[id]?.requests[key] || prefetched.loaderFailures[id]?.[key]) return unavailableReadinessFact;
57039
+ const parsed = schema.safeParse(prefetched.resolvedData[id]?.[key]);
57040
+ return parsed.success ? loadedReadinessFact(parsed.data) : unavailableReadinessFact;
57041
+ }
57042
+ function mapFact(fact, project) {
57043
+ return fact.kind === "Loaded" ? loadedReadinessFact(project(fact.value)) : fact;
57044
+ }
57045
+
57046
+ //#endregion
57047
+ //#region ../blocks/src/system/data/pageReadiness.ts
57048
+ function assessPageReadiness(blocks, facts, interaction) {
57049
+ return blocks.map((block) => ({
57050
+ blockId: block.id,
57051
+ readiness: getBlockDefinition(block.kind)?.readiness?.assess(selectBlockContent(block, "preview"), facts, interaction) ?? ready
57052
+ }));
57053
+ }
57054
+ const PUBLISH_READINESS_COPY = {
57055
+ title: "Some blocks aren't set up yet",
57056
+ body: "These won't show on your live site until they're set up:",
57057
+ publish: "Publish anyway",
57058
+ cancel: "Not yet",
57059
+ repair: "Set up"
57060
+ };
57061
+ function publishReadinessWarning(blocks, facts) {
57062
+ return assessPageReadiness(blocks, facts).flatMap(({ blockId, readiness }) => readiness.kind === "NeedsSetup" ? [{
57063
+ blockId,
57064
+ ...readiness
57065
+ }] : []);
57066
+ }
57067
+ function declaredReadinessNeeds(blocks) {
57068
+ return new Set(blocks.flatMap((block) => getBlockDefinition(block.kind)?.readiness?.needs ?? []));
57069
+ }
57070
+ function publishedReadinessFactsPayload(facts) {
57071
+ return {
57072
+ ...facts,
57073
+ stage: "published",
57074
+ forms: [...facts.forms],
57075
+ products: [...facts.products]
57076
+ };
57077
+ }
57078
+ function readinessFactsFromPayload(stage, payload) {
57079
+ return admitReadinessFacts(stage, {
57080
+ stage: payload.stage,
57081
+ facts: {
57082
+ ...payload,
57083
+ forms: new Map(payload.forms),
57084
+ products: new Map(payload.products)
57085
+ }
57086
+ });
57087
+ }
57088
+
57089
+ //#endregion
57090
+ //#region ../blocks/src/pageRenderAdmission.ts
57091
+ function toPresentationPage(page) {
57092
+ if (!page) return null;
57093
+ return {
57094
+ ...page,
57095
+ blocks: page.blocks.map(presentPublicBlock)
57096
+ };
57097
+ }
57098
+ function toEditorPresentationPage(page) {
57099
+ if (!page) return null;
57100
+ return {
57101
+ ...page,
57102
+ blocks: page.blocks.map(presentEditorBlock)
57103
+ };
57104
+ }
57105
+ function presentPublicBlock(block) {
57106
+ const metadata = {
57107
+ id: block.id,
57108
+ kind: block.kind,
57109
+ purpose: block.purpose,
57110
+ ...block.contentVersionId ? { contentVersionId: block.contentVersionId } : {},
57111
+ ...block.draftContentId !== undefined ? { draftContentId: block.draftContentId } : {},
57112
+ publishedPlacement: block.publishedPlacement,
57113
+ ...block.bindings ? { bindings: block.bindings } : {}
57114
+ };
57115
+ return block.admission.kind === "renderable" ? {
57116
+ ...metadata,
57117
+ content: block.admission.content,
57118
+ presentationAdmission: { kind: "renderable" }
57119
+ } : {
57120
+ ...metadata,
57121
+ presentationAdmission: {
57122
+ kind: "invalid",
57123
+ error: block.admission.error
57124
+ }
57125
+ };
57126
+ }
57127
+ function presentEditorBlock(block) {
57128
+ return {
57129
+ ...block,
57130
+ presentationAdmission: { kind: "editor" }
57131
+ };
57132
+ }
57133
+ function createPresentationPageReader() {
57134
+ const readBlock = memoizePresentationBlock(presentPublicBlock);
57135
+ return (page) => page ? {
57136
+ ...page,
57137
+ blocks: page.blocks.map(readBlock)
57138
+ } : null;
57139
+ }
57140
+ function createEditorPresentationPageReader() {
57141
+ const readBlock = memoizePresentationBlock(presentEditorBlock);
57142
+ return (page) => page ? {
57143
+ ...page,
57144
+ blocks: page.blocks.map(readBlock)
57145
+ } : null;
57146
+ }
57147
+ function memoizePresentationBlock(present) {
57148
+ const blocks = new WeakMap();
57149
+ return (block) => {
57150
+ const cached = blocks.get(block);
57151
+ if (cached) return cached;
57152
+ const presentation = present(block);
57153
+ blocks.set(block, presentation);
57154
+ return presentation;
57155
+ };
57156
+ }
57157
+
56589
57158
  //#endregion
56590
57159
  //#region ../blocks/src/system/transforms/registry/offeringsPreview.ts
56591
57160
  /** Reuse the existing occurrence read for the date strip and card date rows. */
@@ -57294,7 +57863,10 @@ function coerceLinkedContentEntriesPayload(payload) {
57294
57863
  function getLinkedContentEntryMeta(value) {
57295
57864
  if (!isRecord$17(value)) return null;
57296
57865
  const candidate = value[LINKED_CONTENT_ENTRY_META_KEY];
57297
- return isLinkedContentEntryMeta(candidate) ? candidate : null;
57866
+ return isLinkedContentEntryMeta(candidate) ? {
57867
+ ...candidate,
57868
+ editRevision: candidate.editRevision ?? null
57869
+ } : null;
57298
57870
  }
57299
57871
  function buildLinkedContentEditTarget(input) {
57300
57872
  const { entry, sourceBlockId, sourceBlockKind, itemIndex } = input;
@@ -57309,6 +57881,7 @@ function buildLinkedContentEditTarget(input) {
57309
57881
  contentTypeLabel: meta.contentTypeLabel,
57310
57882
  title: meta.title,
57311
57883
  optimisticHash: meta.optimisticHash,
57884
+ editRevision: meta.editRevision,
57312
57885
  sourceBlockId: sourceBlockId ?? null,
57313
57886
  sourceBlockKind: sourceBlockKind ?? null,
57314
57887
  itemIndex,
@@ -57381,6 +57954,7 @@ function enrichLinkedContentEntry(entry, contentType) {
57381
57954
  const title = typeof entry.title === "string" && entry.title.trim().length > 0 ? entry.title : entryId;
57382
57955
  const optimisticHash = typeof entry.optimisticHash === "string" && entry.optimisticHash.length > 0 ? entry.optimisticHash : null;
57383
57956
  const content = isRecord$17(entry.content) ? entry.content : {};
57957
+ const editRevision = typeof entry.editRevision === "number" ? entry.editRevision : null;
57384
57958
  const meta = {
57385
57959
  kind: "linked-content-entry",
57386
57960
  entryId,
@@ -57388,6 +57962,7 @@ function enrichLinkedContentEntry(entry, contentType) {
57388
57962
  contentTypeLabel: contentTypeKeyToLabel(contentType.key),
57389
57963
  title,
57390
57964
  optimisticHash,
57965
+ editRevision,
57391
57966
  support: resolveLinkedContentEditSupport(contentType),
57392
57967
  contentType,
57393
57968
  fieldSources: deriveLinkedEntryFieldSources(entry, contentType, content)
@@ -57525,16 +58100,23 @@ function parseStringArray(value) {
57525
58100
  return value.filter((item) => typeof item === "string");
57526
58101
  }
57527
58102
  function isLinkedContentEntryMeta(value) {
57528
- if (!isRecord$17(value)) return false;
57529
- if (value.kind !== "linked-content-entry") return false;
57530
- if (typeof value.entryId !== "string") return false;
57531
- if (typeof value.contentTypeKey !== "string") return false;
57532
- if (typeof value.contentTypeLabel !== "string") return false;
57533
- if (typeof value.title !== "string") return false;
57534
- if (!(value.optimisticHash === null || typeof value.optimisticHash === "string")) return false;
57535
- if (!isRecord$17(value.contentType)) return false;
57536
- if (!isLinkedEntryFieldSourceArray(value.fieldSources)) return false;
57537
- return isLinkedContentEditSupport(value.support);
58103
+ if (!isRecord$17(value) || value.kind !== "linked-content-entry") return false;
58104
+ return [
58105
+ [
58106
+ "entryId",
58107
+ "contentTypeKey",
58108
+ "contentTypeLabel",
58109
+ "title"
58110
+ ].every((key) => typeof value[key] === "string"),
58111
+ isNullOrOfType(value.optimisticHash, "string"),
58112
+ value.editRevision === undefined || isNullOrOfType(value.editRevision, "number"),
58113
+ isRecord$17(value.contentType),
58114
+ isLinkedEntryFieldSourceArray(value.fieldSources),
58115
+ isLinkedContentEditSupport(value.support)
58116
+ ].every(Boolean);
58117
+ }
58118
+ function isNullOrOfType(value, type) {
58119
+ return value === null || typeof value === type;
57538
58120
  }
57539
58121
  function isLinkedEntryFieldSourceArray(value) {
57540
58122
  return Array.isArray(value) && value.every(isLinkedEntryFieldSource);
@@ -57967,6 +58549,30 @@ function toAbsolutePath(base, path$3) {
57967
58549
  const baseStr = base.endsWith(".") ? base : `${base}.`;
57968
58550
  return `${baseStr}${trimmed}`;
57969
58551
  }
58552
+ /** Copy only the path being changed; existing setters remain for explicitly mutable adapters. */
58553
+ function withValueAtPath(target, path$3, value) {
58554
+ const segments = parsePath(path$3);
58555
+ if (segments.length === 0) return target;
58556
+ const result = replacePathValue(target, segments, value);
58557
+ return isRecord$16(result) ? result : target;
58558
+ }
58559
+ function replacePathValue(current, segments, value) {
58560
+ const [segment, ...rest] = segments;
58561
+ if (segment === undefined) return value;
58562
+ const container = isPathContainer(current) ? current : createPathContainer(typeof segment === "number");
58563
+ const before = getContainerValue(container, segment);
58564
+ const after = replacePathValue(before, rest, value);
58565
+ if (Object.is(before, after) && isPathContainer(current)) return current;
58566
+ if (Array.isArray(container)) {
58567
+ const next = container.slice();
58568
+ Reflect.set(next, segment, after);
58569
+ return next;
58570
+ }
58571
+ return typeof segment === "number" ? container : {
58572
+ ...container,
58573
+ [segment]: after
58574
+ };
58575
+ }
57970
58576
 
57971
58577
  //#endregion
57972
58578
  //#region ../blocks/src/primitives/content/components/Text.tsx
@@ -60289,8 +60895,7 @@ function buildStandardBookingPaymentDisclosure(input, payment, amount) {
60289
60895
  ...discountCode ? { discountCode } : {},
60290
60896
  ...amount,
60291
60897
  ...selectedCollectionOptionKind ? { selectedCollectionOptionKind } : {},
60292
- shownTerms: input.shownTerms ?? snapshotBookingShownTerms(payment, input.promisedDiscountId),
60293
- altchaSolution: input.altchaSolution ?? null
60898
+ shownTerms: input.shownTerms ?? snapshotBookingShownTerms(payment, input.promisedDiscountId)
60294
60899
  };
60295
60900
  }
60296
60901
  function validateBookingSlidingSelection(service, data) {
@@ -60643,8 +61248,7 @@ function buildEventRegistrationSourceProps(input) {
60643
61248
  showVenue: input.showVenue,
60644
61249
  showCapacity: input.showCapacity,
60645
61250
  successMessage: input.successMessage,
60646
- buttonVariant: input.buttonVariant,
60647
- spamProtectionEnabled: input.spamProtectionEnabled
61251
+ buttonVariant: input.buttonVariant
60648
61252
  };
60649
61253
  }
60650
61254
 
@@ -60734,7 +61338,6 @@ const bookingSourceSchema = z.object({
60734
61338
  successMessage: z.string().nullable().optional(),
60735
61339
  form: bookingSourceFormSchema.nullable().optional(),
60736
61340
  services: bookingServicesSourceSchema.nullable().optional(),
60737
- spamProtectionEnabled: z.boolean().optional(),
60738
61341
  className: z.string().nullable().optional()
60739
61342
  });
60740
61343
  const bookingDisplaySchema = z.object({
@@ -60763,8 +61366,7 @@ const bookingHydrationSchema = z.object({
60763
61366
  rebookContext: z.object({ kind: z.literal("portal_rebook") }).nullable().optional(),
60764
61367
  form: bookingConfigSchema.nullable(),
60765
61368
  services: z.array(bookingServiceSchema),
60766
- serviceCategories: z.array(bookingServiceCategorySchema).optional(),
60767
- spamProtectionEnabled: z.boolean().optional()
61369
+ serviceCategories: z.array(bookingServiceCategorySchema).optional()
60768
61370
  });
60769
61371
  const bookingRenderSchema = z.object({
60770
61372
  display: bookingDisplaySchema,
@@ -60815,8 +61417,7 @@ const bookingFormBlockRuntime = defineClientOwnedBlockRuntime({
60815
61417
  rebookContext: source.rebookContext ?? null,
60816
61418
  form: form$1,
60817
61419
  services,
60818
- serviceCategories: normalizeBookingServiceCategories(source.services),
60819
- spamProtectionEnabled: source.spamProtectionEnabled
61420
+ serviceCategories: normalizeBookingServiceCategories(source.services)
60820
61421
  }
60821
61422
  };
60822
61423
  }
@@ -61168,7 +61769,7 @@ function isValidOccurrence(value) {
61168
61769
  //#region ../blocks/src/system/runtime/nodes/events/shared/eventCardListContent.ts
61169
61770
  /** Live offering data only; editorial cards never acquire booking fields. */
61170
61771
  function eventCardListContent(event, context, buttonText) {
61171
- const { content, external } = cardProjectionBase(event, buttonText, context.kind === "offering");
61772
+ const { content, external } = cardProjectionBase(event, buttonText, context.kind === "offering", context.kind === "offering" ? context.upcomingDates ?? [] : []);
61172
61773
  switch (context.kind) {
61173
61774
  case "event-details": return {
61174
61775
  ...content,
@@ -61187,8 +61788,8 @@ function eventCardListContent(event, context, buttonText) {
61187
61788
  default: return assertNever(context);
61188
61789
  }
61189
61790
  }
61190
- function cardProjectionBase(event, buttonText, offering) {
61191
- const cta = offeringCardCta(event, buttonText, offering);
61791
+ function cardProjectionBase(event, buttonText, offering, upcomingDates) {
61792
+ const cta = offeringCardCta(event, buttonText, offering, upcomingDates);
61192
61793
  const places = offeringAvailability(event);
61193
61794
  return {
61194
61795
  external: cta.external,
@@ -61299,8 +61900,8 @@ function offeringFacts(event, places, offering) {
61299
61900
  }]
61300
61901
  ];
61301
61902
  }
61302
- function offeringCardCta(event, buttonText, offering) {
61303
- return resolveEventCta(event, offering && event.destination.kind === "external" ? undefined : buttonText);
61903
+ function offeringCardCta(event, buttonText, offering, upcomingDates) {
61904
+ return resolveDatedSeriesCta(event, upcomingDates, offering && event.destination.kind === "external" ? undefined : buttonText);
61304
61905
  }
61305
61906
  function offeringTypeChips(event, typeLabel) {
61306
61907
  return event.eventCategory ? [event.eventCategory.name] : typeLabel ? [typeLabel] : [];
@@ -61373,26 +61974,39 @@ function EventHeader({ selection, presentation, showCost }) {
61373
61974
  });
61374
61975
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("header", {
61375
61976
  ...listLookSlot(presentation, "frame"),
61376
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
61377
- ...listLookSlot(presentation, "copy"),
61378
- children: [
61379
- part("chips"),
61380
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h1", {
61381
- ...listLookSlot(presentation, "headline"),
61382
- children: item.title
61383
- }),
61384
- item.text ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
61385
- ...listLookSlot(presentation, "lede"),
61386
- children: item.text
61387
- }) : null,
61388
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
61389
- "aria-label": "At a glance",
61390
- children: part("facts")
61391
- }),
61392
- part("availability"),
61393
- part("action")
61394
- ]
61395
- }), part("numeral")]
61977
+ children: [
61978
+ item.media ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("figure", {
61979
+ ...listLookSlot(presentation, "item-media"),
61980
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MediaNodeServer, {
61981
+ value: item.media,
61982
+ size: ImagePresets.full,
61983
+ loading: "eager",
61984
+ fetchPriority: "high",
61985
+ ...listLookSlot(presentation, "photo")
61986
+ })
61987
+ }) : null,
61988
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
61989
+ ...listLookSlot(presentation, "copy"),
61990
+ children: [
61991
+ part("chips"),
61992
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h1", {
61993
+ ...listLookSlot(presentation, "headline"),
61994
+ children: item.title
61995
+ }),
61996
+ item.text ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
61997
+ ...listLookSlot(presentation, "lede"),
61998
+ children: item.text
61999
+ }) : null,
62000
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
62001
+ "aria-label": "At a glance",
62002
+ children: part("facts")
62003
+ }),
62004
+ part("availability"),
62005
+ part("action")
62006
+ ]
62007
+ }),
62008
+ part("numeral")
62009
+ ]
61396
62010
  });
61397
62011
  }
61398
62012
 
@@ -62180,10 +62794,22 @@ function buildLoadedOfferingsPreviewListing(input) {
62180
62794
 
62181
62795
  //#endregion
62182
62796
  //#region ../blocks/src/system/runtime/nodes/events/shared/offeringNextDates.ts
62797
+ /**
62798
+ * The upcoming dates a dated series' card lists: its next three live
62799
+ * occurrences from the block's one occurrence batch. The date rows and the
62800
+ * card's own booking button both read from this, so they can't disagree.
62801
+ */
62802
+ function upcomingOccurrencesBySeries(events, now) {
62803
+ const groups = events.reduce((result, event) => new Map([...result, [event.seriesId, [...result.get(event.seriesId) ?? [], event]]]), new Map());
62804
+ 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)]));
62805
+ }
62183
62806
  /** One occurrence batch supplies every occurrence-targeted card in the block. */
62184
62807
  function offeringDatesBySeries(events, now, booking) {
62185
- const groups = events.reduce((result, event) => new Map([...result, [event.seriesId, [...result.get(event.seriesId) ?? [], event]]]), new Map());
62186
- 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))]));
62808
+ return offeringDateRowsBySeries(upcomingOccurrencesBySeries(events, now), booking);
62809
+ }
62810
+ /** Date rows for occurrences already chosen by {@link upcomingOccurrencesBySeries}. */
62811
+ function offeringDateRowsBySeries(upcoming, booking) {
62812
+ return new Map([...upcoming].map(([seriesId, occurrences]) => [seriesId, occurrences.map((event) => offeringDateRow(event, event, booking))]));
62187
62813
  }
62188
62814
  /** Whole-series sessions share the run-level booking capacity, by contract. */
62189
62815
  function offeringRunDates(event, now) {
@@ -62316,14 +62942,13 @@ function renderOfferingsCatalogueGroups({ props: props$1, groups, shape }) {
62316
62942
  }
62317
62943
  function renderCatalogueItems({ props: props$1, items, shape, groupTitle }) {
62318
62944
  const events = items.map((item) => item.kind === "event" ? item.event : item.run.representative);
62945
+ const dates = catalogueDates(props$1.quickDateEvents ?? [], props$1.now, shape, props$1.pathname);
62319
62946
  if (props$1.lookSlots) {
62320
- const now = props$1.now;
62321
- const dates = offeringDatesBySeries(props$1.quickDateEvents ?? [], now, catalogueDateBooking(shape, props$1.pathname));
62322
62947
  return CardListItems({
62323
62948
  Carousel: props$1.Carousel,
62324
62949
  Title: shape === "single" ? "h3" : "h4",
62325
62950
  presentation: props$1,
62326
- items: items.map((item) => catalogueCardContent(item, now, dates, shape === "single" ? groupTitle : undefined))
62951
+ items: items.map((item) => catalogueCardContent(item, props$1.now, dates, shape === "single" ? groupTitle : undefined))
62327
62952
  });
62328
62953
  }
62329
62954
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
@@ -62331,10 +62956,19 @@ function renderCatalogueItems({ props: props$1, items, shape, groupTitle }) {
62331
62956
  style: { gridTemplateColumns: "repeat(auto-fill, minmax(min(100%, 18rem), 1fr))" },
62332
62957
  children: events.map((event) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EventCard, {
62333
62958
  event,
62959
+ upcomingDates: dates.upcoming.get(event.seriesId),
62334
62960
  ...catalogueEventCardProps(event, props$1.buttonVariant ?? "primary")
62335
62961
  }, event.seriesId))
62336
62962
  });
62337
62963
  }
62964
+ /** The listed dates and their rows, from one reading so the button and the rows agree. */
62965
+ function catalogueDates(events, now, shape, pathname) {
62966
+ const upcoming = upcomingOccurrencesBySeries(events, now);
62967
+ return {
62968
+ upcoming,
62969
+ rows: offeringDateRowsBySeries(upcoming, catalogueDateBooking(shape, pathname))
62970
+ };
62971
+ }
62338
62972
  function catalogueCardContent(item, now, dates, typeLabel) {
62339
62973
  const event = item.kind === "event" ? item.event : item.run.representative;
62340
62974
  return {
@@ -62342,9 +62976,10 @@ function catalogueCardContent(item, now, dates, typeLabel) {
62342
62976
  kind: "offering",
62343
62977
  now,
62344
62978
  nextStartMs: item.nextStartMs,
62345
- typeLabel
62979
+ typeLabel,
62980
+ upcomingDates: dates.upcoming.get(event.seriesId)
62346
62981
  }, catalogueEventCardProps(event).buttonText),
62347
- dates: event.bookingScope === "whole_series" ? offeringRunDates(event, now) : dates.get(event.seriesId)
62982
+ dates: event.bookingScope === "whole_series" ? offeringRunDates(event, now) : dates.rows.get(event.seriesId)
62348
62983
  };
62349
62984
  }
62350
62985
  function renderCatalogueEmpty({ props: props$1, failed }) {
@@ -62359,7 +62994,7 @@ function renderCatalogueEmpty({ props: props$1, failed }) {
62359
62994
  });
62360
62995
  }
62361
62996
  function renderCatalogueMergedList({ props: props$1, listing, now, shape }) {
62362
- const dates = offeringDatesBySeries(props$1.quickDateEvents ?? [], now, catalogueDateBooking(shape, props$1.pathname));
62997
+ const dates = catalogueDates(props$1.quickDateEvents ?? [], now, shape, props$1.pathname);
62363
62998
  const items = listing.items.map(({ item, group }) => catalogueCardContent(item, now, dates, group.singularLabel));
62364
62999
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
62365
63000
  ...listLookSlot(props$1, "layout"),
@@ -62975,13 +63610,12 @@ function previewCardContent(item, props$1, datesBySeries, typeLabel) {
62975
63610
  }
62976
63611
  function nativeRunCardContent(item, content, props$1) {
62977
63612
  const open$1 = resolveWholeSeriesBookingPhase(item.run.run, props$1.now).kind === "open";
63613
+ const path$3 = content.titleLink?.href ?? null;
62978
63614
  return {
62979
63615
  ...content,
62980
- href: item.path,
62981
- titleLink: undefined,
62982
63616
  action: {
62983
- label: open$1 ? item.path ? props$1.buttonText || "Book" : "Details coming soon" : "Registration closed",
62984
- ...open$1 && item.path ? { href: item.path } : {}
63617
+ label: open$1 ? path$3 ? props$1.buttonText || "Book" : "Details coming soon" : "Registration closed",
63618
+ ...open$1 && path$3 ? { href: path$3 } : {}
62985
63619
  }
62986
63620
  };
62987
63621
  }
@@ -64097,7 +64731,11 @@ function EventListBody({ display, renderEventCard: renderEventCard$1, footer })
64097
64731
  className: display.containerClass,
64098
64732
  children: display.events.map(renderEventCard$1)
64099
64733
  });
64100
- if (display.listLayout === "day-groups") return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ol", {
64734
+ if (display.listLayout === "week-columns" && display.week !== undefined) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(WeekColumns, {
64735
+ display,
64736
+ week: display.week
64737
+ });
64738
+ if (display.listLayout === "day-groups" || display.listLayout === "week-columns") return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ol", {
64101
64739
  ...listLookSlot(display, "list"),
64102
64740
  children: display.events.filter((event, index, events) => events.findIndex((candidate) => eventLocalDateKey(candidate) === eventLocalDateKey(event)) === index).map((first) => {
64103
64741
  const date = formatEventCompactDateRail(first.startsAt, eventDateOptions(first), "as-written");
@@ -64154,6 +64792,45 @@ function EventListBody({ display, renderEventCard: renderEventCard$1, footer })
64154
64792
  children: display.events.map(renderEventCard$1)
64155
64793
  });
64156
64794
  }
64795
+ /** All seven days of the shown week; a day known to be empty says so, and a wholly empty week never reaches here. */
64796
+ function WeekColumns({ display, week }) {
64797
+ const todayMark = display.itemSurfaces?.today;
64798
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ol", {
64799
+ ...listLookSlot(display, "list"),
64800
+ children: weekColumnDays(week, display.events, display.allLoaded === true).map((day) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", {
64801
+ ...listLookSlot(display, "group"),
64802
+ ...day.isToday ? { "data-today": "true" } : {},
64803
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("h3", {
64804
+ ...listLookSlot(display, "group-label"),
64805
+ children: [
64806
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
64807
+ ...listLookSlot(display, "group-day"),
64808
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
64809
+ "aria-hidden": "true",
64810
+ children: day.label.weekday
64811
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
64812
+ className: "rb-sr-only",
64813
+ children: day.label.fullWeekday
64814
+ })]
64815
+ }),
64816
+ " ",
64817
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
64818
+ ...listLookSlot(display, "group-date"),
64819
+ ...day.isToday && todayMark !== undefined && display.lookSlots?.["group-date"] !== undefined ? resolvedItemSurfaceProps(todayMark, "group-date") : {},
64820
+ children: day.label.day
64821
+ })
64822
+ ]
64823
+ }), day.sessions.kind === "some" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ol", { children: day.sessions.events.map((event) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EventItem, {
64824
+ ...listItemPresentation(display, display.events.indexOf(event), display.events.length),
64825
+ event,
64826
+ arrangement: "week-columns"
64827
+ }, event.occurrenceId || event.id)) }) : day.sessions.kind === "none" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
64828
+ ...listLookSlot(display, "group-empty"),
64829
+ children: "Nothing on"
64830
+ }) : null]
64831
+ }, day.dateKey))
64832
+ });
64833
+ }
64157
64834
  function hasArrangementPanel(display) {
64158
64835
  return display.state === "ready" && display.lookSlots !== undefined && display.listLayout === "compact";
64159
64836
  }
@@ -64841,13 +65518,19 @@ function renderCombinedSsr(display, prefetchedEvents) {
64841
65518
  });
64842
65519
  }
64843
65520
  function renderListSsr(display, hydration) {
64844
- const listDisplay = buildEventCalendarListingDisplay(display, hydration.prefetchedEvents);
64845
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [display.listBy === "week" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EventListWeekNavigation, {
65521
+ const { initialToday, timeZone } = hydration.calendarContext;
65522
+ const week = display.listBy === "week" ? buildEventListWeek(initialToday, display.startOfWeek, timeZone) : null;
65523
+ const listing = buildEventCalendarListingDisplay(display, hydration.prefetchedEvents);
65524
+ const listDisplay = week === null ? listing : {
65525
+ ...listing,
65526
+ week: eventListWeekDays(week, initialToday, timeZone)
65527
+ };
65528
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [week !== null ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EventListWeekNavigation, {
64846
65529
  ...display,
64847
- title: buildEventListWeek(hydration.calendarContext.initialToday, display.startOfWeek, hydration.calendarContext.timeZone).title
65530
+ title: week.title
64848
65531
  }) : null, /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EventListingFrameView, {
64849
65532
  display: listDisplay,
64850
- emptyState: display.listBy === "week" && display.lookSlots !== undefined ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EventListWeekEmptyState, {
65533
+ emptyState: week !== null && display.lookSlots !== undefined ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EventListWeekEmptyState, {
64851
65534
  ...display,
64852
65535
  nextWeek: {}
64853
65536
  }) : undefined,
@@ -65660,6 +66343,16 @@ function EventRegistrationShell({ display }) {
65660
66343
  }
65661
66344
  var event_registration_server_default = EventRegistrationSSR;
65662
66345
 
66346
+ //#endregion
66347
+ //#region ../blocks/src/system/runtime/shared/components/ProtectedSubmitButton.tsx
66348
+ /** Verification readiness is decided here, never recomputed by individual forms. */
66349
+ function ProtectedSubmitButton({ submission, disabled, ...props$1 }) {
66350
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ThemedButton, {
66351
+ ...props$1,
66352
+ disabled: disabled || submission.kind === "waiting"
66353
+ });
66354
+ }
66355
+
65663
66356
  //#endregion
65664
66357
  //#region ../blocks/src/system/runtime/nodes/form.fields.tsx
65665
66358
  function fieldBasics(field) {
@@ -65842,14 +66535,15 @@ function FormFieldGroups({ groups, lookSlots }) {
65842
66535
  children: group.fields.map(renderField$1)
65843
66536
  }, group.key) : renderField$1(group.field)) });
65844
66537
  }
65845
- function FormSubmitAction({ lookSlots, submitLabel, disabled }) {
66538
+ function FormSubmitAction({ lookSlots, submitLabel, disabled, submission }) {
65846
66539
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
65847
66540
  className: "fb-actions",
65848
66541
  ...listLookSlot({ lookSlots }, "actions"),
65849
66542
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
65850
66543
  className: "fb-actions-inner",
65851
66544
  ...listLookSlot({ lookSlots }, "inline"),
65852
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ThemedButton, {
66545
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ProtectedSubmitButton, {
66546
+ submission,
65853
66547
  ...listLookSlot({ lookSlots }, "action"),
65854
66548
  type: "submit",
65855
66549
  variant: "primary",
@@ -65914,6 +66608,7 @@ const FormNodeSSR = ({ blockId, lookSlots, value, submitLabel, successMessage, c
65914
66608
  lookSlots: display.lookSlots
65915
66609
  }),
65916
66610
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FormSubmitAction, {
66611
+ submission: { kind: "waiting" },
65917
66612
  submitLabel: display.submitLabel,
65918
66613
  lookSlots: display.lookSlots
65919
66614
  })
@@ -65978,7 +66673,7 @@ function NewsletterExtraField({ field, disabled, error: error$1, lookSlots }) {
65978
66673
  });
65979
66674
  }
65980
66675
  /** The email field and submit button sharing one input-styled shell. */
65981
- function NewsletterEmailEntry({ field, buttonVariant, buttonLabel, disabled, error: error$1 }) {
66676
+ function NewsletterEmailEntry({ field, buttonVariant, buttonLabel, submission, disabled, error: error$1 }) {
65982
66677
  const inputId = inputIdFor(field);
65983
66678
  const errorId = `${inputId}-error`;
65984
66679
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
@@ -66005,7 +66700,8 @@ function NewsletterEmailEntry({ field, buttonVariant, buttonLabel, disabled, err
66005
66700
  messageId: errorId
66006
66701
  })
66007
66702
  }),
66008
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ThemedButton, {
66703
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ProtectedSubmitButton, {
66704
+ submission,
66009
66705
  type: "submit",
66010
66706
  variant: buttonVariant,
66011
66707
  size: "md",
@@ -66024,7 +66720,7 @@ function NewsletterEmailEntry({ field, buttonVariant, buttonLabel, disabled, err
66024
66720
  * The submit action: joined to the email field when the preset has one
66025
66721
  * (every current preset does), otherwise a plain themed button.
66026
66722
  */
66027
- function NewsletterSubmitRow({ emailField: emailField$1, lookSlots, buttonVariant, buttonLabel, disabled, error: error$1 }) {
66723
+ function NewsletterSubmitRow({ emailField: emailField$1, lookSlots, buttonVariant, buttonLabel, submission, disabled, error: error$1 }) {
66028
66724
  if (lookSlots) {
66029
66725
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [emailField$1 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(NewsletterExtraField, {
66030
66726
  field: emailField$1,
@@ -66033,7 +66729,8 @@ function NewsletterSubmitRow({ emailField: emailField$1, lookSlots, buttonVarian
66033
66729
  error: error$1
66034
66730
  }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
66035
66731
  ...listLookSlot({ lookSlots }, "actions"),
66036
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ThemedButton, {
66732
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ProtectedSubmitButton, {
66733
+ submission,
66037
66734
  ...listLookSlot({ lookSlots }, "action"),
66038
66735
  type: "submit",
66039
66736
  variant: buttonVariant,
@@ -66048,13 +66745,15 @@ function NewsletterSubmitRow({ emailField: emailField$1, lookSlots, buttonVarian
66048
66745
  field: emailField$1,
66049
66746
  buttonVariant,
66050
66747
  buttonLabel,
66748
+ submission,
66051
66749
  disabled,
66052
66750
  error: error$1
66053
66751
  });
66054
66752
  }
66055
66753
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
66056
66754
  className: "newsletter-submit",
66057
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ThemedButton, {
66755
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ProtectedSubmitButton, {
66756
+ submission,
66058
66757
  type: "submit",
66059
66758
  variant: buttonVariant,
66060
66759
  size: "md",
@@ -66153,6 +66852,7 @@ function NewsletterFormSSR(props$1) {
66153
66852
  }, field.id))
66154
66853
  }) : null,
66155
66854
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(NewsletterSubmitRow, {
66855
+ submission: { kind: "waiting" },
66156
66856
  lookSlots: display.lookSlots,
66157
66857
  emailField: emailField$1,
66158
66858
  buttonVariant: display.buttonVariant,
@@ -66605,6 +67305,47 @@ function derivePreviewLinkedEntryFieldBinding(node, parsedBinding, context) {
66605
67305
  function stripNumericPathSegments(path$3) {
66606
67306
  return path$3.split(".").filter((segment) => !/^\d+$/.test(segment)).join(".");
66607
67307
  }
67308
+ const lookOwnedPathCache = new WeakMap();
67309
+ function lookOwnedPathsOf(content) {
67310
+ if (!isPlainObject$3(content)) return [];
67311
+ const cached = lookOwnedPathCache.get(content);
67312
+ if (cached) return cached;
67313
+ const value = content._lookOwnedPaths;
67314
+ const paths = Array.isArray(value) ? value.filter((path$3) => typeof path$3 === "string") : [];
67315
+ lookOwnedPathCache.set(content, paths);
67316
+ return paths;
67317
+ }
67318
+ /**
67319
+ * Under an arrangement Look, the render plan has already removed the owner's
67320
+ * values for presentation the Look owns, and lists those field paths. A binding
67321
+ * on one of them skips its own default, so the Look decides: its CSS, or a
67322
+ * value the Look wrote itself (the crop its shape knob implies). Transforms
67323
+ * still run, which keeps the base classes they compose. Older styles list none
67324
+ * and bind as before.
67325
+ */
67326
+ function readsLookOwnedField(fromPath, context) {
67327
+ const owned = lookOwnedPathsOf(context.viewModel.content);
67328
+ if (owned.length === 0) return false;
67329
+ const segments = contentFieldSegments(fromPath, context);
67330
+ if (!segments) return false;
67331
+ const path$3 = segments.filter((segment) => typeof segment === "string").join(".");
67332
+ return owned.some((ownedPath) => path$3 === ownedPath || path$3.startsWith(`${ownedPath}.`));
67333
+ }
67334
+ /** The block-content path a binding reads, or undefined when it reads something else. */
67335
+ function contentFieldSegments(fromPath, context) {
67336
+ const [first, ...rest] = splitPath$1(fromPath);
67337
+ if (typeof first !== "string" || first === "$root") return undefined;
67338
+ if (first === "content") return rest;
67339
+ const named = [...context.scopes].reverse().find((entry) => entry.name === first);
67340
+ if (named) return scopedContentSegments(named, rest);
67341
+ const innermost = [...context.scopes].reverse().find((entry) => isPlainObject$3(entry.value) || Array.isArray(entry.value));
67342
+ if (!innermost || first in context.viewModel) return undefined;
67343
+ return innermost.name === "content" ? [first, ...rest] : scopedContentSegments(innermost, [first, ...rest]);
67344
+ }
67345
+ function scopedContentSegments(scope, rest) {
67346
+ const [root, ...base] = scope.basePathSegments ?? [];
67347
+ return root === "content" ? [...base, ...rest] : undefined;
67348
+ }
66608
67349
  /**
66609
67350
  * Resolves a binding path to absolute segments for editor/media metadata injection.
66610
67351
  *
@@ -66938,6 +67679,12 @@ function previewAuthoringFieldsEqual(left, right) {
66938
67679
  * @internal Exported for testing
66939
67680
  */
66940
67681
  function resolveBindingValue(binding, context) {
67682
+ return resolveReadBindingValue(readsLookOwnedField(binding.from, context) ? {
67683
+ ...binding,
67684
+ fallback: undefined
67685
+ } : binding, context);
67686
+ }
67687
+ function resolveReadBindingValue(binding, context) {
66941
67688
  const fullPath = binding.from;
66942
67689
  const segments = splitPath$1(fullPath);
66943
67690
  if (!segments.length) return undefined;
@@ -67985,10 +68732,19 @@ function prepareDefaultBlockRender(manifest, props$1) {
67985
68732
  fieldConstraints: buildPreviewFieldConstraints(manifest)
67986
68733
  };
67987
68734
  }
68735
+ const blockComponentCache = new WeakMap();
68736
+ /** One React component type per manifest, shared by page and standalone rendering. */
67988
68737
  function makeDefaultBlockComponent(args) {
68738
+ const cached = blockComponentCache.get(args.manifest);
68739
+ if (cached) return cached;
68740
+ const component = createDefaultBlockComponent(args.manifest);
68741
+ blockComponentCache.set(args.manifest, component);
68742
+ return component;
68743
+ }
68744
+ function createDefaultBlockComponent(manifest) {
67989
68745
  return function DefaultBlockComponent(props$1) {
67990
68746
  const perf = beginBlockRenderMeasurement();
67991
- const prepared = prepareDefaultBlockRender(args.manifest, props$1);
68747
+ const prepared = prepareDefaultBlockRender(manifest, props$1);
67992
68748
  const result = resolveTree(prepared.layout, {
67993
68749
  registry: prepared.registry,
67994
68750
  viewModel: prepared.viewModel,
@@ -68012,8 +68768,8 @@ function makeDefaultBlockComponent(args) {
68012
68768
  reportSlowBlockRender(perf, {
68013
68769
  content: props$1.content,
68014
68770
  blockId: props$1.blockId,
68015
- blockKind: props$1.blockKind ?? args.manifest.name,
68016
- manifestName: args.manifest.name
68771
+ blockKind: props$1.blockKind ?? manifest.name,
68772
+ manifestName: manifest.name
68017
68773
  });
68018
68774
  return result;
68019
68775
  };
@@ -68156,335 +68912,6 @@ function runtimeDateContext(viewModel) {
68156
68912
  return resolveDateRuntimeContext(typeof root.bookingTimeZone === "string" ? root.bookingTimeZone : undefined);
68157
68913
  }
68158
68914
 
68159
- //#endregion
68160
- //#region ../blocks/src/system/ai/hints/registry.ts
68161
- const HINTS = [
68162
- {
68163
- blockKind: "block.hero",
68164
- fieldPath: "variant",
68165
- hint: {
68166
- fieldLabelOverride: "Layout style",
68167
- impactSummary: "Changes the overall layout of the top banner (how text and media are arranged). Different styles can feel more minimal, more bold, or more split across the page.",
68168
- category: "layout",
68169
- suggestWhen: "visual-request-only"
68170
- }
68171
- },
68172
- {
68173
- blockKind: "block.columns",
68174
- fieldPath: "desktopColumns",
68175
- hint: {
68176
- fieldLabelOverride: "Columns on larger screens",
68177
- impactSummary: "Changes how many columns appear on larger screens. More columns increase density, fewer columns make each column wider.",
68178
- category: "layout",
68179
- suggestWhen: "visual-request-only"
68180
- }
68181
- },
68182
- {
68183
- blockKind: "block.columns",
68184
- fieldPath: "gap",
68185
- hint: {
68186
- fieldLabelOverride: "Column gap",
68187
- impactSummary: "Adjusts the spacing between columns and blocks. Larger gaps feel more open; smaller gaps feel more compact.",
68188
- category: "visual",
68189
- suggestWhen: "visual-request-only"
68190
- }
68191
- },
68192
- {
68193
- blockKind: "block.media-text",
68194
- fieldPath: "imagePosition",
68195
- hint: {
68196
- fieldLabelOverride: "Image position",
68197
- impactSummary: "Moves where the image sits relative to the text. This changes reading flow and visual balance.",
68198
- category: "layout",
68199
- suggestWhen: "visual-request-only"
68200
- }
68201
- },
68202
- {
68203
- blockKind: "block.media-text",
68204
- fieldPath: "wrapTextInCard",
68205
- hint: {
68206
- fieldLabelOverride: "Text card",
68207
- impactSummary: "Wraps text content in a styled card container. This makes text stand out more strongly from the background media.",
68208
- category: "visual",
68209
- suggestWhen: "visual-request-only"
68210
- }
68211
- },
68212
- {
68213
- blockKind: "block.single-button",
68214
- fieldPath: "button.variant",
68215
- hint: {
68216
- fieldLabelOverride: "Button style",
68217
- impactSummary: "Switches the button to a different theme variant (for example primary, secondary, or subtle). This changes emphasis and contrast.",
68218
- category: "theme",
68219
- suggestWhen: "visual-request-only"
68220
- }
68221
- },
68222
- {
68223
- blockKind: "block.body-text",
68224
- fieldPath: "alignment",
68225
- hint: {
68226
- fieldLabelOverride: "Text alignment",
68227
- impactSummary: "Changes whether text is left, center, or right aligned. This affects readability and the overall visual rhythm of the section.",
68228
- category: "layout",
68229
- suggestWhen: "visual-request-only"
68230
- }
68231
- },
68232
- {
68233
- blockKind: "block.testimonials",
68234
- fieldPath: "variant",
68235
- hint: {
68236
- fieldLabelOverride: "Layout style",
68237
- impactSummary: "Changes how testimonials are presented, for example as a grid or carousel, affecting hierarchy and emphasis.",
68238
- category: "layout",
68239
- suggestWhen: "visual-request-only"
68240
- }
68241
- },
68242
- {
68243
- blockKind: "block.testimonials",
68244
- fieldPath: "gridColumns",
68245
- hint: {
68246
- fieldLabelOverride: "Grid columns",
68247
- impactSummary: "Controls how many testimonial cards appear per row in grid layouts. This changes density and scanability.",
68248
- category: "layout",
68249
- suggestWhen: "visual-request-only"
68250
- }
68251
- },
68252
- {
68253
- blockKind: "block.embed",
68254
- fieldPath: "layout",
68255
- hint: {
68256
- fieldLabelOverride: "Layout",
68257
- impactSummary: "Changes how embedded entries are arranged (for example list vs grid). This affects how much content appears per row.",
68258
- category: "layout",
68259
- suggestWhen: "visual-request-only"
68260
- }
68261
- },
68262
- {
68263
- blockKind: "block.embed",
68264
- fieldPath: "contentType",
68265
- hint: {
68266
- fieldLabelOverride: "Content type",
68267
- impactSummary: "Switches which content type is rendered in this block. This changes the kind of items shown, not just wording.",
68268
- category: "structure",
68269
- suggestWhen: "visual-request-only"
68270
- }
68271
- },
68272
- {
68273
- blockKind: "block.blog-listing",
68274
- fieldPath: "variant",
68275
- hint: {
68276
- fieldLabelOverride: "Listing layout",
68277
- impactSummary: "Changes whether blog posts are displayed in a list or grid style. This affects visual density and browsing behavior.",
68278
- category: "layout",
68279
- suggestWhen: "visual-request-only"
68280
- }
68281
- },
68282
- {
68283
- blockKind: "block.blog-listing",
68284
- fieldPath: "columns",
68285
- hint: {
68286
- fieldLabelOverride: "Columns",
68287
- impactSummary: "Sets how many columns appear in grid mode. More columns show more posts at once; fewer columns give each card more space.",
68288
- category: "layout",
68289
- suggestWhen: "visual-request-only"
68290
- }
68291
- },
68292
- {
68293
- blockKind: "block.blog-listing",
68294
- fieldPath: "showImages",
68295
- hint: {
68296
- fieldLabelOverride: "Show featured images",
68297
- impactSummary: "Turns post thumbnails on or off. This strongly changes the visual look and emphasis of each listing item.",
68298
- category: "visual",
68299
- suggestWhen: "visual-request-only"
68300
- }
68301
- },
68302
- {
68303
- blockKind: "block.event-registration",
68304
- fieldPath: "buttonVariant",
68305
- hint: {
68306
- fieldLabelOverride: "Button style",
68307
- impactSummary: "Applies a different theme variant to the registration button, changing its visual prominence and contrast.",
68308
- category: "theme",
68309
- suggestWhen: "visual-request-only"
68310
- }
68311
- },
68312
- {
68313
- blockKind: "block.event-spotlight",
68314
- fieldPath: "layout",
68315
- hint: {
68316
- fieldLabelOverride: "Layout",
68317
- impactSummary: "Changes how spotlight events are arranged (for example stacked or grid). This affects hierarchy and scanability.",
68318
- category: "layout",
68319
- suggestWhen: "visual-request-only"
68320
- }
68321
- },
68322
- {
68323
- blockKind: "block.event-spotlight",
68324
- fieldPath: "columns",
68325
- hint: {
68326
- fieldLabelOverride: "Columns",
68327
- impactSummary: "Controls how many spotlight cards appear per row in grid layouts, affecting density and card width.",
68328
- category: "layout",
68329
- suggestWhen: "visual-request-only"
68330
- }
68331
- },
68332
- {
68333
- blockKind: "block.event-spotlight",
68334
- fieldPath: "_cardStyles.role",
68335
- hint: {
68336
- fieldLabelOverride: "Card style",
68337
- impactSummary: "Switches the visual style of each event card, such as emphasis, borders, and spacing.",
68338
- category: "theme",
68339
- suggestWhen: "visual-request-only"
68340
- }
68341
- },
68342
- {
68343
- blockKind: "block.event-listing",
68344
- fieldPath: "layout",
68345
- hint: {
68346
- fieldLabelOverride: "Layout",
68347
- impactSummary: "Changes how listing events are arranged (for example stacked or grid). This affects browsing flow and density.",
68348
- category: "layout",
68349
- suggestWhen: "visual-request-only"
68350
- }
68351
- },
68352
- {
68353
- blockKind: "block.event-listing",
68354
- fieldPath: "columns",
68355
- hint: {
68356
- fieldLabelOverride: "Columns",
68357
- impactSummary: "Controls how many event cards appear per row in grid layouts, changing balance between density and readability.",
68358
- category: "layout",
68359
- suggestWhen: "visual-request-only"
68360
- }
68361
- },
68362
- {
68363
- blockKind: "block.event-listing",
68364
- fieldPath: "_cardStyles.role",
68365
- hint: {
68366
- fieldLabelOverride: "Card style",
68367
- impactSummary: "Switches the visual style of event cards, including emphasis and overall card presentation.",
68368
- category: "theme",
68369
- suggestWhen: "visual-request-only"
68370
- }
68371
- },
68372
- {
68373
- blockKind: "*",
68374
- fieldPath: "_sectionStyles",
68375
- hint: {
68376
- fieldLabelOverride: "Section styles",
68377
- impactSummary: "Controls spacing and background for this section (padding, background color/image). These changes affect the look and feel, not the wording.",
68378
- category: "visual",
68379
- suggestWhen: "visual-request-only"
68380
- }
68381
- },
68382
- {
68383
- blockKind: "*",
68384
- fieldPath: "_sectionStyles.background",
68385
- hint: {
68386
- fieldLabelOverride: "Background",
68387
- impactSummary: "Controls the section background (color, gradient, or image). This changes the visual mood and contrast behind the content.",
68388
- category: "visual",
68389
- suggestWhen: "visual-request-only"
68390
- }
68391
- },
68392
- {
68393
- blockKind: "*",
68394
- fieldPath: "_cardStyles",
68395
- hint: {
68396
- fieldLabelOverride: "Card styles",
68397
- impactSummary: "Controls the look of the cards inside this section (rounded corners, shadow, padding, background, border). This affects this section’s cards, not the whole site theme.",
68398
- category: "visual",
68399
- suggestWhen: "visual-request-only"
68400
- }
68401
- },
68402
- {
68403
- blockKind: "*",
68404
- fieldPath: "_cardStyles.rounded",
68405
- hint: {
68406
- fieldLabelOverride: "Rounded corners",
68407
- impactSummary: "Adjusts how rounded the card corners are for this section’s cards only (small, medium, large, fully rounded).",
68408
- category: "visual",
68409
- suggestWhen: "visual-request-only"
68410
- }
68411
- },
68412
- {
68413
- blockKind: "*",
68414
- fieldPath: "_containerStyles",
68415
- hint: {
68416
- fieldLabelOverride: "Container styles",
68417
- impactSummary: "Controls the main container styling for this section (rounded corners, shadow, padding, background). This is section-specific, not a whole-site theme change.",
68418
- category: "visual",
68419
- suggestWhen: "visual-request-only"
68420
- }
68421
- },
68422
- {
68423
- blockKind: "*",
68424
- fieldPath: "_containerStyles.rounded",
68425
- hint: {
68426
- fieldLabelOverride: "Rounded corners",
68427
- impactSummary: "Adjusts how rounded the container corners are for this section only (small, medium, large, fully rounded).",
68428
- category: "visual",
68429
- suggestWhen: "visual-request-only"
68430
- }
68431
- },
68432
- {
68433
- blockKind: "block.event-calendar",
68434
- fieldPath: "displayMode",
68435
- hint: {
68436
- fieldLabelOverride: "Display mode",
68437
- impactSummary: "Changes how events are shown (list view, calendar view, or both). This affects the layout and how visitors browse events.",
68438
- category: "layout",
68439
- suggestWhen: "visual-request-only"
68440
- }
68441
- },
68442
- {
68443
- blockKind: "block.event-calendar",
68444
- fieldPath: "listLayout",
68445
- hint: {
68446
- fieldLabelOverride: "List layout",
68447
- impactSummary: "Changes the layout style for the event list (stacked cards vs a grid). This affects how many events show per row and the overall density.",
68448
- category: "layout",
68449
- suggestWhen: "visual-request-only"
68450
- }
68451
- }
68452
- ];
68453
- function isBoundaryMatch(prefix, fieldPath) {
68454
- if (prefix === fieldPath) return true;
68455
- if (!fieldPath.startsWith(prefix)) return false;
68456
- const next = fieldPath.charAt(prefix.length);
68457
- return next === ".";
68458
- }
68459
- function resolveByExactMatch(blockKind, fieldPath) {
68460
- return HINTS.find((entry) => entry.blockKind === blockKind && entry.fieldPath === fieldPath) ?? HINTS.find((entry) => entry.blockKind === "*" && entry.fieldPath === fieldPath) ?? null;
68461
- }
68462
- function resolveByPrefixMatch(blockKind, fieldPath) {
68463
- const candidates = HINTS.filter((entry) => {
68464
- if (entry.fieldPath === fieldPath) return false;
68465
- if (!(entry.blockKind === blockKind || entry.blockKind === "*")) return false;
68466
- return isBoundaryMatch(entry.fieldPath, fieldPath);
68467
- });
68468
- if (candidates.length === 0) return null;
68469
- candidates.sort((a$1, b$1) => {
68470
- if (a$1.blockKind !== b$1.blockKind) {
68471
- if (a$1.blockKind !== "*" && b$1.blockKind === "*") return -1;
68472
- if (a$1.blockKind === "*" && b$1.blockKind !== "*") return 1;
68473
- }
68474
- return b$1.fieldPath.length - a$1.fieldPath.length;
68475
- });
68476
- return candidates[0] ?? null;
68477
- }
68478
- function resolveAiFieldHint(input) {
68479
- const blockKind = input.blockKind.trim();
68480
- const fieldPath = input.fieldPath.trim();
68481
- if (!blockKind || !fieldPath) return null;
68482
- const exact = resolveByExactMatch(blockKind, fieldPath);
68483
- if (exact) return exact.hint;
68484
- const prefix = resolveByPrefixMatch(blockKind, fieldPath);
68485
- return prefix?.hint ?? null;
68486
- }
68487
-
68488
68915
  //#endregion
68489
68916
  //#region ../blocks/src/system/media/constrainedVideoMedia.ts
68490
68917
  function isRecord$10(value) {
@@ -68793,7 +69220,8 @@ function composePageJoins(input) {
68793
69220
  return [{
68794
69221
  previousBlockId: previous.id,
68795
69222
  nextBlockId: next.id,
68796
- join: join$1 ? composeJoin(join$1, previous, next) : null
69223
+ join: join$1 ? composeJoin(join$1, previous, next) : null,
69224
+ fieldsMeet: sectionShapeFromContent(previous.content) === "field" && sectionShapeFromContent(next.content) === "field"
68797
69225
  }];
68798
69226
  });
68799
69227
  }
@@ -68833,11 +69261,31 @@ function pairKey(previousBlockId, nextBlockId) {
68833
69261
  * runs inside a `useMemo` whose recomputation React makes no promises about.
68834
69262
  */
68835
69263
  function buildPageRenderPlan(input) {
69264
+ return planPageRender(input).plan;
69265
+ }
69266
+ /** Owner-local derived reuse; shared settings and admitted rhythm position remain inputs. */
69267
+ function createPageRenderPlanReader() {
69268
+ const memo = { current: null };
69269
+ return (input) => {
69270
+ memo.current = planPageRender(input, memo.current);
69271
+ return memo.current.plan;
69272
+ };
69273
+ }
69274
+ function planPageRender(input, previous = null) {
68836
69275
  const resolveTarget = createRenderTargetResolver(input);
68837
- const outcomes = input.page.blocks.map((block) => planPageBlock(block, input, resolveTarget));
69276
+ const reusable = previous && samePlanSettings(previous.input, input) ? previous : null;
69277
+ const planned = input.page.blocks.map((block) => [block, reusable?.outcomes.get(block) ?? planPageBlock(block, input, resolveTarget)]);
69278
+ const outcomes = planned.map(([, outcome]) => outcome);
68838
69279
  const entries = outcomes.flatMap((outcome) => outcome.kind === "admitted" ? [outcome.entry] : []);
68839
- return {
68840
- entries: entries.map(applyArrangementRhythm),
69280
+ const rhythmic = entries.map((entry, position) => {
69281
+ const cached = reusable?.rhythm.get(entry);
69282
+ return [entry, {
69283
+ position,
69284
+ entry: cached?.position === position ? cached.entry : applyArrangementRhythm(entry, position)
69285
+ }];
69286
+ });
69287
+ const plan = {
69288
+ entries: rhythmic.map(([, value]) => value.entry),
68841
69289
  omitted: outcomes.flatMap((outcome) => outcome.kind === "omitted" ? [outcome.omission] : []),
68842
69290
  runtimeJoins: retargetJoinsAcrossOmissions({
68843
69291
  joins: input.runtimeJoins ?? [],
@@ -68845,6 +69293,15 @@ function buildPageRenderPlan(input) {
68845
69293
  survivingBlocks: new Set(entries.map((entry) => entry.block))
68846
69294
  })
68847
69295
  };
69296
+ return {
69297
+ input,
69298
+ outcomes: new Map(planned),
69299
+ rhythm: new Map(rhythmic),
69300
+ plan
69301
+ };
69302
+ }
69303
+ function samePlanSettings(previous, current) {
69304
+ return previous.siteStyleId === current.siteStyleId && previous.audience === current.audience && previous.previewStage === current.previewStage && previous.sdkConfig === current.sdkConfig && previous.customBlocks === current.customBlocks && previous.blockOverrides === current.blockOverrides;
68848
69305
  }
68849
69306
  /**
68850
69307
  * Mirrors the order of the checks `MemoBlockSection` used to make inline, so no
@@ -68992,10 +69449,15 @@ function arrangementRuntime(content) {
68992
69449
  const value = parseSurfaceTree(content._arrangementLooks);
68993
69450
  return isObjectRecord(value) && isObjectRecord(value.byMode) && Array.isArray(value.available) && Array.isArray(value.rhythm) ? restoreArrangementRuntime(value) : null;
68994
69451
  }
68995
- /** JSON transports carry resolver inputs; rebuild every surface at this boundary. */
69452
+ /**
69453
+ * JSON transports carry resolver inputs; rebuild every surface at this boundary.
69454
+ * A payload cached before compiled looks carried `slotRoles` gets the Look's own.
69455
+ */
68996
69456
  function restoreCompiledLook(look) {
69457
+ const transported = look;
68997
69458
  return {
68998
69459
  ...look,
69460
+ slotRoles: transported.slotRoles ?? look.look.structure.slotRoles ?? {},
68999
69461
  itemSurfaces: Object.fromEntries(Object.entries(look.itemSurfaces).map(([slot, surface]) => [slot, parseResolvedSurface(surface)])),
69000
69462
  ...look.roleSurfaces ? { roleSurfaces: {
69001
69463
  card: parseResolvedSurface(look.roleSurfaces.card),
@@ -69005,8 +69467,11 @@ function restoreCompiledLook(look) {
69005
69467
  };
69006
69468
  }
69007
69469
  function restoreArrangementRuntime(runtime) {
69470
+ const transported = runtime;
69471
+ const fieldGrounds = Array.isArray(transported.fieldGrounds) ? transported.fieldGrounds.filter((token) => typeof token === "string") : [];
69008
69472
  return {
69009
69473
  ...runtime,
69474
+ fieldGrounds,
69010
69475
  available: runtime.available.map(restoreCompiledLook),
69011
69476
  byMode: Object.fromEntries(Object.entries(runtime.byMode).map(([mode, look]) => [mode, restoreCompiledLook(look)]))
69012
69477
  };
@@ -69027,7 +69492,7 @@ function planArrangementContent(blockKind, manifest, content, audience) {
69027
69492
  const { facts } = arrangementContentFacts(content);
69028
69493
  const published = resolvePublishedLook({
69029
69494
  look: selected.look,
69030
- contentFacts: facts,
69495
+ facts,
69031
69496
  audience,
69032
69497
  catalogue: runtime.available.map((entry) => entry.look)
69033
69498
  });
@@ -69039,7 +69504,12 @@ function planArrangementContent(blockKind, manifest, content, audience) {
69039
69504
  });
69040
69505
  const values = Object.fromEntries(Object.entries(knobs).flatMap(([key, knob]) => knob.kind === "kept" ? [] : [[key, knob.value]]));
69041
69506
  const effectiveContent = Object.fromEntries(Object.entries(values).map(([key, value]) => [key, effectiveContentKnobValue(blockKind, key, value)]));
69042
- const activeContent = Object.fromEntries(Object.entries(content).filter(([key]) => knobs[key]?.kind !== "kept"));
69507
+ const lookOwnedPaths = contentPathsOwnedBy(resolveFieldOwnership({
69508
+ blockKind,
69509
+ manifest,
69510
+ arrangementLook: true
69511
+ }), ["look"]);
69512
+ const activeContent = withoutLookOwnedContent(Object.fromEntries(Object.entries(content).filter(([key]) => knobs[key]?.kind !== "kept")), lookOwnedPaths);
69043
69513
  const photoContent = arrangementPhotoContent(activeContent, effectiveContent);
69044
69514
  const visiblePhotos = arrangementContentFacts({
69045
69515
  ...activeContent,
@@ -69048,35 +69518,45 @@ function planArrangementContent(blockKind, manifest, content, audience) {
69048
69518
  });
69049
69519
  return {
69050
69520
  ...activeContent,
69521
+ ...arrangementPhotoTreatmentContent(activeContent, effective.look),
69051
69522
  ...mode !== null ? { variant: mode } : {},
69052
69523
  ...effectiveContent,
69053
69524
  ...photoContent,
69054
- ...arrangementShapeContent(effective.look.id, {
69055
- ...activeContent,
69056
- ...effectiveContent
69057
- }),
69525
+ ...arrangementShapeContent(knobs),
69058
69526
  ...arrangementPanelContent(activeContent, effective, mode),
69059
69527
  ...arrangementQuoteContent(blockKind, effective, values),
69060
69528
  _arrangementLooks: runtime,
69061
69529
  _effectiveLook: effective,
69062
69530
  _lookHooks: arrangementContentHooks(effective, mode, length, {
69063
- ...facts,
69064
- photo: visiblePhotos.facts.photo
69531
+ ...facts.content,
69532
+ photo: visiblePhotos.facts.content.photo
69065
69533
  }, values, visiblePhotos.photoCount),
69066
69534
  _effectiveKnobs: knobs,
69535
+ _lookOwnedPaths: lookOwnedPaths,
69067
69536
  _lookAudience: audience,
69068
69537
  _lookSlots: arrangementContentSlots(blockKind),
69069
69538
  blockLook: effective.look.id
69070
69539
  };
69071
69540
  }
69541
+ /** Typed Look composition owns contrast treatment; parsing preserves authored paint. */
69542
+ function arrangementPhotoTreatmentContent(content, look) {
69543
+ if (!look.structure.photoTreatment) return {};
69544
+ const authored = parseCanonicalRuntimeBackground(content);
69545
+ if (authored.kind === "none") return {};
69546
+ return { _sectionStyles: {
69547
+ ...isObjectRecord(content._sectionStyles) ? content._sectionStyles : {},
69548
+ background: applyLookPhotoTreatment(authored.background, look.structure.photoTreatment)
69549
+ } };
69550
+ }
69072
69551
  /** Widget section hooks use the theme; hero background geometry never travels to list islands. */
69073
69552
  function arrangementContentSlots(blockKind) {
69074
69553
  return Object.fromEntries(arrangementSlotNames.filter((slot) => (!slot.startsWith("price-") || blockKind === "block.shop") && slot !== "schedule-section" && slot !== "shop-section" && (slot !== "background" || blockKind === "block.hero")).map((slot) => [slot, slot]));
69075
69554
  }
69076
- /** C photo Looks render shape-specific crops without rewriting authored preferences. */
69077
- function arrangementShapeContent(lookId, content) {
69078
- if (lookId !== "intro-photo-beside-text" && lookId !== "media-text-photo-beside-text") return {};
69079
- return content.imageShape === "circle" ? { aspectRatio: "1/1" } : content.imageShape === "arch" ? { aspectRatio: "4/5" } : {};
69555
+ /** Where a Look offers the photo shape, the shape sets the crop, without rewriting authored preferences. */
69556
+ function arrangementShapeContent(knobs) {
69557
+ const shape = knobs.imageShape;
69558
+ if (!shape || shape.kind === "kept") return {};
69559
+ return shape.value === "circle" ? { aspectRatio: "1/1" } : shape.value === "arch" ? { aspectRatio: "4/5" } : {};
69080
69560
  }
69081
69561
  function arrangementQuoteContent(blockKind, effective, values) {
69082
69562
  if (blockKind !== "block.testimonials") return {};
@@ -69107,18 +69587,25 @@ function arrangementPhotoContent(content, knobs) {
69107
69587
  return copy;
69108
69588
  }) };
69109
69589
  }
69590
+ /**
69591
+ * The one owner of the facts `whenMissing` rules read from block content.
69592
+ * Content facts also become `data-has-*` hooks; setting facts never do.
69593
+ */
69110
69594
  function arrangementContentFacts(content) {
69111
69595
  const photoCount = arrangementPhotoCount(content);
69112
69596
  const featured = typeof content.featured === "string" ? content.featured.trim().length > 0 : content.featured !== undefined && content.featured !== null;
69113
69597
  return {
69114
69598
  photoCount,
69115
69599
  facts: {
69116
- photo: photoCount > 0,
69117
- facts: Array.isArray(content.facts) && content.facts.length > 0,
69118
- featured,
69119
- outcome: typeof content.outcome === "string" && content.outcome.length > 0,
69120
- figure: typeof content.figure === "string" && content.figure.trim().length > 0,
69121
- entrance: isObjectRecord(content.entrancePhoto)
69600
+ content: {
69601
+ photo: photoCount > 0,
69602
+ facts: Array.isArray(content.facts) && content.facts.length > 0,
69603
+ featured,
69604
+ outcome: typeof content.outcome === "string" && content.outcome.length > 0,
69605
+ figure: typeof content.figure === "string" && content.figure.trim().length > 0,
69606
+ entrance: isObjectRecord(content.entrancePhoto)
69607
+ },
69608
+ settings: { "listed-by-week": content.listBy === "week" }
69122
69609
  }
69123
69610
  };
69124
69611
  }
@@ -69128,9 +69615,7 @@ function arrangementPhotoCount(content) {
69128
69615
  if (Array.isArray(content.members)) return content.members.filter((member) => isObjectRecord(member) && isObjectRecord(member.photo)).length;
69129
69616
  if (Array.isArray(content.images)) return content.images.filter((item) => isObjectRecord(item) && isObjectRecord(item.image)).length;
69130
69617
  if (isObjectRecord(content.media) || isObjectRecord(content.entrancePhoto)) return 1;
69131
- const section$2 = isObjectRecord(content._sectionStyles) ? content._sectionStyles : {};
69132
- const background = isObjectRecord(section$2.background) ? section$2.background : {};
69133
- return isObjectRecord(background.image) ? 1 : 0;
69618
+ return storedSectionPhoto(content) === null ? 0 : 1;
69134
69619
  }
69135
69620
  function effectiveContentKnobValue(blockKind, key, value) {
69136
69621
  const facet = systemCustomizeFacetDefinitionsForBlock(blockKind).find((entry) => entry.target.kind === "content-field" && entry.target.field === key);
@@ -69154,11 +69639,12 @@ function applyArrangementRhythm(entry, position) {
69154
69639
  if (!runtime || !look) return entry;
69155
69640
  const rhythm = runtime.rhythm.length === 0 ? null : runtime.rhythm[position % runtime.rhythm.length];
69156
69641
  const content = entry.renderableContent;
69157
- const resolved = resolveSectionBackground(parseCanonicalRuntimeBackground(content), null, rhythm, heroPhotoGround(entry));
69642
+ const resolved = resolveSectionBackground(parseCanonicalRuntimeBackground(content), null, rhythm, heroPhotoGround(entry.block.kind, entry.kind === "renderable" ? entry.effectiveArrangementKey ?? undefined : undefined));
69158
69643
  const updated$1 = applyResolvedArrangementBackground(content, resolved);
69159
69644
  const surface = arrangementGroundToken(resolved);
69160
69645
  const grounded = resolveArrangementRoleSurfaces(look, runtime, resolved);
69161
69646
  const tinted = resolveArrangementTints(updated$1, grounded, runtime, surface) ?? grounded;
69647
+ const shape = sectionShapeHook(sectionShapeForGround(runtime.fieldGrounds, surface));
69162
69648
  return {
69163
69649
  ...entry,
69164
69650
  styleBackground: arrangementGroundToken(resolveSectionBackground({ kind: "none" }, null, rhythm)),
@@ -69167,7 +69653,8 @@ function applyArrangementRhythm(entry, position) {
69167
69653
  _effectiveLook: tinted,
69168
69654
  _lookHooks: {
69169
69655
  ...isObjectRecord(updated$1._lookHooks) ? updated$1._lookHooks : {},
69170
- "data-surface": surface
69656
+ "data-surface": surface,
69657
+ ...shape
69171
69658
  }
69172
69659
  }
69173
69660
  };
@@ -69274,15 +69761,19 @@ function resolveArrangementRoleSurfaces(look, runtime, background) {
69274
69761
  ...look,
69275
69762
  ground,
69276
69763
  roleSurfaces,
69277
- itemSurfaces: resolveLookSlotSurfaces(look.look, look.itemRoles, roleSurfaces)
69764
+ itemSurfaces: resolveLookSlotSurfaces(look, look.itemRoles, roleSurfaces)
69278
69765
  };
69279
69766
  }
69280
- /** The arrangement key is resolved once by planBlock, including pinned Looks. */
69281
- function heroPhotoGround(entry) {
69282
- return entry.kind === "renderable" && entry.block.kind === "block.hero" ? { paintsGround: heroPhotoPaintsGround(entry.effectiveArrangementKey ?? undefined) } : undefined;
69767
+ function heroPhotoGround(blockKind, arrangementKey) {
69768
+ return blockKind === "block.hero" ? { paintsGround: heroPhotoPaintsGround(arrangementKey) } : undefined;
69769
+ }
69770
+ /** Both admitted server openings and current editor projections use the decided arrangement key. */
69771
+ function pageOpeningPhotoPlacement(blockKind, content, arrangementKey) {
69772
+ const background = resolveSectionBackground(parseCanonicalRuntimeBackground(content), null);
69773
+ return resolveSectionPhotoPlacement(background, heroPhotoGround(blockKind, arrangementKey));
69283
69774
  }
69284
69775
  /** Header consumers receive the opening that the public render plan actually admits. */
69285
- function resolvePageOpeningSection(page, options = {}) {
69776
+ function resolvePageOpeningSection(page, options) {
69286
69777
  const presentation = toPresentationPage(page);
69287
69778
  if (!presentation) return null;
69288
69779
  const opening = buildPageRenderPlan({
@@ -69296,11 +69787,12 @@ function resolvePageOpeningSection(page, options = {}) {
69296
69787
  blockOverrides: undefined
69297
69788
  }).entries[0];
69298
69789
  if (!opening) return null;
69299
- const background = resolveSectionBackground(parseCanonicalRuntimeBackground(opening.renderableContent), null);
69790
+ const appearance = resolveCompiledSectionContextFromContent(opening.renderableContent, expandPalette(options.theme.palette), heroPhotoGround(opening.block.kind, opening.kind === "renderable" ? opening.effectiveArrangementKey ?? undefined : undefined));
69300
69791
  return {
69301
69792
  blockKind: opening.block.kind,
69302
69793
  content: opening.renderableContent,
69303
- photoPlacement: resolveSectionPhotoPlacement(background, heroPhotoGround(opening))
69794
+ appearance,
69795
+ photoPlacement: appearance.openingPhotoBehindText ? "behind-text" : "none"
69304
69796
  };
69305
69797
  }
69306
69798
 
@@ -69654,12 +70146,12 @@ function shouldSkipResolvedLoader(input) {
69654
70146
  async function prefetchBlockData(page, context, options) {
69655
70147
  return (await prefetchBlockDataWithFailures(page, context, options)).resolvedData;
69656
70148
  }
69657
- async function prefetchBlockDataWithFailures(page, context, options) {
70149
+ /** Resolve once through the shared bindings owner; request reuse never reuses content provenance. */
70150
+ function planBlockDataRequests(page, context, options = {}) {
69658
70151
  const runtime = admitLoaderDateRuntime(context);
69659
70152
  const blocks = page.blocks.flatMap((block) => block.id ? [planBlockRequests(block, block.id, context, options, runtime)] : []);
69660
- const outcomes = await Promise.all(blocks.flatMap((block) => block.requests.map((request) => executeLoaderRequest(request, options))));
69661
70153
  return {
69662
- ...projectLoaderOutcomes(blocks, outcomes),
70154
+ blocks,
69663
70155
  loaderSnapshot: {
69664
70156
  stage: context.previewStage === "preview" ? "draft" : "published",
69665
70157
  blocks: Object.fromEntries(blocks.map((block) => [block.id, {
@@ -69673,6 +70165,17 @@ async function prefetchBlockDataWithFailures(page, context, options) {
69673
70165
  }
69674
70166
  };
69675
70167
  }
70168
+ async function prefetchBlockDataWithFailures(page, context, options) {
70169
+ const plan = planBlockDataRequests(page, context, options);
70170
+ const outcomes = await Promise.all(plan.blocks.flatMap((block) => block.requests.map((request) => executeBlockDataRequest(request, options))));
70171
+ return projectBlockDataOutcomes(plan, outcomes);
70172
+ }
70173
+ function projectBlockDataOutcomes(plan, outcomes) {
70174
+ return {
70175
+ ...projectLoaderOutcomes(plan.blocks, outcomes),
70176
+ loaderSnapshot: plan.loaderSnapshot
70177
+ };
70178
+ }
69676
70179
  function planBlockRequests(block, id, context, options, runtime) {
69677
70180
  const definition$1 = (options.getBlockDefinition ?? getBlockDefinition)(block.kind);
69678
70181
  const loaders = definition$1 ? normalizeDataLoaders(definition$1) : customLoaders(block.kind, options);
@@ -69722,7 +70225,7 @@ function planLoaderRequest({ key, loader }, block, blockId, vm, options, runtime
69722
70225
  params
69723
70226
  };
69724
70227
  }
69725
- async function executeLoaderRequest(request, options) {
70228
+ async function executeBlockDataRequest(request, options) {
69726
70229
  try {
69727
70230
  return {
69728
70231
  kind: "loaded",
@@ -78748,7 +79251,8 @@ const THEME_FIELD_CATEGORY_MAP = {
78748
79251
  "Site Style Dressing": [
78749
79252
  "skin",
78750
79253
  "skinTokens",
78751
- "skinMarks"
79254
+ "skinMarks",
79255
+ "skinBookingBar"
78752
79256
  ],
78753
79257
  "Custom CSS": [
78754
79258
  "customCssRules",
@@ -79544,9 +80048,21 @@ function renderSystemBlockDefinition(definition$1) {
79544
80048
  } else {
79545
80049
  lines.push(...renderFieldList(manifest.fields, 0));
79546
80050
  }
80051
+ lines.push(...renderLookOwnedFields(manifest));
79547
80052
  lines.push("");
79548
80053
  return lines;
79549
80054
  }
80055
+ /** Fields an arrangement Look takes over, from the same decision the editor uses. */
80056
+ function renderLookOwnedFields(manifest) {
80057
+ if (!blockHasArrangementLooks(manifest.name)) return [];
80058
+ const ownership = resolveFieldOwnership({
80059
+ blockKind: manifest.name,
80060
+ manifest,
80061
+ arrangementLook: true
80062
+ });
80063
+ const paths = fieldPathsOwnedBy(ownership, ["look"]);
80064
+ return paths.length === 0 ? [] : ["", `On site styles with Looks, the Look sets these while it shows the block, and stored values have no effect: ${paths.join(", ")}`];
80065
+ }
79550
80066
  function renderVariantDocumentation(manifest) {
79551
80067
  if (!manifest.variants || Object.keys(manifest.variants).length === 0) {
79552
80068
  return [];
@@ -80032,7 +80548,7 @@ async function loadConfig(configPath, output) {
80032
80548
  return { errorMessage: "No config path provided." };
80033
80549
  }
80034
80550
  try {
80035
- const { loadConfigFile: loadConfigFile$1 } = await import("../load-config-DAdJwh-i.mjs");
80551
+ const { loadConfigFile: loadConfigFile$1 } = await import("../load-config-DX04ekBQ.mjs");
80036
80552
  const rawConfig = await loadConfigFile$1(configPath);
80037
80553
  const parsed = riverbankSiteConfigSchema.safeParse(rawConfig);
80038
80554
  if (!parsed.success) {
@@ -82790,6 +83306,7 @@ function cancelledRunInput(run) {
82790
83306
  status: "cancelled",
82791
83307
  visibility: run.visibility,
82792
83308
  capacity: run.capacity,
83309
+ waitlistMode: run.waitlistMode,
82793
83310
  bookingOffer: run.bookingOffer,
82794
83311
  venueRef: run.venueRef,
82795
83312
  formRef: run.formRef,
@@ -93898,7 +94415,7 @@ async function publishContentEntry(apiClient, { type, siteId, entryId, body, opt
93898
94415
  return normalizeApiError(error$1, "Failed to publish entry");
93899
94416
  }
93900
94417
  }
93901
- async function scheduleContentEntry(apiClient, { type, siteId, entryId, publishAt, options }) {
94418
+ async function scheduleContentEntry(apiClient, { type, siteId, entryId, publishAt, expectedPublishAt, options }) {
93902
94419
  try {
93903
94420
  return unwrapResponse(await apiClient({
93904
94421
  endpoint: "scheduleContentEntry",
@@ -93907,21 +94424,29 @@ async function scheduleContentEntry(apiClient, { type, siteId, entryId, publishA
93907
94424
  type,
93908
94425
  entryId
93909
94426
  },
93910
- body: { publishAt },
94427
+ body: expectedPublishAt === undefined ? { publishAt } : {
94428
+ publishAt,
94429
+ expectedPublishAt
94430
+ },
93911
94431
  options
93912
94432
  }));
93913
94433
  } catch (error$1) {
93914
94434
  return normalizeApiError(error$1, "Failed to schedule publish");
93915
94435
  }
93916
94436
  }
93917
- async function cancelScheduledContentEntry(apiClient, { type, siteId, entryId, options }) {
94437
+ async function cancelScheduledContentEntry(apiClient, { type, siteId, entryId, expectedPublishAt, options }) {
93918
94438
  try {
93919
94439
  return unwrapResponse(await apiClient({
93920
94440
  endpoint: "cancelScheduledContentEntry",
93921
- params: {
94441
+ params: expectedPublishAt === undefined ? {
93922
94442
  siteId,
93923
94443
  type,
93924
94444
  entryId
94445
+ } : {
94446
+ siteId,
94447
+ type,
94448
+ entryId,
94449
+ expectedPublishAt
93925
94450
  },
93926
94451
  options
93927
94452
  }));
@@ -94108,12 +94633,13 @@ const blocksKeys = {
94108
94633
  function normalizeError(error$1, fallback) {
94109
94634
  return normalizeApiError(error$1, fallback);
94110
94635
  }
94111
- async function createBlock(apiClient, { siteId, pageId, kind, position, purpose, duplicatedFromBlockId, options }) {
94636
+ async function createBlock(apiClient, { siteId, pageId, kind, position, purpose, duplicatedFromBlockId, initialLookId, options }) {
94112
94637
  const payload = {
94113
94638
  kind,
94114
94639
  position,
94115
94640
  purpose,
94116
- duplicatedFromBlockId
94641
+ duplicatedFromBlockId,
94642
+ ...initialLookId ? { initialLookId } : {}
94117
94643
  };
94118
94644
  try {
94119
94645
  return unwrapResponse(await apiClient({
@@ -94433,16 +94959,6 @@ async function savePageDesignState(apiClient, { siteId, pageId, body, options })
94433
94959
  options
94434
94960
  }));
94435
94961
  }
94436
- async function getPageDesignEditorState(apiClient, { siteId, pageId, options }) {
94437
- return unwrapResponse(await apiClient({
94438
- endpoint: "getPageDesignEditorState",
94439
- params: {
94440
- siteId,
94441
- pageId
94442
- },
94443
- options
94444
- }));
94445
- }
94446
94962
  async function applyPageDesignEditorAction(apiClient, { siteId, pageId, body, options }) {
94447
94963
  return unwrapResponse(await apiClient({
94448
94964
  endpoint: "applyPageDesignEditorAction",
@@ -95596,257 +96112,6 @@ async function retryResendRequest(apiClient, { domainId, options }) {
95596
96112
  }
95597
96113
  }
95598
96114
 
95599
- //#endregion
95600
- //#region ../api/src/admin.ts
95601
- async function startImpersonation(apiClient, body, options) {
95602
- try {
95603
- return unwrapResponse(await apiClient({
95604
- endpoint: "adminStartImpersonation",
95605
- body,
95606
- options
95607
- }));
95608
- } catch (error$1) {
95609
- return normalizeApiError(error$1, "Failed to start impersonation session");
95610
- }
95611
- }
95612
- async function stopImpersonation(apiClient, body, options) {
95613
- try {
95614
- return unwrapResponse(await apiClient({
95615
- endpoint: "adminStopImpersonation",
95616
- body,
95617
- options
95618
- }));
95619
- } catch (error$1) {
95620
- return normalizeApiError(error$1, "Failed to stop impersonation session");
95621
- }
95622
- }
95623
- async function assignAdminRole(apiClient, body, options) {
95624
- try {
95625
- return unwrapResponse(await apiClient({
95626
- endpoint: "adminAssignRole",
95627
- body,
95628
- options
95629
- }));
95630
- } catch (error$1) {
95631
- return normalizeApiError(error$1, "Failed to assign admin role");
95632
- }
95633
- }
95634
- async function revokeAdminRole(apiClient, body, options) {
95635
- try {
95636
- return unwrapResponse(await apiClient({
95637
- endpoint: "adminRevokeRole",
95638
- body,
95639
- options
95640
- }));
95641
- } catch (error$1) {
95642
- return normalizeApiError(error$1, "Failed to revoke admin role");
95643
- }
95644
- }
95645
- async function adminChangePlan(apiClient, body, options) {
95646
- try {
95647
- return unwrapResponse(await apiClient({
95648
- endpoint: "adminChangePlan",
95649
- body: {
95650
- ...body,
95651
- attemptId: body.attemptId ?? crypto.randomUUID()
95652
- },
95653
- options
95654
- }));
95655
- } catch (error$1) {
95656
- return normalizeApiError(error$1, "Failed to update billing plan");
95657
- }
95658
- }
95659
- async function listAdminInvites(apiClient, params = {}, options) {
95660
- try {
95661
- return unwrapResponse(await apiClient({
95662
- endpoint: "adminListInvites",
95663
- params,
95664
- options
95665
- }));
95666
- } catch (error$1) {
95667
- return normalizeApiError(error$1, "Failed to load invites");
95668
- }
95669
- }
95670
- async function createAdminInvite(apiClient, body, options) {
95671
- try {
95672
- return unwrapResponse(await apiClient({
95673
- endpoint: "adminCreateInvite",
95674
- body,
95675
- options
95676
- }));
95677
- } catch (error$1) {
95678
- return normalizeApiError(error$1, "Failed to create invite");
95679
- }
95680
- }
95681
- async function revokeAdminInvite(apiClient, inviteId, options) {
95682
- try {
95683
- return unwrapResponse(await apiClient({
95684
- endpoint: "adminRevokeInvite",
95685
- params: { inviteId },
95686
- options
95687
- }));
95688
- } catch (error$1) {
95689
- return normalizeApiError(error$1, "Failed to revoke invite");
95690
- }
95691
- }
95692
- async function createAdminUser(apiClient, body, options) {
95693
- try {
95694
- return unwrapResponse(await apiClient({
95695
- endpoint: "adminCreateUser",
95696
- body,
95697
- options
95698
- }));
95699
- } catch (error$1) {
95700
- return normalizeApiError(error$1, "Failed to create user");
95701
- }
95702
- }
95703
- async function adminDeleteSite(apiClient, siteId, options) {
95704
- try {
95705
- return unwrapResponse(await apiClient({
95706
- endpoint: "adminDeleteSite",
95707
- params: { siteId },
95708
- options
95709
- }));
95710
- } catch (error$1) {
95711
- return normalizeApiError(error$1, "Failed to delete site");
95712
- }
95713
- }
95714
- async function adminDeleteUser(apiClient, userId, params = {}, options) {
95715
- const forceQuery = params.force ? { force: "true" } : {};
95716
- try {
95717
- return unwrapResponse(await apiClient({
95718
- endpoint: "adminDeleteUser",
95719
- params: {
95720
- userId,
95721
- ...forceQuery
95722
- },
95723
- options
95724
- }));
95725
- } catch (error$1) {
95726
- return normalizeApiError(error$1, "Failed to delete user");
95727
- }
95728
- }
95729
- async function listAllowedDomains(apiClient, params = {}, options) {
95730
- try {
95731
- return unwrapResponse(await apiClient({
95732
- endpoint: "adminListAllowedDomains",
95733
- params,
95734
- options
95735
- }));
95736
- } catch (error$1) {
95737
- return normalizeApiError(error$1, "Failed to load allowed domains");
95738
- }
95739
- }
95740
- async function addAllowedDomain(apiClient, body, options) {
95741
- try {
95742
- return unwrapResponse(await apiClient({
95743
- endpoint: "adminAddAllowedDomain",
95744
- body,
95745
- options
95746
- }));
95747
- } catch (error$1) {
95748
- return normalizeApiError(error$1, "Failed to add domain");
95749
- }
95750
- }
95751
- async function deleteAllowedDomain(apiClient, domainId, options) {
95752
- try {
95753
- return unwrapResponse(await apiClient({
95754
- endpoint: "adminDeleteAllowedDomain",
95755
- params: { domainId },
95756
- options
95757
- }));
95758
- } catch (error$1) {
95759
- return normalizeApiError(error$1, "Failed to remove domain");
95760
- }
95761
- }
95762
- async function listGscPropertiesAdmin(apiClient, options) {
95763
- try {
95764
- return unwrapResponse(await apiClient({
95765
- endpoint: "listGscPropertiesAdmin",
95766
- options
95767
- }));
95768
- } catch (error$1) {
95769
- return normalizeApiError(error$1, "Failed to load GSC properties");
95770
- }
95771
- }
95772
- async function setGscPersistEnabled(apiClient, body, options) {
95773
- try {
95774
- return unwrapResponse(await apiClient({
95775
- endpoint: "adminGscMetaPersist",
95776
- body,
95777
- options
95778
- }));
95779
- } catch (error$1) {
95780
- return normalizeApiError(error$1, "Failed to update GSC persist toggle");
95781
- }
95782
- }
95783
- async function startGscVerification(apiClient, body, options) {
95784
- try {
95785
- return unwrapResponse(await apiClient({
95786
- endpoint: "adminGscVerifyStart",
95787
- body,
95788
- options
95789
- }));
95790
- } catch (error$1) {
95791
- return normalizeApiError(error$1, "Failed to start GSC verification");
95792
- }
95793
- }
95794
- async function confirmGscVerification(apiClient, body, options) {
95795
- try {
95796
- return unwrapResponse(await apiClient({
95797
- endpoint: "adminGscVerifyConfirm",
95798
- body,
95799
- options
95800
- }));
95801
- } catch (error$1) {
95802
- return normalizeApiError(error$1, "Failed to confirm GSC verification");
95803
- }
95804
- }
95805
- async function runGscIngestionForSite(apiClient, body, options) {
95806
- try {
95807
- return unwrapResponse(await apiClient({
95808
- endpoint: "adminSeoIngestRun",
95809
- body,
95810
- options
95811
- }));
95812
- } catch (error$1) {
95813
- return normalizeApiError(error$1, "Failed to run GSC ingestion");
95814
- }
95815
- }
95816
- async function getPriceOverride(apiClient, params, options) {
95817
- try {
95818
- return unwrapResponse(await apiClient({
95819
- endpoint: "adminGetPriceOverride",
95820
- params,
95821
- options
95822
- }));
95823
- } catch (error$1) {
95824
- return normalizeApiError(error$1, "Failed to get price override");
95825
- }
95826
- }
95827
- async function upsertPriceOverride(apiClient, body, options) {
95828
- try {
95829
- return unwrapResponse(await apiClient({
95830
- endpoint: "adminUpsertPriceOverride",
95831
- body,
95832
- options
95833
- }));
95834
- } catch (error$1) {
95835
- return normalizeApiError(error$1, "Failed to set custom price");
95836
- }
95837
- }
95838
- async function deletePriceOverride(apiClient, body, options) {
95839
- try {
95840
- return unwrapResponse(await apiClient({
95841
- endpoint: "adminDeletePriceOverride",
95842
- body,
95843
- options
95844
- }));
95845
- } catch (error$1) {
95846
- return normalizeApiError(error$1, "Failed to clear custom price");
95847
- }
95848
- }
95849
-
95850
96115
  //#endregion
95851
96116
  //#region ../api/src/auth.ts
95852
96117
  function extractErrorMessage(error$1, fallback) {