riverbankcms 0.24.0 → 0.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
- import { $ as createFormRef, $n as parseSafeDownloadFilename, $r as surfaceForegroundValue, An as mediaSchema, Ar as resolveSurface, At as generateMobileOverlayBackdropFilterFix, Br as mapDrawingStyle, Bt as getComponentShadowVar, C as sortRecord, Cn as isExplicitRectCrop, Cr as offeringsPreviewCompositionTreatmentValues, Ct as requireCuratedSiteStyle, D as mapEventCommandContent, Dn as getDirectImageUrlForSiteScopedPath, Dr as visibleHeadingDecorationFamilyValues, Dt as parseGradientPresetId, En as getDirectImageUrlForRelativePath, Er as toNonEmptyReadonlyArray, Et as getGradientPreset, F as pageIdentifierForBlockCommand, Fn as mediaTypeDiscriminants, Fr as backgroundColorStyle, Ft as BREAKPOINT_SM, G as ianaTimezoneSchema, Gn as getMimeType, Gr as resolveTokenOrCssColorValue, Gt as themeButtonSizeClassName, H as bookingPaymentTermsSchema, Hn as deriveVideoSlotPolicy, Hr as isCssColorLiteral, Ht as generateDefaultButtonSystem, I as pageIdentifierForCommand, In as mediaIdentifierSchema, Ir as borderColorStyle, It as BREAKPOINT_XL, J as createCommandRef, Jn as parseRelativeStoragePath, Jr as surfaceToneFromForegroundToken, K as createBlockRef, Kn as asRecord, Kr as PUBLIC_BUTTON_ROLES, Kt as themeButtonVariantClassNames, L as pagePathForCommand, Ln as buildMediaIdentifierFromFilename, Lr as mergeStyles, Lt as MQ_MD_DOWN, M as blockIdentifierForCommand, Mn as runtimeMediaSchema, Mr as surfaceDecorationColors, Mt as renderHeaderPaintTargetRules, N as blockOrderIdentifiersForCommand, Nn as buildRenderableMediaAssetIndex, Nr as resolveSurfaceForeground, Nt as BREAKPOINT_LG, On as getImageUrl, Or as parseResolvedSurface, Ot as themeSchema, P as entryIdentifierForCommand, Pn as resolveManagedMediaReference, Pr as TokenResolver, Pt as BREAKPOINT_MD, Q as createFooterRef, Qn as managementMediaLibraryUploadLimitForMimeType, Qr as surfaceForegroundStyle, R as hasConfiguredBookingVertical, Rn as parseCanonicalMediaIdentifier, Rr as rgbColorValue, Rt as headerVariantValues, S as venueManagementFields, Sn as normalizeWidthCandidates, Sr as makeBoundaryId, St as deriveSiteStyleBlockPolicy, Tn as resolveMediaTransformForAspect, Tr as tileTreatmentValues, Tt as gradientToCss, U as require_jsx_runtime, Un as resolveVideoSelectionIntentForMediaField, Ur as resolveOnColorForThemeToken, Ut as parseThemeButtonVariantId, V as bookingPaymentCollectionOptionSchema, Vr as opaqueSurfaceDeclarations, Vt as ICON_CONFIG, W as require_react, Wr as resolveThemeColorReferenceValue, Wt as themeButtonExtraClassesWithTrailingIcon, X as createEventCategoryRef, Xr as surfaceForegroundDeclarations, Xt as buildTextContrastShadow, Y as createContentEntryRef, Yn as FILE_SIZE_LIMITS, Yr as defaultThemeTokens, Yt as footerForegroundCandidates, Z as createEventSeriesRef, Zn as classifyKnownMimeType, Zr as surfaceForegroundInputFromResolved, Zt as generateNavLinkCSS, _n as summarizePortableMediaReferences, _r as eventListTreatmentValues, _t as arrangementManifestFromVariants, ai as __toESM, an as deriveSectionGround, ar as resolveEffectiveKnobs, b as isEventVisibility, bn as looksLikeUuid, br as headingDecorationColorTokenValues, bt as resolveModeArrangement, c as customLinkSchema$1, cn as resolveSectionBackground, ct as headerLeafTextColor, d as internalLinkSchema, dn as boxBackgroundOverlaySchema, dt as mergeHeaderNavTypographyPreference, ei as expandPalette, er as renderCssDeclarations, et as createNavigationRef, f as internalResolvedLinkSchema, fn as boxBackgroundSchema, fr as asSiteStyleId, ft as readHeaderNavFontSizePreference, g as linkSchema, gn as collectPortableMediaReferencesFromContent, gr as defineNoBlockDesignCapability, gt as resolveLookSlotSurfaces, h as isResolvedInternalLinkEntityType, hn as stripStaleTransitionStyleGroup, hr as defineFrameCapability, ht as resolveItemSurface, ii as __commonJSMin, in as sectionFactsForContent, ir as defineBlockDesignMetadata, it as refSlug, j as eventManagementTiming, jn as persistableMediaSchema, jr as serializeSurfaceTree, jt as getHeaderPaintTargets, kn as isSiteScopedDirectImageStoragePath, kr as parseSurfaceTree, kt as generateHeaderScrollTreatmentStyles, l as entryLinkSchema$1, ln as resolveSectionPhotoPlacement, lr as asDesignBlockId, lt as transparentHeaderForegroundInput, mn as siteChromeBackgroundOverrideOwner, mr as defineBlockDesignCapability, mt as arrangementSlotNames, ni as parseThemeColorToken, nn as boundaryLayout, nr as cardVariantRoleValues, o as classifySdkEventBookingOffer, on as heroPhotoPaintsGround, or as cardListFamilyBlocks, ot as effectiveHeaderNavLinkStyle, p as internalRouteOnlyLinkSchema, pn as runtimeBoxBackgroundSchema, pr as assertNever$11, pt as arrangementLookHooks, q as createBlocksRef, qr as selectLogoVariant, qt as parseThemeForPersistence, ri as parseBlockColorToken, rn as composeBoundary, rr as normalizeCardRole, rt as createVenueRef, s as RESOLVED_INTERNAL_LINK_ENTITY_TYPES, sn as parseCanonicalRuntimeBackground, sr as cardListKnobBlocks, st as headerForegroundCandidates, t as classifySdkEventTiming, ti as getTextColorForBackground, tn as headerRootPaint, tr as cardRoleSchema, tt as createPageRef, u as externalLinkSchema$1, un as sectionForegroundBackground, ur as asLayoutVariantKey, ut as readOpeningForegroundProjection, v as pageLinkSchema$1, vn as walkAndCollectImageAttrs, vr as eyebrowTreatmentValues, vt as readStoredMode, w as stableStringify, wn as parseAspectRatioValue, wr as testimonialsCompositionTreatmentValues, wt as compiledRuntimeStyleFieldNames, xn as rotateNormalizedPoint, xr as introCompositionTreatmentValues, xt as resolvePublishedLook, yn as deleteEnvSpecificKeys, yr as featureCardCompositionTreatmentValues, yt as resolveEffectiveArrangement, z as eventCommandScheduleSchema, zn as parseMediaIdentifier, zr as textColorStyle, zt as getComponentBorderWidthPx } from "../sdk-event-upsert-DmNSeHgP.mjs";
3
- import { $ as selectCategoryView, $t as parseNonNegativeCents, A as DEFAULT_MAILING_LIST_SUCCESS_MESSAGE, At as clampConfiguredAmount, B as parseWeeklyOpeningHours, Bt as formatBookingPriceDisplay, C as parseManagementKey, Ct as toUtcIsoDateTimeString, D as parseMailingListSignedSourceToken, Dt as isSettleableFlexibleBalanceContractStatus, E as parseMailingListContentVersionId, En as unsafeAsDemoCapability, Et as isLiveOrderInstalmentPlanStatus, F as DEFAULT_MAILING_LIST_TARGETING, Ft as splitAmountWithRemainderInFirst, G as locationValueSchema, Gt as publicEventPricingOptions, H as decideLocationSave, Ht as isPublicEventPricingOptionDisplayable, I as planMailingListChoicePresentation, In as unsafeAsPassId, It as resolveFlexibleBalanceDueAt, J as projectPublicLocation, Jt as resolvePricingOptionsPriceDisplay, K as normalizeLocationAddressText, Kt as publicEventPricingType, L as isCanonicalRichTextDoc, Ln as unsafeAsPositiveByteCount, Lt as resolveFlexibleBalanceInitialPaymentCents, M as parseFooterCompositionV1, Mt as getBookingInstalmentPlanIntervalCount, Nn as unsafeAsMediaAssetId, Nt as getBookingInstalmentProtectedDepositAmountCents, O as parseMailingListRuntimeContext, Ot as isSettleableOrderInstalmentPlanStatus, P as parseMailingListPlacementTargeting, Pn as unsafeAsOccurrenceId, Pt as omitZeroAmountFutureRows, Q as mapDrawingSchema, Qt as isNonNegativeWholeCents$1, R as formatOpeningHoursRows, Rt as deriveTotalTicketQuantity, S as exposeSecret, St as toScheduledBookingDateTime, T as parseMailingListBlockId, Tt as validateBookingPaymentOptionKinds, Ut as publicEventPricingCurrency, V as assertAllowedPublicUrl, Vt as formatEventPricing, W as locationMapLinks, Wt as publicEventPricingDisplay, X as toLocationCoordinates, Xn as err, Y as publicLocationSchema$1, Yt as fromArray, Zn as ok, Zt as mapReadonlyNonEmptyArray, _ as nextLiveRunSessionStartMs, _n as parseRetiredCourseId, _t as parseLocalScheduleTime, an as formatCurrencyAmount, at as formatTimeRange, b as resolveWholeSeriesRunLifecycle, bn as parseUserId, bt as resolveBookingTimeZoneId, cn as formatDurationUnitLabel, ct as buildBookingUtcDateWindow, d as EVENT_PRESET_VALUES, dn as parseDatedOfferingCapacityHoldAuditRef, dt as formatLocalScheduleTime, en as parsePositiveCents, et as formatDate, fn as parseDatedOfferingCapacityHoldId, ft as getBookingLocalDateKey, g as CANCELLED_SESSION_STATUS, gt as parseBookingLocalDate, hn as parseMembershipId, i as NAVIGATION_LOCATIONS, in as unsafeAsPositiveCents, it as formatTime$1, j as parseMailingListProviderScope, jt as getBookingInstalmentDepositRefundability, k as assessMailingListTargeting, kn as unsafeAsEventInstanceId, kt as addIntervalPreservingMonthAnchor, l as resolveSiteVerticalBookingConfig, ln as parseApiKeyId, lt as compareLocalScheduleDates, m as WHOLE_SERIES_EVENT_PRESET_VALUES, mt as getLocalScheduleTime, nn as toNonNegativeCents, nt as formatDateTime, on as parseCurrencyCode, ot as inferSiteDateLocale, p as SURFACE_EVENT_PRESET_VALUES, pn as parseEventSeriesId, pt as getLocalScheduleDate, q as parseLocationValue, qt as resolveExactOrFreePriceDisplay, r as EVENT_PRESET_VOCABULARY, rn as unsafeAsNonNegativeCents, rt as formatDateTimeRange, sn as assertNever, st as resolveBookingDisplayContext, tn as toCents, tt as formatDateRange, un as parseCustomerId, ut as formatLocalScheduleDate, v as orderedLiveRunSessions, vn as parseSiteId, vt as parseUtcIsoDateTimeString, w as slugify, wn as unsafeAsCheckoutLineId, x as createSecret, xt as toBookingTimeZone, y as resolveWholeSeriesBookingPhase, yn as parseSiteTermsVersionId, yt as resolveBookingBusinessTimeZone, zn as unsafeAsPricingOptionId, zt as parseEventPageSurfaceSubject } from "../src-B03aw4Tv.mjs";
4
- import { $ as normalizeMediaValueToIdentifierOnly, $t as bindRequestTimeout, A as formatDiffDetail, An as transportSuggestion, At as navigationIdentity, B as buildFieldChanges, Bn as sdkEventScheduleSchema, Bt as preparePushConfigTarget, C as reportFromOutcomes, Cn as parseEnvironmentSelection, Ct as fileExists, D as normalizeRemoteHomepageReference, Dn as withRiverbankEnv, Dt as writeJsonFileAtomic, E as createEmptySyncResult, En as requireEnvironmentWriteAuthorization, Et as writeJsonFile, F as calculatePullDiff, Fn as isLocalConfigured, Ft as navigationCommandItemToManagementInput, G as syncLocalMediaForPull, Gt as APPOINTMENT_SERVICE_VISIBILITY_VALUES, H as formatFieldPath, Hn as linkPayloadSchema, Ht as extractApiErrorMessage, I as buildJsonDiff, In as isRemoteConfigured, It as normalizeNavigationConfigItemForCommand, J as admitBinaryWriteDestination, Jt as ApiEnvelopeError, K as applyLocalMediaPush, Kt as ApiRequestError, L as hasPageOperations, Ln as loadSdkEnvironment, Lt as applyPushConfigPlan, M as hasPendingChanges, Mt as convertPulledFooterToLocal, N as findChangedFieldsWithValues, Nn as getEnvPrefix, Nt as convertPulledNavigationToLocal, O as calculateDiff, On as ErrorCodes, Ot as isMediaValue, P as formatHumanDiff, Pn as getEnvironmentDebugInfo, Pt as convertPulledPagesToLocal, Q as normalizeMediaIdentifierInput, Qt as mapEnvironmentExecutionOutcomesJson, R as pageMetadataForUpsert, Rn as createManagementClient, Rt as createPushConfigCommand, S as planCliCommandBatchForBindings, Sn as executeEnvironmentPlan, St as ensureDir, T as executeResidualSettingsSyncPlan, Tn as planEnvironmentWriteAuthorization, Tt as readJsonFile, U as revalidateLocalMediaPushPlan, Un as portablePageDesignSchema, Ut as normalizeApiError, V as formatFieldChange, Vn as sdkSettingsUpdateSchema, Vt as revalidatePushConfigPlan, Wn as sdkConfiguredBookingVerticalConfigSchema, Wt as isRecord$2, X as writeBinaryFileAtomic, Xt as deriveCmsApiUrlFromDashboardUrl, Y as readStableBinaryFile, Yt as unwrapResponse, Z as sha256, Zt as API_ENDPOINTS, _ as commandExecutionToReport, _n as runWithInvocation, _t as metadataFilePath, a as executeEntryCommandPlanAsReport, an as createOutputForCommand, at as readEntries, b as executeCompiledCliCommandPlanAsReport, bn as withErrorHandling, bt as writeMetadataFile, c as titleFromEntryData, cn as getOutputContext, ct as readEventsMeta, d as unsafeAsCliEntryIdentifier, dn as managementClientConfigFor, dt as readNavigationMeta, en as confirmAction, et as walkLocalContentMedia, f as unsafeAsCliFormSlug, fn as mapEntryForOutput, ft as readPagesMeta, g as commandCompileFailureToReport, gn as resolveCommandPath, gt as ensureMetadataDir, h as mutationCounterForEffect, hn as parsePaginationOptions, ht as writeMediaManifest, i as entrySiteCommandTypes, in as createListCommand, it as findLegacyEntryFiles, j as formatDiffSummary, jn as CliExit, jt as navigationIdentityMap, k as calculateFooterDiff, kn as formatError, kt as duplicateNavigationIdentityMessage, l as unsafeAsCliBlockIdentifier, ln as getOutputOnlyContext, lt as readFooterMeta, m as commandReportToSyncResult, mn as parseJsonData, mt as readVenuesMeta, n as entryCommandCompileErrorToReport, nn as createCommandContext, nt as downloadMedia, o as executeEntryCommandPlanAsSyncResult, on as currentInvocationEnvelope, ot as readAllMeta, p as unsafeAsCliPageIdentifier, pn as parseJsonArray, pt as readSettingsMeta, q as prepareLocalMediaForPush, qt as createBearerAPIClient, r as entryCommandReportToSyncResult, rn as createGetCommand, rt as extractMediaIdentifiers, s as syncResultForEntryCommandCompileError, sn as formatDateShort, st as readEventCategoriesMeta, t as compileEntryPushCommands, tn as createClientForEnv, tt as buildStorageUrl, u as unsafeAsCliContentTypeKey, un as handleCommandError, ut as readFormsMeta, v as commandReportHasFailures, vn as withCommandContext, vt as metadataTargetFromEnvironment, w as mergeManySyncResults, wn as planEnvironmentExecution, wt as listFiles, x as formatManagementError, xn as withOutputOnlyErrorHandling, xt as writeMetadataRecordMap, y as executeCliCommandPlan, yn as withConfirmation, yt as readMetadataFile, zn as ManagementApiError, zt as loadPushConfigTarget } from "../entryCommands-C0xbLW5L.mjs";
5
- import { r as CLI_VERSION, t as loadConfigFile } from "../load-config-h2Ri_tDO.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-C-cDv9vR.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-Dyv1rMTT.mjs";
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";
8
8
  import { config } from "dotenv";
9
9
  import { Command, CommanderError } from "commander";
10
10
  import * as fs$2 from "fs/promises";
@@ -7601,11 +7601,14 @@ const manifestSchema = z.object({
7601
7601
  }).optional()
7602
7602
  }).optional(),
7603
7603
  promotedFields: z.array(z.string().min(1)).optional(),
7604
+ arrangementOwnedFieldIds: z.array(z.string().min(1)).readonly().optional(),
7604
7605
  variantMeaning: z.discriminatedUnion("kind", [z.object({
7605
7606
  kind: z.literal("arrangement"),
7606
7607
  lookOnlyKeys: z.array(z.string().min(1)).readonly().optional()
7607
7608
  }), z.object({
7608
7609
  kind: z.literal("mode"),
7610
+ modes: z.array(z.enum(arrangementModes)).min(1).readonly(),
7611
+ defaultMode: z.enum(arrangementModes),
7609
7612
  arrangementField: z.string().min(1),
7610
7613
  keys: z.array(z.string().min(1)).min(1).readonly(),
7611
7614
  defaultKey: z.string().min(1),
@@ -9348,7 +9351,7 @@ const ALLOWED_URL_PROTOCOLS = ["http:", "https:"];
9348
9351
  const DATE_PATTERN = /^(?<year>[1-9]\d{3})-(?<month>\d{2})-(?<day>\d{2})$/;
9349
9352
  const TIME_PATTERN = /^(?<hours>[01]\d|2[0-3]):(?<minutes>[0-5]\d)$/;
9350
9353
  const DATETIME_PATTERN = /^(?<date>[1-9]\d{3}-\d{2}-\d{2})T(?<time>(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d)(?:\.\d+)?(?<offset>Z|[+-](?:[01]\d|2[0-3]):[0-5]\d)$/;
9351
- function assertNever$12(value) {
9354
+ function assertNever$11(value) {
9352
9355
  throw new Error(`Unhandled field validation variant: ${JSON.stringify(value)}`);
9353
9356
  }
9354
9357
  function validationContext(options = {}) {
@@ -9415,7 +9418,7 @@ function fieldIssueToMessage(issue$1) {
9415
9418
  case "invalidPhone":
9416
9419
  case "invalidTime":
9417
9420
  case "invalidUrl": return simpleIssueMessages[issue$1.kind];
9418
- default: return assertNever$12(issue$1);
9421
+ default: return assertNever$11(issue$1);
9419
9422
  }
9420
9423
  }
9421
9424
  function pluralize(label, count) {
@@ -9544,7 +9547,7 @@ function deriveFieldValidationPlan(field, path$3 = [field.id]) {
9544
9547
  case "presetOrCustom":
9545
9548
  case "contentTypeSelect":
9546
9549
  case "entryPicker": return makePlan("passthrough", "unknown", field, path$3, false, []);
9547
- default: return assertNever$12(field);
9550
+ default: return assertNever$11(field);
9548
9551
  }
9549
9552
  }
9550
9553
  function deriveRepeaterFieldValidationPlan(field, path$3) {
@@ -9653,7 +9656,7 @@ function resolveSelectConstraintSource(field) {
9653
9656
  kind: "runtime",
9654
9657
  source: source.kind
9655
9658
  };
9656
- default: return assertNever$12(source);
9659
+ default: return assertNever$11(source);
9657
9660
  }
9658
9661
  }
9659
9662
  function fieldPlanToNativeInputProps(plan) {
@@ -9705,7 +9708,7 @@ function fieldPlanToNativeInputProps(plan) {
9705
9708
  case "linkObject":
9706
9709
  case "referenceText":
9707
9710
  case "blockIconValue": break;
9708
- default: assertNever$12(constraint);
9711
+ default: assertNever$11(constraint);
9709
9712
  }
9710
9713
  }
9711
9714
  return props$1;
@@ -9713,32 +9716,6 @@ function fieldPlanToNativeInputProps(plan) {
9713
9716
  function normalizeFieldInput(plan, value, options = {}) {
9714
9717
  return normalizeFieldValue(plan, value, validationContext(options));
9715
9718
  }
9716
- /** Drop obsolete presentation containers only when reading persisted content.
9717
- * Flat data remains authoritative; unknown variants and legitimate groups survive.
9718
- */
9719
- function normalizeLegacyStoredGroupContainers(plans, content) {
9720
- if (!isPlainObject$6(content)) return content;
9721
- const planMap = new Map(plans.map((plan) => [plan.fieldId, plan]));
9722
- const entries = Object.entries(content).map(([key, value]) => {
9723
- const plan = planMap.get(key);
9724
- return [key, plan ? normalizeLegacyStoredField(plan, value) : value];
9725
- });
9726
- return entries.every(([key, value]) => value === content[key]) ? content : Object.fromEntries(entries);
9727
- }
9728
- function normalizeLegacyStoredField(plan, value) {
9729
- if (plan.kind === "group") {
9730
- return normalizeLegacyStoredGroupContainers(selectedGroupChildPlans(plan, value), value);
9731
- }
9732
- if (plan.kind !== "repeater" || !isUnknownArray$2(value)) return value;
9733
- const items = value.map((item) => {
9734
- if (!isPlainObject$6(item)) return item;
9735
- const selection = selectRepeaterItemPlan(plan, item);
9736
- if (selection.kind !== "fields") return item;
9737
- const retained = selection.flattenedGroupIds.some((key) => Object.prototype.hasOwnProperty.call(item, key)) ? Object.fromEntries(Object.entries(item).filter(([key]) => !selection.flattenedGroupIds.includes(key))) : item;
9738
- return normalizeLegacyStoredGroupContainers(selection.fields, retained);
9739
- });
9740
- return items.every((item, index) => item === value[index]) ? value : items;
9741
- }
9742
9719
  function normalizeStoredContentValues(plans, content, options = {}) {
9743
9720
  if (!content || typeof content !== "object" || Array.isArray(content)) {
9744
9721
  return {};
@@ -9780,7 +9757,7 @@ function normalizeStoredFieldValueWithContext(plan, value, ctx) {
9780
9757
  case "link":
9781
9758
  case "select":
9782
9759
  case "passthrough": return normalizeFieldValue(plan, value, ctx);
9783
- default: return assertNever$12(plan);
9760
+ default: return assertNever$11(plan);
9784
9761
  }
9785
9762
  }
9786
9763
  function normalizeStoredObjectChildren(children, value, ctx) {
@@ -9831,7 +9808,7 @@ function normalizeFieldValue(plan, value, ctx) {
9831
9808
  case "select":
9832
9809
  case "passthrough": return value;
9833
9810
  case "media": return value;
9834
- default: return assertNever$12(plan);
9811
+ default: return assertNever$11(plan);
9835
9812
  }
9836
9813
  }
9837
9814
  function normalizeObjectChildren(children, value, ctx) {
@@ -9895,7 +9872,7 @@ function validateNormalizedFieldValue(plan, value, ctx) {
9895
9872
  case "repeater": return validateRepeaterPlan(plan, value, ctx);
9896
9873
  case "group": return validateGroupPlan(plan, value, ctx);
9897
9874
  case "passthrough": return [];
9898
- default: return assertNever$12(plan);
9875
+ default: return assertNever$11(plan);
9899
9876
  }
9900
9877
  }
9901
9878
  function validateMediaPlan(plan, value, ctx) {
@@ -10000,7 +9977,7 @@ function validateNumberConstraint(plan, constraint, value) {
10000
9977
  case "numberType": return [];
10001
9978
  case "numberMin": return value < constraint.minimum ? [issue(plan, "tooSmall", { minimum: constraint.minimum })] : [];
10002
9979
  case "numberMax": return value > constraint.maximum ? [issue(plan, "tooLarge", { maximum: constraint.maximum })] : [];
10003
- default: return assertNever$12(constraint);
9980
+ default: return assertNever$11(constraint);
10004
9981
  }
10005
9982
  }
10006
9983
  function validateSelectPlan(plan, value) {
@@ -10022,7 +9999,7 @@ function validateRepeaterPlan(plan, value, ctx) {
10022
9999
  maximum: constraint.maximum,
10023
10000
  itemLabel: "item"
10024
10001
  })] : [];
10025
- default: return assertNever$12(constraint);
10002
+ default: return assertNever$11(constraint);
10026
10003
  }
10027
10004
  });
10028
10005
  return [...constraintIssues, ...value.flatMap((item, index) => validateRepeaterItem(plan, item, index, ctx))];
@@ -10154,7 +10131,7 @@ function rebaseFieldPlanPath(plan, fromPrefix, toPrefix) {
10154
10131
  ...plan,
10155
10132
  path: path$3
10156
10133
  };
10157
- default: return assertNever$12(plan);
10134
+ default: return assertNever$11(plan);
10158
10135
  }
10159
10136
  }
10160
10137
  function validateInlineTextPlan(plan, value, ctx) {
@@ -10207,7 +10184,7 @@ function fieldPlanToObjectPropertyZod(plan, options = {}, layoutGridCoordinates
10207
10184
  switch (presence.kind) {
10208
10185
  case "required": return schema;
10209
10186
  case "optional": return schema.optional();
10210
- default: return assertNever$12(presence);
10187
+ default: return assertNever$11(presence);
10211
10188
  }
10212
10189
  }
10213
10190
  /** Validate stored or runtime fields without applying editor/write normalization. */
@@ -10297,7 +10274,7 @@ function findNestedFieldValidationPlan(plan, path$3) {
10297
10274
  case "link":
10298
10275
  case "select":
10299
10276
  case "passthrough": return null;
10300
- default: return assertNever$12(plan);
10277
+ default: return assertNever$11(plan);
10301
10278
  }
10302
10279
  }
10303
10280
  function fieldValidationDescriptor(plan) {
@@ -10535,33 +10512,36 @@ function compileManifestContentContract(manifestOrFields, options = {}) {
10535
10512
  const plans = derivePlansFromManifestOrFields(manifestOrFields);
10536
10513
  const strictOptions = { allowNull: false };
10537
10514
  const strictStoredSchema = deriveStrictContentZodFromPlans(plans);
10538
- return Object.freeze({ [compiledManifestContentContract]: Object.freeze({
10539
- plans,
10540
- strictStoredSchema,
10541
- renderSourceSchema: deriveStrictContentZodFromPlans(plans, "render-source"),
10542
- writeSchema: deriveNormalizedContentZodFromPlans(plans, strictOptions, normalizeManifestContentForWrite).superRefine((value, ctx) => {
10543
- if (options.unknownFields !== "reject") return;
10544
- unknownManifestFieldPaths(plans, value).forEach((path$3) => {
10545
- ctx.addIssue({
10546
- code: "custom",
10547
- path: path$3,
10548
- message: `Unknown content field: ${path$3.join(".")}`
10515
+ return Object.freeze({
10516
+ fields: Array.isArray(manifestOrFields) ? manifestOrFields : manifestOrFields.fields,
10517
+ [compiledManifestContentContract]: Object.freeze({
10518
+ plans,
10519
+ strictStoredSchema,
10520
+ renderSourceSchema: deriveStrictContentZodFromPlans(plans, "render-source"),
10521
+ writeSchema: deriveNormalizedContentZodFromPlans(plans, strictOptions, normalizeManifestContentForWrite).superRefine((value, ctx) => {
10522
+ if (options.unknownFields !== "reject") return;
10523
+ unknownManifestFieldPaths(plans, value).forEach((path$3) => {
10524
+ ctx.addIssue({
10525
+ code: "custom",
10526
+ path: path$3,
10527
+ message: `Unknown content field: ${path$3.join(".")}`
10528
+ });
10549
10529
  });
10550
- });
10551
- }).transform((value) => canonicalizeObjectForWrite(plans, value)),
10552
- draftSchema: deriveNormalizedContentZodFromPlans(plans, {
10553
- allowNull: true,
10554
- allowIncomplete: true,
10555
- mode: "draft"
10556
- }, normalizeStoredContentValues),
10557
- renderDraftSchema: deriveNormalizedContentZodFromPlans(plans, {
10558
- allowNull: true,
10559
- allowIncomplete: true,
10560
- mode: "draft"
10561
- }, normalizeStoredContentValues, false),
10562
- renderSchema: deriveStrictContentZodFromPlans(plans, "render"),
10563
- findNonPortableMediaPaths: (content) => findNonPortableMediaPaths(plans, content)
10564
- }) });
10530
+ }).transform((value) => canonicalizeObjectForWrite(plans, value)),
10531
+ draftSchema: deriveNormalizedContentZodFromPlans(plans, {
10532
+ allowNull: true,
10533
+ allowIncomplete: true,
10534
+ mode: "draft"
10535
+ }, normalizeStoredContentValues),
10536
+ renderDraftSchema: deriveNormalizedContentZodFromPlans(plans, {
10537
+ allowNull: true,
10538
+ allowIncomplete: true,
10539
+ mode: "draft"
10540
+ }, normalizeStoredContentValues, false),
10541
+ renderSchema: deriveStrictContentZodFromPlans(plans, "render"),
10542
+ findNonPortableMediaPaths: (content) => findNonPortableMediaPaths(plans, content)
10543
+ })
10544
+ });
10565
10545
  }
10566
10546
  function unknownManifestFieldPaths(plans, value, parent = [], discriminator) {
10567
10547
  if (!isPlainRecord$1(value)) return [];
@@ -10597,8 +10577,7 @@ function findNonPortableManifestMediaPaths(contract, content) {
10597
10577
  /** Strictly admits already-persisted content without repairing it. */
10598
10578
  function admitStoredManifestContent(contract, content) {
10599
10579
  const state = contract[compiledManifestContentContract];
10600
- const normalized = normalizeLegacyStoredGroupContainers(state.plans, content);
10601
- const nonPortablePaths = state.findNonPortableMediaPaths(normalized);
10580
+ const nonPortablePaths = state.findNonPortableMediaPaths(content);
10602
10581
  if (nonPortablePaths.length > 0) {
10603
10582
  return {
10604
10583
  ok: false,
@@ -10608,20 +10587,23 @@ function admitStoredManifestContent(contract, content) {
10608
10587
  }
10609
10588
  };
10610
10589
  }
10611
- const parsed = state.strictStoredSchema.safeParse(normalized);
10590
+ const parsed = state.strictStoredSchema.safeParse(content);
10612
10591
  return parsed.success ? {
10613
10592
  ok: true,
10614
- value: normalized
10593
+ value: content
10615
10594
  } : {
10616
10595
  ok: false,
10617
10596
  error: zodAdmissionError(parsed.error)
10618
10597
  };
10619
10598
  }
10599
+ /** Presentation recovery preserves authored payloads and does not admit them for a write. */
10600
+ function projectStoredManifestContentForRendering(contract, content) {
10601
+ return projectLayoutGridPlansForRendering(contract[compiledManifestContentContract].plans, content);
10602
+ }
10620
10603
  /** Public reads alone may project invalid grid geometry. All other stored-shape and portability checks remain strict. */
10621
10604
  function admitStoredManifestContentForRendering(contract, content) {
10622
10605
  const state = contract[compiledManifestContentContract];
10623
- const normalized = normalizeLegacyStoredGroupContainers(state.plans, content);
10624
- const paths = state.findNonPortableMediaPaths(normalized);
10606
+ const paths = state.findNonPortableMediaPaths(content);
10625
10607
  if (paths.length > 0) return {
10626
10608
  ok: false,
10627
10609
  error: {
@@ -10629,7 +10611,7 @@ function admitStoredManifestContentForRendering(contract, content) {
10629
10611
  paths
10630
10612
  }
10631
10613
  };
10632
- const projected = projectLayoutGridPlansForRendering(state.plans, normalized);
10614
+ const projected = projectStoredManifestContentForRendering(contract, content);
10633
10615
  const parsed = state.renderSourceSchema.safeParse(projected);
10634
10616
  return parsed.success ? {
10635
10617
  ok: true,
@@ -10726,7 +10708,7 @@ function validateManifestWriteCandidate(contract, data) {
10726
10708
  */
10727
10709
  function deriveRenderableManifestContent(contract, stored, project) {
10728
10710
  const state = contract[compiledManifestContentContract];
10729
- const projected = projectLayoutGridPlansForRendering(state.plans, normalizeLegacyStoredGroupContainers(state.plans, project(stored)));
10711
+ const projected = projectLayoutGridPlansForRendering(state.plans, project(stored));
10730
10712
  const parsed = state.renderSchema.safeParse(projected);
10731
10713
  return parsed.success ? {
10732
10714
  ok: true,
@@ -10743,7 +10725,7 @@ function deriveRenderableManifestContent(contract, stored, project) {
10743
10725
  */
10744
10726
  function admitTransportedRenderableManifestContent(contract, content) {
10745
10727
  const state = contract[compiledManifestContentContract];
10746
- const projected = projectLayoutGridPlansForRendering(state.plans, content);
10728
+ const projected = projectStoredManifestContentForRendering(contract, content);
10747
10729
  const parsed = state.renderSchema.safeParse(projected);
10748
10730
  return parsed.success ? {
10749
10731
  ok: true,
@@ -13814,13 +13796,14 @@ const FLOATING_BLUR = "blur(16px)";
13814
13796
  * Similar to button system - generates theme-scoped CSS using [data-theme-scope] selector
13815
13797
  */
13816
13798
  function generateHeaderCss(options) {
13817
- const { themeId, theme, responsiveMode = DEFAULT_THEME_RESPONSIVE_MODE } = options;
13799
+ const { themeId, theme, responsiveMode = DEFAULT_THEME_RESPONSIVE_MODE, solvedInks = "withhold" } = options;
13818
13800
  const tokens = new TokenResolver(theme);
13819
13801
  const header = theme.header;
13820
13802
  const cssChunks = [];
13821
13803
  const headerContrastTreatment = resolveHeaderContrastTreatment(header);
13822
13804
  const headerNavTextSize = resolveHeaderNavTextSize(header);
13823
- cssChunks.push(generateHeaderRootStyles(header, themeId, tokens));
13805
+ cssChunks.push(generateHeaderRootStyles(header, themeId, tokens, headerPaintInks(header, theme, solvedInks)));
13806
+ cssChunks.push(generateOpeningPhotoShade(header, themeId));
13824
13807
  cssChunks.push(generateMobileOverlayBackdropFilterFix(themeId, header.variant));
13825
13808
  cssChunks.push(generateHeaderLogoStyles({
13826
13809
  logo: header.logo,
@@ -13834,20 +13817,27 @@ function generateHeaderCss(options) {
13834
13817
  }));
13835
13818
  cssChunks.push(generateLogoTextBehaviorStyles(header.logoText, themeId));
13836
13819
  cssChunks.push(generateHeaderNavLinkStyles(header, themeId, tokens, theme, headerContrastTreatment, headerNavTextSize));
13837
- cssChunks.push(generateDropdownContainerStyles(header, themeId, tokens, theme));
13838
- cssChunks.push(generateDropdownLinkStyles(header, themeId, tokens, theme));
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));
13839
13824
  cssChunks.push(generateDropdownCaretStyles(themeId));
13840
13825
  cssChunks.push(generateDropdownTriggerOverrides(header, themeId));
13841
- cssChunks.push(generateMobilePanelStyles(header, themeId, tokens, theme));
13826
+ cssChunks.push(generateMobilePanelStyles(themeId, dropdown));
13842
13827
  if (header.variant === "floating" && header.container) {
13843
13828
  cssChunks.push(generateFloatingContainerStyles(header, themeId, tokens, responsiveMode));
13844
13829
  }
13845
- cssChunks.push(generateNavContainerStyles(header, themeId, tokens));
13830
+ cssChunks.push(generateNavContainerStyles(header, themeId, tokens, theme, solvedInks));
13846
13831
  cssChunks.push(generateHeaderCtaTreatmentStyles(header, themeId, tokens));
13847
13832
  cssChunks.push(generateCtaGapStyles(header, themeId));
13848
13833
  return cssChunks.filter(Boolean).join("\n\n");
13849
13834
  }
13850
13835
  const _testExports = { generateHeaderRootStyles };
13836
+ /** Scope shading to the actual opening under overlay chrome, including hidden-header pages. */
13837
+ function generateOpeningPhotoShade(header, themeId) {
13838
+ const shade = headerNeedsPhotoShade(header) ? "linear-gradient(to bottom, rgba(0,0,0,0.78) 0px, rgba(0,0,0,0.64) 110px, transparent 220px)" : "linear-gradient(transparent, transparent)";
13839
+ return `:where([data-theme-scope="${themeId}"]) [data-site-document-layout-mode="header-overlay"] :is([data-page-block-position="first"], [data-page-block-position="only"]) { --rb-opening-photo-shade: ${shade}; }`;
13840
+ }
13851
13841
  function resolveHeaderContrastTreatment(header) {
13852
13842
  if (header.navLinkStyle?.contrastTreatment) {
13853
13843
  return header.navLinkStyle.contrastTreatment;
@@ -13870,7 +13860,7 @@ function isDetachedFloatingHeaderShape(header) {
13870
13860
  /**
13871
13861
  * Generate root header container styles
13872
13862
  */
13873
- function generateHeaderRootStyles(header, themeId, tokens) {
13863
+ function generateHeaderRootStyles(header, themeId, tokens, inks) {
13874
13864
  const selector = `:where([data-theme-scope="${themeId}"]) .header-root`;
13875
13865
  const rules = [];
13876
13866
  const isContainedNav = headerRootPaint(header) === "contained-nav";
@@ -13882,7 +13872,11 @@ function generateHeaderRootStyles(header, themeId, tokens) {
13882
13872
  } : buildHeaderSurfaceRules(header, tokens);
13883
13873
  const floatingSurfaceBorder = header.variant === "floating";
13884
13874
  if (!floatingSurfaceBorder) rules.push(...surfaceRules.border);
13885
- const basePaintRules = floatingSurfaceBorder ? [...surfaceRules.base, ...surfaceRules.border] : surfaceRules.base;
13875
+ const basePaintRules = floatingSurfaceBorder ? [
13876
+ ...surfaceRules.base,
13877
+ ...surfaceRules.border,
13878
+ ...inks
13879
+ ] : [...surfaceRules.base, ...inks];
13886
13880
  const scrolledPaintRules = floatingSurfaceBorder ? surfaceRules.border : [];
13887
13881
  if (header.positioning === "sticky" || header.positioning === "fixed") {
13888
13882
  const shadowElevation = header.shadow?.elevation ?? "none";
@@ -13941,14 +13935,13 @@ function generateLogoTextBehaviorStyles(logoText, themeId) {
13941
13935
  /**
13942
13936
  * Generate dropdown menu container styles
13943
13937
  */
13944
- function generateDropdownContainerStyles(header, themeId, tokens, theme) {
13938
+ function generateDropdownContainerStyles(header, themeId, tokens, surface) {
13945
13939
  const selector = `:where([data-theme-scope="${themeId}"]) .nav-dropdown-menu`;
13946
13940
  const rules = [];
13947
13941
  const dropdownStyle = header.dropdownStyle;
13948
13942
  rules.push(...NAV_DROPDOWN_CONTAINER_RAIL_CSS_RULES);
13949
- const surface = resolveDropdownSurface(header, theme);
13950
- rules.push(`background-color: ${tokens.getColor(surface.backgroundToken)};`);
13951
- rules.push(...surface.declarations(tokens));
13943
+ rules.push(`background-color: ${surface.backgroundColor};`);
13944
+ rules.push(...surface.foregroundDeclarations);
13952
13945
  const borderToken = dropdownStyle?.borderColor;
13953
13946
  if (borderToken === null) {
13954
13947
  rules.push(`border: none;`);
@@ -13969,79 +13962,63 @@ function generateDropdownContainerStyles(header, themeId, tokens, theme) {
13969
13962
  };
13970
13963
  rules.push(`border-radius: ${radiusMap[borderRadius]};`);
13971
13964
  rules.push(`padding: 0.5rem 0;`);
13972
- return `\n${selector} {\n ${rules.join("\n ")}\n}\n`;
13973
- }
13974
- function generateDropdownLinkStyles(header, themeId, tokens, theme) {
13975
- const configuredDropdownStyle = header.dropdownStyle;
13976
- const textColorToken = resolveDropdownSurface(header, theme).textToken;
13977
- const hoverBgToken = configuredDropdownStyle?.hoverBackground ?? textColorToken;
13978
- const hoverEffects = {
13979
- hover: hoverBgToken === null ? [] : [{
13980
- effectId: "background-on-hover-alpha",
13981
- options: {
13982
- colorToken: hoverBgToken,
13983
- opacity: 12
13984
- }
13985
- }],
13986
- active: hoverBgToken === null ? [] : [{
13987
- effectId: "background-on-hover-alpha",
13988
- options: {
13989
- colorToken: hoverBgToken,
13990
- opacity: 18
13991
- }
13992
- }]
13993
- };
13994
- if (configuredDropdownStyle?.hoverTextColor) {
13995
- hoverEffects.hover?.push({
13996
- effectId: "text-color-change",
13997
- options: { hoverColorToken: configuredDropdownStyle.hoverTextColor }
13998
- });
13999
- hoverEffects.active?.push({
14000
- effectId: "text-color-change",
14001
- options: { hoverColorToken: configuredDropdownStyle.hoverTextColor }
14002
- });
14003
- }
14004
- const dropdownLinkStyle = {
13965
+ return `\n${selector} {\n ${rules.join("\n ")}\n}\n` + generateDropdownFrosting(selector, surface);
13966
+ }
13967
+ function dropdownLinkEffects(style, textToken, opacity) {
13968
+ const background = style?.hoverBackground === undefined ? textToken : style.hoverBackground;
13969
+ return [...background === null ? [] : [{
13970
+ effectId: "background-on-hover-alpha",
13971
+ options: {
13972
+ colorToken: background,
13973
+ opacity
13974
+ }
13975
+ }], ...style?.hoverTextColor ? [{
13976
+ effectId: "text-color-change",
13977
+ options: { hoverColorToken: style.hoverTextColor }
13978
+ }] : []];
13979
+ }
13980
+ function dropdownNavLinkStyle(header, textToken) {
13981
+ const style = header.dropdownStyle;
13982
+ return {
14005
13983
  name: "Dropdown",
14006
13984
  typography: "body",
14007
- fontWeight: configuredDropdownStyle?.fontWeight ?? header.navWeight ?? "medium",
14008
- textTransform: configuredDropdownStyle?.textTransform ?? "none",
13985
+ fontWeight: style?.fontWeight ?? header.navWeight ?? "medium",
13986
+ textTransform: style?.textTransform ?? "none",
14009
13987
  italic: false,
14010
- colorToken: textColorToken,
13988
+ colorToken: textToken,
14011
13989
  padding: "compact",
14012
13990
  borderRadius: "sm",
14013
- effects: hoverEffects
13991
+ effects: {
13992
+ hover: dropdownLinkEffects(style, textToken, 12),
13993
+ active: dropdownLinkEffects(style, textToken, 18)
13994
+ }
14014
13995
  };
13996
+ }
13997
+ function dropdownTypographyRules(style) {
13998
+ const letterSpacing = style?.letterSpacing ?? "normal";
13999
+ const spacing = {
14000
+ normal: "0em",
14001
+ wide: "0.05em",
14002
+ wider: "0.1em"
14003
+ };
14004
+ const sizes = {
14005
+ xs: "0.75rem",
14006
+ sm: "0.875rem",
14007
+ base: "1rem",
14008
+ lg: "1.125rem"
14009
+ };
14010
+ return [...letterSpacing === "normal" ? [] : [`letter-spacing: ${spacing[letterSpacing]};`], `font-size: ${sizes[style?.textSize ?? "sm"]};`];
14011
+ }
14012
+ function generateDropdownLinkStyles(header, themeId, tokens, theme, surface) {
14015
14013
  const baseCSS = generateNavLinkCSS({
14016
14014
  themeId,
14017
14015
  tokens,
14018
14016
  theme,
14019
- style: dropdownLinkStyle,
14017
+ style: dropdownNavLinkStyle(header, surface.textToken),
14020
14018
  className: "nav-dropdown-link"
14021
14019
  });
14022
- const additionalRules = [];
14023
- const letterSpacing = configuredDropdownStyle?.letterSpacing ?? "normal";
14024
- if (letterSpacing !== "normal") {
14025
- const letterSpacingMap = {
14026
- normal: "0em",
14027
- wide: "0.05em",
14028
- wider: "0.1em"
14029
- };
14030
- additionalRules.push(`letter-spacing: ${letterSpacingMap[letterSpacing]};`);
14031
- }
14032
- const textSize = configuredDropdownStyle?.textSize ?? "sm";
14033
- const textSizeMap = {
14034
- xs: "0.75rem",
14035
- sm: "0.875rem",
14036
- base: "1rem",
14037
- lg: "1.125rem"
14038
- };
14039
- additionalRules.push(`font-size: ${textSizeMap[textSize]};`);
14040
- if (additionalRules.length > 0) {
14041
- const selector = `:where([data-theme-scope="${themeId}"]) .nav-dropdown-link`;
14042
- return baseCSS + `\n${selector} {\n ${additionalRules.join("\n ")}\n}\n`;
14043
- }
14044
- return baseCSS;
14020
+ const selector = `:where([data-theme-scope="${themeId}"]) .nav-dropdown-link`;
14021
+ return baseCSS + `\n${selector} {\n ${dropdownTypographyRules(header.dropdownStyle).join("\n ")}\n}\n`;
14045
14022
  }
14046
14023
  function generateDropdownCaretStyles(themeId) {
14047
14024
  const selector = `:where([data-theme-scope="${themeId}"]) .nav-caret`;
@@ -14072,43 +14049,76 @@ ${selector} {
14072
14049
  }
14073
14050
  `.trim();
14074
14051
  }
14075
- /**
14076
- * The dropdown menu and mobile panel share one surface: `dropdownStyle`'s
14077
- * background, with the text candidate (the dropdown's own colour, then the
14078
- * header's nav colour) validated against it through the surface contract. The
14079
- * nav colour is chosen for the header bar, which can be dark or transparent,
14080
- * so it only carries over when it is legible on the menu too.
14081
- */
14082
- function resolveDropdownSurface(header, theme) {
14052
+ /** Reuse the header's decided opening tone; unknown openings retain opaque paint. */
14053
+ function contextualDropdownHeader(header) {
14054
+ const style = header.dropdownStyle;
14055
+ 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
+ }
14064
+ };
14065
+ const dark = opening.backgroundTone === "dark";
14066
+ const textColor = dark ? "neutral-50" : "neutral-950";
14067
+ return {
14068
+ ...header,
14069
+ dropdownStyle: {
14070
+ ...style,
14071
+ background: dark ? "neutral-950" : "neutral-50",
14072
+ textColor,
14073
+ hoverBackground: textColor,
14074
+ borderColor: null
14075
+ }
14076
+ };
14077
+ }
14078
+ function dropdownTextCandidate(header) {
14079
+ return header.dropdownStyle?.textColor ?? ((header.navColor ?? header.textColor)?.trim() || "text");
14080
+ }
14081
+ function resolveDropdownSurface(header, theme, tokens, solvedInks) {
14083
14082
  const backgroundToken = header.dropdownStyle?.background ?? "surface";
14084
- const candidate = header.dropdownStyle?.textColor ?? ((header.navColor ?? header.textColor)?.trim() || "text");
14083
+ const candidate = dropdownTextCandidate(header);
14085
14084
  const foreground = resolveSurfaceForeground({
14086
14085
  type: "color",
14087
14086
  color: backgroundToken,
14088
14087
  textColor: candidate
14089
14088
  }, expandPalette(theme.palette));
14090
14089
  return {
14091
- backgroundToken,
14090
+ backgroundColor: tokens.getColor(backgroundToken),
14092
14091
  textToken: foreground.kind === "known" ? foreground.roles.text : candidate,
14093
- declarations: (tokens) => foreground.kind === "known" ? surfaceForegroundDeclarations(surfaceForegroundInputFromResolved(foreground, (token) => tokens.getColor(token))) : [`color: ${tokens.getColor(candidate)};`]
14092
+ foregroundDeclarations: [...foreground.kind === "known" ? surfaceForegroundDeclarations(surfaceForegroundInputFromResolved(foreground, (token) => tokens.getColor(token))) : [`color: ${tokens.getColor(candidate)};`], ...surfaceInkDeclarations(surfaceInkPublication(foreground, solvedInks))],
14093
+ treatment: header.dropdownStyle?.surfaceTreatment
14094
14094
  };
14095
14095
  }
14096
- /**
14097
- * Generate mobile navigation panel styles
14098
- * Uses the same dropdownStyle settings as the desktop dropdown menus
14099
- */
14100
- function generateMobilePanelStyles(header, themeId, tokens, theme) {
14096
+ /** Solid paint is the fallback. Blur is enhancement, never the readability mechanism. */
14097
+ function generateDropdownFrosting(selector, surface) {
14098
+ if (surface.treatment?.kind !== "frosted") return "";
14099
+ const blur = surface.treatment.blur === "sm" ? "8px" : "12px";
14100
+ return `
14101
+ @supports (background-color: color-mix(in srgb, white, transparent)) and ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
14102
+ ${selector} {
14103
+ background-color: color-mix(in srgb, ${surface.backgroundColor} ${surface.treatment.opacity * 100}%, transparent);
14104
+ backdrop-filter: blur(${blur});
14105
+ -webkit-backdrop-filter: blur(${blur});
14106
+ ${surface.treatment.opacity < 1 ? surfaceInkDeclarations({ kind: "reset" }).join("\n ") : ""}
14107
+ }
14108
+ }
14109
+ `;
14110
+ }
14111
+ /** Mobile shares the resolved opaque surface, never desktop translucency. */
14112
+ function generateMobilePanelStyles(themeId, surface) {
14101
14113
  const selector = `:where([data-theme-scope="${themeId}"]) .nav-mobile-panel`;
14102
14114
  const selfSelector = `:where(.nav-mobile-panel[data-theme-scope="${themeId}"])`;
14103
- const surface = resolveDropdownSurface(header, theme);
14104
- const rules = [`background-color: ${tokens.getColor(surface.backgroundToken)};`, ...surface.declarations(tokens)];
14105
- const body = renderCssDeclarations(rules);
14115
+ const body = renderCssDeclarations([`background-color: ${surface.backgroundColor};`, ...surface.foregroundDeclarations]);
14106
14116
  return `\n${selector} {\n ${body}\n}\n\n${selfSelector} {\n ${body}\n}\n`;
14107
14117
  }
14108
14118
  /**
14109
14119
  * Generate nav container styles (pill/glass)
14110
14120
  */
14111
- function generateNavContainerStyles(header, themeId, tokens) {
14121
+ function generateNavContainerStyles(header, themeId, tokens, theme, solvedInks) {
14112
14122
  const navContainer = header.navContainer;
14113
14123
  const navContainerType = navContainer?.type ?? "none";
14114
14124
  if (!navContainer || navContainerType === "none") return "";
@@ -14124,27 +14134,31 @@ function generateNavContainerStyles(header, themeId, tokens) {
14124
14134
  rules.push("align-self: flex-start;");
14125
14135
  }
14126
14136
  }
14127
- if (navContainerType === "glass") {
14128
- const opacity = resolveFloatingGlassOpacity(header, navContainer.opacity, .15);
14129
- const background = navContainer.tint ? buildTint(tokens.getColor(navContainer.tint), opacity) : buildRgbWhite(opacity);
14130
- rules.push(`background-color: ${background};`);
14131
- rules.push(`backdrop-filter: ${HEADER_BLUR};`);
14132
- rules.push(`-webkit-backdrop-filter: ${HEADER_BLUR};`);
14133
- rules.push("border: 1px solid rgba(255, 255, 255, 0.2);");
14134
- rules.push("box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);");
14135
- } else if (navContainerType === "pill") {
14136
- const opacity = clampOpacity(navContainer.opacity, .15);
14137
- if (navContainer.tint) {
14138
- rules.push(`background-color: ${buildTint(tokens.getColor(navContainer.tint), opacity)};`);
14139
- } else {
14140
- rules.push(`background-color: ${tokens.getColor("surface")};`);
14141
- }
14142
- rules.push(`border: 1px solid ${tokens.getColor("border")};`);
14143
- }
14144
- if (rules.length > 0) {
14145
- return `${selector} { ${rules.join(" ")} }`;
14137
+ rules.push(...navContainerSurfaceRules(header, navContainer, tokens, theme, solvedInks));
14138
+ return `${selector} { ${rules.join(" ")} }`;
14139
+ }
14140
+ /** Paint and publication are decided together, so translucent containers cannot borrow solid inks. */
14141
+ function navContainerSurfaceRules(header, container, tokens, theme, policy) {
14142
+ if (container.type === "glass") {
14143
+ const opacity$1 = resolveFloatingGlassOpacity(header, container.opacity, .15);
14144
+ const background$1 = container.tint ? buildTint(tokens.getColor(container.tint), opacity$1) : buildRgbWhite(opacity$1);
14145
+ return [
14146
+ `background-color: ${background$1};`,
14147
+ `backdrop-filter: ${HEADER_BLUR};`,
14148
+ `-webkit-backdrop-filter: ${HEADER_BLUR};`,
14149
+ "border: 1px solid rgba(255, 255, 255, 0.2);",
14150
+ "box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);",
14151
+ ...surfaceInkDeclarations({ kind: "reset" })
14152
+ ];
14146
14153
  }
14147
- return "";
14154
+ const opacity = clampOpacity(container.opacity, .15);
14155
+ const background = container.tint ? buildTint(tokens.getColor(container.tint), opacity) : tokens.getColor("surface");
14156
+ const solid = container.tint ? opacity === 1 ? container.tint : null : "surface";
14157
+ return [
14158
+ `background-color: ${background};`,
14159
+ `border: 1px solid ${tokens.getColor("border")};`,
14160
+ ...headerContainerInks(solid, theme, policy)
14161
+ ];
14148
14162
  }
14149
14163
  /**
14150
14164
  * Generate floating container styles
@@ -14162,6 +14176,7 @@ function generateFloatingContainerStyles(header, themeId, tokens, responsiveMode
14162
14176
  }
14163
14177
  rules.push(`backdrop-filter: ${FLOATING_BLUR};`);
14164
14178
  rules.push(`-webkit-backdrop-filter: ${FLOATING_BLUR};`);
14179
+ rules.push(...surfaceInkDeclarations({ kind: "reset" }));
14165
14180
  if (container.border) {
14166
14181
  rules.push(`border: 1px solid rgb(255 255 255 / 0.2);`);
14167
14182
  }
@@ -14288,6 +14303,21 @@ function applyAlpha(color, opacity) {
14288
14303
  }
14289
14304
  return color;
14290
14305
  }
14306
+ /** Container glass is deliberately unmeasured; an opaque pill owns its solid paint. */
14307
+ function headerContainerInks(color, theme, policy) {
14308
+ if (color === null) return surfaceInkDeclarations({ kind: "reset" });
14309
+ const foreground = resolveSurfaceForeground({
14310
+ type: "color",
14311
+ color
14312
+ }, expandPalette(theme.palette));
14313
+ return surfaceInkDeclarations(surfaceInkPublication(foreground, policy));
14314
+ }
14315
+ /** Floating mobile bars paint the header background even when the root overlays the page. */
14316
+ function headerPaintInks(header, theme, policy) {
14317
+ if (headerRootPaint(header) === "contained-nav") return [];
14318
+ const foreground = resolveSurfaceForeground(header.background, expandPalette(theme.palette));
14319
+ return surfaceInkDeclarations(surfaceInkPublication(foreground, policy));
14320
+ }
14291
14321
 
14292
14322
  //#endregion
14293
14323
  //#region ../blocks/src/system/transforms/registry/_utils/themeColorResolution.ts
@@ -14299,7 +14329,7 @@ function resolveBackgroundColorValue(value, context) {
14299
14329
  //#region ../blocks/src/system/transforms/registry/_utils/surfaceForegroundStyles.ts
14300
14330
  const sectionSurfaceCache = new WeakMap();
14301
14331
  function resolveHeaderRootForeground(header, palette, isTransparent) {
14302
- if (isTransparent) return readOpeningForegroundProjection(header) ?? { kind: "unknown" };
14332
+ if (isTransparent) return readOpeningForegroundProjection(header) ?? { kind: "inherits" };
14303
14333
  const background = header?.background;
14304
14334
  return resolveSurfaceForeground(background ?? {
14305
14335
  type: "color",
@@ -14315,12 +14345,32 @@ function resolveFooterRootForeground(footer, palette, proseHoverCandidate) {
14315
14345
  function resolveSurfaceForegroundStyles(value, context, options) {
14316
14346
  const resolved = cachedSectionSurface(value, context, options);
14317
14347
  const foreground = resolved.foreground;
14318
- if (foreground.kind === "unknown") return { ...resolved.buttonStyles };
14319
- return {
14320
- ...arrangementSurfaceInk(foreground, context),
14321
- ...resolved.buttonStyles,
14322
- ...surfaceForegroundStyle(surfaceForegroundInputFromResolved(foreground, (token) => resolveBackgroundColorValue(token, context)))
14323
- };
14348
+ const inks = surfaceInkStyle(resolved.inks);
14349
+ switch (foreground.kind) {
14350
+ case "inherits":
14351
+ case "unmeasured-paint": return {
14352
+ ...resolved.buttonStyles,
14353
+ ...inks
14354
+ };
14355
+ case "known": return {
14356
+ ...arrangementSurfaceInk(foreground, context),
14357
+ ...resolved.buttonStyles,
14358
+ ...surfaceForegroundStyle(surfaceForegroundInputFromResolved(foreground, (token) => resolveBackgroundColorValue(token, context))),
14359
+ ...inks
14360
+ };
14361
+ }
14362
+ }
14363
+ /**
14364
+ * The render's ink policy, set by the runtime its theme tokens came from. A
14365
+ * render that can't vouch for its runtime withholds, so its owned surfaces
14366
+ * reset the inks rather than publish ones solved for tokens that may differ.
14367
+ */
14368
+ function transformSolvedInks(context) {
14369
+ return context.theme.solvedInks ?? "withhold";
14370
+ }
14371
+ /** Chrome roots publish the same ink decision as sections. */
14372
+ function solvedInkStyle(foreground, context) {
14373
+ return surfaceInkStyle(surfaceInkPublication(foreground, transformSolvedInks(context)));
14324
14374
  }
14325
14375
  /** The section ground's resolved foreground, for decorations drawn on that ground (maps). */
14326
14376
  function resolveSectionSurfaceForeground(value, context, options) {
@@ -14352,7 +14402,8 @@ function resolveRuntimeSectionSurface(value, context, options) {
14352
14402
  palette: context.theme.palette,
14353
14403
  buttonSystem: context.theme.buttons,
14354
14404
  linkHoverToken: context.proseHoverCandidate,
14355
- compositeBase: options?.fallbackToken
14405
+ compositeBase: options?.fallbackToken,
14406
+ solvedInks: transformSolvedInks(context)
14356
14407
  });
14357
14408
  }
14358
14409
  function arrangementSurfaceInk(foreground, context) {
@@ -14361,7 +14412,7 @@ function arrangementSurfaceInk(foreground, context) {
14361
14412
  }
14362
14413
  /** Decoration roles already resolved by the surface owner, shared with footer arrangements. */
14363
14414
  function surfaceInkStyles(foreground, palette) {
14364
- if (foreground.kind === "unknown") return {};
14415
+ if (foreground.kind !== "known") return {};
14365
14416
  const decorations$1 = surfaceDecorationColors(foreground, palette);
14366
14417
  return {
14367
14418
  "--rb-surface-muted-color": foreground.roles.muted ?? foreground.roles.text,
@@ -18490,6 +18541,7 @@ function createBlockManifest(config$1) {
18490
18541
  icon: config$1.icon ?? "Box",
18491
18542
  layout,
18492
18543
  variants,
18544
+ arrangementOwnedFieldIds: config$1.arrangementOwnedFieldIds,
18493
18545
  variantMeaning: config$1.variantMeaning,
18494
18546
  defaultVariant: config$1.defaultVariant,
18495
18547
  variantOptions: config$1.variantOptions,
@@ -18568,7 +18620,12 @@ const lookSticker = text({
18568
18620
  as: "p",
18569
18621
  ...lookSlot("sticker")
18570
18622
  }, when("content._effectiveKnobs.stickerLine.value"), bind("content.stickerLine"));
18571
- const heroContentNodes = [lookCaption, ...heroCopyAndCta.layout];
18623
+ const heroActionsNote = richText({ className: "hero-actions-note" }, when("content.actionsNote"), bind("content.actionsNote"));
18624
+ const heroContentNodes = [
18625
+ lookCaption,
18626
+ ...heroCopyAndCta.layout,
18627
+ heroActionsNote
18628
+ ];
18572
18629
  function heroContentCard(children, gap, copyAtCard) {
18573
18630
  return styledContainer({
18574
18631
  bindFrom: "_contentCardStyles",
@@ -18697,7 +18754,8 @@ const headlineRowLayout = heroLookLayout([
18697
18754
  el("div", lookSlot("copy"), [
18698
18755
  lookCaption,
18699
18756
  ...heroCopyFragment.layout.slice(2),
18700
- ...heroCtaRowFragment.layout
18757
+ ...heroCtaRowFragment.layout,
18758
+ heroActionsNote
18701
18759
  ]),
18702
18760
  lookPhoto
18703
18761
  ]);
@@ -18784,6 +18842,17 @@ const heroConfig = {
18784
18842
  hidden: true
18785
18843
  }
18786
18844
  },
18845
+ {
18846
+ id: "actionsNote",
18847
+ type: "richText",
18848
+ label: "Line in place of the buttons",
18849
+ required: false,
18850
+ ui: {
18851
+ intent: "display",
18852
+ hidden: true,
18853
+ richTextVariant: "limited"
18854
+ }
18855
+ },
18787
18856
  createImageShapeField({
18788
18857
  id: "imageShape",
18789
18858
  label: "Image shape",
@@ -21658,7 +21727,7 @@ function planSiteChromePlacement(positioning) {
21658
21727
  headerRootClassName: "rb-fixed rb-top-0 rb-left-0 rb-right-0",
21659
21728
  standaloneShellClassName: "fixed left-0 right-0 top-0 z-40 w-full"
21660
21729
  };
21661
- default: return assertNever$11(positioning);
21730
+ default: return assertNever$10(positioning);
21662
21731
  }
21663
21732
  }
21664
21733
  function splitSiteChromePlacementClasses(className) {
@@ -21842,8 +21911,11 @@ function resolveHeaderVisualStyles(header) {
21842
21911
  return visuals;
21843
21912
  }
21844
21913
  function resolvedForegroundStyle(foreground) {
21845
- if (foreground.kind === "unknown") return undefined;
21846
- return surfaceForegroundStyle(surfaceForegroundInputFromResolved(foreground, rgbColorValue));
21914
+ switch (foreground.kind) {
21915
+ case "inherits":
21916
+ case "unmeasured-paint": return undefined;
21917
+ case "known": return surfaceForegroundStyle(surfaceForegroundInputFromResolved(foreground, rgbColorValue));
21918
+ }
21847
21919
  }
21848
21920
  function footerBottomBarBorderWidthStyle(width) {
21849
21921
  if (!width) return undefined;
@@ -21929,7 +22001,7 @@ const headerRootStyleTransform = {
21929
22001
  const foreground = resolveHeaderRootForeground(header, context.theme.palette, visuals.isTransparent);
21930
22002
  const foregroundStyle = resolvedForegroundStyle(foreground) ?? (visuals.isTransparent ? surfaceForegroundStyle(transparentHeaderForegroundInput(header, context.theme.palette)) : { color: rgbColorValue(headerLeafTextColor(header)) });
21931
22003
  const borderColorToken = header?.border?.colorToken ?? "border";
21932
- return mergeStyles(foregroundStyle, borderColorStyle(borderColorToken));
22004
+ return mergeStyles(foregroundStyle, solvedInkStyle(foreground, context), borderColorStyle(borderColorToken));
21933
22005
  }
21934
22006
  };
21935
22007
  const headerSectionBackgroundTransform = {
@@ -21958,9 +22030,10 @@ const footerRootStyleTransform = {
21958
22030
  styleParts.push(backgroundColorStyle(token));
21959
22031
  }
21960
22032
  }
21961
- styleParts.push(resolvedForegroundStyle(resolveFooterRootForeground(footer, context.theme.palette, context.proseHoverCandidate)));
22033
+ const foreground = resolveFooterRootForeground(footer, context.theme.palette, context.proseHoverCandidate);
22034
+ styleParts.push(resolvedForegroundStyle(foreground), solvedInkStyle(foreground, context));
21962
22035
  if (footer?.variant === "centred") {
21963
- styleParts.push(surfaceInkStyles(resolveFooterRootForeground(footer, context.theme.palette, context.proseHoverCandidate), context.theme.palette));
22036
+ styleParts.push(surfaceInkStyles(foreground, context.theme.palette));
21964
22037
  }
21965
22038
  styleParts.push(borderColorStyle("border"));
21966
22039
  return mergeStyles(...styleParts);
@@ -22026,21 +22099,27 @@ const footerBottomBarStyleTransform = {
22026
22099
  run: (value, _options, context) => {
22027
22100
  const footer = asPartialObject(value);
22028
22101
  const bottomBar = footer?.bottomBar;
22029
- return mergeStyles(bottomBar?.background?.type === "color" ? backgroundColorStyle(bottomBar.background.color ?? "surface") : undefined, footerBottomBarBorderColorStyle(footer), footerBottomBarBorderWidthStyle(bottomBar?.borderTop?.width), footerBottomBarForegroundStyle(footer, context.theme.palette));
22102
+ return mergeStyles(bottomBar?.background?.type === "color" ? backgroundColorStyle(bottomBar.background.color ?? "surface") : undefined, footerBottomBarBorderColorStyle(footer), footerBottomBarBorderWidthStyle(bottomBar?.borderTop?.width), footerBottomBarForegroundStyle(footer, context.theme.palette), footerBottomBarInkStyle(footer, context));
22030
22103
  }
22031
22104
  };
22032
22105
  function footerBottomBarForegroundStyle(footer, palette) {
22033
22106
  if (!footer?.bottomBar) return undefined;
22107
+ const foreground = footerBottomBarSurfaceForeground(footer, palette);
22108
+ return foreground === null ? backgroundlessBottomBarForegroundStyle(footer) : resolvedForegroundStyle(foreground);
22109
+ }
22110
+ /** A bar without its own colour paints nothing, so the footer's inks carry on. */
22111
+ function footerBottomBarInkStyle(footer, context) {
22112
+ const foreground = footer ? footerBottomBarSurfaceForeground(footer, context.theme.palette) : null;
22113
+ return foreground === null ? undefined : solvedInkStyle(foreground, context);
22114
+ }
22115
+ function footerBottomBarSurfaceForeground(footer, palette) {
22034
22116
  const bar = footer.bottomBar;
22035
- if (bar.background?.type !== "color") {
22036
- return backgroundlessBottomBarForegroundStyle(footer);
22037
- }
22038
- const foreground = resolveSurfaceForeground(bar.background, palette, {
22117
+ if (bar?.background?.type !== "color") return null;
22118
+ return resolveSurfaceForeground(bar.background, palette, {
22039
22119
  text: bar.textColor,
22040
22120
  link: footer.bottomTextLinkStyle?.colorToken ?? bar.textColor,
22041
22121
  linkHover: footer.bottomTextLinkStyle?.hoverColorToken
22042
22122
  }, { compositeBase: measuredFooterBackdrop(footer, palette) });
22043
- return resolvedForegroundStyle(foreground);
22044
22123
  }
22045
22124
  function backgroundlessBottomBarForegroundStyle(footer) {
22046
22125
  if (footer.background?.contentOwner === siteChromeBackgroundOverrideOwner) {
@@ -22237,6 +22316,100 @@ function readRuntimeNow(value) {
22237
22316
  return parsed.value;
22238
22317
  }
22239
22318
 
22319
+ //#endregion
22320
+ //#region ../blocks/src/system/blocks/shared/teamMembers.ts
22321
+ const teamMemberSpecialtiesInputSchema = z.union([z.string(), z.array(z.string())]).nullish();
22322
+ function parseTeamMemberSpecialties(value) {
22323
+ const parsed = teamMemberSpecialtiesInputSchema.safeParse(value);
22324
+ if (!parsed.success) return [];
22325
+ const parts = typeof parsed.data === "string" ? parsed.data.split(/\r?\n|,/) : parsed.data ?? [];
22326
+ return [...new Set(parts.map((part) => part.trim()).filter(Boolean))];
22327
+ }
22328
+ const biographyTextSchema = z.string().transform((text$1) => text$1.split(/\r?\n\s*\r?\n/).map((paragraph) => paragraph.trim()).filter(Boolean));
22329
+ const biographySourceSchema = z.union([RichTextDocSchema, biographyTextSchema]).nullish().catch(null);
22330
+ const teamMemberBiographySchema = z.object({
22331
+ profileBio: biographySourceSchema,
22332
+ bio: biographySourceSchema,
22333
+ summary: biographySourceSchema
22334
+ });
22335
+ /**
22336
+ * The bio a section about one person shows, or null when they have none: the
22337
+ * bio from their profile when it says anything, else their short bio. A page
22338
+ * deciding whether someone has a bio and the block showing it both read this,
22339
+ * so a section is never promised words that aren't there.
22340
+ */
22341
+ function teamMemberBiography(member) {
22342
+ return firstBiography(member, [
22343
+ "profileBio",
22344
+ "bio",
22345
+ "summary"
22346
+ ]);
22347
+ }
22348
+ /**
22349
+ * The bio a compact card shows when a page asks for whichever bio the person
22350
+ * has: their short bio first, then their summary, and their profile bio only
22351
+ * when neither says anything.
22352
+ */
22353
+ function teamMemberCardBiography(member) {
22354
+ return firstBiography(member, [
22355
+ "bio",
22356
+ "summary",
22357
+ "profileBio"
22358
+ ]);
22359
+ }
22360
+ /**
22361
+ * What an older grid or stack card adds under its short bio slot: the card
22362
+ * bio, unless the short bio is already a rich-text document that slot shows.
22363
+ * That slot only renders documents, so a staff member's plain-text short bio
22364
+ * comes through here too, and the two never show together.
22365
+ */
22366
+ function teamMemberCardBiographyFallback(member) {
22367
+ const shortBio = firstBiography(member, ["bio"]);
22368
+ if (shortBio?.kind === "document") return null;
22369
+ const biography = teamMemberCardBiography(member);
22370
+ return biography ? teamMemberBiographyDocument(biography) : null;
22371
+ }
22372
+ /** A bio as one rich-text document, each plain paragraph its own paragraph. */
22373
+ function teamMemberBiographyDocument(biography) {
22374
+ if (biography.kind === "document") return biography.document;
22375
+ return {
22376
+ type: "doc",
22377
+ content: biography.paragraphs.map((text$1) => ({
22378
+ type: "paragraph",
22379
+ content: [{
22380
+ type: "text",
22381
+ text: text$1
22382
+ }]
22383
+ }))
22384
+ };
22385
+ }
22386
+ function firstBiography(member, order) {
22387
+ const parsed = teamMemberBiographySchema.safeParse(member);
22388
+ if (!parsed.success) return null;
22389
+ return order.map((key) => toBiography(parsed.data[key])).find((biography) => biography !== null) ?? null;
22390
+ }
22391
+ function toBiography(source) {
22392
+ if (source === null || source === undefined) return null;
22393
+ if (Array.isArray(source)) return source.length > 0 ? {
22394
+ kind: "text",
22395
+ paragraphs: source
22396
+ } : null;
22397
+ const document$1 = source;
22398
+ return hasText$1(document$1) ? {
22399
+ kind: "document",
22400
+ document: document$1
22401
+ } : null;
22402
+ }
22403
+ const textNodeSchema = z.object({
22404
+ text: z.string().optional(),
22405
+ content: z.array(z.unknown()).optional()
22406
+ });
22407
+ function hasText$1(node) {
22408
+ const parsed = textNodeSchema.safeParse(node);
22409
+ if (!parsed.success) return false;
22410
+ return (parsed.data.text?.trim().length ?? 0) > 0 || (parsed.data.content ?? []).some(hasText$1);
22411
+ }
22412
+
22240
22413
  //#endregion
22241
22414
  //#region ../blocks/src/system/transforms/registry/content.ts
22242
22415
  const supportedRichTextTokenSchema = z.enum(["year", "site_name"]);
@@ -22318,7 +22491,14 @@ const interpolateRichTextTokensTransform = {
22318
22491
  schema: interpolateRichTextTokensOptionsSchema,
22319
22492
  run: (value, options, context) => interpolateRichTextTokens(value, options, context)
22320
22493
  };
22321
- const contentTransforms = [interpolateRichTextTokensTransform];
22494
+ /** An older team card's bio when it has no short bio; see teamMemberCardBiographyFallback. */
22495
+ const teamMemberCardBiographyFallbackTransform = {
22496
+ id: "teamMember.cardBiographyFallback",
22497
+ kind: "formatter",
22498
+ summary: "A team member's card bio when they have no short bio",
22499
+ run: (value) => teamMemberCardBiographyFallback(value)
22500
+ };
22501
+ const contentTransforms = [interpolateRichTextTokensTransform, teamMemberCardBiographyFallbackTransform];
22322
22502
 
22323
22503
  //#endregion
22324
22504
  //#region ../blocks/src/system/transforms/typed.ts
@@ -23266,6 +23446,7 @@ const dataLoaders = { ...entriesLoader ? { entries: {
23266
23446
  }
23267
23447
  } } : {} };
23268
23448
  const testimonialsManifest = createBlockManifest({
23449
+ arrangementOwnedFieldIds: ["maxEntries", "avatarLayout"],
23269
23450
  variantMeaning: {
23270
23451
  kind: "arrangement",
23271
23452
  lookOnlyKeys: [
@@ -25623,6 +25804,14 @@ const eventVenueSchema = z.object({
25623
25804
  }).nullable()
25624
25805
  });
25625
25806
  /**
25807
+ * The map for an event details page: one drawing, for the venue of the event the page is about.
25808
+ * It travels beside the events rather than on any of them, so a list of events has no place for one.
25809
+ */
25810
+ const eventVenueDrawingSchema = z.object({
25811
+ venueId: z.string(),
25812
+ drawing: z.lazy(() => mapDrawingSchema)
25813
+ });
25814
+ /**
25626
25815
  * Zod schema for event category data
25627
25816
  */
25628
25817
  const eventCategorySchema = z.object({
@@ -26100,6 +26289,53 @@ function normalizeEventStaffMemberId(value) {
26100
26289
  return trimmed ? trimmed : null;
26101
26290
  }
26102
26291
 
26292
+ //#endregion
26293
+ //#region ../blocks/src/system/blocks/events/shared/detailsSelection.ts
26294
+ function isFutureOrNow(iso, nowIso) {
26295
+ const ts = Date.parse(iso);
26296
+ const now = Date.parse(nowIso);
26297
+ if (!Number.isFinite(ts) || !Number.isFinite(now)) return false;
26298
+ return ts >= now;
26299
+ }
26300
+ const localDateKey = (startsAt, timeZone) => getBookingLocalDateKey(toScheduledBookingDateTime({
26301
+ startsAt,
26302
+ timeZone
26303
+ }));
26304
+ function selectRequested(events, requested) {
26305
+ if (!requested) return null;
26306
+ const byId = events.find((event) => event.occurrenceId === requested.id || event.id === requested.id);
26307
+ if (byId) return byId;
26308
+ if (!requested.startsAt || !requested.timeZone) return null;
26309
+ const requestedDate = localDateKey(requested.startsAt, requested.timeZone);
26310
+ return events.find((event) => localDateKey(event.startsAt, event.timeZone) === requestedDate) ?? null;
26311
+ }
26312
+ function selectNextUpcoming(events, nowIso) {
26313
+ return [...events].filter((event) => isFutureOrNow(event.startsAt, nowIso)).sort((left, right) => Date.parse(left.startsAt) - Date.parse(right.startsAt))[0] ?? null;
26314
+ }
26315
+ function selectCompletedWholeSeries(events) {
26316
+ if (events.length === 0 || !events.every((event) => event.bookingScope === "whole_series")) {
26317
+ return null;
26318
+ }
26319
+ return [...events].sort((left, right) => Date.parse(right.startsAt) - Date.parse(left.startsAt))[0] ?? null;
26320
+ }
26321
+ function selectEventDetailsCandidate(events, requested, nowIso) {
26322
+ const selected = selectRequested(events, requested);
26323
+ if (selected) return {
26324
+ event: selected,
26325
+ mode: "selected"
26326
+ };
26327
+ const upcoming = selectNextUpcoming(events, nowIso);
26328
+ if (upcoming) return {
26329
+ event: upcoming,
26330
+ mode: "next"
26331
+ };
26332
+ const completed = selectCompletedWholeSeries(events);
26333
+ return completed ? {
26334
+ event: completed,
26335
+ mode: "completed"
26336
+ } : null;
26337
+ }
26338
+
26103
26339
  //#endregion
26104
26340
  //#region ../blocks/src/system/blocks/shop.shared.ts
26105
26341
  /**
@@ -31760,20 +31996,20 @@ const FIELD_LABELS = {
31760
31996
  description: "Short, concrete examples you can refer back to when writing new copy."
31761
31997
  }
31762
31998
  };
31763
- const IDLE_FEEDBACK$2 = idleFeedback$3();
31764
- function idleFeedback$3() {
31999
+ const IDLE_FEEDBACK$2 = idleFeedback$2();
32000
+ function idleFeedback$2() {
31765
32001
  return { tag: "idle" };
31766
32002
  }
31767
32003
  function pendingFeedback$1() {
31768
32004
  return { tag: "pending" };
31769
32005
  }
31770
- function errorFeedback$3(message) {
32006
+ function errorFeedback$2(message) {
31771
32007
  return {
31772
32008
  tag: "error",
31773
32009
  message
31774
32010
  };
31775
32011
  }
31776
- function assertNever$10(value) {
32012
+ function assertNever$9(value) {
31777
32013
  throw new Error(`Unexpected value: ${String(value)}`);
31778
32014
  }
31779
32015
  function createAiBrandGuidelinesGenerationDialogState(sessionId, open$1) {
@@ -31813,7 +32049,7 @@ function aiBrandGuidelinesGenerationDialogReducer(state, action) {
31813
32049
  case "context-load-failed": return {
31814
32050
  ...state,
31815
32051
  context: null,
31816
- contextFeedback: errorFeedback$3(action.message)
32052
+ contextFeedback: errorFeedback$2(action.message)
31817
32053
  };
31818
32054
  case "use-site-content-changed": return state.useSiteContent === action.value ? state : {
31819
32055
  ...state,
@@ -31859,13 +32095,13 @@ function aiBrandGuidelinesGenerationDialogReducer(state, action) {
31859
32095
  if (!state.open || state.sessionId !== action.sessionId) return state;
31860
32096
  return {
31861
32097
  ...state,
31862
- generateFeedback: errorFeedback$3(action.message)
32098
+ generateFeedback: errorFeedback$2(action.message)
31863
32099
  };
31864
32100
  case "current-proposal-accepted":
31865
32101
  if (state.proposal === null) return state;
31866
32102
  return advanceWizardField(state, mergeLockedSettings(state.lockedSettings, state.proposal));
31867
32103
  case "current-proposal-skipped": return advanceWizardField(state, state.lockedSettings);
31868
- default: return assertNever$10(action);
32104
+ default: return assertNever$9(action);
31869
32105
  }
31870
32106
  }
31871
32107
  function advanceWizardField(state, nextLockedSettings) {
@@ -31947,8 +32183,8 @@ function mergeLockedSettings(lockedSettings, proposal) {
31947
32183
  ...proposal
31948
32184
  };
31949
32185
  }
31950
- const idleFeedback$2 = () => ({ tag: "idle" });
31951
- const errorFeedback$2 = (message) => ({
32186
+ const idleFeedback$1 = () => ({ tag: "idle" });
32187
+ const errorFeedback$1 = (message) => ({
31952
32188
  tag: "error",
31953
32189
  message
31954
32190
  });
@@ -31966,14 +32202,14 @@ const err$1 = (error$1) => ({
31966
32202
  error: error$1
31967
32203
  });
31968
32204
  function resetDialogFeedback(feedback) {
31969
- return feedback.tag === "idle" ? feedback : idleFeedback$2();
32205
+ return feedback.tag === "idle" ? feedback : idleFeedback$1();
31970
32206
  }
31971
32207
  function createDialogState(dialog) {
31972
32208
  switch (dialog.kind) {
31973
32209
  case "create-preview": return {
31974
32210
  tag: "create-preview",
31975
32211
  draft: { name: "" },
31976
- feedback: idleFeedback$2()
32212
+ feedback: idleFeedback$1()
31977
32213
  };
31978
32214
  case "create-content": return {
31979
32215
  tag: "create-content",
@@ -31981,19 +32217,19 @@ function createDialogState(dialog) {
31981
32217
  name: "",
31982
32218
  environment: "live"
31983
32219
  },
31984
- feedback: idleFeedback$2()
32220
+ feedback: idleFeedback$1()
31985
32221
  };
31986
32222
  case "create-management": return {
31987
32223
  tag: "create-management",
31988
32224
  draft: { name: "" },
31989
- feedback: idleFeedback$2()
32225
+ feedback: idleFeedback$1()
31990
32226
  };
31991
32227
  case "confirm-operation": return {
31992
32228
  tag: "confirm-operation",
31993
32229
  operation: dialog.operation,
31994
- feedback: idleFeedback$2()
32230
+ feedback: idleFeedback$1()
31995
32231
  };
31996
- default: return assertNever$9(dialog);
32232
+ default: return assertNever$8(dialog);
31997
32233
  }
31998
32234
  }
31999
32235
  function getOperationKeyType(operation) {
@@ -32004,7 +32240,7 @@ function getOperationKeyType(operation) {
32004
32240
  case "revoke-content": return "content";
32005
32241
  case "create-management":
32006
32242
  case "revoke-management": return "management";
32007
- default: return assertNever$9(operation);
32243
+ default: return assertNever$8(operation);
32008
32244
  }
32009
32245
  }
32010
32246
  function getRefreshToken(refresh$1, keyType) {
@@ -32012,7 +32248,7 @@ function getRefreshToken(refresh$1, keyType) {
32012
32248
  case "preview": return refresh$1.preview;
32013
32249
  case "content": return refresh$1.content;
32014
32250
  case "management": return refresh$1.management;
32015
- default: return assertNever$9(keyType);
32251
+ default: return assertNever$8(keyType);
32016
32252
  }
32017
32253
  }
32018
32254
  function isSameOperation(left, right) {
@@ -32024,7 +32260,7 @@ function isSameOperation(left, right) {
32024
32260
  case "revoke-preview":
32025
32261
  case "revoke-content":
32026
32262
  case "revoke-management": return "keyId" in right && left.keyId === right.keyId;
32027
- default: return assertNever$9(left);
32263
+ default: return assertNever$8(left);
32028
32264
  }
32029
32265
  }
32030
32266
  function matchesDialogOperation(dialog, operation) {
@@ -32035,7 +32271,7 @@ function matchesDialogOperation(dialog, operation) {
32035
32271
  case "confirm-operation": return isSameOperation(dialog.operation, operation);
32036
32272
  case "closed":
32037
32273
  case "show-new-key": return false;
32038
- default: return assertNever$9(dialog);
32274
+ default: return assertNever$8(dialog);
32039
32275
  }
32040
32276
  }
32041
32277
  function isFeedbackDialog(dialog) {
@@ -32091,7 +32327,7 @@ function reduceRefreshState(refresh$1, action) {
32091
32327
  ...refresh$1,
32092
32328
  management: action.refreshToken
32093
32329
  };
32094
- default: return assertNever$9(keyType);
32330
+ default: return assertNever$8(keyType);
32095
32331
  }
32096
32332
  }
32097
32333
  function reduceCommandState(command, action) {
@@ -32114,7 +32350,7 @@ function reduceCommandState(command, action) {
32114
32350
  case "preview-draft-invalid":
32115
32351
  case "data-refreshed":
32116
32352
  case "refresh-warning-reported": return command;
32117
- default: return assertNever$9(action);
32353
+ default: return assertNever$8(action);
32118
32354
  }
32119
32355
  }
32120
32356
  function reduceDialogState(dialog, action) {
@@ -32147,19 +32383,19 @@ function reduceDialogState(dialog, action) {
32147
32383
  } : dialog;
32148
32384
  case "preview-draft-invalid": return dialog.tag === "create-preview" ? {
32149
32385
  ...dialog,
32150
- feedback: errorFeedback$2(action.message)
32386
+ feedback: errorFeedback$1(action.message)
32151
32387
  } : dialog;
32152
32388
  case "content-draft-invalid": return dialog.tag === "create-content" ? {
32153
32389
  ...dialog,
32154
- feedback: errorFeedback$2(action.message)
32390
+ feedback: errorFeedback$1(action.message)
32155
32391
  } : dialog;
32156
32392
  case "command-started": return matchesDialogOperation(dialog, action.operation) && isFeedbackDialog(dialog) ? {
32157
32393
  ...dialog,
32158
- feedback: idleFeedback$2()
32394
+ feedback: idleFeedback$1()
32159
32395
  } : dialog;
32160
32396
  case "command-failed": return matchesDialogOperation(dialog, action.operation) && isFeedbackDialog(dialog) ? {
32161
32397
  ...dialog,
32162
- feedback: errorFeedback$2(action.message)
32398
+ feedback: errorFeedback$1(action.message)
32163
32399
  } : dialog;
32164
32400
  case "new-key-received": return {
32165
32401
  tag: "show-new-key",
@@ -32171,7 +32407,7 @@ function reduceDialogState(dialog, action) {
32171
32407
  case "page-feedback-reported":
32172
32408
  case "data-refreshed":
32173
32409
  case "refresh-warning-reported": return dialog;
32174
- default: return assertNever$9(action);
32410
+ default: return assertNever$8(action);
32175
32411
  }
32176
32412
  }
32177
32413
  function reduceDataState(data, action) {
@@ -32189,7 +32425,7 @@ function reduceDataState(data, action) {
32189
32425
  ...data,
32190
32426
  managementKeys: action.managementKeys
32191
32427
  };
32192
- default: return assertNever$9(action);
32428
+ default: return assertNever$8(action);
32193
32429
  }
32194
32430
  case "key-revoked": switch (action.operation.kind) {
32195
32431
  case "revoke-preview": return {
@@ -32204,7 +32440,7 @@ function reduceDataState(data, action) {
32204
32440
  ...data,
32205
32441
  managementKeys: data.managementKeys.filter((key) => key.id !== action.operation.keyId)
32206
32442
  };
32207
- default: return assertNever$9(action.operation);
32443
+ default: return assertNever$8(action.operation);
32208
32444
  }
32209
32445
  case "dialog-opened":
32210
32446
  case "dialog-closed":
@@ -32219,7 +32455,7 @@ function reduceDataState(data, action) {
32219
32455
  case "command-failed":
32220
32456
  case "new-key-received":
32221
32457
  case "refresh-warning-reported": return data;
32222
- default: return assertNever$9(action);
32458
+ default: return assertNever$8(action);
32223
32459
  }
32224
32460
  }
32225
32461
  function reducePageFeedback(pageFeedback, action) {
@@ -32242,7 +32478,7 @@ function reducePageFeedback(pageFeedback, action) {
32242
32478
  case "preview-draft-invalid":
32243
32479
  case "data-refreshed":
32244
32480
  case "command-failed": return pageFeedback;
32245
- default: return assertNever$9(action);
32481
+ default: return assertNever$8(action);
32246
32482
  }
32247
32483
  }
32248
32484
  function isBlockedWhilePending(action) {
@@ -32270,7 +32506,7 @@ function apiKeysSettingsReducer(state, action) {
32270
32506
  function isApiKeysCommandPending(command, operation) {
32271
32507
  return isPendingCommand(command, operation);
32272
32508
  }
32273
- function assertNever$9(value, message) {
32509
+ function assertNever$8(value, message) {
32274
32510
  throw new Error(message ?? `Unexpected value: ${String(value)}`);
32275
32511
  }
32276
32512
  function selectApiKeysSubmitting(state) {
@@ -32371,300 +32607,6 @@ function toggleAsset(selected, asset) {
32371
32607
  function selectAllAssets(assets) {
32372
32608
  return [...assets];
32373
32609
  }
32374
- const EMPTY_FIELD_ERRORS = [];
32375
- const EMPTY_COUNT_ENTRIES = [];
32376
- const IMPORT_COUNT_ENTRIES_CACHE = /* @__PURE__ */ new WeakMap();
32377
- const ZERO_SUMMARY = {
32378
- totalUpdated: 0,
32379
- totalFailed: 0
32380
- };
32381
- function parseBackupMembershipMode(value) {
32382
- switch (value) {
32383
- case "skip":
32384
- case "invite":
32385
- case "preview": return value;
32386
- default: throw new Error(`Unexpected membership mode: ${value}`);
32387
- }
32388
- }
32389
- function parseBackupApiKeyMode(value) {
32390
- switch (value) {
32391
- case "skip":
32392
- case "regenerate":
32393
- case "preview": return value;
32394
- default: throw new Error(`Unexpected API key mode: ${value}`);
32395
- }
32396
- }
32397
- function buildBackupImportCountEntries(result) {
32398
- if (result?.counts === void 0 || result.counts === null) return EMPTY_COUNT_ENTRIES;
32399
- const cachedEntries = IMPORT_COUNT_ENTRIES_CACHE.get(result);
32400
- if (cachedEntries !== void 0) return cachedEntries;
32401
- const entries = Object.entries(result.counts).map(([table, counts]) => ({
32402
- table,
32403
- counts
32404
- }));
32405
- IMPORT_COUNT_ENTRIES_CACHE.set(result, entries);
32406
- return entries;
32407
- }
32408
- function deriveBackupImportSummary(entries) {
32409
- if (entries.length === 0) return ZERO_SUMMARY;
32410
- return entries.reduce((sum, entry) => ({
32411
- totalUpdated: sum.totalUpdated + entry.counts.updated,
32412
- totalFailed: sum.totalFailed + entry.counts.failed
32413
- }), ZERO_SUMMARY);
32414
- }
32415
- function clearBackupImportOutcome(state) {
32416
- return {
32417
- ...state,
32418
- phase: "idle",
32419
- fileError: null,
32420
- fieldErrors: null,
32421
- feedback: idleFeedback$1()
32422
- };
32423
- }
32424
- function backupImportOptionsReducer(state, action) {
32425
- switch (action.type) {
32426
- case "clean-import-changed": return state.cleanImport === action.value ? state : {
32427
- ...state,
32428
- cleanImport: action.value
32429
- };
32430
- case "dry-run-changed": return state.dryRun === action.value ? state : {
32431
- ...state,
32432
- dryRun: action.value
32433
- };
32434
- case "membership-mode-changed": return state.membershipMode === action.value ? state : {
32435
- ...state,
32436
- membershipMode: action.value
32437
- };
32438
- case "api-key-mode-changed": return state.apiKeyMode === action.value ? state : {
32439
- ...state,
32440
- apiKeyMode: action.value
32441
- };
32442
- case "send-emails-changed": return state.sendEmails === action.value ? state : {
32443
- ...state,
32444
- sendEmails: action.value
32445
- };
32446
- default: return assertNever$8(action);
32447
- }
32448
- }
32449
- function backupExportStateReducer(state, action) {
32450
- switch (action.type) {
32451
- case "include-media-changed": return state.includeMedia === action.value ? state : {
32452
- ...state,
32453
- includeMedia: action.value
32454
- };
32455
- case "include-access-changed": return state.includeAccess === action.value ? state : {
32456
- ...state,
32457
- includeAccess: action.value
32458
- };
32459
- case "export-started": return state.exporting ? state : {
32460
- ...state,
32461
- exporting: true
32462
- };
32463
- case "export-finished": return state.exporting ? {
32464
- ...state,
32465
- exporting: false
32466
- } : state;
32467
- default: return assertNever$8(action);
32468
- }
32469
- }
32470
- function backupImportStateReducer(state, action) {
32471
- switch (action.type) {
32472
- case "import-file-cleared": return {
32473
- ...clearBackupImportOutcome(state),
32474
- file: null
32475
- };
32476
- case "import-file-invalid": return {
32477
- ...clearBackupImportOutcome(state),
32478
- file: null,
32479
- fileError: action.message
32480
- };
32481
- case "import-file-selected": return {
32482
- ...clearBackupImportOutcome(state),
32483
- file: action.file
32484
- };
32485
- case "import-failed": return {
32486
- ...clearBackupImportOutcome(state),
32487
- feedback: errorFeedback$1(action.message)
32488
- };
32489
- case "import-validation-errors-received": return {
32490
- ...clearBackupImportOutcome(state),
32491
- fieldErrors: action.errors
32492
- };
32493
- case "import-succeeded": return {
32494
- ...clearBackupImportOutcome(state),
32495
- feedback: successFeedback$1(action.result)
32496
- };
32497
- case "clean-import-changed":
32498
- case "dry-run-changed":
32499
- case "membership-mode-changed":
32500
- case "api-key-mode-changed":
32501
- case "send-emails-changed": {
32502
- const options = backupImportOptionsReducer(state.options, action);
32503
- return options === state.options ? state : {
32504
- ...state,
32505
- options
32506
- };
32507
- }
32508
- case "clean-confirm-opened": return state.cleanConfirmOpen ? state : {
32509
- ...state,
32510
- cleanConfirmOpen: true
32511
- };
32512
- case "clean-confirm-closed": return state.cleanConfirmOpen ? {
32513
- ...state,
32514
- cleanConfirmOpen: false
32515
- } : state;
32516
- case "import-confirmed": return {
32517
- ...clearBackupImportOutcome(state),
32518
- phase: "uploading",
32519
- cleanConfirmOpen: false
32520
- };
32521
- case "api-import-started": return state.phase === "calling-api" ? state : {
32522
- ...state,
32523
- phase: "calling-api"
32524
- };
32525
- case "import-finished": return state.phase === "idle" ? state : {
32526
- ...state,
32527
- phase: "idle"
32528
- };
32529
- default: return assertNever$8(action);
32530
- }
32531
- }
32532
- function createInitialBackupClientState() {
32533
- return {
32534
- exportState: {
32535
- exporting: false,
32536
- includeMedia: true,
32537
- includeAccess: false
32538
- },
32539
- importState: {
32540
- phase: "idle",
32541
- file: null,
32542
- fileError: null,
32543
- fieldErrors: null,
32544
- feedback: idleFeedback$1(),
32545
- cleanConfirmOpen: false,
32546
- options: {
32547
- cleanImport: false,
32548
- dryRun: false,
32549
- membershipMode: "skip",
32550
- apiKeyMode: "skip",
32551
- sendEmails: true
32552
- }
32553
- }
32554
- };
32555
- }
32556
- function backupClientReducer(state, action) {
32557
- switch (action.type) {
32558
- case "include-media-changed":
32559
- case "include-access-changed":
32560
- case "export-started":
32561
- case "export-finished": {
32562
- const exportState = backupExportStateReducer(state.exportState, action);
32563
- return exportState === state.exportState ? state : {
32564
- ...state,
32565
- exportState
32566
- };
32567
- }
32568
- case "import-file-cleared":
32569
- case "import-file-invalid":
32570
- case "import-file-selected":
32571
- case "import-failed":
32572
- case "import-validation-errors-received":
32573
- case "import-succeeded":
32574
- case "clean-import-changed":
32575
- case "dry-run-changed":
32576
- case "membership-mode-changed":
32577
- case "api-key-mode-changed":
32578
- case "send-emails-changed":
32579
- case "clean-confirm-opened":
32580
- case "clean-confirm-closed":
32581
- case "import-confirmed":
32582
- case "api-import-started":
32583
- case "import-finished": {
32584
- const importState = backupImportStateReducer(state.importState, action);
32585
- return importState === state.importState ? state : {
32586
- ...state,
32587
- importState
32588
- };
32589
- }
32590
- default: return assertNever$8(action);
32591
- }
32592
- }
32593
- function selectBackupExporting(state) {
32594
- return state.exportState.exporting;
32595
- }
32596
- function selectBackupImporting(state) {
32597
- return state.importState.phase !== "idle";
32598
- }
32599
- function selectBackupCleanConfirmOpen(state) {
32600
- return state.importState.cleanConfirmOpen;
32601
- }
32602
- function selectBackupShouldConfirmCleanImport(state) {
32603
- return state.importState.file !== null && state.importState.options.cleanImport && !state.importState.options.dryRun;
32604
- }
32605
- function selectBackupIncludeMedia(state) {
32606
- return state.exportState.includeMedia;
32607
- }
32608
- function selectBackupIncludeAccess(state) {
32609
- return state.exportState.includeAccess;
32610
- }
32611
- function selectBackupImportFile(state) {
32612
- return state.importState.file;
32613
- }
32614
- function selectBackupImportFileError(state) {
32615
- return state.importState.fileError;
32616
- }
32617
- function selectBackupCleanImport(state) {
32618
- return state.importState.options.cleanImport;
32619
- }
32620
- function selectBackupDryRun(state) {
32621
- return state.importState.options.dryRun;
32622
- }
32623
- function selectBackupMembershipMode(state) {
32624
- return state.importState.options.membershipMode;
32625
- }
32626
- function selectBackupApiKeyMode(state) {
32627
- return state.importState.options.apiKeyMode;
32628
- }
32629
- function selectBackupSendEmails(state) {
32630
- return state.importState.options.sendEmails;
32631
- }
32632
- function selectBackupImportResult(state) {
32633
- return state.importState.feedback.tag === "success" ? state.importState.feedback.result : null;
32634
- }
32635
- function selectBackupImportAccess(state) {
32636
- return selectBackupImportResult(state)?.access;
32637
- }
32638
- function selectBackupImportErrorMessage(state) {
32639
- return state.importState.feedback.tag === "error" ? state.importState.feedback.message : null;
32640
- }
32641
- function selectBackupImportFieldErrors(state) {
32642
- return state.importState.fieldErrors ?? EMPTY_FIELD_ERRORS;
32643
- }
32644
- function selectBackupImportSummary(state) {
32645
- return deriveBackupImportSummary(selectBackupImportCountEntries(state));
32646
- }
32647
- function selectBackupImportCountEntries(state) {
32648
- return buildBackupImportCountEntries(selectBackupImportResult(state));
32649
- }
32650
- function assertNever$8(value, message) {
32651
- throw new Error(message ?? `Unexpected value: ${String(value)}`);
32652
- }
32653
- function idleFeedback$1() {
32654
- return { tag: "idle" };
32655
- }
32656
- function errorFeedback$1(message) {
32657
- return {
32658
- tag: "error",
32659
- message
32660
- };
32661
- }
32662
- function successFeedback$1(result) {
32663
- return {
32664
- tag: "success",
32665
- result
32666
- };
32667
- }
32668
32610
  const ADD_CUSTOM_DOMAIN_SUCCESS_MESSAGE = "Custom domain added successfully! Redirecting...";
32669
32611
  const IDLE_FEEDBACK$1 = { tag: "idle" };
32670
32612
  const SUCCESS_FEEDBACK = {
@@ -36741,6 +36683,7 @@ function buildOrderConfirmationContent(input) {
36741
36683
  })) } : null
36742
36684
  };
36743
36685
  const templateVars = {
36686
+ customer_first_name: firstWordOf(customerDisplayName),
36744
36687
  customer_name: customerDisplayName,
36745
36688
  site_name: input.siteTitle ?? "Your Business",
36746
36689
  order_subject: confirmationCopy.subject,
@@ -36772,6 +36715,10 @@ function buildOrderConfirmationContent(input) {
36772
36715
  }
36773
36716
  };
36774
36717
  }
36718
+ /** The first word of their name (or their email, when that's all there is), for the headline. */
36719
+ function firstWordOf(displayName) {
36720
+ return displayName.trim().split(/\s+/)[0] || displayName;
36721
+ }
36775
36722
  function resolveConfirmationCopy(variant, orderNumber) {
36776
36723
  switch (variant.kind) {
36777
36724
  case "pass_only": {
@@ -40968,15 +40915,6 @@ function resolveAutoCtaPath(source, routes) {
40968
40915
  }
40969
40916
  return routeByNormalizedPath.get("/offerings") ?? null;
40970
40917
  }
40971
- function resolveOfferingsPreviewRunPath(run, routes) {
40972
- const routeIds = [run.eventSeriesId, run.eventOfferingId];
40973
- for (const entityId of routeIds) {
40974
- const route = (routes ?? []).find((candidate) => candidate.entityId === entityId);
40975
- const path$3 = normalizeRoutePath(route?.path);
40976
- if (path$3) return path$3;
40977
- }
40978
- return null;
40979
- }
40980
40918
  function preferredPathsForSource(source) {
40981
40919
  switch (source.kind) {
40982
40920
  case "eventPreset": switch (source.preset) {
@@ -41244,6 +41182,11 @@ function resolveEventRegistrationScopedEvents(events, context) {
41244
41182
  //#endregion
41245
41183
  //#region ../blocks/src/system/constants/events.ts
41246
41184
  /**
41185
+ * Event-related constants
41186
+ *
41187
+ * Shared constants for event content types and booking system integration.
41188
+ */
41189
+ /**
41247
41190
  * Content type slugs that represent event content.
41248
41191
  * These are the standard slugs used when creating event content types in the CMS.
41249
41192
  *
@@ -41398,6 +41341,8 @@ function getPreviewContext(contentTypeKey) {
41398
41341
  /** The calendar manifest owns its secondary arrangement axis. */
41399
41342
  const eventCalendarVariantMeaning = {
41400
41343
  kind: "mode",
41344
+ modes: arrangementModes,
41345
+ defaultMode: "list",
41401
41346
  arrangementField: "listLayout",
41402
41347
  keys: eventCalendarListLayoutValues,
41403
41348
  lookOnlyKeys: [
@@ -42451,6 +42396,10 @@ const eventDetailsManifest = createBlockManifest({
42451
42396
  fallback: null
42452
42397
  } },
42453
42398
  events: { $bind: { from: "data.eventDetailsData.events" } },
42399
+ venueDrawing: { $bind: {
42400
+ from: "data.eventDetailsData.venueDrawing",
42401
+ fallback: null
42402
+ } },
42454
42403
  showVenue: { $bind: { from: "content.showVenue" } },
42455
42404
  showTitle: { $bind: { from: "content.showTitle" } },
42456
42405
  showDescription: { $bind: { from: "content.showDescription" } },
@@ -42490,6 +42439,7 @@ const eventDetailsBlockDefinition = {
42490
42439
  dataSchemas: {
42491
42440
  eventDetailsData: z.object({
42492
42441
  events: publicEventsArraySchema,
42442
+ venueDrawing: eventVenueDrawingSchema.optional().catch(undefined),
42493
42443
  sitePasses: publicPassProductCollectionSchema,
42494
42444
  siteMemberships: publicMembershipProductCollectionSchema,
42495
42445
  autoApplyDiscount: eventAutoApplyDiscountPreviewSchema.nullable().optional().default(null)
@@ -44486,17 +44436,7 @@ function resolveCardListSchedule(item, mode) {
44486
44436
  }
44487
44437
  /** Each part owns optional-content collapse once, for calendar and catalogue items. */
44488
44438
  const partRenderers = {
44489
- title: ({ item, presentation, Title = "h3" }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Title, {
44490
- ...listLookSlot(presentation, "item-title"),
44491
- children: item.titleLink || item.href ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", {
44492
- ...item.titleLink,
44493
- href: item.titleLink?.href ?? item.href ?? undefined,
44494
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LinkedLabel, {
44495
- label: item.title,
44496
- newTabHint: item.newTabHint
44497
- })
44498
- }) : item.title
44499
- }),
44439
+ title: CardListTitle,
44500
44440
  text: ({ item, presentation }) => item.textDocument ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RichText, {
44501
44441
  doc: item.textDocument,
44502
44442
  ...listLookSlot(presentation, "item-text"),
@@ -44505,14 +44445,7 @@ const partRenderers = {
44505
44445
  ...listLookSlot(presentation, "item-text"),
44506
44446
  children: item.text
44507
44447
  }) : null,
44508
- media: ({ item, presentation }) => item.media ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
44509
- ...listLookSlot(presentation, "item-media"),
44510
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MediaNodeServer, {
44511
- value: item.media,
44512
- size: ImagePresets.card,
44513
- ...listLookSlot(presentation, "photo")
44514
- })
44515
- }) : null,
44448
+ media: CardListMedia,
44516
44449
  facts: ({ item, presentation }) => item.facts?.length ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("dl", {
44517
44450
  ...listLookSlot(presentation, "facts"),
44518
44451
  children: item.facts.map(({ label, value }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
@@ -44551,14 +44484,23 @@ const partRenderers = {
44551
44484
  ...listLookSlot(presentation, "dates"),
44552
44485
  children: item.dates.map((date, index) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", {
44553
44486
  ...listLookSlot(presentation, "date"),
44554
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("time", {
44555
- dateTime: date.startsAt,
44556
- children: date.label
44557
- }), date.places ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
44558
- ...listLookSlot(presentation, "date-places"),
44559
- "data-availability": date.places.status,
44560
- children: date.places.label
44561
- }) : null]
44487
+ children: [
44488
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("time", {
44489
+ dateTime: date.startsAt,
44490
+ children: date.label
44491
+ }),
44492
+ date.places ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
44493
+ ...listLookSlot(presentation, "date-places"),
44494
+ "data-availability": date.places.status,
44495
+ children: date.places.label
44496
+ }) : null,
44497
+ date.booking ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ThemedButtonLink, {
44498
+ ...date.booking,
44499
+ variant: presentation.buttonVariant ?? "primary",
44500
+ size: "sm",
44501
+ extraClassName: "rb-card-list-date-booking"
44502
+ }) : null
44503
+ ]
44562
44504
  }, `${date.startsAt}-${index}`))
44563
44505
  }) : null,
44564
44506
  availability: ({ item, presentation }) => item.availability ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
@@ -44591,6 +44533,41 @@ const partRenderers = {
44591
44533
  children: props$1.actionNode
44592
44534
  })
44593
44535
  };
44536
+ /** Title and photo share the same destination and external-link behavior. */
44537
+ function cardListItemLink(item) {
44538
+ return item.titleLink ?? (item.href ? { href: item.href } : null);
44539
+ }
44540
+ function CardListTitle({ item, presentation, Title = "h3" }) {
44541
+ const link$2 = cardListItemLink(item);
44542
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Title, {
44543
+ ...listLookSlot(presentation, "item-title"),
44544
+ children: link$2 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", {
44545
+ ...link$2,
44546
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LinkedLabel, {
44547
+ label: item.title,
44548
+ newTabHint: item.newTabHint
44549
+ })
44550
+ }) : item.title
44551
+ });
44552
+ }
44553
+ function CardListMedia({ item, presentation }) {
44554
+ if (!item.media) return null;
44555
+ const link$2 = cardListItemLink(item);
44556
+ const photo = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MediaNodeServer, {
44557
+ value: item.media,
44558
+ size: ImagePresets.card,
44559
+ ...listLookSlot(presentation, "photo")
44560
+ });
44561
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
44562
+ ...listLookSlot(presentation, "item-media"),
44563
+ children: link$2 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", {
44564
+ ...link$2,
44565
+ className: "rb-block rb-h-full",
44566
+ "aria-label": `${item.title}${item.newTabHint ? " (opens in a new tab)" : ""}`,
44567
+ children: photo
44568
+ }) : photo
44569
+ });
44570
+ }
44594
44571
  function CardListContentPart({ part, ...props$1 }) {
44595
44572
  return partRenderers[part](props$1);
44596
44573
  }
@@ -44671,6 +44648,56 @@ function LinkedLabel({ label, newTabHint }) {
44671
44648
  })] });
44672
44649
  }
44673
44650
 
44651
+ //#endregion
44652
+ //#region ../blocks/src/system/runtime/nodes/events/shared/EventCardIcons.tsx
44653
+ function MapPinIcon({ className, size = 16, strokeWidth = 2 }) {
44654
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", {
44655
+ className,
44656
+ width: size,
44657
+ height: size,
44658
+ viewBox: "0 0 24 24",
44659
+ fill: "none",
44660
+ stroke: "currentColor",
44661
+ strokeWidth,
44662
+ strokeLinecap: "round",
44663
+ strokeLinejoin: "round",
44664
+ "aria-hidden": "true",
44665
+ focusable: "false",
44666
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z" }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", {
44667
+ cx: "12",
44668
+ cy: "10",
44669
+ r: "3"
44670
+ })]
44671
+ });
44672
+ }
44673
+ function CalendarIcon({ className, size = 16, strokeWidth = 2 }) {
44674
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", {
44675
+ className,
44676
+ width: size,
44677
+ height: size,
44678
+ viewBox: "0 0 24 24",
44679
+ fill: "none",
44680
+ stroke: "currentColor",
44681
+ strokeWidth,
44682
+ strokeLinecap: "round",
44683
+ strokeLinejoin: "round",
44684
+ "aria-hidden": "true",
44685
+ focusable: "false",
44686
+ children: [
44687
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", {
44688
+ x: "3",
44689
+ y: "4",
44690
+ width: "18",
44691
+ height: "18",
44692
+ rx: "2"
44693
+ }),
44694
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M16 2v4" }),
44695
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M8 2v4" }),
44696
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M3 10h18" })
44697
+ ]
44698
+ });
44699
+ }
44700
+
44674
44701
  //#endregion
44675
44702
  //#region ../blocks/src/system/runtime/nodes/events/shared/EventItem.tsx
44676
44703
  /** Arrangement content choices are data, ready for other live offering lists to reuse. */
@@ -44704,6 +44731,8 @@ const eventItemParts = {
44704
44731
  "date",
44705
44732
  "title",
44706
44733
  "meta",
44734
+ "time",
44735
+ "places",
44707
44736
  "action"
44708
44737
  ],
44709
44738
  "month-day": [
@@ -44720,16 +44749,31 @@ function eventItemFacts(props$1) {
44720
44749
  date: formatEventCompactDateRail(props$1.event.startsAt, options, "as-written"),
44721
44750
  time: formatEventTimeRange(props$1.event, options),
44722
44751
  price: formatEventPrice(props$1.event),
44723
- meta: [
44724
- ...(props$1.parts ?? eventItemParts[props$1.arrangement]).includes("time") ? [] : [formatEventTimeRange(props$1.event, options)],
44725
- formatEventTeacherLine(props$1.event),
44726
- props$1.showVenue !== false ? props$1.event.venue?.name : null
44727
- ].filter(Boolean).join(" · "),
44752
+ meta: eventItemMeta(props$1),
44753
+ venueIcon: props$1.arrangement === "compact" && props$1.showVenue !== false && Boolean(props$1.event.venue),
44728
44754
  places: props$1.showCapacity ? formatEventRemainingPlaces(props$1.event, { full: "Sold out" }) : null,
44729
44755
  availability: availability.isFull ? "full" : availability.status === "filling" ? "low" : "available",
44730
44756
  description: props$1.event.presentation?.summary ?? props$1.event.description
44731
44757
  };
44732
44758
  }
44759
+ /** Compact rows keep pricing in the details rail and time in the action rail. */
44760
+ function eventItemMeta(props$1) {
44761
+ const parts = props$1.parts ?? eventItemParts[props$1.arrangement];
44762
+ const venue = props$1.showVenue !== false ? props$1.event.venue?.name : null;
44763
+ 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;
44766
+ return (props$1.arrangement === "compact" ? [
44767
+ venue,
44768
+ teacher,
44769
+ price$1,
44770
+ time
44771
+ ] : [
44772
+ time,
44773
+ teacher,
44774
+ venue
44775
+ ]).filter(Boolean).join(" · ");
44776
+ }
44733
44777
  /**
44734
44778
  * Keep one RSC component boundary per item. Re-forwarding shared presentation
44735
44779
  * props through layout/part components multiplies React's development debug
@@ -44763,15 +44807,22 @@ function renderCalendarItem(props$1) {
44763
44807
  ...listLookSlot(props$1, props$1.arrangement === "grid" ? "item-body" : "what"),
44764
44808
  children: parts.filter(body).map(renderPart)
44765
44809
  }),
44766
- parts.filter((part) => [
44810
+ renderCalendarTrailingParts(props$1, parts.filter((part) => [
44767
44811
  "time",
44768
44812
  "places",
44769
44813
  "price",
44770
44814
  "action"
44771
- ].includes(part) && !body(part)).map(renderPart)
44815
+ ].includes(part) && !body(part)), renderPart)
44772
44816
  ]
44773
44817
  });
44774
44818
  }
44819
+ function renderCalendarTrailingParts(props$1, parts, renderPart) {
44820
+ const content = parts.map(renderPart);
44821
+ return props$1.arrangement === "compact" && parts.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
44822
+ ...listLookSlot(props$1, "item-actions"),
44823
+ children: content
44824
+ }) : content;
44825
+ }
44775
44826
  function eventItemTag(arrangement) {
44776
44827
  return arrangement === "ledger" || arrangement === "day-groups" ? "li" : "article";
44777
44828
  }
@@ -44804,9 +44855,9 @@ function renderEventItemContentPart({ part, props: props$1, facts }) {
44804
44855
  children: props$1.event.title
44805
44856
  })
44806
44857
  });
44807
- case "time": return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
44858
+ case "time": return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", {
44808
44859
  ...listLookSlot(props$1, "time"),
44809
- children: facts.time
44860
+ children: [props$1.arrangement === "compact" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ClockIcon, { "aria-hidden": "true" }) : null, facts.time]
44810
44861
  });
44811
44862
  case "places": return facts.places ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
44812
44863
  ...listLookSlot(props$1, "places"),
@@ -44841,6 +44892,7 @@ function renderEventItemMeta({ props: props$1, facts }) {
44841
44892
  return facts.meta || places ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", {
44842
44893
  ...listLookSlot(props$1, "item-meta"),
44843
44894
  children: [
44895
+ facts.venueIcon ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MapPinIcon, {}) : null,
44844
44896
  facts.meta,
44845
44897
  facts.meta && places ? " · " : null,
44846
44898
  places ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
@@ -44851,13 +44903,15 @@ function renderEventItemMeta({ props: props$1, facts }) {
44851
44903
  }) : null;
44852
44904
  }
44853
44905
  function renderEventItemImage(props$1) {
44906
+ const link$2 = resolveEventLinkProps(props$1.event);
44854
44907
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CardListContentPart, {
44855
44908
  part: "media",
44856
44909
  item: {
44857
44910
  id: props$1.event.id,
44858
44911
  title: props$1.event.title,
44859
44912
  media: props$1.event.presentation?.image,
44860
- action: { label: "" }
44913
+ titleLink: link$2,
44914
+ newTabHint: link$2.target === "_blank"
44861
44915
  },
44862
44916
  presentation: props$1
44863
44917
  });
@@ -45247,106 +45301,6 @@ function cropHeightStyle(height, heightAs) {
45247
45301
  return heightAs === "minimum" ? { minHeight: height } : { height };
45248
45302
  }
45249
45303
 
45250
- //#endregion
45251
- //#region ../blocks/src/system/runtime/nodes/shared/LocationMapActions.tsx
45252
- /**
45253
- * `compact` (event details, cards and modals) keeps two small ghost buttons;
45254
- * `block` (the map block) leads with a secondary directions button and keeps
45255
- * Google Maps as a plain text link beside it.
45256
- */
45257
- function LocationMapActions(props$1) {
45258
- const links = locationMapLinks(props$1);
45259
- const directionsLabel = props$1.directionsLabel ?? "Get directions";
45260
- const googleMapsLabel = props$1.googleMapsLabel ?? "Open in Google Maps";
45261
- if (props$1.layout === "block") {
45262
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
45263
- className: "rb-location-map-actions",
45264
- children: [links.directions ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ThemedButtonLink, {
45265
- href: links.directions,
45266
- target: "_blank",
45267
- rel: "noreferrer",
45268
- variant: "secondary",
45269
- size: "sm",
45270
- label: directionsLabel
45271
- }) : null, links.googleMaps ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", {
45272
- className: "rb-location-map-link",
45273
- href: links.googleMaps,
45274
- target: "_blank",
45275
- rel: "noreferrer",
45276
- children: googleMapsLabel
45277
- }) : null]
45278
- });
45279
- }
45280
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
45281
- className: "rb-flex rb-flex-wrap rb-gap-2",
45282
- children: [links.directions ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ThemedButtonLink, {
45283
- href: links.directions,
45284
- target: "_blank",
45285
- rel: "noreferrer",
45286
- variant: "ghost",
45287
- size: "sm",
45288
- label: directionsLabel
45289
- }) : null, links.googleMaps ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ThemedButtonLink, {
45290
- href: links.googleMaps,
45291
- target: "_blank",
45292
- rel: "noreferrer",
45293
- variant: "ghost",
45294
- size: "sm",
45295
- label: googleMapsLabel
45296
- }) : null]
45297
- });
45298
- }
45299
-
45300
- //#endregion
45301
- //#region ../blocks/src/system/runtime/nodes/events/shared/EventCardIcons.tsx
45302
- function MapPinIcon({ className, size = 16, strokeWidth = 2 }) {
45303
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", {
45304
- className,
45305
- width: size,
45306
- height: size,
45307
- viewBox: "0 0 24 24",
45308
- fill: "none",
45309
- stroke: "currentColor",
45310
- strokeWidth,
45311
- strokeLinecap: "round",
45312
- strokeLinejoin: "round",
45313
- "aria-hidden": "true",
45314
- focusable: "false",
45315
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z" }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", {
45316
- cx: "12",
45317
- cy: "10",
45318
- r: "3"
45319
- })]
45320
- });
45321
- }
45322
- function CalendarIcon({ className, size = 16, strokeWidth = 2 }) {
45323
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", {
45324
- className,
45325
- width: size,
45326
- height: size,
45327
- viewBox: "0 0 24 24",
45328
- fill: "none",
45329
- stroke: "currentColor",
45330
- strokeWidth,
45331
- strokeLinecap: "round",
45332
- strokeLinejoin: "round",
45333
- "aria-hidden": "true",
45334
- focusable: "false",
45335
- children: [
45336
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", {
45337
- x: "3",
45338
- y: "4",
45339
- width: "18",
45340
- height: "18",
45341
- rx: "2"
45342
- }),
45343
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M16 2v4" }),
45344
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M8 2v4" }),
45345
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M3 10h18" })
45346
- ]
45347
- });
45348
- }
45349
-
45350
45304
  //#endregion
45351
45305
  //#region ../blocks/src/system/runtime/nodes/events/shared/EventCard.tsx
45352
45306
  /** The category's badge, when the event has a category. */
@@ -45533,20 +45487,13 @@ function EventCardVenue(props$1) {
45533
45487
  if (!venue) return null;
45534
45488
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
45535
45489
  className: "rb-mb-3",
45536
- children: [
45537
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
45538
- className: "rb-flex rb-items-center rb-gap-2 rb-caption",
45539
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(MapPinIcon, { className: "rb-shrink-0" }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: venue.name }), venue.address ? ` · ${venue.address}` : null] })]
45540
- }),
45541
- props$1.allowMap ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LocationMapActions, {
45542
- location: venue.location,
45543
- addressText: venue.address
45544
- }) : null,
45545
- props$1.showMap && props$1.allowMap && venue.location && props$1.mapSlot && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
45546
- className: "rb-mt-2",
45547
- children: props$1.mapSlot
45548
- })
45549
- ]
45490
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
45491
+ className: "rb-flex rb-items-center rb-gap-2 rb-caption",
45492
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(MapPinIcon, { className: "rb-shrink-0" }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: venue.name }), venue.address ? ` · ${venue.address}` : null] })]
45493
+ }), props$1.showMap && props$1.allowMap && venue.location && props$1.mapSlot && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
45494
+ className: "rb-mt-2",
45495
+ children: props$1.mapSlot
45496
+ })]
45550
45497
  });
45551
45498
  }
45552
45499
  function EventCardFooter(props$1) {
@@ -45835,25 +45782,33 @@ function EventQuickDates({ events, pathname, buttonVariant = "primary", dateStyl
45835
45782
  })]
45836
45783
  });
45837
45784
  }
45838
- /** Decide the formatted date and complete booking link before rendering. */
45839
- function quickDateCardPresentation(props$1) {
45840
- const event = props$1.event;
45841
- const date = formatEventQuickDate(event, props$1.dateStyle);
45785
+ /**
45786
+ * The complete link that books one date, shared by the strip and by date rows.
45787
+ * Null when the date has no registration path (closed, paused, not open yet,
45788
+ * no registration, or full with no waitlist), so no caller repeats that gate.
45789
+ */
45790
+ function eventDateBookingLink(event, pathname, dateLabel$1) {
45791
+ if (!isBookableEvent(event)) return null;
45842
45792
  const cta = resolveEventCta(event);
45843
45793
  const destination = resolveRuntimeEventDestination(event);
45844
- const ctaHref = destination.kind === "external" ? cta.href : resolveDedicatedBookingHref(props$1.pathname, {
45794
+ const href = destination.kind === "external" ? cta.href : resolveDedicatedBookingHref(pathname, {
45845
45795
  kind: "event_occurrence",
45846
45796
  occurrenceId: event.occurrenceId
45847
45797
  });
45798
+ return {
45799
+ href,
45800
+ target: cta.external ? "_blank" : undefined,
45801
+ rel: cta.external ? "noopener noreferrer" : undefined,
45802
+ "aria-label": `${cta.label} ${event.title}, ${dateLabel$1}`,
45803
+ label: cta.label
45804
+ };
45805
+ }
45806
+ /** Decide the formatted date and complete booking link before rendering. */
45807
+ function quickDateCardPresentation(props$1) {
45808
+ const date = formatEventQuickDate(props$1.event, props$1.dateStyle);
45848
45809
  return {
45849
45810
  date,
45850
- bookingLink: {
45851
- href: ctaHref,
45852
- target: cta.external ? "_blank" : undefined,
45853
- rel: cta.external ? "noopener noreferrer" : undefined,
45854
- "aria-label": `${cta.label} ${event.title}, ${date.label}`,
45855
- label: cta.label
45856
- }
45811
+ bookingLink: eventDateBookingLink(props$1.event, props$1.pathname, date.label)
45857
45812
  };
45858
45813
  }
45859
45814
  function EventQuickDateCard(props$1) {
@@ -45889,12 +45844,12 @@ function EventQuickDateCard(props$1) {
45889
45844
  children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
45890
45845
  className: "event-quick-date-price",
45891
45846
  children: formatEventPrice(event)
45892
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ThemedButtonLink, {
45847
+ }), bookingLink ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ThemedButtonLink, {
45893
45848
  variant: props$1.buttonVariant,
45894
45849
  size: "sm",
45895
45850
  extraClassName: "event-quick-date-cta",
45896
45851
  ...bookingLink
45897
- })]
45852
+ }) : null]
45898
45853
  })
45899
45854
  ]
45900
45855
  });
@@ -46417,7 +46372,7 @@ function buildEventCollectionListDisplay(source) {
46417
46372
  events: Array.isArray(source.events) ? [...source.events] : [],
46418
46373
  listLayout: source.listLayout ?? "stack",
46419
46374
  listColumns: source.listColumns ?? "3",
46420
- eventsPerPage: source.lookSlots !== undefined && source.listLayout === "compact" ? 3 : resolveEventCalendarListPageSize({ eventsPerPage: source.eventsPerPage }),
46375
+ eventsPerPage: resolveEventCalendarListPageSize({ eventsPerPage: source.eventsPerPage ?? (source.lookSlots !== undefined && source.listLayout === "compact" ? "3" : undefined) }),
46421
46376
  paginationAction,
46422
46377
  sectionAction: paginationAction.kind === "seeAllLink" ? {
46423
46378
  href: paginationAction.href,
@@ -48799,6 +48754,7 @@ const eventCalendarConfig = {
48799
48754
  icon: "CalendarDays",
48800
48755
  layout: eventCalendarLayout,
48801
48756
  variants: eventCalendarVariants,
48757
+ arrangementOwnedFieldIds: ["defaultCalendarView"],
48802
48758
  variantMeaning: eventCalendarVariantMeaning,
48803
48759
  defaultVariant: "combined",
48804
48760
  variantOptions: {
@@ -49260,6 +49216,16 @@ const offeringsPreviewFields = [
49260
49216
  schema: { fields: groupOverrideFields }
49261
49217
  },
49262
49218
  createButtonVariantField(),
49219
+ {
49220
+ id: "oneOffering",
49221
+ type: "boolean",
49222
+ label: "Show one offering with its dates",
49223
+ required: false,
49224
+ ui: {
49225
+ intent: "display",
49226
+ hidden: true
49227
+ }
49228
+ },
49263
49229
  {
49264
49230
  id: "buttonText",
49265
49231
  type: "text",
@@ -49355,6 +49321,18 @@ function buildOfferingsCatalogueListing(input) {
49355
49321
  now: input.now
49356
49322
  });
49357
49323
  }
49324
+ function offeringsCatalogueShape(listing, cards) {
49325
+ return cards.oneOfferingRequested && cards.listDates && countListedOfferings(listing) === 1 ? "single" : "several";
49326
+ }
49327
+ function countListedOfferings(listing) {
49328
+ switch (listing.kind) {
49329
+ case "no-groups":
49330
+ case "nothing-to-show": return 0;
49331
+ case "by-date": return listing.items.length;
49332
+ case "by-type": return listing.groups.reduce((count, load) => count + (load.kind === "items" ? load.items.length : 0), 0);
49333
+ default: return assertNever(listing);
49334
+ }
49335
+ }
49358
49336
  function matchesGroup(group, event) {
49359
49337
  const source = group.source;
49360
49338
  switch (source.kind) {
@@ -49430,6 +49408,10 @@ const offeringsPreviewLayout = [styledSection({
49430
49408
  carouselRegion: { $bind: { from: "content.heading" } },
49431
49409
  renderInput: { $bind: { from: "content._offeringsPreviewInput" } },
49432
49410
  displayMode: { $bind: displayModeBinding },
49411
+ oneOffering: { $bind: {
49412
+ from: "content.oneOffering",
49413
+ fallback: false
49414
+ } },
49433
49415
  pathname: { $bind: { from: "$root.pathname" } },
49434
49416
  catalogueEvents: { $bind: { from: "data.catalogueEvents" } },
49435
49417
  quickDateEvents: { $bind: { from: "data.quickDateEvents" } },
@@ -49471,6 +49453,7 @@ const offeringsPreviewLayout = [styledSection({
49471
49453
  spacing: "comfortable"
49472
49454
  })];
49473
49455
  const offeringsPreviewConfig = {
49456
+ arrangementOwnedFieldIds: ["groupOverrides.presentation"],
49474
49457
  variantMeaning: {
49475
49458
  kind: "arrangement",
49476
49459
  lookOnlyKeys: [
@@ -49527,6 +49510,7 @@ const offeringsPreviewBlockDefinition = {
49527
49510
  contentNormalizer: {
49528
49511
  fieldIds: [
49529
49512
  "displayMode",
49513
+ "oneOffering",
49530
49514
  "heading",
49531
49515
  "description",
49532
49516
  "itemLimit",
@@ -49628,6 +49612,7 @@ function normalizeOfferingsPreviewBlockContent(value) {
49628
49612
  if (!record) return { displayMode: DEFAULT_OFFERINGS_PREVIEW_DISPLAY_MODE };
49629
49613
  const normalized = {
49630
49614
  displayMode: normalizeOfferingsPreviewDisplayMode(record.displayMode),
49615
+ ...oneOfferingContent(record.oneOffering),
49631
49616
  ...normalizeCardListContent(record)
49632
49617
  };
49633
49618
  if (typeof record.heading === "string" || record.heading === null) {
@@ -49668,6 +49653,9 @@ function normalizeOfferingsPreviewBlockContent(value) {
49668
49653
  }
49669
49654
  return normalized;
49670
49655
  }
49656
+ function oneOfferingContent(value) {
49657
+ return typeof value === "boolean" || value === null ? { oneOffering: value } : {};
49658
+ }
49671
49659
  function normalizeOfferingsPreviewDisplayMode(value) {
49672
49660
  return value === "catalogue" ? "catalogue" : DEFAULT_OFFERINGS_PREVIEW_DISPLAY_MODE;
49673
49661
  }
@@ -52146,7 +52134,7 @@ const shopBlockRuntime = defineProgressiveBlockRuntime({
52146
52134
  buildRender: (source) => {
52147
52135
  const passPurchaseMode = source.passPurchaseMode ?? "add_to_cart";
52148
52136
  const subscribeButtonText = source.subscribeButtonText ?? "Subscribe";
52149
- const products = shopDisplayedProducts(source);
52137
+ const products = decideShopDisplayedCatalogue(source);
52150
52138
  const dateContext = source.dateContext ?? resolveDateRuntimeContext(undefined);
52151
52139
  return {
52152
52140
  display: buildPassesMembershipsDisplay({
@@ -52423,16 +52411,18 @@ function shopCardListPresentation(source) {
52423
52411
  [key]: source[key]
52424
52412
  }), {});
52425
52413
  }
52426
- function shopDisplayedProducts(source) {
52414
+ function decideShopDisplayedCatalogue(source) {
52415
+ const passes = source.showPasses === false ? [] : source.passes ?? [];
52416
+ const memberships = source.showMemberships === false ? [] : source.memberships ?? [];
52417
+ const featured = [...passes, ...memberships].some(({ id }) => id === source.featured) ? source.featured ?? null : null;
52427
52418
  return {
52428
- passes: source.showPasses === false ? [] : source.passes ?? [],
52429
- memberships: source.showMemberships === false ? [] : source.memberships ?? []
52419
+ passes,
52420
+ memberships,
52421
+ featured
52430
52422
  };
52431
52423
  }
52432
52424
  function shopFeaturedProduct(source, products) {
52433
- const selectedId = source.featured;
52434
- const visible = [...products.passes, ...products.memberships].some(({ id }) => id === selectedId);
52435
- return source.lookSlots && source.itemRoles?.featured && selectedId && visible ? { featured: selectedId } : {};
52425
+ return source.lookSlots && source.itemRoles?.featured && products.featured !== null ? { featured: products.featured } : {};
52436
52426
  }
52437
52427
  /** Server and hydrated cards share the same decided role and featured marker. */
52438
52428
  function shopProductPresentation(hydration, productId, index, count) {
@@ -52463,6 +52453,7 @@ function shopProductPresentation(hydration, productId, index, count) {
52463
52453
  * - Stripe handles payment security
52464
52454
  */
52465
52455
  const shopManifest = createBlockManifest({
52456
+ arrangementOwnedFieldIds: ["layout", "columns"],
52466
52457
  variantMeaning: {
52467
52458
  kind: "arrangement",
52468
52459
  lookOnlyKeys: [
@@ -54152,6 +54143,18 @@ const wrapVariant = (variantLayout) => styledSection({
54152
54143
  baseClass: "",
54153
54144
  spacing: "comfortable"
54154
54145
  });
54146
+ const cardBiographyFallbackNode = richText({ className: "rb-prose rb-max-w-none" }, when("content.cardBiography", { equals: "any" }), bind(ITEM_NAME, { transforms: [{ id: "teamMember.cardBiographyFallback" }] }));
54147
+ const teamMemberGridLayout = withCardBiographyFallback(teamMemberFragment.layout);
54148
+ function withCardBiographyFallback(layout) {
54149
+ const roots = Array.isArray(layout) ? layout : [layout];
54150
+ const [card] = roots;
54151
+ if (!card || roots.length !== 1) throw new Error("teamMember fragment must have one root node");
54152
+ const children = card.children ?? [];
54153
+ return {
54154
+ ...card,
54155
+ children: [...children, cardBiographyFallbackNode]
54156
+ };
54157
+ }
54155
54158
  const teamMemberStackLayout = el("div", { className: "rb-team-member rb-team-member--stack rb-flex rb-flex-col rb-md-flex-row rb-items-start rb-gap-3" }, [el("div", { className: "rb-team-member-photo-col rb-w-full rb-shrink-0" }, [el("div", { className: memberPhotoClassName("rb-team-member-photo-wrap rb-w-full") }, [media({
54156
54159
  className: "rb-team-member-photo rb-w-full rb-object-cover",
54157
54160
  style: { aspectRatio: "1 / 1" },
@@ -54174,12 +54177,42 @@ const teamMemberStackLayout = el("div", { className: "rb-team-member rb-team-mem
54174
54177
  as: "p",
54175
54178
  className: "rb-team-member-role"
54176
54179
  }, when("role"), bind("role")),
54177
- richText({ className: "rb-prose rb-max-w-none" }, when("bio"), bind("bio"))
54180
+ richText({ className: "rb-prose rb-max-w-none" }, when("bio"), bind("bio")),
54181
+ cardBiographyFallbackNode
54178
54182
  ])]);
54183
+ const onePersonAboutWhen = { equals: "about" };
54184
+ const notOnePersonAboutWhen = {
54185
+ equals: "about",
54186
+ not: true
54187
+ };
54188
+ const aboutVariant = styledSection({
54189
+ children: sectionContainer([el("div", {
54190
+ className: "rb-team-layout",
54191
+ "data-one-person": "about"
54192
+ }, [el("div", { className: "rb-team-head" }, [headingNode], when("content.heading")), el("team-members", {
54193
+ onePerson: { $bind: { from: "content.onePerson" } },
54194
+ source: { $bind: {
54195
+ from: "content.source",
54196
+ fallback: "manual"
54197
+ } },
54198
+ members: { $bind: {
54199
+ from: "content.members",
54200
+ fallback: []
54201
+ } },
54202
+ siteMembers: { $bind: {
54203
+ from: "data.members",
54204
+ fallback: []
54205
+ } },
54206
+ sectionHeading: { $bind: { from: "content.heading" } }
54207
+ })])], { gap: "md" }),
54208
+ baseClass: "",
54209
+ spacing: "comfortable"
54210
+ });
54179
54211
  const manualGridMembersNode = when("content.source", manualSourceWhen)(repeaterFragmentLayout({
54180
54212
  collectionPath: "content.members",
54181
54213
  itemName: ITEM_NAME,
54182
54214
  fragments: { teamMember: teamMemberFragment },
54215
+ layoutOverrides: { teamMember: teamMemberGridLayout },
54183
54216
  itemGap: "sm",
54184
54217
  itemClassName: memberCardClassName
54185
54218
  }));
@@ -54187,6 +54220,7 @@ const dynamicGridMembersNode = when("content.source", dynamicSourceWhen)(repeate
54187
54220
  collectionPath: "data.members",
54188
54221
  itemName: ITEM_NAME,
54189
54222
  fragments: { teamMember: teamMemberFragment },
54223
+ layoutOverrides: { teamMember: teamMemberGridLayout },
54190
54224
  itemGap: "sm",
54191
54225
  itemClassName: memberCardClassName
54192
54226
  }));
@@ -54222,14 +54256,23 @@ const stackVariant = wrapVariant({
54222
54256
  children: [manualStackMembersNode, dynamicStackMembersNode]
54223
54257
  });
54224
54258
  const cardListVariant = styledSection({
54225
- children: sectionContainer([el("div", { ...lookSlot("layout") }, [
54226
- el("div", { ...lookSlot("head") }, [text({
54259
+ children: sectionContainer([el("div", {
54260
+ className: "rb-team-layout",
54261
+ ...lookSlot("layout"),
54262
+ "data-one-person": { $bind: { from: "content.onePerson" } }
54263
+ }, [
54264
+ el("div", {
54265
+ className: "rb-team-head",
54266
+ ...lookSlot("head")
54267
+ }, [text({
54227
54268
  as: "h2",
54228
54269
  ...lookSlot("heading")
54229
54270
  }, bind("content.heading"), when("content.heading"))], when("content.heading")),
54230
54271
  el("team-members", {
54231
54272
  ...cardListPresentationBindings,
54232
54273
  biographySource: { $bind: { from: "content._effectiveLook.look.structure.teamBiography" } },
54274
+ onePerson: { $bind: { from: "content.onePerson" } },
54275
+ cardBiography: { $bind: { from: "content.cardBiography" } },
54233
54276
  source: { $bind: {
54234
54277
  from: "content.source",
54235
54278
  fallback: "manual"
@@ -54303,6 +54346,37 @@ const teamMembersManifest = createBlockManifest({
54303
54346
  }],
54304
54347
  ui: { intent: "behavior" }
54305
54348
  }),
54349
+ parseFieldDefinition({
54350
+ id: "onePerson",
54351
+ type: "select",
54352
+ label: "One person",
54353
+ required: false,
54354
+ options: [{
54355
+ value: "about",
54356
+ label: "The section is about them, with their bio"
54357
+ }, {
54358
+ value: "portrait",
54359
+ label: "One small portrait"
54360
+ }],
54361
+ ui: {
54362
+ intent: "display",
54363
+ hidden: true
54364
+ }
54365
+ }),
54366
+ parseFieldDefinition({
54367
+ id: "cardBiography",
54368
+ type: "select",
54369
+ label: "Card bio",
54370
+ required: false,
54371
+ options: [{
54372
+ value: "any",
54373
+ label: "Whichever bio the person has"
54374
+ }],
54375
+ ui: {
54376
+ intent: "display",
54377
+ hidden: true
54378
+ }
54379
+ }),
54306
54380
  parseFieldDefinition({
54307
54381
  id: "layoutAlign",
54308
54382
  type: "select",
@@ -54448,10 +54522,19 @@ const teamMembersManifest = createBlockManifest({
54448
54522
  ],
54449
54523
  layout: gridVariant,
54450
54524
  variants: {
54451
- grid: gridVariant,
54525
+ grid: [when("content.onePerson", notOnePersonAboutWhen)(gridVariant), when("content.onePerson", onePersonAboutWhen)(aboutVariant)],
54452
54526
  stack: [when("content._effectiveLook", { not: true })(stackVariant), when("content._effectiveLook")(cardListVariant)],
54453
54527
  ...Object.fromEntries(arrangementOnlyKeys.map((key) => [key, cardListVariant]))
54454
54528
  },
54529
+ arrangementOwnedFieldIds: [
54530
+ "layoutWidth",
54531
+ "thumbnailShape",
54532
+ "thumbnailPadding",
54533
+ "imageColSize",
54534
+ "stackImagePosition",
54535
+ "stackContentAlignment",
54536
+ "gap"
54537
+ ],
54455
54538
  variantMeaning: {
54456
54539
  kind: "arrangement",
54457
54540
  lookOnlyKeys: [...arrangementOnlyKeys]
@@ -55874,6 +55957,58 @@ function clearBlockDefinitions() {
55874
55957
  resetSystemBlockDefinitionRegistration();
55875
55958
  }
55876
55959
 
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
+
55877
56012
  //#endregion
55878
56013
  //#region ../blocks/src/system/data/selectBlockContent.ts
55879
56014
  /** Canonical admitted content: legacy publishedContent never selects a version. */
@@ -56056,7 +56191,7 @@ function toEditorPresentationPage(page) {
56056
56191
  */
56057
56192
  function resolveArrangementKnobs(input) {
56058
56193
  const length = input.blockKind === "block.hero" ? resolveHeroTitleLength({ ...input.content }, "look") : null;
56059
- const exposure = arrangementKnobExposure(input.blockKind, input.look, length);
56194
+ const exposure = arrangementKnobExposure(input.blockKind, input.look, length, storedSplitPhotoSide(input.blockKind, input.content));
56060
56195
  const knobs = resolveEffectiveKnobs({
56061
56196
  exposure,
56062
56197
  content: normalizedHeadlinePreference(input.content)
@@ -56071,15 +56206,16 @@ function resolveArrangementKnobs(input) {
56071
56206
  function arrangementKnobChoices(exposure) {
56072
56207
  return exposure.definition.values.filter((value) => (exposure.lookValues?.includes(value) ?? true) && (exposure.styleValues?.includes(value) ?? true));
56073
56208
  }
56074
- function arrangementKnobExposure(blockKind, look, length) {
56209
+ function arrangementKnobExposure(blockKind, look, length, splitPhotoSide) {
56075
56210
  return systemCustomizeFacetDefinitionsForBlock(blockKind).flatMap((facet) => {
56076
56211
  if (facet.knob === undefined || facet.target.kind !== "content-field") return [];
56077
56212
  const id = facet.target.field;
56078
56213
  const defaults = look.look.structure.knobDefaults ?? {};
56214
+ const storedDefault = id === "imagePosition" ? splitPhotoSide : null;
56079
56215
  return [{
56080
56216
  definition: {
56081
56217
  id,
56082
- defaultValue: defaults[id] ?? facet.defaultValue,
56218
+ defaultValue: defaults[id] ?? storedDefault ?? facet.defaultValue,
56083
56219
  values: facet.values.map((value) => value.value),
56084
56220
  ...knobKindMetadata(facet.knob)
56085
56221
  },
@@ -56091,6 +56227,19 @@ function arrangementKnobExposure(blockKind, look, length) {
56091
56227
  }];
56092
56228
  });
56093
56229
  }
56230
+ /**
56231
+ * A hero stored as "Split, photo on the left" or "Split, photo on the right"
56232
+ * already says which side its photo is on. Under a Look that side is the Photo
56233
+ * side default, so the photo stays where it was until the owner picks a side.
56234
+ */
56235
+ function storedSplitPhotoSide(blockKind, content) {
56236
+ if (blockKind !== "block.hero") return null;
56237
+ switch (content.variant) {
56238
+ case "split": return "left";
56239
+ case "splitReverse": return "right";
56240
+ default: return null;
56241
+ }
56242
+ }
56094
56243
  function knobKindMetadata(knob) {
56095
56244
  return knob.kind === "fixed" ? { ordered: knob.ordered } : {
56096
56245
  ordered: false,
@@ -56299,7 +56448,10 @@ const systemCustomizeFacetDefinitions = [
56299
56448
  ], "icons"),
56300
56449
  blockKinds: cardListFamilyBlocks
56301
56450
  },
56302
- fixedKnob("block.event-calendar", "showCapacity", "Show places left", onOff, "true", false, true)
56451
+ {
56452
+ ...fixedKnob("block.event-calendar", "showCapacity", "Places left", onOff, "true", false, true),
56453
+ description: "Show how many places are left on each event"
56454
+ }
56303
56455
  ];
56304
56456
  const systemCustomizeFacetIds = systemCustomizeFacetDefinitions.map((definition$1) => definition$1.id);
56305
56457
  const systemCustomizeFacetValues = Array.from(new Set(systemCustomizeFacetDefinitions.flatMap((definition$1) => definition$1.values.map((option) => option.value))));
@@ -57894,6 +58046,45 @@ function renderMark(mark, key, child) {
57894
58046
  }
57895
58047
  }
57896
58048
 
58049
+ //#endregion
58050
+ //#region ../blocks/src/system/runtime/nodes/shared/LocationMapActions.tsx
58051
+ /**
58052
+ * `compact` (event details) is one plain Google Maps text link under the venue;
58053
+ * `block` (the map block) leads with a secondary directions button and keeps
58054
+ * the same Google Maps text link beside it.
58055
+ */
58056
+ function LocationMapActions(props$1) {
58057
+ const links = locationMapLinks(props$1);
58058
+ const directionsLabel = props$1.directionsLabel ?? "Get directions";
58059
+ const googleMapsLabel = props$1.googleMapsLabel ?? "Open in Google Maps";
58060
+ if (props$1.layout === "block") {
58061
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
58062
+ className: "rb-location-map-actions",
58063
+ children: [links.directions ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ThemedButtonLink, {
58064
+ href: links.directions,
58065
+ target: "_blank",
58066
+ rel: "noreferrer",
58067
+ variant: "secondary",
58068
+ size: "sm",
58069
+ label: directionsLabel
58070
+ }) : null, links.googleMaps ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", {
58071
+ className: "rb-location-map-link",
58072
+ href: links.googleMaps,
58073
+ target: "_blank",
58074
+ rel: "noreferrer",
58075
+ children: googleMapsLabel
58076
+ }) : null]
58077
+ });
58078
+ }
58079
+ return links.googleMaps ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", {
58080
+ className: "rb-location-map-link",
58081
+ href: links.googleMaps,
58082
+ target: "_blank",
58083
+ rel: "noreferrer",
58084
+ children: googleMapsLabel
58085
+ }) }) : null;
58086
+ }
58087
+
57897
58088
  //#endregion
57898
58089
  //#region ../blocks/src/system/runtime/nodes/location-map.view.tsx
57899
58090
  function OpeningHoursTable({ hours: hours$1, lookLayout }) {
@@ -59059,6 +59250,15 @@ const publicAppointmentServicesSchema = z.union([z.array(publicAppointmentServic
59059
59250
  services: z.array(publicAppointmentServiceSchema),
59060
59251
  categories: z.array(publicServiceCategorySchema)
59061
59252
  })]);
59253
+ /**
59254
+ * How many services the loader's data lists, or null when the data isn't the
59255
+ * catalogue at all (a failed load). For composers deciding whether the block
59256
+ * has anything to show, so they read the data the way the block does.
59257
+ */
59258
+ function countPublicAppointmentServices(value) {
59259
+ const result = publicAppointmentServicesSchema.safeParse(value);
59260
+ return result.success ? result.data.services.length : null;
59261
+ }
59062
59262
  const EMPTY_MESSAGE = "No appointments are available right now.";
59063
59263
  const ERROR_MESSAGE = "Appointments are temporarily unavailable. Please try again shortly.";
59064
59264
  const OTHER_GROUP_KEY = "other";
@@ -59407,16 +59607,6 @@ function appointmentServicesListing(view, arrangement) {
59407
59607
  } : view;
59408
59608
  }
59409
59609
 
59410
- //#endregion
59411
- //#region ../blocks/src/system/blocks/shared/teamMembers.ts
59412
- const teamMemberSpecialtiesInputSchema = z.union([z.string(), z.array(z.string())]).nullish();
59413
- function parseTeamMemberSpecialties(value) {
59414
- const parsed = teamMemberSpecialtiesInputSchema.safeParse(value);
59415
- if (!parsed.success) return [];
59416
- const parts = typeof parsed.data === "string" ? parsed.data.split(/\r?\n|,/) : parsed.data ?? [];
59417
- return [...new Set(parts.map((part) => part.trim()).filter(Boolean))];
59418
- }
59419
-
59420
59610
  //#endregion
59421
59611
  //#region ../blocks/src/system/runtime/nodes/team-members.tsx
59422
59612
  const teamMemberCardSchema = z.object({
@@ -59426,12 +59616,13 @@ const teamMemberCardSchema = z.object({
59426
59616
  bio: z.union([z.string(), RichTextDocSchema]).nullish(),
59427
59617
  profileBio: RichTextDocSchema.nullish(),
59428
59618
  photo: runtimeMediaSchema.refine((value) => value.type === "image").nullish(),
59619
+ summary: z.string().nullish(),
59429
59620
  profilePath: z.string().nullish(),
59430
59621
  specialties: z.unknown().transform(parseTeamMemberSpecialties)
59431
59622
  });
59432
59623
  /** Staff and manual members meet at one boundary; Look data chooses biography length. */
59433
- function teamMemberCardContent(member, index, biographySource) {
59434
- const biography = biographySource === "profile" && member.profileBio ? member.profileBio : member.bio;
59624
+ function teamMemberCardContent(member, index, biographySource, cardBiography) {
59625
+ const biography = cardBiography === "any" ? cardText(teamMemberCardBiography(member)) : biographySource === "profile" && member.profileBio ? member.profileBio : member.bio;
59435
59626
  const href = sanitizeHref(member.profilePath);
59436
59627
  return {
59437
59628
  id: member.id ?? `member-${index}`,
@@ -59449,12 +59640,84 @@ function teamMemberCardContent(member, index, biographySource) {
59449
59640
  } } : {}
59450
59641
  };
59451
59642
  }
59643
+ function cardText(biography) {
59644
+ if (!biography) return null;
59645
+ return biography.kind === "document" ? biography.document : biography.paragraphs.join("\n\n");
59646
+ }
59647
+ /**
59648
+ * The quiet line under an "About" heading: the person's name and role. The
59649
+ * name is left out when the heading already says it, so it isn't read twice.
59650
+ */
59651
+ function teamMemberAboutLine(input) {
59652
+ const name = input.name.trim();
59653
+ const said = name.length > 0 && (input.heading ?? "").toLocaleLowerCase().includes(name.toLocaleLowerCase());
59654
+ const parts = [said ? "" : name, input.role?.trim() ?? ""].filter(Boolean);
59655
+ return parts.length > 0 ? parts.join(", ") : null;
59656
+ }
59657
+ /** The one person a section can be about: the list's only member, with a bio to read. */
59658
+ function personToWriteAbout(members) {
59659
+ const [member, ...others] = members;
59660
+ const biography = member && others.length === 0 ? teamMemberBiography(member) : null;
59661
+ return member && biography ? {
59662
+ member,
59663
+ biography
59664
+ } : null;
59665
+ }
59666
+ /**
59667
+ * One person given the section: their photo in the look's frame, a name and
59668
+ * role line, and their bio in full. The section's heading stays where the
59669
+ * block puts it; the stylesheet sets it beside the photo.
59670
+ */
59671
+ function TeamMemberAbout({ member, biography, props: props$1 }) {
59672
+ const line = teamMemberAboutLine({
59673
+ heading: props$1.sectionHeading,
59674
+ name: member.name,
59675
+ role: member.role
59676
+ });
59677
+ const photo = props$1.showPhotos === false ? null : member.photo;
59678
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
59679
+ className: "rb-team-about",
59680
+ "data-team-about": true,
59681
+ "data-has-photo": String(Boolean(photo)),
59682
+ children: [
59683
+ photo ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
59684
+ className: "rb-team-about-photo",
59685
+ ...listLookSlot(props$1, "item-media"),
59686
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MediaNodeServer, {
59687
+ value: photo,
59688
+ size: ImagePresets.hero,
59689
+ ...listLookSlot(props$1, "photo")
59690
+ })
59691
+ }) : null,
59692
+ line ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
59693
+ className: "rb-team-about-line",
59694
+ ...listLookSlot(props$1, "item-meta"),
59695
+ children: line
59696
+ }) : null,
59697
+ biography.kind === "document" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RichText, {
59698
+ doc: biography.document,
59699
+ className: "rb-team-about-bio",
59700
+ ...listLookSlot(props$1, "item-text"),
59701
+ lookSlots: props$1.lookSlots
59702
+ }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
59703
+ className: "rb-team-about-bio",
59704
+ ...listLookSlot(props$1, "item-text"),
59705
+ children: biography.paragraphs.map((paragraph, index) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { children: paragraph }, index))
59706
+ })
59707
+ ]
59708
+ });
59709
+ }
59452
59710
  function TeamMembersNode(props$1) {
59453
59711
  const parsed = z.array(teamMemberCardSchema).safeParse(props$1.source === "site_staff" ? props$1.siteMembers : props$1.members);
59454
59712
  if (!parsed.success) return null;
59713
+ const about = props$1.onePerson === "about" ? personToWriteAbout(parsed.data) : null;
59714
+ if (about) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TeamMemberAbout, {
59715
+ ...about,
59716
+ props: props$1
59717
+ });
59455
59718
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CardListItems, {
59456
59719
  Carousel: props$1.Carousel,
59457
- items: parsed.data.map((member, index) => teamMemberCardContent(member, index, props$1.biographySource)),
59720
+ items: parsed.data.map((member, index) => teamMemberCardContent(member, index, props$1.biographySource, props$1.cardBiography)),
59458
59721
  presentation: {
59459
59722
  ...props$1,
59460
59723
  bodyParts: [
@@ -59585,77 +59848,68 @@ function getBookingRedirectStateFromLocation(location) {
59585
59848
  return { kind: "none" };
59586
59849
  }
59587
59850
  function resolveAppointmentCheckoutVerificationState(input) {
59588
- if (!input.config) {
59589
- return { tag: "idle" };
59851
+ if (!input.config) return { tag: "idle" };
59852
+ const sessionId = input.config.sessionId;
59853
+ if (input.pollingStatus === "completed") {
59854
+ const confirmed = confirmedAppointmentCheckout(sessionId, input.result);
59855
+ if (confirmed) return confirmed;
59590
59856
  }
59591
59857
  const appointmentId = input.result?.appointmentId ?? null;
59592
- const paymentStatus = input.result?.paymentStatus ?? null;
59593
- const appointmentStatus = input.result?.appointmentStatus ?? null;
59594
- if (input.pollingStatus === "completed" && appointmentId && (paymentStatus === "completed" || paymentStatus === "not_required")) {
59595
- return {
59596
- tag: "confirmed",
59597
- sessionId: input.config.sessionId,
59598
- appointmentId,
59599
- resourceName: input.result?.resourceName ?? null,
59600
- paymentStatus
59601
- };
59602
- }
59603
- if (input.pollingStatus === "timeout") {
59604
- return {
59858
+ switch (input.pollingStatus) {
59859
+ case "timeout": return {
59605
59860
  tag: "timeout",
59606
- sessionId: input.config.sessionId,
59861
+ sessionId,
59607
59862
  appointmentId,
59608
59863
  message: checkoutCopy.checkoutStillConfirming
59609
59864
  };
59610
- }
59611
- if (input.pollingStatus === "failed") {
59612
- if (paymentStatus === "refunded") {
59613
- return {
59614
- tag: "failed",
59615
- sessionId: input.config.sessionId,
59616
- reason: "payment_refunded",
59617
- message: "Payment was refunded. Please contact support.",
59618
- appointmentId
59619
- };
59620
- }
59621
- if (paymentStatus === "cancelled") {
59622
- return {
59623
- tag: "failed",
59624
- sessionId: input.config.sessionId,
59625
- reason: "checkout_cancelled",
59626
- message: "Checkout was cancelled before the appointment could be confirmed.",
59627
- appointmentId
59628
- };
59629
- }
59630
- if (appointmentStatus === "cancelled") {
59631
- return {
59632
- tag: "failed",
59633
- sessionId: input.config.sessionId,
59634
- reason: "appointment_cancelled",
59635
- message: "The appointment was cancelled before it could be confirmed.",
59636
- appointmentId
59637
- };
59638
- }
59639
- if (paymentStatus === "failed") {
59640
- return {
59641
- tag: "failed",
59642
- sessionId: input.config.sessionId,
59643
- reason: "payment_failed",
59644
- message: "Payment could not be verified. Please try again.",
59645
- appointmentId
59646
- };
59647
- }
59648
- return {
59865
+ case "failed": return {
59649
59866
  tag: "failed",
59650
- sessionId: input.config.sessionId,
59651
- reason: "unknown",
59652
- message: input.error?.message ?? "Payment could not be verified. Please try again.",
59653
- appointmentId
59867
+ sessionId,
59868
+ appointmentId,
59869
+ ...appointmentCheckoutFailure(input.result, input.error)
59870
+ };
59871
+ case "completed":
59872
+ case "idle":
59873
+ case "polling": return {
59874
+ tag: "verifying",
59875
+ sessionId
59654
59876
  };
59655
59877
  }
59878
+ }
59879
+ /** Verified payment carries its booked facts instead of asking the view to rebuild them. */
59880
+ function confirmedAppointmentCheckout(sessionId, result) {
59881
+ if (!result || !result.appointmentId) return null;
59882
+ if (result.paymentStatus !== "completed" && result.paymentStatus !== "not_required") return null;
59883
+ return {
59884
+ tag: "confirmed",
59885
+ sessionId,
59886
+ appointmentId: result.appointmentId,
59887
+ appointment: result.appointment,
59888
+ resourceName: result.resourceName,
59889
+ paymentStatus: result.paymentStatus
59890
+ };
59891
+ }
59892
+ /** Failure priority is shared by every polling failure, including missing provider evidence. */
59893
+ function appointmentCheckoutFailure(result, error$1) {
59894
+ if (result?.paymentStatus === "refunded") return {
59895
+ reason: "payment_refunded",
59896
+ message: "Payment was refunded. Please contact support."
59897
+ };
59898
+ if (result?.paymentStatus === "cancelled") return {
59899
+ reason: "checkout_cancelled",
59900
+ message: "Checkout was cancelled before the appointment could be confirmed."
59901
+ };
59902
+ if (result?.appointmentStatus === "cancelled") return {
59903
+ reason: "appointment_cancelled",
59904
+ message: "The appointment was cancelled before it could be confirmed."
59905
+ };
59906
+ if (result?.paymentStatus === "failed") return {
59907
+ reason: "payment_failed",
59908
+ message: "Payment could not be verified. Please try again."
59909
+ };
59656
59910
  return {
59657
- tag: "verifying",
59658
- sessionId: input.config.sessionId
59911
+ reason: "unknown",
59912
+ message: error$1?.message ?? "Payment could not be verified. Please try again."
59659
59913
  };
59660
59914
  }
59661
59915
  function deriveBookingFormViewState(input) {
@@ -60733,12 +60987,6 @@ function parseLimit$1(value, fallback) {
60733
60987
  const n$1 = typeof value === "string" ? parseInt(value, 10) : typeof value === "number" ? value : NaN;
60734
60988
  return Number.isFinite(n$1) && n$1 > 0 ? n$1 : fallback;
60735
60989
  }
60736
- function isFutureOrNow(iso, nowIso) {
60737
- const ts = Date.parse(iso);
60738
- const now = Date.parse(nowIso);
60739
- if (!Number.isFinite(ts) || !Number.isFinite(now)) return false;
60740
- return ts >= now;
60741
- }
60742
60990
  function uniqByOccurrenceId(events) {
60743
60991
  const seen = new Set();
60744
60992
  const out = [];
@@ -60750,45 +60998,6 @@ function uniqByOccurrenceId(events) {
60750
60998
  }
60751
60999
  return out;
60752
61000
  }
60753
- function selectFromOccurrenceContext(events, occurrenceContext) {
60754
- if (!occurrenceContext) return null;
60755
- const byId = events.find((event) => event.occurrenceId === occurrenceContext.id || event.id === occurrenceContext.id);
60756
- if (byId) return byId;
60757
- const contextDate = getBookingLocalDateKey(toScheduledBookingDateTime({
60758
- startsAt: occurrenceContext.startsAt,
60759
- timeZone: occurrenceContext.timeZone
60760
- }));
60761
- return events.find((event) => getBookingLocalDateKey(toScheduledBookingDateTime({
60762
- startsAt: event.startsAt,
60763
- timeZone: event.timeZone
60764
- })) === contextDate) ?? null;
60765
- }
60766
- function selectNextUpcoming(events, nowIso) {
60767
- return [...events].filter((event) => isFutureOrNow(event.startsAt, nowIso)).sort((left, right) => Date.parse(left.startsAt) - Date.parse(right.startsAt))[0] ?? null;
60768
- }
60769
- function selectCompletedWholeSeries(events) {
60770
- if (events.length === 0 || !events.every((event) => event.bookingScope === "whole_series")) {
60771
- return null;
60772
- }
60773
- return [...events].sort((left, right) => Date.parse(right.startsAt) - Date.parse(left.startsAt))[0] ?? null;
60774
- }
60775
- function selectEventCandidate(events, occurrenceContext, nowIso) {
60776
- const selected = selectFromOccurrenceContext(events, occurrenceContext);
60777
- if (selected) return {
60778
- event: selected,
60779
- mode: "selected"
60780
- };
60781
- const upcoming = selectNextUpcoming(events, nowIso);
60782
- if (upcoming) return {
60783
- event: upcoming,
60784
- mode: "next"
60785
- };
60786
- const completed = selectCompletedWholeSeries(events);
60787
- return completed ? {
60788
- event: completed,
60789
- mode: "completed"
60790
- } : null;
60791
- }
60792
61001
  function isWholeSeriesEvent(event) {
60793
61002
  return event.bookingScope === "whole_series";
60794
61003
  }
@@ -60823,7 +61032,7 @@ function selectEventDetails(args) {
60823
61032
  const all = uniqByOccurrenceId(scopedEvents);
60824
61033
  const occurrenceContext = args.occurrenceContext ?? null;
60825
61034
  const otherLimit = parseLimit$1(args.otherDatesLimit, 5);
60826
- const candidate = selectEventCandidate(all, occurrenceContext, args.nowIso);
61035
+ const candidate = selectEventDetailsCandidate(all, occurrenceContext, args.nowIso);
60827
61036
  const rawTz = candidate?.event.timeZone ?? all[0]?.timeZone ?? null;
60828
61037
  const timeZone = toBookingTimeZone(rawTz);
60829
61038
  if (!candidate) return emptySelection(timeZone);
@@ -60890,6 +61099,10 @@ function resolveEligibility(input, selected) {
60890
61099
  applicableMemberships: filterMembershipsForEvent(input.siteMemberships?.memberships ?? null, selected)
60891
61100
  };
60892
61101
  }
61102
+ /** The response's one drawing belongs to the selected event only when it is for that event's venue. */
61103
+ function resolveSelectedVenueDrawing(venueDrawing, selected) {
61104
+ return venueDrawing && selected?.venue?.id === venueDrawing.venueId ? venueDrawing.drawing : null;
61105
+ }
60893
61106
  function resolveEventDetailsPresentation(input) {
60894
61107
  const selection = resolveSelection(input);
60895
61108
  const selected = selection.kind === "empty" ? null : selection.selected;
@@ -60903,7 +61116,8 @@ function resolveEventDetailsPresentation(input) {
60903
61116
  panelHeading: input.panelHeading,
60904
61117
  ...resolveDisplaySettings(input),
60905
61118
  ...resolveEligibility(input, selected),
60906
- autoApplyDiscount: input.autoApplyDiscount ?? null
61119
+ autoApplyDiscount: input.autoApplyDiscount ?? null,
61120
+ selectedVenueDrawing: resolveSelectedVenueDrawing(input.venueDrawing, selected)
60907
61121
  };
60908
61122
  }
60909
61123
 
@@ -61490,10 +61704,10 @@ function acceptedProductNames(props$1) {
61490
61704
  const memberships = props$1.showAcceptedMemberships !== false ? (props$1.applicableMemberships ?? []).map(({ name }) => name) : [];
61491
61705
  return [...passes, ...memberships];
61492
61706
  }
61493
- function EventVenueMap({ venue, showMap, mapHeight, mapClassName }) {
61494
- if (!showMap || !venue?.drawing) return null;
61707
+ function EventVenueMap({ venue, drawing, showMap, mapHeight, mapClassName }) {
61708
+ if (!showMap || !venue || !drawing) return null;
61495
61709
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MapDrawingSvg, {
61496
- drawing: venue.drawing,
61710
+ drawing,
61497
61711
  label: venue.name,
61498
61712
  className: mapClassName,
61499
61713
  height: mapHeight
@@ -61544,7 +61758,8 @@ function SelectedEventDetailsView(props$1) {
61544
61758
  venue,
61545
61759
  showMap,
61546
61760
  mapHeight,
61547
- mapClassName
61761
+ mapClassName,
61762
+ drawing: props$1.selectedVenueDrawing
61548
61763
  })]
61549
61764
  }),
61550
61765
  showOtherDates ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(OtherEventDates, { selection }) : null
@@ -61569,6 +61784,7 @@ function LegacyEventDetailsView(props$1) {
61569
61784
  showDescription: props$1.showDescription ?? false,
61570
61785
  showCapacity: props$1.showCapacity ?? false,
61571
61786
  autoApplyDiscount: props$1.autoApplyDiscount ?? null,
61787
+ selectedVenueDrawing: props$1.selectedVenueDrawing,
61572
61788
  mapHeight: props$1.mapHeight ?? 200,
61573
61789
  mapClassName: props$1.mapClassName ?? "event-details-map",
61574
61790
  acceptedItems: acceptedProductNames(props$1)
@@ -61624,6 +61840,7 @@ function EventDetailsHydration({ props: props$1, presentation, scopedEvents, sub
61624
61840
  occurrenceContext: props$1.occurrenceContext ?? null,
61625
61841
  subject,
61626
61842
  events: scopedEvents,
61843
+ venueDrawing: props$1.venueDrawing ?? null,
61627
61844
  showVenue: presentation.showVenue,
61628
61845
  showMap: presentation.showMap,
61629
61846
  showOtherDates: presentation.showOtherDates,
@@ -61910,9 +62127,8 @@ var EventCombined_server_default = EventCombinedSSR;
61910
62127
  //#endregion
61911
62128
  //#region ../blocks/src/system/blocks/offerings-preview/itemData.ts
61912
62129
  function buildItemDataMap(props$1) {
61913
- const routeCandidates = props$1.routeCandidates?.routes ?? [];
61914
62130
  const entries = OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS.map((definition$1) => [definition$1.sourceKey, eventDataFromMaybeArray(props$1[definition$1.dataKey])]);
61915
- return new Map([...entries, ["course", runDataFromMaybeArray(props$1.wholeSeriesRunEvents, routeCandidates)]]);
62131
+ return new Map([...entries, ["course", runDataFromMaybeArray(props$1.wholeSeriesRunEvents)]]);
61916
62132
  }
61917
62133
  function eventDataFromMaybeArray(events) {
61918
62134
  return events ? {
@@ -61926,7 +62142,7 @@ function eventDataFromMaybeArray(events) {
61926
62142
  reason: "not_loaded"
61927
62143
  };
61928
62144
  }
61929
- function runDataFromMaybeArray(events, routes) {
62145
+ function runDataFromMaybeArray(events) {
61930
62146
  if (!events) return {
61931
62147
  kind: "failed",
61932
62148
  reason: "not_loaded"
@@ -61934,7 +62150,7 @@ function runDataFromMaybeArray(events, routes) {
61934
62150
  const items = [...groupPublicEventsByRun(events)].map((run) => ({
61935
62151
  kind: "run",
61936
62152
  run,
61937
- path: resolveOfferingsPreviewRunPath(run.run, routes)
62153
+ path: run.representative.destination.kind === "native" ? run.representative.destination.path : null
61938
62154
  }));
61939
62155
  return {
61940
62156
  kind: "ready",
@@ -61965,9 +62181,9 @@ function buildLoadedOfferingsPreviewListing(input) {
61965
62181
  //#endregion
61966
62182
  //#region ../blocks/src/system/runtime/nodes/events/shared/offeringNextDates.ts
61967
62183
  /** One occurrence batch supplies every occurrence-targeted card in the block. */
61968
- function offeringDatesBySeries(events, now) {
62184
+ function offeringDatesBySeries(events, now, booking) {
61969
62185
  const groups = events.reduce((result, event) => new Map([...result, [event.seriesId, [...result.get(event.seriesId) ?? [], event]]]), new Map());
61970
- 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))]));
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))]));
61971
62187
  }
61972
62188
  /** Whole-series sessions share the run-level booking capacity, by contract. */
61973
62189
  function offeringRunDates(event, now) {
@@ -61975,7 +62191,7 @@ function offeringRunDates(event, now) {
61975
62191
  const nextStart = nextLiveRunSessionStartMs(event.run.sessions, now);
61976
62192
  return nextStart === null ? [] : orderedLiveRunSessions(event.run.sessions).filter((session) => Date.parse(session.startsAt) >= nextStart).slice(0, 3).map((session) => offeringDateRow(session, event));
61977
62193
  }
61978
- function offeringDateRow(session, event) {
62194
+ function offeringDateRow(session, event, booking) {
61979
62195
  const options = eventDateOptions({
61980
62196
  ...event,
61981
62197
  timeZone: session.timeZone
@@ -61983,9 +62199,12 @@ function offeringDateRow(session, event) {
61983
62199
  const date = formatEventCompactDateRail(session.startsAt, options, "as-written");
61984
62200
  const capacity = getEventAvailability(event);
61985
62201
  const status = getEventAvailabilityStatus(event);
62202
+ const label = `${date.weekday} ${date.day} ${date.month}, ${formatTime(session.startsAt, options)}`;
62203
+ const bookingLink = booking?.(event, label) ?? null;
61986
62204
  return {
61987
62205
  startsAt: session.startsAt,
61988
- label: `${date.weekday} ${date.day} ${date.month}, ${formatTime(session.startsAt, options)}`,
62206
+ label,
62207
+ ...bookingLink ? { booking: bookingLink } : {},
61989
62208
  places: capacity.available === null ? null : {
61990
62209
  label: capacity.isFull ? "Sold out" : `${capacity.available} place${capacity.available === 1 ? "" : "s"} left`,
61991
62210
  status: capacity.isFull ? "full" : status.status === "filling" ? "low" : "available"
@@ -62004,6 +62223,10 @@ function OfferingsCatalogue(props$1) {
62004
62223
  presets: props$1.bookingOfferingPresets,
62005
62224
  events: props$1.catalogueEvents
62006
62225
  });
62226
+ const shape = offeringsCatalogueShape(state, {
62227
+ listDates: props$1.lookSlots !== undefined && props$1.datesMode === "next-dates",
62228
+ oneOfferingRequested: props$1.oneOffering === true
62229
+ });
62007
62230
  switch (state.kind) {
62008
62231
  case "no-groups": return renderCatalogueEmpty({
62009
62232
  props: props$1,
@@ -62016,7 +62239,8 @@ function OfferingsCatalogue(props$1) {
62016
62239
  case "by-date": return renderCatalogueMergedList({
62017
62240
  props: props$1,
62018
62241
  listing: state,
62019
- now
62242
+ now,
62243
+ shape
62020
62244
  });
62021
62245
  case "by-type": return props$1.lookSlots ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
62022
62246
  ...listLookSlot(props$1, "layout"),
@@ -62029,26 +62253,37 @@ function OfferingsCatalogue(props$1) {
62029
62253
  now,
62030
62254
  children: undefined
62031
62255
  },
62032
- groups: state.groups
62256
+ groups: state.groups,
62257
+ shape
62033
62258
  }) })]
62034
62259
  }) : renderOfferingsCatalogueGroups({
62035
62260
  props: {
62036
62261
  ...props$1,
62037
62262
  now
62038
62263
  },
62039
- groups: state.groups
62264
+ groups: state.groups,
62265
+ shape
62040
62266
  });
62041
62267
  default: return assertNever(state);
62042
62268
  }
62043
62269
  }
62044
- function renderOfferingsCatalogueGroups({ props: props$1, groups }) {
62270
+ /** The hook the single-offering layout hangs from; absent for several. */
62271
+ function catalogueShapeHook(shape) {
62272
+ return shape === "single" ? { "data-has-one-offering": "true" } : {};
62273
+ }
62274
+ /** One offering has room for a Book link on each date; several keep plain rows. */
62275
+ function catalogueDateBooking(shape, pathname) {
62276
+ return shape === "single" ? (event, dateLabel$1) => eventDateBookingLink(event, pathname ?? "/", dateLabel$1) : undefined;
62277
+ }
62278
+ function renderOfferingsCatalogueGroups({ props: props$1, groups, shape }) {
62045
62279
  const enabledSeriesIds = new Set(groups.flatMap((load) => load.kind === "items" ? load.items.map((item) => item.kind === "event" ? item.event.seriesId : item.run.eventSeriesId) : []));
62046
- const quickDateEvents = selectQuickDateEvents((props$1.quickDateEvents ?? []).filter((event) => enabledSeriesIds.has(event.seriesId)));
62280
+ const quickDateEvents = shape === "single" ? [] : selectQuickDateEvents((props$1.quickDateEvents ?? []).filter((event) => enabledSeriesIds.has(event.seriesId)));
62047
62281
  const populated = groups.flatMap(catalogueGroupItems);
62048
62282
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
62049
62283
  className: "offerings-preview rb-flex rb-flex-col rb-gap-6",
62050
62284
  "data-block": "offerings-preview",
62051
62285
  "data-offerings-mode": "catalogue",
62286
+ ...catalogueShapeHook(shape),
62052
62287
  children: [
62053
62288
  quickDateEvents.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
62054
62289
  className: "offerings-preview-quick-dates rb-flex rb-flex-col rb-gap-4",
@@ -62065,28 +62300,30 @@ function renderOfferingsCatalogueGroups({ props: props$1, groups }) {
62065
62300
  children: populated.map(({ group, items }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", {
62066
62301
  className: "rb-flex rb-flex-col rb-gap-5",
62067
62302
  "data-offering-source": group.sourceKey,
62068
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", {
62303
+ children: [shape === "single" ? null : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", {
62069
62304
  ...listLookSlot(props$1, "heading"),
62070
62305
  children: group.title
62071
62306
  }), renderCatalogueItems({
62072
62307
  props: props$1,
62073
- items
62308
+ items,
62309
+ shape,
62310
+ groupTitle: group.title
62074
62311
  })]
62075
62312
  }, group.sourceKey))
62076
62313
  })
62077
62314
  ]
62078
62315
  });
62079
62316
  }
62080
- function renderCatalogueItems({ props: props$1, items }) {
62317
+ function renderCatalogueItems({ props: props$1, items, shape, groupTitle }) {
62081
62318
  const events = items.map((item) => item.kind === "event" ? item.event : item.run.representative);
62082
62319
  if (props$1.lookSlots) {
62083
62320
  const now = props$1.now;
62084
- const dates = offeringDatesBySeries(props$1.quickDateEvents ?? [], now);
62321
+ const dates = offeringDatesBySeries(props$1.quickDateEvents ?? [], now, catalogueDateBooking(shape, props$1.pathname));
62085
62322
  return CardListItems({
62086
62323
  Carousel: props$1.Carousel,
62087
- Title: "h4",
62324
+ Title: shape === "single" ? "h3" : "h4",
62088
62325
  presentation: props$1,
62089
- items: items.map((item) => catalogueCardContent(item, now, dates))
62326
+ items: items.map((item) => catalogueCardContent(item, now, dates, shape === "single" ? groupTitle : undefined))
62090
62327
  });
62091
62328
  }
62092
62329
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
@@ -62121,11 +62358,12 @@ function renderCatalogueEmpty({ props: props$1, failed }) {
62121
62358
  })]
62122
62359
  });
62123
62360
  }
62124
- function renderCatalogueMergedList({ props: props$1, listing, now }) {
62125
- const dates = offeringDatesBySeries(props$1.quickDateEvents ?? [], now);
62361
+ function renderCatalogueMergedList({ props: props$1, listing, now, shape }) {
62362
+ const dates = offeringDatesBySeries(props$1.quickDateEvents ?? [], now, catalogueDateBooking(shape, props$1.pathname));
62126
62363
  const items = listing.items.map(({ item, group }) => catalogueCardContent(item, now, dates, group.singularLabel));
62127
62364
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
62128
62365
  ...listLookSlot(props$1, "layout"),
62366
+ ...catalogueShapeHook(shape),
62129
62367
  children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("header", {
62130
62368
  ...listLookSlot(props$1, "head"),
62131
62369
  children: props$1.children
@@ -68810,6 +69048,7 @@ function planArrangementContent(blockKind, manifest, content, audience) {
68810
69048
  });
68811
69049
  return {
68812
69050
  ...activeContent,
69051
+ ...mode !== null ? { variant: mode } : {},
68813
69052
  ...effectiveContent,
68814
69053
  ...photoContent,
68815
69054
  ...arrangementShapeContent(effective.look.id, {
@@ -68922,6 +69161,7 @@ function applyArrangementRhythm(entry, position) {
68922
69161
  const tinted = resolveArrangementTints(updated$1, grounded, runtime, surface) ?? grounded;
68923
69162
  return {
68924
69163
  ...entry,
69164
+ styleBackground: arrangementGroundToken(resolveSectionBackground({ kind: "none" }, null, rhythm)),
68925
69165
  renderableContent: {
68926
69166
  ...updated$1,
68927
69167
  _effectiveLook: tinted,
@@ -77805,7 +78045,7 @@ function parseJson(text$1) {
77805
78045
  }
77806
78046
  /** The revision a push must present: whatever the page holds right now. */
77807
78047
  function expectedRevisionFor(read) {
77808
- return read.kind === "absent" ? { kind: "absent" } : read.revision;
78048
+ return read.revision;
77809
78049
  }
77810
78050
  /** Plain data with object keys in a fixed order, so equal designs compare equal. */
77811
78051
  function canonical(value) {
@@ -79792,7 +80032,7 @@ async function loadConfig(configPath, output) {
79792
80032
  return { errorMessage: "No config path provided." };
79793
80033
  }
79794
80034
  try {
79795
- const { loadConfigFile: loadConfigFile$1 } = await import("../load-config-BGzlsmtt.mjs");
80035
+ const { loadConfigFile: loadConfigFile$1 } = await import("../load-config-DAdJwh-i.mjs");
79796
80036
  const rawConfig = await loadConfigFile$1(configPath);
79797
80037
  const parsed = riverbankSiteConfigSchema.safeParse(rawConfig);
79798
80038
  if (!parsed.success) {
@@ -79877,64 +80117,6 @@ const createInitDocsCommand = () => new Command("init-docs").description("Scaffo
79877
80117
  await runInitDocs(options, command);
79878
80118
  }));
79879
80119
 
79880
- //#endregion
79881
- //#region src/commands/identifiers.ts
79882
- /**
79883
- * Identifiers Command
79884
- *
79885
- * Manage SDK identifiers for pages, blocks, and entries.
79886
- *
79887
- * Usage:
79888
- * riverbankcms identifiers backfill # Backfill identifiers for content without them
79889
- */
79890
- function createBackfillCommand() {
79891
- return new Command("backfill").description("Backfill identifiers for pages, blocks, and entries that don't have one").addHelpText("after", `
79892
- This command generates stable identifiers for content created before the SDK was available.
79893
- Identifiers are generated from titles (slugified) and are idempotent - running this
79894
- command multiple times won't overwrite existing identifiers.
79895
-
79896
- Examples:
79897
- $ riverbankcms identifiers backfill
79898
- $ riverbankcms identifiers backfill --env=remote
79899
- `).action(withErrorHandling(async (_options, command) => {
79900
- const { output, client } = createCommandContext(command);
79901
- output.info("Backfilling identifiers for pages, blocks, and entries...");
79902
- const result = await client.identifiers.backfill();
79903
- const totalUpdated = result.pages.pagesUpdated + result.blocks.total + result.entries.entriesUpdated;
79904
- if (totalUpdated === 0) {
79905
- output.success("All content already has identifiers - nothing to backfill");
79906
- return;
79907
- }
79908
- output.success("Backfill complete", {
79909
- pages: {
79910
- updated: result.pages.pagesUpdated,
79911
- identifiers: result.pages.identifiersAssigned
79912
- },
79913
- blocks: {
79914
- updated: result.blocks.total,
79915
- byPage: Object.keys(result.blocks.byPage).length > 0 ? result.blocks.byPage : undefined
79916
- },
79917
- entries: {
79918
- updated: result.entries.entriesUpdated,
79919
- identifiers: result.entries.identifiersAssigned
79920
- }
79921
- });
79922
- }));
79923
- }
79924
- function createIdentifiersCommand() {
79925
- return new Command("identifiers").description("Manage SDK identifiers").addHelpText("after", `
79926
- Identifiers are stable, human-readable names used to reference content in the SDK.
79927
- They are automatically generated when content is created via the SDK, but older
79928
- content may need backfilling.
79929
-
79930
- Commands:
79931
- backfill Generate identifiers for content that doesn't have one
79932
-
79933
- Examples:
79934
- $ riverbankcms identifiers backfill
79935
- `).addCommand(createBackfillCommand());
79936
- }
79937
-
79938
80120
  //#endregion
79939
80121
  //#region src/constants.ts
79940
80122
  /** Default directory used by the deploy command for generated prebuild data. */
@@ -91189,6 +91371,13 @@ function parsePreviewRefreshResponse(value) {
91189
91371
  };
91190
91372
  }
91191
91373
  const previewStopRequestSchema = z.object({ accessToken: z.string().min(1).max(8192) }).strict();
91374
+ /** Shared by the framed frontend reporter and the dashboard receiver. */
91375
+ const previewFrameHeightMessageSchema = z.object({
91376
+ type: z.literal("riverbank:preview-height"),
91377
+ height: z.number().finite().positive()
91378
+ }).strict();
91379
+ /** Sent by a framed request that has no preview authority, so the dashboard stops waiting. */
91380
+ const previewFrameFailedMessageSchema = z.object({ type: z.literal("riverbank:preview-failed") }).strict();
91192
91381
 
91193
91382
  //#endregion
91194
91383
  //#region ../api/src/footerSettings.ts
@@ -91289,6 +91478,7 @@ const allowedPathPrefixes = [
91289
91478
  "/sites/{siteId}/bookings/event-offerings",
91290
91479
  "/sites/{siteId}/bookings/event-series",
91291
91480
  "/sites/{siteId}/bookings/event-attendees",
91481
+ "/sites/{siteId}/bookings/attendees/",
91292
91482
  "/sites/{siteId}/bookings/event-categories",
91293
91483
  "/sites/{siteId}/bookings/venues",
91294
91484
  "/sites/{siteId}/location/geocode",
@@ -92982,22 +93172,6 @@ const DEFAULT_ANALYTICS_COOKIE_BANNER_COPY = {
92982
93172
  policyLinkLabel: "Cookie policy"
92983
93173
  };
92984
93174
 
92985
- //#endregion
92986
- //#region ../api/src/eventAttendanceLabels.ts
92987
- function getEventAttendanceModeLabel(mode) {
92988
- switch (mode) {
92989
- case "in_person": return "In person";
92990
- case "online": return "Online";
92991
- }
92992
- }
92993
- function getEventDeliveryModeLabel(mode) {
92994
- switch (mode) {
92995
- case "in_person": return "In person";
92996
- case "online": return "Online";
92997
- case "hybrid": return "In person and online";
92998
- }
92999
- }
93000
-
93001
93175
  //#endregion
93002
93176
  //#region ../api/src/siteBanner.ts
93003
93177
  const SITE_BANNER_SCOPE_VALUES = ["homepage", "all-pages"];
@@ -93417,6 +93591,14 @@ function isSiteBannerTone(value) {
93417
93591
 
93418
93592
  //#endregion
93419
93593
  //#region ../api/src/privacyPolicy.ts
93594
+ const SITE_LEGAL_JURISDICTIONS = [
93595
+ "UK",
93596
+ "US",
93597
+ "EU",
93598
+ "CA",
93599
+ "AU",
93600
+ "OTHER"
93601
+ ];
93420
93602
  /**
93421
93603
  * A legal profile saved before the source flags existed carries values an
93422
93604
  * administrator typed by hand, so a saved value is an override and only an
@@ -93457,6 +93639,17 @@ function isSitePrivacyIdentityReady(identity) {
93457
93639
  return identity.entityName !== null;
93458
93640
  }
93459
93641
  /**
93642
+ * Whether a site links to and serves its managed privacy policy. An
93643
+ * administrator has to have turned it on, and it has to be able to name a
93644
+ * controller. Every producer of the link calls this.
93645
+ */
93646
+ function resolveManagedPrivacyPolicyLink(input) {
93647
+ return {
93648
+ path: MANAGED_PRIVACY_POLICY_PATH,
93649
+ enabled: input.isPublished && isSitePrivacyIdentityReady(input.identity)
93650
+ };
93651
+ }
93652
+ /**
93460
93653
  * EU member states, used both to place a site in the EU privacy jurisdiction
93461
93654
  * and to seed the shop's default shipping countries.
93462
93655
  */
@@ -93881,6 +94074,11 @@ async function restorePageVersion(apiClient, input) {
93881
94074
  }));
93882
94075
  }
93883
94076
 
94077
+ //#endregion
94078
+ //#region ../api/src/contentVersionHistory.ts
94079
+ /** Page restore uses the journal's document revision; entries retain their own draft marker. */
94080
+ const restorePageVersionRequestSchema = z.object({ expectedRevision: z.number().int().nonnegative() }).strict();
94081
+
93884
94082
  //#endregion
93885
94083
  //#region ../api/src/blocksKeys.ts
93886
94084
  const blocksKeys = {
@@ -94145,8 +94343,7 @@ async function mutateBlockContent(apiClient, args) {
94145
94343
  const payload$1 = {
94146
94344
  data: args.data,
94147
94345
  optimistic_hash: args.optimisticHash ?? undefined,
94148
- expected_entry_slot_hash: args.expectedEntrySlotHash,
94149
- expected_surface_slot_hash: args.expectedSurfaceSlotHash,
94346
+ expected_slot_hash: args.expectedSlotHash,
94150
94347
  expected_mailing_list_provider_scope: args.expectedMailingListProviderScope
94151
94348
  };
94152
94349
  return unwrapResponse(await apiClient({
@@ -94160,8 +94357,7 @@ async function mutateBlockContent(apiClient, args) {
94160
94357
  path: args.path,
94161
94358
  value: args.value,
94162
94359
  optimistic_hash: args.optimisticHash ?? undefined,
94163
- expected_entry_slot_hash: args.expectedEntrySlotHash,
94164
- expected_surface_slot_hash: args.expectedSurfaceSlotHash,
94360
+ expected_slot_hash: args.expectedSlotHash,
94165
94361
  expected_mailing_list_provider_scope: args.expectedMailingListProviderScope
94166
94362
  };
94167
94363
  return unwrapResponse(await apiClient({
@@ -94284,6 +94480,16 @@ async function updateRouteMetadata(apiClient, { siteId, routeId, body, options }
94284
94480
  return normalizeApiError(error$1, "Failed to update route metadata");
94285
94481
  }
94286
94482
  }
94483
+ /** Metadata has one canonical editor representation, including an empty homepage slug. */
94484
+ function savedRouteMetadataValues(route) {
94485
+ return {
94486
+ draftTitle: route.draftTitle,
94487
+ draftSlug: route.draftSlug ?? "",
94488
+ draftMetaTitle: route.draftMetaTitle ?? null,
94489
+ draftMetaDescription: route.draftMetaDescription ?? null,
94490
+ ogImageId: route.ogImageId ?? null
94491
+ };
94492
+ }
94287
94493
 
94288
94494
  //#endregion
94289
94495
  //#region ../api/src/emailSettings.ts
@@ -94858,16 +95064,6 @@ async function changePlan(apiClient, request) {
94858
95064
  return normalizeApiError(error$1, "Failed to update billing plan");
94859
95065
  }
94860
95066
  }
94861
- async function createBillingPortalSession(apiClient, options) {
94862
- try {
94863
- return unwrapResponse(await apiClient({
94864
- endpoint: "createBillingPortalSession",
94865
- options
94866
- }));
94867
- } catch (error$1) {
94868
- return normalizeApiError(error$1, "Failed to open billing details");
94869
- }
94870
- }
94871
95067
  async function billingCheckout(apiClient, { attemptId, planId, continuation, options }) {
94872
95068
  try {
94873
95069
  return unwrapResponse(await apiClient({
@@ -94890,9 +95086,8 @@ async function billingCheckout(apiClient, { attemptId, planId, continuation, opt
94890
95086
  //#endregion
94891
95087
  //#region ../api/src/aiPlayground.ts
94892
95088
  const PreparedPagePreconditionSchema = z.object({
94893
- schemaVersion: z.literal(1),
94894
95089
  pageId: z.string().uuid(),
94895
- fingerprint: z.string().regex(/^[a-f0-9]{64}$/)
95090
+ revision: z.number().int().nonnegative()
94896
95091
  }).strict();
94897
95092
  /**
94898
95093
  * RFC-6902 JSON Patch Operations
@@ -99168,7 +99363,6 @@ function createProgram(dependencies = {}) {
99168
99363
  program.addCommand(createContentCommand());
99169
99364
  program.addCommand(createDraftsCommand());
99170
99365
  program.addCommand(createInitDocsCommand());
99171
- program.addCommand(createIdentifiersCommand());
99172
99366
  program.addCommand(createDeployCommand());
99173
99367
  program.addCommand(createContentTypeCommand());
99174
99368
  program.addCommand(createVerifyCommand());